/* * Copyright (C) 2012-2017 CypherCore * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using Framework.Constants; using Game.AI; using Game.Entities; using Game.Scripting; using Game.Spells; using System; namespace Scripts.World { public struct GuardsConst { public const int CreatureCooldown = 5000; public const int SaySilAggro = 0; } struct CreatureIds { public const int CenarionHoldIndantry = 15184; public const int StormwindCityGuard = 68; public const int StormwindCityPatroller = 1976; public const int OrgimmarGrunt = 3296; } struct Spells { public const uint BanishedA = 36642; public const uint BanishedS = 36671; public const uint BanishTeleport = 36643; public const uint Exile = 39533; } [Script] class guard_generic : CreatureScript { public guard_generic() : base("guard_generic") { } class guard_genericAI : GuardAI { public guard_genericAI(Creature creature) : base(creature) { } public override void Reset() { globalCooldown = 0; buffTimer = 0; } public override void EnterCombat(Unit who) { if (me.GetEntry() == CreatureIds.CenarionHoldIndantry) Talk(GuardsConst.SaySilAggro, who); SpellInfo spell = me.reachWithSpellAttack(who); if (spell != null) DoCast(who, spell.Id); } public override void UpdateAI(uint 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 (me.IsAlive() && !me.IsInCombat()) { if (buffTimer <= diff) { //Find a spell that targets friendly and applies an aura (these are generally buffs) SpellInfo info = SelectSpell(me, 0, 0, SelectTargetType.AnyFriend, 0, 0, SelectEffect.Aura); if (info != null && globalCooldown == 0) { //Cast the buff spell DoCast(me, info.Id); //Set our global cooldown globalCooldown = GuardsConst.CreatureCooldown; //Set our timer to 10 minutes before rebuff buffTimer = 600000; } //Try again in 30 seconds else buffTimer = 30000; } else buffTimer -= diff; } //Return since we have no target if (!UpdateVictim()) return; // Make sure our attack is ready and we arn't currently casting if (me.isAttackReady() && !me.IsNonMeleeSpellCast(false)) { //If we are within range melee the target if (me.IsWithinMeleeRange(me.GetVictim())) { bool healing = false; SpellInfo info = null; //Select a healing spell if less than 30% hp if (me.HealthBelowPct(30)) info = SelectSpell(me, 0, 0, SelectTargetType.AnyFriend, 0, 0, SelectEffect.Healing); //No healing spell available, select a hostile spell if (info != null) healing = true; else info = SelectSpell(me.GetVictim(), 0, 0, SelectTargetType.AnyEnemy, 0, 0, SelectEffect.DontCare); //20% chance to replace our white hit with a spell if (info != null && RandomHelper.IRand(0, 99) < 20 && globalCooldown == 0) { //Cast the spell if (healing) DoCast(me, info.Id); else DoCastVictim(info.Id); //Set our global cooldown globalCooldown = GuardsConst.CreatureCooldown; } else me.AttackerStateUpdate(me.GetVictim()); me.resetAttackTimer(); } } else { //Only run this code if we arn't already casting if (!me.IsNonMeleeSpellCast(false)) { bool healing = false; SpellInfo info = null; //Select a healing spell if less than 30% hp ONLY 33% of the time if (me.HealthBelowPct(30) && 33 > RandomHelper.IRand(0, 99)) info = SelectSpell(me, 0, 0, SelectTargetType.AnyFriend, 0, 0, SelectEffect.Healing); //No healing spell available, See if we can cast a ranged spell (Range must be greater than ATTACK_DISTANCE) if (info != null) healing = true; else info = SelectSpell(me.GetVictim(), 0, 0, SelectTargetType.AnyEnemy, SharedConst.NominalMeleeRange, 0, SelectEffect.DontCare); //Found a spell, check if we arn't on cooldown if (info != null && globalCooldown == 0) { //If we are currently moving stop us and set the movement generator if (me.GetMotionMaster().GetCurrentMovementGeneratorType() != MovementGeneratorType.Idle) { me.GetMotionMaster().Clear(false); me.GetMotionMaster().MoveIdle(); } //Cast spell if (healing) DoCast(me, info.Id); else DoCastVictim(info.Id); //Set our global cooldown globalCooldown = GuardsConst.CreatureCooldown; } //If no spells available and we arn't moving run to target else if (me.GetMotionMaster().GetCurrentMovementGeneratorType() != MovementGeneratorType.Chase) { //Cancel our current spell and then mutate new movement generator me.InterruptNonMeleeSpells(false); me.GetMotionMaster().Clear(false); me.GetMotionMaster().MoveChase(me.GetVictim()); } } } DoMeleeAttackIfReady(); } public void DoReplyToTextEmote(TextEmotes emote) { switch (emote) { case TextEmotes.Kiss: me.HandleEmoteCommand(Emote.OneshotBow); break; case TextEmotes.Wave: me.HandleEmoteCommand(Emote.OneshotWave); break; case TextEmotes.Salute: me.HandleEmoteCommand(Emote.OneshotSalute); break; case TextEmotes.Shy: me.HandleEmoteCommand(Emote.OneshotFlex); break; case TextEmotes.Rude: case TextEmotes.Chicken: me.HandleEmoteCommand(Emote.OneshotPoint); break; } } public override void ReceiveEmote(Player player, TextEmotes textEmote) { switch (me.GetEntry()) { case CreatureIds.StormwindCityGuard: case CreatureIds.StormwindCityPatroller: case CreatureIds.OrgimmarGrunt: break; default: return; } if (!me.IsFriendlyTo(player)) return; DoReplyToTextEmote(textEmote); } uint globalCooldown; uint buffTimer; } public override CreatureAI GetAI(Creature creature) { return new guard_genericAI(creature); } } [Script] class guard_shattrath_scryer : CreatureScript { public guard_shattrath_scryer() : base("guard_shattrath_scryer") { } class guard_shattrath_scryerAI : GuardAI { public guard_shattrath_scryerAI(Creature creature) : base(creature) { } public override void Reset() { playerGUID.Clear(); canTeleport = false; _scheduler.Schedule(TimeSpan.FromSeconds(5), task => { Unit temp = me.GetVictim(); if (temp && temp.IsTypeId(TypeId.Player)) { DoCast(temp, Spells.BanishedA); playerGUID = temp.GetGUID(); if (!playerGUID.IsEmpty()) canTeleport = true; task.Repeat(TimeSpan.FromSeconds(9)); } }); _scheduler.Schedule(TimeSpan.FromSeconds(8.5), task => { if (canTeleport) { Unit temp = Global.ObjAccessor.GetUnit(me, playerGUID); if (temp) { temp.CastSpell(temp, Spells.Exile, true); temp.CastSpell(temp, Spells.BanishTeleport, true); } playerGUID.Clear(); canTeleport = false; task.Repeat(); } }); } public override void UpdateAI(uint diff) { if (!UpdateVictim()) return; _scheduler.Update(diff); DoMeleeAttackIfReady(); } ObjectGuid playerGUID; bool canTeleport; } public override CreatureAI GetAI(Creature creature) { return new guard_shattrath_scryerAI(creature); } } [Script] class guard_shattrath_aldor : CreatureScript { public guard_shattrath_aldor() : base("guard_shattrath_aldor") { } class guard_shattrath_aldorAI : GuardAI { public guard_shattrath_aldorAI(Creature creature) : base(creature) { } public override void Reset() { playerGUID.Clear(); canTeleport = false; _scheduler.Schedule(TimeSpan.FromSeconds(5), task => { Unit temp = me.GetVictim(); if (temp && temp.IsTypeId(TypeId.Player)) { DoCast(temp, Spells.BanishedA); playerGUID = temp.GetGUID(); if (!playerGUID.IsEmpty()) canTeleport = true; task.Repeat(TimeSpan.FromSeconds(9)); } }); _scheduler.Schedule(TimeSpan.FromSeconds(8.5), task => { if (canTeleport) { Unit temp = Global.ObjAccessor.GetUnit(me, playerGUID); if (temp) { temp.CastSpell(temp, Spells.Exile, true); temp.CastSpell(temp, Spells.BanishTeleport, true); } playerGUID.Clear(); canTeleport = false; task.Repeat(); } }); } public override void UpdateAI(uint diff) { if (!UpdateVictim()) return; _scheduler.Update(diff); DoMeleeAttackIfReady(); } ObjectGuid playerGUID; bool canTeleport; } public override CreatureAI GetAI(Creature creature) { return new guard_shattrath_aldorAI(creature); } } }