Files
CypherCore/Source/Scripts/World/NpcSpecial.cs
T

2354 lines
88 KiB
C#

/*
* Copyright (C) 2012-2020 CypherCore <http://github.com/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 <http://www.gnu.org/licenses/>.
*/
using Framework.Constants;
using Framework.GameMath;
using Game;
using Game.AI;
using Game.Entities;
using Game.Maps;
using Game.Scripting;
using Game.Spells;
using System;
using System.Collections.Generic;
using System.Linq;
using Framework.Dynamic;
using Game.Movement;
namespace Scripts.World.NpcSpecial
{
enum SpawnType
{
TripwireRooftop, // no warning, summon Creature at smaller range
AlarmBot, // cast guards mark and summon npc - if player shows up with that buff duration < 5 seconds attack
}
class SpawnAssociation
{
public SpawnAssociation(uint _thisCreatureEntry, uint _spawnedCreatureEntry, SpawnType _spawnType)
{
thisCreatureEntry = _thisCreatureEntry;
spawnedCreatureEntry = _spawnedCreatureEntry;
spawnType = _spawnType;
}
public uint thisCreatureEntry;
public uint spawnedCreatureEntry;
public SpawnType spawnType;
}
struct CreatureIds
{
//Torchtossingtarget
public const uint TorchTossingTargetBunny = 25535;
//Garments
public const uint Shaya = 12429;
public const uint Roberts = 12423;
public const uint Dolf = 12427;
public const uint Korja = 12430;
public const uint DgKel = 12428;
//Doctor
public const uint DoctorAlliance = 12939;
public const uint DoctorHorde = 12920;
//Fireworks
public const uint Omen = 15467;
public const uint MinionOfOmen = 15466;
public const uint FireworkBlue = 15879;
public const uint FireworkGreen = 15880;
public const uint FireworkPurple = 15881;
public const uint FireworkRed = 15882;
public const uint FireworkYellow = 15883;
public const uint FireworkWhite = 15884;
public const uint FireworkBigBlue = 15885;
public const uint FireworkBigGreen = 15886;
public const uint FireworkBigPurple = 15887;
public const uint FireworkBigRed = 15888;
public const uint FireworkBigYellow = 15889;
public const uint FireworkBigWhite = 15890;
public const uint ClusterBlue = 15872;
public const uint ClusterRed = 15873;
public const uint ClusterGreen = 15874;
public const uint ClusterPurple = 15875;
public const uint ClusterWhite = 15876;
public const uint ClusterYellow = 15877;
public const uint ClusterBigBlue = 15911;
public const uint ClusterBigGreen = 15912;
public const uint ClusterBigPurple = 15913;
public const uint ClusterBigRed = 15914;
public const uint ClusterBigWhite = 15915;
public const uint ClusterBigYellow = 15916;
public const uint ClusterElune = 15918;
// Rabbitspells
public const uint SpringRabbit = 32791;
// TrainWrecker
public const uint ExultingWindUpTrainWrecker = 81071;
// Argent squire/gruntling
public const uint ArgentSquire = 33238;
// BountifulTable
public const uint TheTurkeyChair = 34812;
public const uint TheCranberryChair = 34823;
public const uint TheStuffingChair = 34819;
public const uint TheSweetPotatoChair = 34824;
public const uint ThePieChair = 34822;
}
struct GameobjectIds
{
//Fireworks
public const uint FireworkLauncher1 = 180771;
public const uint FireworkLauncher2 = 180868;
public const uint FireworkLauncher3 = 180850;
public const uint ClusterLauncher1 = 180772;
public const uint ClusterLauncher2 = 180859;
public const uint ClusterLauncher3 = 180869;
public const uint ClusterLauncher4 = 180874;
//TrainWrecker
public const uint ToyTrain = 193963;
//RibbonPole
public const uint RibbonPole = 181605;
}
struct SpellIds
{
public const uint GuardsMark = 38067;
//Dancingflames
public const uint Brazier = 45423;
public const uint Seduction = 47057;
public const uint FieryAura = 45427;
//RibbonPole
public const uint RibbonDanceCosmetic = 29726;
public const uint RedFireRing = 46836;
public const uint BlueFireRing = 46842;
//Torchtossingtarget
public const uint TargetIndicator = 45723;
//Garments
public const uint LesserHealR2 = 2052;
public const uint FortitudeR1 = 1243;
//Guardianspells
public const uint Deathtouch = 5;
//Sayge
public const uint Strength = 23735; // +10% Strength
public const uint Agility = 23736; // +10% Agility
public const uint Stamina = 23737; // +10% Stamina
public const uint Spirit = 23738; // +10% Spirit
public const uint Intellect = 23766; // +10% Intellect
public const uint Armor = 23767; // +10% Armor
public const uint Damage = 23768; // +10% Damage
public const uint Resistance = 23769; // +25 Magic Resistance (All)
public const uint Fortune = 23765; // Darkmoon Faire Fortune
//Tonkmine
public const uint TonkMineDetonate = 25099;
//Brewfestreveler
public const uint BrewfestToast = 41586;
//Wormholespells
public const uint BoreanTundra = 67834;
public const uint SholazarBasin = 67835;
public const uint Icecrown = 67836;
public const uint StormPeaks = 67837;
public const uint HowlingFjord = 67838;
public const uint Underground = 68081;
//Fireworks
public const uint RocketBlue = 26344;
public const uint RocketGreen = 26345;
public const uint RocketPurple = 26346;
public const uint RocketRed = 26347;
public const uint RocketWhite = 26348;
public const uint RocketYellow = 26349;
public const uint RocketBigBlue = 26351;
public const uint RocketBigGreen = 26352;
public const uint RocketBigPurple = 26353;
public const uint RocketBigRed = 26354;
public const uint RocketBigWhite = 26355;
public const uint RocketBigYellow = 26356;
public const uint LunarFortune = 26522;
//Rabbitspells
public const uint SpringFling = 61875;
public const uint SpringRabbitJump = 61724;
public const uint SpringRabbitWander = 61726;
public const uint SummonBabyBunny = 61727;
public const uint SpringRabbitInLove = 61728;
//TrainWrecker
public const uint ToyTrainPulse = 61551;
public const uint WreckTrain = 62943;
//Argent squire/gruntling
public const uint DarnassusPennant = 63443;
public const uint ExodarPennant = 63439;
public const uint GnomereganPennant = 63442;
public const uint IronforgePennant = 63440;
public const uint StormwindPennant = 62727;
public const uint SenjinPennant = 63446;
public const uint UndercityPennant = 63441;
public const uint OrgrimmarPennant = 63444;
public const uint SilvermoonPennant = 63438;
public const uint ThunderbluffPennant = 63445;
public const uint AuraPostmanS = 67376;
public const uint AuraShopS = 67377;
public const uint AuraBankS = 67368;
public const uint AuraTiredS = 67401;
public const uint AuraBankG = 68849;
public const uint AuraPostmanG = 68850;
public const uint AuraShopG = 68851;
public const uint AuraTiredG = 68852;
public const uint TiredPlayer = 67334;
//BountifulTable
public const uint CranberryServer = 61793;
public const uint PieServer = 61794;
public const uint StuffingServer = 61795;
public const uint TurkeyServer = 61796;
public const uint SweetPotatoesServer = 61797;
public static Dictionary<uint, uint> ChairSpells = new Dictionary<uint, uint>()
{
{ CreatureIds.TheCranberryChair, CranberryServer },
{ CreatureIds.ThePieChair, PieServer },
{ CreatureIds.TheStuffingChair, StuffingServer },
{ CreatureIds.TheTurkeyChair, TurkeyServer },
{ CreatureIds.TheSweetPotatoChair, SweetPotatoesServer },
};
}
struct QuestConst
{
//Lunaclawspirit
public const uint BodyHeartA = 6001;
public const uint BodyHeartH = 6002;
//ChickenCluck
public const uint Cluck = 3861;
//Garments
public const uint Moon = 5621;
public const uint Light1 = 5624;
public const uint Light2 = 5625;
public const uint Spirit = 5648;
public const uint Darkness = 5650;
}
struct TextIds
{
//Lunaclawspirit
public const uint TextIdDefault = 4714;
public const uint TextIdProgress = 4715;
//Chickencluck
public const uint EmoteHelloA = 0;
public const uint EmoteHelloH = 1;
public const uint EmoteCluck = 2;
//Doctor
public const uint SayDoc = 0;
// Garments
// Used By 12429; 12423; 12427; 12430; 12428; But Signed For 12429
public const uint SayThanks = 0;
public const uint SayGoodbye = 1;
public const uint SayHealed = 2;
//Wormholespells
public const uint Wormhole = 14785;
//NpcExperience
public const uint XpOnOff = 14736;
}
struct GossipMenus
{
//Sayge
public const int OptionIdAnswer1 = 0;
public const int OptionIdAnswer2 = 1;
public const int OptionIdAnswer3 = 2;
public const int OptionIdAnswer4 = 3;
public const int IAmReadyToDiscover = 6186;
public const int OptionSayge = 6185;
public const int OptionSayge2 = 6187;
public const int OptionSayge3 = 6208;
public const int OptionSayge4 = 6209;
public const int OptionSayge5 = 6210;
public const int OptionSayge6 = 6211;
public const int IHaveLongKnown = 7339;
public const int YouHaveBeenTasked = 7340;
public const int SwornExecutioner = 7341;
public const int DiplomaticMission = 7361;
public const int YourBrotherSeeks = 7362;
public const int ATerribleBeast = 7363;
public const int YourFortuneIsCast = 7364;
public const int HereIsYourFortune = 7365;
public const int CantGiveYouYour = 7393;
//Wormhole
public const int MenuIdWormhole = 10668; // "This tear in the fabric of time and space looks ominous."
public const int OptionIdWormhole1 = 0; // "Borean Tundra"
public const int OptionIdWormhole2 = 1; // "Howling Fjord"
public const int OptionIdWormhole3 = 2; // "Sholazar Basin"
public const int OptionIdWormhole4 = 3; // "Icecrown"
public const int OptionIdWormhole5 = 4; // "Storm Peaks"
public const int OptionIdWormhole6 = 5; // "Underground..."
//Lunaclawspirit
public const string ItemGrant = "You Have Thought Well; Spirit. I Ask You To Grant Me The Strength Of Your Body And The Strength Of Your Heart.";
//Pettrainer
public const uint MenuIdPetUnlearn = 6520;
public const uint OptionIdPleaseDo = 0;
//NpcExperience
public const uint MenuIdXpOnOff = 10638;
public const uint OptionIdXpOff = 0;
public const uint OptionIdXpOn = 1;
//Argent squire/gruntling
public const uint OptionIdBank = 0;
public const uint OptionIdShop = 1;
public const uint OptionIdMail = 2;
public const uint OptionIdDarnassusSenjinPennant = 3;
public const uint OptionIdExodarUndercityPennant = 4;
public const uint OptionIdGnomereganOrgrimmarPennant = 5;
public const uint OptionIdIronforgeSilvermoonPennant = 6;
public const uint OptionIdStormwindThunderbluffPennant = 7;
}
enum SeatIds
{
//BountifulTable
TurkeyChair = 0,
CranberryChair = 1,
StuffingChair = 2,
SweetPotatoChair = 3,
PieChair = 4,
FoodHolder = 5,
PlateHolder = 6
}
struct Misc
{
public static SpawnAssociation[] spawnAssociations =
{
new SpawnAssociation(2614, 15241, SpawnType.AlarmBot), //Air Force Alarm Bot (Alliance)
new SpawnAssociation(2615, 15242, SpawnType.AlarmBot), //Air Force Alarm Bot (Horde)
new SpawnAssociation(21974, 21976, SpawnType.AlarmBot), //Air Force Alarm Bot (Area 52)
new SpawnAssociation(21993, 15242, SpawnType.AlarmBot), //Air Force Guard Post (Horde - Bat Rider)
new SpawnAssociation(21996, 15241, SpawnType.AlarmBot), //Air Force Guard Post (Alliance - Gryphon)
new SpawnAssociation(21997, 21976, SpawnType.AlarmBot), //Air Force Guard Post (Goblin - Area 52 - Zeppelin)
new SpawnAssociation(21999, 15241, SpawnType.TripwireRooftop), //Air Force Trip Wire - Rooftop (Alliance)
new SpawnAssociation(22001, 15242, SpawnType.TripwireRooftop), //Air Force Trip Wire - Rooftop (Horde)
new SpawnAssociation(22002, 15242, SpawnType.TripwireRooftop), //Air Force Trip Wire - Ground (Horde)
new SpawnAssociation(22003, 15241, SpawnType.TripwireRooftop), //Air Force Trip Wire - Ground (Alliance)
new SpawnAssociation(22063, 21976, SpawnType.TripwireRooftop), //Air Force Trip Wire - Rooftop (Goblin - Area 52)
new SpawnAssociation(22065, 22064, SpawnType.AlarmBot), //Air Force Guard Post (Ethereal - Stormspire)
new SpawnAssociation(22066, 22067, SpawnType.AlarmBot), //Air Force Guard Post (Scryer - Dragonhawk)
new SpawnAssociation(22068, 22064, SpawnType.TripwireRooftop), //Air Force Trip Wire - Rooftop (Ethereal - Stormspire)
new SpawnAssociation(22069, 22064, SpawnType.AlarmBot), //Air Force Alarm Bot (Stormspire)
new SpawnAssociation(22070, 22067, SpawnType.TripwireRooftop), //Air Force Trip Wire - Rooftop (Scryer)
new SpawnAssociation(22071, 22067, SpawnType.AlarmBot), //Air Force Alarm Bot (Scryer)
new SpawnAssociation(22078, 22077, SpawnType.AlarmBot), //Air Force Alarm Bot (Aldor)
new SpawnAssociation(22079, 22077, SpawnType.AlarmBot), //Air Force Guard Post (Aldor - Gryphon)
new SpawnAssociation(22080, 22077, SpawnType.TripwireRooftop), //Air Force Trip Wire - Rooftop (Aldor)
new SpawnAssociation(22086, 22085, SpawnType.AlarmBot), //Air Force Alarm Bot (Sporeggar)
new SpawnAssociation(22087, 22085, SpawnType.AlarmBot), //Air Force Guard Post (Sporeggar - Spore Bat)
new SpawnAssociation(22088, 22085, SpawnType.TripwireRooftop), //Air Force Trip Wire - Rooftop (Sporeggar)
new SpawnAssociation(22090, 22089, SpawnType.AlarmBot), //Air Force Guard Post (Toshley's Station - Flying Machine)
new SpawnAssociation(22124, 22122, SpawnType.AlarmBot), //Air Force Alarm Bot (Cenarion)
new SpawnAssociation(22125, 22122, SpawnType.AlarmBot), //Air Force Guard Post (Cenarion - Stormcrow)
new SpawnAssociation(22126, 22122, SpawnType.AlarmBot) //Air Force Trip Wire - Rooftop (Cenarion Expedition)
};
public const float RangeTripwire = 15.0f;
public const float RangeGuardsMark = 50.0f;
//ChickenCluck
public const uint FactionFriendly = 35;
public const uint FactionChicken = 31;
//Doctor
public static Position[] DoctorAllianceCoords =
{
new Position(-3757.38f, -4533.05f, 14.16f, 3.62f), // Top-far-right bunk as seen from entrance
new Position(-3754.36f, -4539.13f, 14.16f, 5.13f), // Top-far-left bunk
new Position(-3749.54f, -4540.25f, 14.28f, 3.34f), // Far-right bunk
new Position(-3742.10f, -4536.85f, 14.28f, 3.64f), // Right bunk near entrance
new Position(-3755.89f, -4529.07f, 14.05f, 0.57f), // Far-left bunk
new Position(-3749.51f, -4527.08f, 14.07f, 5.26f), // Mid-left bunk
new Position(-3746.37f, -4525.35f, 14.16f, 5.22f), // Left bunk near entrance
};
//alliance run to where
public static Position DoctorAllianceRunTo = new Position(-3742.96f, -4531.52f, 11.91f);
public static Position[] DoctorHordeCoords =
{
new Position(-1013.75f, -3492.59f, 62.62f, 4.34f), // Left, Behind
new Position(-1017.72f, -3490.92f, 62.62f, 4.34f), // Right, Behind
new Position(-1015.77f, -3497.15f, 62.82f, 4.34f), // Left, Mid
new Position(-1019.51f, -3495.49f, 62.82f, 4.34f), // Right, Mid
new Position(-1017.25f, -3500.85f, 62.98f, 4.34f), // Left, front
new Position(-1020.95f, -3499.21f, 62.98f, 4.34f) // Right, Front
};
//horde run to where
public static Position DoctorHordeRunTo = new Position(-1016.44f, -3508.48f, 62.96f);
public static uint[] AllianceSoldierId =
{
12938, // 12938 Injured Alliance Soldier
12936, // 12936 Badly injured Alliance Soldier
12937 // 12937 Critically injured Alliance Soldier
};
public static uint[] HordeSoldierId =
{
12923, //12923 Injured Soldier
12924, //12924 Badly injured Soldier
12925 //12925 Critically injured Soldier
};
// WormholeSpells
public const uint DataShowUnderground = 1;
//Fireworks
public const uint AnimGoLaunchFirework = 3;
public const uint ZoneMoonglade = 493;
public static Position omenSummonPos = new Position(7558.993f, -2839.999f, 450.0214f, 4.46f);
public const uint AuraDurationTimeLeft = 5000;
//Argent squire/gruntling
public static Tuple<uint, uint>[] bannerSpells =
{
Tuple.Create(SpellIds.DarnassusPennant, SpellIds.SenjinPennant),
Tuple.Create(SpellIds.ExodarPennant, SpellIds.UndercityPennant),
Tuple.Create(SpellIds.GnomereganPennant, SpellIds.OrgrimmarPennant),
Tuple.Create(SpellIds.IronforgePennant, SpellIds.SilvermoonPennant),
Tuple.Create(SpellIds.StormwindPennant, SpellIds.ThunderbluffPennant)
};
}
[Script]
class npc_air_force_bots : ScriptedAI
{
public npc_air_force_bots(Creature creature) : base(creature)
{
SpawnAssoc = null;
SpawnedGUID.Clear();
// find the correct spawnhandling
foreach (var association in Misc.spawnAssociations)
{
if (association.thisCreatureEntry == creature.GetEntry())
{
SpawnAssoc = association;
break;
}
}
if (SpawnAssoc == null)
Log.outError(LogFilter.Sql, "TCSR: Creature template entry {0} has ScriptName npc_air_force_bots, but it's not handled by that script", creature.GetEntry());
else
{
CreatureTemplate spawnedTemplate = Global.ObjectMgr.GetCreatureTemplate(SpawnAssoc.spawnedCreatureEntry);
if (spawnedTemplate == null)
{
Log.outError(LogFilter.Sql, "TCSR: Creature template entry {0} does not exist in DB, which is required by npc_air_force_bots", SpawnAssoc.spawnedCreatureEntry);
SpawnAssoc = null;
return;
}
}
}
SpawnAssociation SpawnAssoc;
ObjectGuid SpawnedGUID;
public override void Reset() { }
Creature SummonGuard()
{
Creature summoned = me.SummonCreature(SpawnAssoc.spawnedCreatureEntry, 0.0f, 0.0f, 0.0f, 0.0f, TempSummonType.TimedDespawnOutOfCombat, 300000);
if (summoned)
SpawnedGUID = summoned.GetGUID();
else
{
Log.outError(LogFilter.Sql, "npc_air_force_bots: wasn't able to spawn Creature {0}", SpawnAssoc.spawnedCreatureEntry);
SpawnAssoc = null;
}
return summoned;
}
Creature GetSummonedGuard()
{
Creature creature = ObjectAccessor.GetCreature(me, SpawnedGUID);
if (creature && creature.IsAlive())
return creature;
return null;
}
public override void MoveInLineOfSight(Unit who)
{
if (SpawnAssoc == null)
return;
if (me.IsValidAttackTarget(who))
{
Player playerTarget = who.ToPlayer();
// airforce guards only spawn for players
if (!playerTarget)
return;
Creature lastSpawnedGuard = SpawnedGUID.IsEmpty() ? null : GetSummonedGuard();
// prevent calling Unit::GetUnit at next MoveInLineOfSight call - speedup
if (!lastSpawnedGuard)
SpawnedGUID.Clear();
switch (SpawnAssoc.spawnType)
{
case SpawnType.AlarmBot:
{
if (!who.IsWithinDistInMap(me, Misc.RangeGuardsMark))
return;
Aura markAura = who.GetAura(SpellIds.GuardsMark);
if (markAura != null)
{
// the target wasn't able to move out of our range within 25 seconds
if (!lastSpawnedGuard)
{
lastSpawnedGuard = SummonGuard();
if (!lastSpawnedGuard)
return;
}
if (markAura.GetDuration() < Misc.AuraDurationTimeLeft)
if (!lastSpawnedGuard.GetVictim())
lastSpawnedGuard.GetAI().AttackStart(who);
}
else
{
if (!lastSpawnedGuard)
lastSpawnedGuard = SummonGuard();
if (!lastSpawnedGuard)
return;
lastSpawnedGuard.CastSpell(who, SpellIds.GuardsMark, true);
}
break;
}
case SpawnType.TripwireRooftop:
{
if (!who.IsWithinDistInMap(me, Misc.RangeTripwire))
return;
if (!lastSpawnedGuard)
lastSpawnedGuard = SummonGuard();
if (!lastSpawnedGuard)
return;
// ROOFTOP only triggers if the player is on the ground
if (!playerTarget.IsFlying() && !lastSpawnedGuard.GetVictim())
lastSpawnedGuard.GetAI().AttackStart(who);
break;
}
}
}
}
}
[Script]
class npc_chicken_cluck : ScriptedAI
{
public npc_chicken_cluck(Creature creature) : base(creature)
{
Initialize();
}
void Initialize()
{
ResetFlagTimer = 120000;
}
uint ResetFlagTimer;
public override void Reset()
{
Initialize();
me.SetFaction(Misc.FactionChicken);
me.RemoveNpcFlag(NPCFlags.QuestGiver);
}
public override void JustEngagedWith(Unit who) { }
public override void UpdateAI(uint diff)
{
// Reset flags after a certain time has passed so that the next player has to start the 'event' again
if (me.HasNpcFlag(NPCFlags.QuestGiver))
{
if (ResetFlagTimer <= diff)
{
EnterEvadeMode();
return;
}
else
ResetFlagTimer -= diff;
}
if (UpdateVictim())
DoMeleeAttackIfReady();
}
public override void ReceiveEmote(Player player, TextEmotes emote)
{
switch (emote)
{
case TextEmotes.Chicken:
if (player.GetQuestStatus(QuestConst.Cluck) == QuestStatus.None && RandomHelper.Rand32() % 30 == 1)
{
me.AddNpcFlag(NPCFlags.QuestGiver);
me.SetFaction(Misc.FactionFriendly);
Talk(player.GetTeam() == Team.Horde ? TextIds.EmoteHelloH : TextIds.EmoteHelloA);
}
break;
case TextEmotes.Cheer:
if (player.GetQuestStatus(QuestConst.Cluck) == QuestStatus.Complete)
{
me.AddNpcFlag(NPCFlags.QuestGiver);
me.SetFaction(Misc.FactionFriendly);
Talk(TextIds.EmoteCluck);
}
break;
}
}
public override void QuestAccept(Player player, Quest quest)
{
if (quest.Id == QuestConst.Cluck)
Reset();
}
public override void QuestReward(Player player, Quest quest, uint opt)
{
if (quest.Id == QuestConst.Cluck)
Reset();
}
}
[Script]
class npc_dancing_flames : ScriptedAI
{
public npc_dancing_flames(Creature creature) : base(creature)
{
Initialize();
}
void Initialize()
{
Active = true;
CanIteract = 3500;
}
bool Active;
uint CanIteract;
public override void Reset()
{
Initialize();
DoCast(me, SpellIds.Brazier, new CastSpellExtraArgs(true));
DoCast(me, SpellIds.FieryAura, new CastSpellExtraArgs(false));
float x, y, z;
me.GetPosition(out x, out y, out z);
me.Relocate(x, y, z + 0.94f);
me.SetDisableGravity(true);
me.HandleEmoteCommand(Emote.OneshotDance);
}
public override void UpdateAI(uint diff)
{
if (!Active)
{
if (CanIteract <= diff)
{
Active = true;
CanIteract = 3500;
me.HandleEmoteCommand(Emote.OneshotDance);
}
else
CanIteract -= diff;
}
}
public override void JustEngagedWith(Unit who) { }
public override void ReceiveEmote(Player player, TextEmotes emote)
{
if (me.IsWithinLOS(player.GetPositionX(), player.GetPositionY(), player.GetPositionZ()) && me.IsWithinDistInMap(player, 30.0f))
{
me.SetFacingToObject(player);
Active = false;
switch (emote)
{
case TextEmotes.Kiss:
me.HandleEmoteCommand(Emote.OneshotShy);
break;
case TextEmotes.Wave:
me.HandleEmoteCommand(Emote.OneshotWave);
break;
case TextEmotes.Bow:
me.HandleEmoteCommand(Emote.OneshotBow);
break;
case TextEmotes.Joke:
me.HandleEmoteCommand(Emote.OneshotLaugh);
break;
case TextEmotes.Dance:
if (!player.HasAura(SpellIds.Seduction))
DoCast(player, SpellIds.Seduction, new CastSpellExtraArgs(true));
break;
}
}
}
}
[Script]
class npc_torch_tossing_target_bunny_controller : ScriptedAI
{
public npc_torch_tossing_target_bunny_controller(Creature creature) : base(creature)
{
_targetTimer = 3000;
}
ObjectGuid DoSearchForTargets(ObjectGuid lastTargetGUID)
{
List<Creature> targets = new List<Creature>();
me.GetCreatureListWithEntryInGrid(targets, CreatureIds.TorchTossingTargetBunny, 60.0f);
targets.RemoveAll(creature => creature.GetGUID() == lastTargetGUID);
if (!targets.Empty())
{
_lastTargetGUID = targets.SelectRandom().GetGUID();
return _lastTargetGUID;
}
return ObjectGuid.Empty;
}
public override void UpdateAI(uint diff)
{
if (_targetTimer < diff)
{
Unit target = Global.ObjAccessor.GetUnit(me, DoSearchForTargets(_lastTargetGUID));
if (target)
target.CastSpell(target, SpellIds.TargetIndicator, true);
_targetTimer = 3000;
}
else
_targetTimer -= diff;
}
uint _targetTimer;
ObjectGuid _lastTargetGUID;
}
[Script]
class npc_midsummer_bunny_pole : ScriptedAI
{
public npc_midsummer_bunny_pole(Creature creature) : base(creature)
{
Initialize();
}
void Initialize()
{
_scheduler.CancelAll();
running = false;
}
public override void Reset()
{
Initialize();
_scheduler.SetValidator(() => running);
_scheduler.Schedule(TimeSpan.FromMilliseconds(1), task =>
{
if (checkNearbyPlayers())
{
Reset();
return;
}
GameObject go = me.FindNearestGameObject(GameobjectIds.RibbonPole, 10.0f);
if (go)
me.CastSpell(go, SpellIds.RedFireRing, true);
task.Schedule(TimeSpan.FromSeconds(5), task1 =>
{
if (checkNearbyPlayers())
{
Reset();
return;
}
go = me.FindNearestGameObject(GameobjectIds.RibbonPole, 10.0f);
if (go)
me.CastSpell(go, SpellIds.BlueFireRing, true);
task.Repeat(TimeSpan.FromSeconds(5));
});
});
}
public override void DoAction(int action)
{
// Don't start event if it's already running.
if (running)
return;
running = true;
//events.ScheduleEvent(EVENT_CAST_RED_FIRE_RING, 1);
}
bool checkNearbyPlayers()
{
// Returns true if no nearby player has aura "Test Ribbon Pole Channel".
List<Unit> players = new List<Unit>();
var check = new UnitAuraCheck<Player>(true, SpellIds.RibbonDanceCosmetic);
var searcher = new PlayerListSearcher(me, players, check);
Cell.VisitWorldObjects(me, searcher, 10.0f);
return players.Empty();
}
public override void UpdateAI(uint diff)
{
if (!running)
return;
_scheduler.Update(diff);
}
bool running;
}
[Script]
class npc_doctor : ScriptedAI
{
public npc_doctor(Creature creature) : base(creature)
{
Initialize();
}
void Initialize()
{
PlayerGUID.Clear();
SummonPatientTimer = 10000;
SummonPatientCount = 0;
PatientDiedCount = 0;
PatientSavedCount = 0;
Patients.Clear();
Coordinates.Clear();
Event = false;
}
public override void Reset()
{
Initialize();
me.RemoveUnitFlag(UnitFlags.NotSelectable);
}
public void BeginEvent(Player player)
{
PlayerGUID = player.GetGUID();
SummonPatientTimer = 10000;
SummonPatientCount = 0;
PatientDiedCount = 0;
PatientSavedCount = 0;
switch (me.GetEntry())
{
case CreatureIds.DoctorAlliance:
foreach (var coord in Misc.DoctorAllianceCoords)
Coordinates.Add(coord);
break;
case CreatureIds.DoctorHorde:
foreach (var coord in Misc.DoctorHordeCoords)
Coordinates.Add(coord);
break;
}
Event = true;
me.AddUnitFlag(UnitFlags.NotSelectable);
}
public void PatientDied(Position point)
{
Player player = Global.ObjAccessor.GetPlayer(me, PlayerGUID);
if (player && ((player.GetQuestStatus(6624) == QuestStatus.Incomplete) || (player.GetQuestStatus(6622) == QuestStatus.Incomplete)))
{
++PatientDiedCount;
if (PatientDiedCount > 5 && Event)
{
if (player.GetQuestStatus(6624) == QuestStatus.Incomplete)
player.FailQuest(6624);
else if (player.GetQuestStatus(6622) == QuestStatus.Incomplete)
player.FailQuest(6622);
Reset();
return;
}
Coordinates.Add(point);
}
else
// If no player or player abandon quest in progress
Reset();
}
public void PatientSaved(Creature soldier, Player player, Position point)
{
if (player && PlayerGUID == player.GetGUID())
{
if ((player.GetQuestStatus(6624) == QuestStatus.Incomplete) || (player.GetQuestStatus(6622) == QuestStatus.Incomplete))
{
++PatientSavedCount;
if (PatientSavedCount == 15)
{
if (!Patients.Empty())
{
foreach (var guid in Patients)
{
Creature patient = ObjectAccessor.GetCreature(me, guid);
if (patient)
patient.SetDeathState(DeathState.JustDied);
}
}
if (player.GetQuestStatus(6624) == QuestStatus.Incomplete)
player.AreaExploredOrEventHappens(6624);
else if (player.GetQuestStatus(6622) == QuestStatus.Incomplete)
player.AreaExploredOrEventHappens(6622);
Reset();
return;
}
Coordinates.Add(point);
}
}
}
public override void UpdateAI(uint diff)
{
if (Event && SummonPatientCount >= 20)
{
Reset();
return;
}
if (Event)
{
if (SummonPatientTimer <= diff)
{
if (Coordinates.Empty())
return;
uint patientEntry;
switch (me.GetEntry())
{
case CreatureIds.DoctorAlliance:
patientEntry = Misc.AllianceSoldierId[RandomHelper.Rand32() % 3];
break;
case CreatureIds.DoctorHorde:
patientEntry = Misc.HordeSoldierId[RandomHelper.Rand32() % 3];
break;
default:
Log.outError(LogFilter.Scripts, "Invalid entry for Triage doctor. Please check your database");
return;
}
var index = RandomHelper.IRand(0, Coordinates.Count - 1);
Creature Patient = me.SummonCreature(patientEntry, Coordinates[index], TempSummonType.TimedDespawnOutOfCombat, 5000);
if (Patient)
{
//303, this flag appear to be required for client side item.spell to work (TARGET_SINGLE_FRIEND)
Patient.AddUnitFlag(UnitFlags.PvpAttackable);
Patients.Add(Patient.GetGUID());
((npc_injured_patient)Patient.GetAI()).DoctorGUID = me.GetGUID();
((npc_injured_patient)Patient.GetAI()).Coord = Coordinates[index];
Coordinates.RemoveAt(index);
}
SummonPatientTimer = 10000;
++SummonPatientCount;
}
else
SummonPatientTimer -= diff;
}
}
public override void JustEngagedWith(Unit who) { }
public override void QuestAccept(Player player, Quest quest)
{
if ((quest.Id == 6624) || (quest.Id == 6622))
BeginEvent(player);
}
ObjectGuid PlayerGUID;
uint SummonPatientTimer;
uint SummonPatientCount;
uint PatientDiedCount;
uint PatientSavedCount;
bool Event;
List<ObjectGuid> Patients = new List<ObjectGuid>();
List<Position> Coordinates = new List<Position>();
}
[Script]
public class npc_injured_patient : ScriptedAI
{
public npc_injured_patient(Creature creature) : base(creature)
{
Initialize();
}
void Initialize()
{
DoctorGUID.Clear();
Coord = null;
}
public ObjectGuid DoctorGUID;
public Position Coord;
public override void Reset()
{
Initialize();
//no select
me.RemoveUnitFlag(UnitFlags.NotSelectable);
//no regen health
me.AddUnitFlag(UnitFlags.InCombat);
//to make them lay with face down
me.SetStandState(UnitStandStateType.Dead);
uint mobId = me.GetEntry();
switch (mobId)
{ //lower max health
case 12923:
case 12938: //Injured Soldier
me.SetHealth(me.CountPctFromMaxHealth(75));
break;
case 12924:
case 12936: //Badly injured Soldier
me.SetHealth(me.CountPctFromMaxHealth(50));
break;
case 12925:
case 12937: //Critically injured Soldier
me.SetHealth(me.CountPctFromMaxHealth(25));
break;
}
}
public override void JustEngagedWith(Unit who) { }
public override void SpellHit(Unit caster, SpellInfo spell)
{
Player player = caster.ToPlayer();
if (!player || !me.IsAlive() || spell.Id != 20804)
return;
if (player.GetQuestStatus(6624) == QuestStatus.Incomplete || player.GetQuestStatus(6622) == QuestStatus.Incomplete)
{
if (!DoctorGUID.IsEmpty())
{
Creature doctor = ObjectAccessor.GetCreature(me, DoctorGUID);
if (doctor)
((npc_doctor)doctor.GetAI()).PatientSaved(me, player, Coord);
}
}
//make not selectable
me.AddUnitFlag(UnitFlags.NotSelectable);
//regen health
me.RemoveUnitFlag(UnitFlags.InCombat);
//stand up
me.SetStandState(UnitStandStateType.Stand);
Talk(TextIds.SayDoc);
uint mobId = me.GetEntry();
me.SetWalk(false);
switch (mobId)
{
case 12923:
case 12924:
case 12925:
me.GetMotionMaster().MovePoint(0, Misc.DoctorHordeRunTo);
break;
case 12936:
case 12937:
case 12938:
me.GetMotionMaster().MovePoint(0, Misc.DoctorAllianceRunTo);
break;
}
}
public override void UpdateAI(uint diff)
{
//lower HP on every world tick makes it a useful counter, not officlone though
if (me.IsAlive() && me.GetHealth() > 6)
me.ModifyHealth(-5);
if (me.IsAlive() && me.GetHealth() <= 6)
{
me.RemoveUnitFlag(UnitFlags.InCombat);
me.AddUnitFlag(UnitFlags.NotSelectable);
me.SetDeathState(DeathState.JustDied);
me.AddDynamicFlag(UnitDynFlags.Dead);
if (!DoctorGUID.IsEmpty())
{
Creature doctor = ObjectAccessor.GetCreature((me), DoctorGUID);
if (doctor)
((npc_doctor)doctor.GetAI()).PatientDied(Coord);
}
}
}
}
[Script]
class npc_garments_of_quests : EscortAI
{
public npc_garments_of_quests(Creature creature) : base(creature)
{
switch (me.GetEntry())
{
case CreatureIds.Shaya:
quest = QuestConst.Moon;
break;
case CreatureIds.Roberts:
quest = QuestConst.Light1;
break;
case CreatureIds.Dolf:
quest = QuestConst.Light2;
break;
case CreatureIds.Korja:
quest = QuestConst.Spirit;
break;
case CreatureIds.DgKel:
quest = QuestConst.Darkness;
break;
default:
quest = 0;
break;
}
Reset();
}
ObjectGuid CasterGUID;
bool IsHealed;
bool CanRun;
uint RunAwayTimer;
uint quest;
public override void Reset()
{
CasterGUID.Clear();
IsHealed = false;
CanRun = false;
RunAwayTimer = 5000;
me.SetStandState(UnitStandStateType.Kneel);
// expect database to have RegenHealth=0
me.SetHealth(me.CountPctFromMaxHealth(70));
}
public override void JustEngagedWith(Unit who) { }
public override void SpellHit(Unit caster, SpellInfo spell)
{
if (spell.Id == SpellIds.LesserHealR2 || spell.Id == SpellIds.FortitudeR1)
{
//not while in combat
if (me.IsInCombat())
return;
//nothing to be done now
if (IsHealed && CanRun)
return;
Player player = caster.ToPlayer();
if (player)
{
if (quest != 0 && player.GetQuestStatus(quest) == QuestStatus.Incomplete)
{
if (IsHealed && !CanRun && spell.Id == SpellIds.FortitudeR1)
{
Talk(TextIds.SayThanks, caster);
CanRun = true;
}
else if (!IsHealed && spell.Id == SpellIds.LesserHealR2)
{
CasterGUID = caster.GetGUID();
me.SetStandState(UnitStandStateType.Stand);
Talk(TextIds.SayHealed, caster);
IsHealed = true;
}
}
// give quest credit, not expect any special quest objectives
if (CanRun)
player.TalkedToCreature(me.GetEntry(), me.GetGUID());
}
}
}
public override void WaypointReached(uint waypointId, uint pathId)
{
}
public override void UpdateAI(uint diff)
{
if (CanRun && !me.IsInCombat())
{
if (RunAwayTimer <= diff)
{
Unit unit = Global.ObjAccessor.GetUnit(me, CasterGUID);
if (unit)
{
switch (me.GetEntry())
{
case CreatureIds.Shaya:
case CreatureIds.Roberts:
case CreatureIds.Dolf:
case CreatureIds.Korja:
case CreatureIds.DgKel:
Talk(TextIds.SayGoodbye, unit);
break;
}
Start(false, true);
}
else
EnterEvadeMode(); //something went wrong
RunAwayTimer = 30000;
}
else
RunAwayTimer -= diff;
}
base.UpdateAI(diff);
}
}
[Script]
class npc_guardian : ScriptedAI
{
public npc_guardian(Creature creature) : base(creature) { }
public override void Reset()
{
me.AddUnitFlag(UnitFlags.NonAttackable);
}
public override void JustEngagedWith(Unit who) { }
public override void UpdateAI(uint diff)
{
if (!UpdateVictim())
return;
if (me.IsAttackReady())
{
DoCastVictim(SpellIds.Deathtouch, new CastSpellExtraArgs(true));
me.ResetAttackTimer();
}
}
}
[Script]
class npc_sayge : ScriptedAI
{
public npc_sayge(Creature creature) : base(creature) { }
public override bool GossipHello(Player player)
{
if (me.IsQuestGiver())
player.PrepareQuestMenu(me.GetGUID());
if (player.GetSpellHistory().HasCooldown(SpellIds.Strength) ||
player.GetSpellHistory().HasCooldown(SpellIds.Agility) ||
player.GetSpellHistory().HasCooldown(SpellIds.Stamina) ||
player.GetSpellHistory().HasCooldown(SpellIds.Spirit) ||
player.GetSpellHistory().HasCooldown(SpellIds.Intellect) ||
player.GetSpellHistory().HasCooldown(SpellIds.Armor) ||
player.GetSpellHistory().HasCooldown(SpellIds.Damage) ||
player.GetSpellHistory().HasCooldown(SpellIds.Resistance))
player.SendGossipMenu(GossipMenus.CantGiveYouYour, me.GetGUID());
else
{
player.ADD_GOSSIP_ITEM_DB(GossipMenus.IAmReadyToDiscover, GossipMenus.OptionIdAnswer1, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 1);
player.SendGossipMenu(GossipMenus.IHaveLongKnown, me.GetGUID());
}
return true;
}
void SendAction(Player player, uint action)
{
switch (action)
{
case eTradeskill.GossipActionInfoDef + 1:
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge, GossipMenus.OptionIdAnswer1, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 2);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge, GossipMenus.OptionIdAnswer2, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 3);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge, GossipMenus.OptionIdAnswer3, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 4);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge, GossipMenus.OptionIdAnswer4, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 5);
player.SendGossipMenu(GossipMenus.YouHaveBeenTasked, me.GetGUID());
break;
case eTradeskill.GossipActionInfoDef + 2:
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge2, GossipMenus.OptionIdAnswer1, eTradeskill.GossipSenderMain + 1, eTradeskill.GossipActionInfoDef);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge2, GossipMenus.OptionIdAnswer2, eTradeskill.GossipSenderMain + 2, eTradeskill.GossipActionInfoDef);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge2, GossipMenus.OptionIdAnswer3, eTradeskill.GossipSenderMain + 3, eTradeskill.GossipActionInfoDef);
player.SendGossipMenu(GossipMenus.SwornExecutioner, me.GetGUID());
break;
case eTradeskill.GossipActionInfoDef + 3:
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge3, GossipMenus.OptionIdAnswer1, eTradeskill.GossipSenderMain + 4, eTradeskill.GossipActionInfoDef);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge3, GossipMenus.OptionIdAnswer2, eTradeskill.GossipSenderMain + 5, eTradeskill.GossipActionInfoDef);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge3, GossipMenus.OptionIdAnswer3, eTradeskill.GossipSenderMain + 2, eTradeskill.GossipActionInfoDef);
player.SendGossipMenu(GossipMenus.DiplomaticMission, me.GetGUID());
break;
case eTradeskill.GossipActionInfoDef + 4:
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge4, GossipMenus.OptionIdAnswer1, eTradeskill.GossipSenderMain + 6, eTradeskill.GossipActionInfoDef);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge4, GossipMenus.OptionIdAnswer2, eTradeskill.GossipSenderMain + 7, eTradeskill.GossipActionInfoDef);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge4, GossipMenus.OptionIdAnswer3, eTradeskill.GossipSenderMain + 8, eTradeskill.GossipActionInfoDef);
player.SendGossipMenu(GossipMenus.YourBrotherSeeks, me.GetGUID());
break;
case eTradeskill.GossipActionInfoDef + 5:
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge5, GossipMenus.OptionIdAnswer1, eTradeskill.GossipSenderMain + 5, eTradeskill.GossipActionInfoDef);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge5, GossipMenus.OptionIdAnswer2, eTradeskill.GossipSenderMain + 4, eTradeskill.GossipActionInfoDef);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge5, GossipMenus.OptionIdAnswer3, eTradeskill.GossipSenderMain + 3, eTradeskill.GossipActionInfoDef);
player.SendGossipMenu(GossipMenus.ATerribleBeast, me.GetGUID());
break;
case eTradeskill.GossipActionInfoDef:
player.ADD_GOSSIP_ITEM_DB(GossipMenus.OptionSayge6, GossipMenus.OptionIdAnswer1, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 6);
player.SendGossipMenu(GossipMenus.YourFortuneIsCast, me.GetGUID());
break;
case eTradeskill.GossipActionInfoDef + 6:
DoCast(player, SpellIds.Fortune, new CastSpellExtraArgs(false));
player.SendGossipMenu(GossipMenus.HereIsYourFortune, me.GetGUID());
break;
}
}
public override bool GossipSelect(Player player, uint menuId, uint gossipListId)
{
uint sender = player.PlayerTalkClass.GetGossipOptionSender(gossipListId);
uint action = player.PlayerTalkClass.GetGossipOptionAction(gossipListId);
player.PlayerTalkClass.ClearMenus();
uint spellId = 0;
switch (sender)
{
case eTradeskill.GossipSenderMain:
SendAction(player, action);
break;
case eTradeskill.GossipSenderMain + 1:
spellId = SpellIds.Damage;
break;
case eTradeskill.GossipSenderMain + 2:
spellId = SpellIds.Resistance;
break;
case eTradeskill.GossipSenderMain + 3:
spellId = SpellIds.Armor;
break;
case eTradeskill.GossipSenderMain + 4:
spellId = SpellIds.Spirit;
break;
case eTradeskill.GossipSenderMain + 5:
spellId = SpellIds.Intellect;
break;
case eTradeskill.GossipSenderMain + 6:
spellId = SpellIds.Stamina;
break;
case eTradeskill.GossipSenderMain + 7:
spellId = SpellIds.Strength;
break;
case eTradeskill.GossipSenderMain + 8:
spellId = SpellIds.Agility;
break;
}
if (spellId != 0)
{
DoCast(player, spellId, new CastSpellExtraArgs(false));
player.GetSpellHistory().AddCooldown(spellId, 0, TimeSpan.FromHours(2));
SendAction(player, action);
}
return true;
}
}
[Script]
class npc_steam_tonk : ScriptedAI
{
public npc_steam_tonk(Creature creature) : base(creature) { }
public override void Reset() { }
public override void JustEngagedWith(Unit who) { }
public override void OnPossess(bool apply)
{
if (apply)
{
// Initialize the action bar without the melee attack command
me.InitCharmInfo();
me.GetCharmInfo().InitEmptyActionBar(false);
me.SetReactState(ReactStates.Passive);
}
else
me.SetReactState(ReactStates.Aggressive);
}
}
[Script]
class npc_tonk_mine : ScriptedAI
{
public npc_tonk_mine(Creature creature) : base(creature)
{
Initialize();
me.SetReactState(ReactStates.Passive);
}
void Initialize()
{
ExplosionTimer = 3000;
}
uint ExplosionTimer;
public override void Reset()
{
Initialize();
}
public override void JustEngagedWith(Unit who) { }
public override void AttackStart(Unit who) { }
public override void MoveInLineOfSight(Unit who) { }
public override void UpdateAI(uint diff)
{
if (ExplosionTimer <= diff)
{
DoCast(me, SpellIds.TonkMineDetonate, new CastSpellExtraArgs(true));
me.SetDeathState(DeathState.Dead); // unsummon it
}
else
ExplosionTimer -= diff;
}
}
[Script]
class npc_brewfest_reveler : ScriptedAI
{
public npc_brewfest_reveler(Creature creature) : base(creature) { }
public override void ReceiveEmote(Player player, TextEmotes emote)
{
if (!Global.GameEventMgr.IsHolidayActive(HolidayIds.Brewfest))
return;
if (emote == TextEmotes.Dance)
me.CastSpell(player, SpellIds.BrewfestToast, false);
}
}
[Script]
class npc_training_dummy : ScriptedAI
{
public npc_training_dummy(Creature creature) : base(creature)
{
SetCombatMovement(false);
}
public override void Reset()
{
// TODO: solve this in a different way! setting them as stunned prevents dummies from parrying
me.SetControlled(true, UnitState.Stunned);//disable rotate
_scheduler.CancelAll();
_damageTimes.Clear();
if (me.GetEntry() != AdvancedTargetDummy && me.GetEntry() != TargetDummy)
{
_scheduler.Schedule(TimeSpan.FromSeconds(1), task =>
{
long now = GameTime.GetGameTime();
var pveRefs = me.GetCombatManager().GetPvECombatRefs();
foreach (var pair in _damageTimes)
{
// If unit has not dealt damage to training dummy for 5 seconds, Remove him from combat
if (pair.Value < now - 5)
{
var refe = pveRefs.LookupByKey(pair.Key);
if (refe != null)
refe.EndCombat();
_damageTimes.Remove(pair.Key);
}
}
foreach (var pair in pveRefs)
if (!_damageTimes.ContainsKey(pair.Key))
_damageTimes[pair.Key] = now;
task.Repeat();
});
}
else
_scheduler.Schedule(TimeSpan.FromSeconds(15), task => me.DespawnOrUnsummon());
}
public override void EnterEvadeMode(EvadeReason why)
{
if (!_EnterEvadeMode(why))
return;
Reset();
}
public override void DamageTaken(Unit doneBy, ref uint damage)
{
AddThreat(doneBy, damage); // just to create threat reference
_damageTimes[doneBy.GetGUID()] = GameTime.GetGameTime();
damage = 0;
}
public override void UpdateAI(uint diff)
{
if (!me.IsInCombat())
return;
if (!me.HasUnitState(UnitState.Stunned))
me.SetControlled(true, UnitState.Stunned);//disable rotate
_scheduler.Update(diff);
}
public override void MoveInLineOfSight(Unit who) { }
Dictionary<ObjectGuid, long> _damageTimes = new Dictionary<ObjectGuid, long>();
const uint AdvancedTargetDummy = 2674;
const uint TargetDummy = 2673;
}
[Script]
class npc_wormhole : PassiveAI
{
public npc_wormhole(Creature creature) : base(creature)
{
Initialize();
}
void Initialize()
{
_showUnderground = RandomHelper.URand(0, 100) == 0; // Guessed value, it is really rare though
}
public override void InitializeAI()
{
Initialize();
}
public override bool GossipHello(Player player)
{
if (me.IsSummon())
{
if (player == me.ToTempSummon().GetSummoner())
{
player.ADD_GOSSIP_ITEM_DB(GossipMenus.MenuIdWormhole, GossipMenus.OptionIdWormhole1, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 1);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.MenuIdWormhole, GossipMenus.OptionIdWormhole2, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 2);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.MenuIdWormhole, GossipMenus.OptionIdWormhole3, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 3);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.MenuIdWormhole, GossipMenus.OptionIdWormhole4, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 4);
player.ADD_GOSSIP_ITEM_DB(GossipMenus.MenuIdWormhole, GossipMenus.OptionIdWormhole5, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 5);
if (_showUnderground)
player.ADD_GOSSIP_ITEM_DB(GossipMenus.MenuIdWormhole, GossipMenus.OptionIdWormhole6, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 6);
player.SendGossipMenu(TextIds.Wormhole, me.GetGUID());
}
}
return true;
}
public override bool GossipSelect(Player player, uint menuId, uint gossipListId)
{
uint action = player.PlayerTalkClass.GetGossipOptionAction(gossipListId);
player.PlayerTalkClass.ClearMenus();
switch (action)
{
case eTradeskill.GossipActionInfoDef + 1: // Borean Tundra
player.CloseGossipMenu();
DoCast(player, SpellIds.BoreanTundra, new CastSpellExtraArgs(false));
break;
case eTradeskill.GossipActionInfoDef + 2: // Howling Fjord
player.CloseGossipMenu();
DoCast(player, SpellIds.HowlingFjord, new CastSpellExtraArgs(false));
break;
case eTradeskill.GossipActionInfoDef + 3: // Sholazar Basin
player.CloseGossipMenu();
DoCast(player, SpellIds.SholazarBasin, new CastSpellExtraArgs(false));
break;
case eTradeskill.GossipActionInfoDef + 4: // Icecrown
player.CloseGossipMenu();
DoCast(player, SpellIds.Icecrown, new CastSpellExtraArgs(false));
break;
case eTradeskill.GossipActionInfoDef + 5: // Storm peaks
player.CloseGossipMenu();
DoCast(player, SpellIds.StormPeaks, new CastSpellExtraArgs(false));
break;
case eTradeskill.GossipActionInfoDef + 6: // Underground
player.CloseGossipMenu();
DoCast(player, SpellIds.Underground, new CastSpellExtraArgs(false));
break;
}
return true;
}
bool _showUnderground;
}
[Script]
class npc_experience : ScriptedAI
{
public npc_experience(Creature creature) : base(creature) { }
public override bool GossipHello(Player player)
{
if (player.HasPlayerFlag(PlayerFlags.NoXPGain)) // not gaining XP
{
player.ADD_GOSSIP_ITEM_DB(GossipMenus.MenuIdXpOnOff, GossipMenus.OptionIdXpOn, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 1);
player.SendGossipMenu(TextIds.XpOnOff, me.GetGUID());
}
else // currently gaining XP
{
player.ADD_GOSSIP_ITEM_DB(GossipMenus.MenuIdXpOnOff, GossipMenus.OptionIdXpOff, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 2);
player.SendGossipMenu(TextIds.XpOnOff, me.GetGUID());
}
return true;
}
public override bool GossipSelect(Player player, uint menuId, uint gossipListId)
{
uint action = player.PlayerTalkClass.GetGossipOptionAction(gossipListId);
player.PlayerTalkClass.ClearMenus();
switch (action)
{
case eTradeskill.GossipActionInfoDef + 1:// XP ON selected
player.RemovePlayerFlag(PlayerFlags.NoXPGain); // turn on XP gain
break;
case eTradeskill.GossipActionInfoDef + 2:// XP OFF selected
player.AddPlayerFlag(PlayerFlags.NoXPGain); // turn off XP gain
break;
}
player.PlayerTalkClass.SendCloseGossip();
return true;
}
}
[Script]
class npc_firework : ScriptedAI
{
public npc_firework(Creature creature) : base(creature) { }
bool isCluster()
{
switch (me.GetEntry())
{
case CreatureIds.FireworkBlue:
case CreatureIds.FireworkGreen:
case CreatureIds.FireworkPurple:
case CreatureIds.FireworkRed:
case CreatureIds.FireworkYellow:
case CreatureIds.FireworkWhite:
case CreatureIds.FireworkBigBlue:
case CreatureIds.FireworkBigGreen:
case CreatureIds.FireworkBigPurple:
case CreatureIds.FireworkBigRed:
case CreatureIds.FireworkBigYellow:
case CreatureIds.FireworkBigWhite:
return false;
case CreatureIds.ClusterBlue:
case CreatureIds.ClusterGreen:
case CreatureIds.ClusterPurple:
case CreatureIds.ClusterRed:
case CreatureIds.ClusterYellow:
case CreatureIds.ClusterWhite:
case CreatureIds.ClusterBigBlue:
case CreatureIds.ClusterBigGreen:
case CreatureIds.ClusterBigPurple:
case CreatureIds.ClusterBigRed:
case CreatureIds.ClusterBigYellow:
case CreatureIds.ClusterBigWhite:
case CreatureIds.ClusterElune:
default:
return true;
}
}
GameObject FindNearestLauncher()
{
GameObject launcher = null;
if (isCluster())
{
GameObject launcher1 = GetClosestGameObjectWithEntry(me, GameobjectIds.ClusterLauncher1, 0.5f);
GameObject launcher2 = GetClosestGameObjectWithEntry(me, GameobjectIds.ClusterLauncher2, 0.5f);
GameObject launcher3 = GetClosestGameObjectWithEntry(me, GameobjectIds.ClusterLauncher3, 0.5f);
GameObject launcher4 = GetClosestGameObjectWithEntry(me, GameobjectIds.ClusterLauncher4, 0.5f);
if (launcher1)
launcher = launcher1;
else if (launcher2)
launcher = launcher2;
else if (launcher3)
launcher = launcher3;
else if (launcher4)
launcher = launcher4;
}
else
{
GameObject launcher1 = GetClosestGameObjectWithEntry(me, GameobjectIds.FireworkLauncher1, 0.5f);
GameObject launcher2 = GetClosestGameObjectWithEntry(me, GameobjectIds.FireworkLauncher2, 0.5f);
GameObject launcher3 = GetClosestGameObjectWithEntry(me, GameobjectIds.FireworkLauncher3, 0.5f);
if (launcher1)
launcher = launcher1;
else if (launcher2)
launcher = launcher2;
else if (launcher3)
launcher = launcher3;
}
return launcher;
}
uint GetFireworkSpell(uint entry)
{
switch (entry)
{
case CreatureIds.FireworkBlue:
return SpellIds.RocketBlue;
case CreatureIds.FireworkGreen:
return SpellIds.RocketGreen;
case CreatureIds.FireworkPurple:
return SpellIds.RocketPurple;
case CreatureIds.FireworkRed:
return SpellIds.RocketRed;
case CreatureIds.FireworkYellow:
return SpellIds.RocketYellow;
case CreatureIds.FireworkWhite:
return SpellIds.RocketWhite;
case CreatureIds.FireworkBigBlue:
return SpellIds.RocketBigBlue;
case CreatureIds.FireworkBigGreen:
return SpellIds.RocketBigGreen;
case CreatureIds.FireworkBigPurple:
return SpellIds.RocketBigPurple;
case CreatureIds.FireworkBigRed:
return SpellIds.RocketBigRed;
case CreatureIds.FireworkBigYellow:
return SpellIds.RocketBigYellow;
case CreatureIds.FireworkBigWhite:
return SpellIds.RocketBigWhite;
default:
return 0;
}
}
uint GetFireworkGameObjectId()
{
uint spellId = 0;
switch (me.GetEntry())
{
case CreatureIds.ClusterBlue:
spellId = GetFireworkSpell(CreatureIds.FireworkBlue);
break;
case CreatureIds.ClusterGreen:
spellId = GetFireworkSpell(CreatureIds.FireworkGreen);
break;
case CreatureIds.ClusterPurple:
spellId = GetFireworkSpell(CreatureIds.FireworkPurple);
break;
case CreatureIds.ClusterRed:
spellId = GetFireworkSpell(CreatureIds.FireworkRed);
break;
case CreatureIds.ClusterYellow:
spellId = GetFireworkSpell(CreatureIds.FireworkYellow);
break;
case CreatureIds.ClusterWhite:
spellId = GetFireworkSpell(CreatureIds.FireworkWhite);
break;
case CreatureIds.ClusterBigBlue:
spellId = GetFireworkSpell(CreatureIds.FireworkBigBlue);
break;
case CreatureIds.ClusterBigGreen:
spellId = GetFireworkSpell(CreatureIds.FireworkBigGreen);
break;
case CreatureIds.ClusterBigPurple:
spellId = GetFireworkSpell(CreatureIds.FireworkBigPurple);
break;
case CreatureIds.ClusterBigRed:
spellId = GetFireworkSpell(CreatureIds.FireworkBigRed);
break;
case CreatureIds.ClusterBigYellow:
spellId = GetFireworkSpell(CreatureIds.FireworkBigYellow);
break;
case CreatureIds.ClusterBigWhite:
spellId = GetFireworkSpell(CreatureIds.FireworkBigWhite);
break;
case CreatureIds.ClusterElune:
spellId = GetFireworkSpell(RandomHelper.URand(CreatureIds.FireworkBlue, CreatureIds.FireworkWhite));
break;
}
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None);
if (spellInfo != null && spellInfo.GetEffect(0).Effect == SpellEffectName.SummonObjectWild)
return (uint)spellInfo.GetEffect(0).MiscValue;
return 0;
}
public override void Reset()
{
GameObject launcher = FindNearestLauncher();
if (launcher)
{
launcher.SendCustomAnim(Misc.AnimGoLaunchFirework);
me.SetOrientation(launcher.GetOrientation() + MathFunctions.PI / 2);
}
else
return;
if (isCluster())
{
// Check if we are near Elune'ara lake south, if so try to summon Omen or a minion
if (me.GetZoneId() == Misc.ZoneMoonglade)
{
if (!me.FindNearestCreature(CreatureIds.Omen, 100.0f) && me.GetDistance2d(Misc.omenSummonPos.GetPositionX(), Misc.omenSummonPos.GetPositionY()) <= 100.0f)
{
switch (RandomHelper.URand(0, 9))
{
case 0:
case 1:
case 2:
case 3:
Creature minion = me.SummonCreature(CreatureIds.MinionOfOmen, me.GetPositionX() + RandomHelper.FRand(-5.0f, 5.0f), me.GetPositionY() + RandomHelper.FRand(-5.0f, 5.0f), me.GetPositionZ(), 0.0f, TempSummonType.CorpseTimedDespawn, 20000);
if (minion)
minion.GetAI().AttackStart(me.SelectNearestPlayer(20.0f));
break;
case 9:
me.SummonCreature(CreatureIds.Omen, Misc.omenSummonPos);
break;
}
}
}
if (me.GetEntry() == CreatureIds.ClusterElune)
DoCast(SpellIds.LunarFortune);
float displacement = 0.7f;
for (byte i = 0; i < 4; i++)
me.SummonGameObject(GetFireworkGameObjectId(), me.GetPositionX() + (i % 2 == 0 ? displacement : -displacement), me.GetPositionY() + (i > 1 ? displacement : -displacement), me.GetPositionZ() + 4.0f, me.GetOrientation(), Quaternion.fromEulerAnglesZYX(me.GetOrientation(), 0.0f, 0.0f), 1);
}
else
//me.CastSpell(me, GetFireworkSpell(me.GetEntry()), true);
me.CastSpell(me.GetPosition(), GetFireworkSpell(me.GetEntry()), new CastSpellExtraArgs(true));
}
}
[Script]
class npc_spring_rabbit : ScriptedAI
{
public npc_spring_rabbit(Creature creature) : base(creature)
{
Initialize();
}
void Initialize()
{
inLove = false;
rabbitGUID.Clear();
jumpTimer = RandomHelper.URand(5000, 10000);
bunnyTimer = RandomHelper.URand(10000, 20000);
searchTimer = RandomHelper.URand(5000, 10000);
}
bool inLove;
uint jumpTimer;
uint bunnyTimer;
uint searchTimer;
ObjectGuid rabbitGUID;
public override void Reset()
{
Initialize();
Unit owner = me.GetOwner();
if (owner)
me.GetMotionMaster().MoveFollow(owner, SharedConst.PetFollowDist, SharedConst.PetFollowAngle);
}
public override void JustEngagedWith(Unit who) { }
public override void DoAction(int param)
{
inLove = true;
Unit owner = me.GetOwner();
if (owner)
owner.CastSpell(owner, SpellIds.SpringFling, true);
}
public override void UpdateAI(uint diff)
{
if (inLove)
{
if (jumpTimer <= diff)
{
Unit rabbit = Global.ObjAccessor.GetUnit(me, rabbitGUID);
if (rabbit)
DoCast(rabbit, SpellIds.SpringRabbitJump);
jumpTimer = RandomHelper.URand(5000, 10000);
}
else jumpTimer -= diff;
if (bunnyTimer <= diff)
{
DoCast(SpellIds.SummonBabyBunny);
bunnyTimer = RandomHelper.URand(20000, 40000);
}
else bunnyTimer -= diff;
}
else
{
if (searchTimer <= diff)
{
Creature rabbit = me.FindNearestCreature(CreatureIds.SpringRabbit, 10.0f);
if (rabbit)
{
if (rabbit == me || rabbit.HasAura(SpellIds.SpringRabbitInLove))
return;
me.AddAura(SpellIds.SpringRabbitInLove, me);
DoAction(1);
rabbit.AddAura(SpellIds.SpringRabbitInLove, rabbit);
rabbit.GetAI().DoAction(1);
rabbit.CastSpell(rabbit, SpellIds.SpringRabbitJump, true);
rabbitGUID = rabbit.GetGUID();
}
searchTimer = RandomHelper.URand(5000, 10000);
}
else searchTimer -= diff;
}
}
}
[Script]
class npc_imp_in_a_ball : ScriptedAI
{
public npc_imp_in_a_ball(Creature creature) : base(creature)
{
summonerGUID.Clear();
}
public override void IsSummonedBy(Unit summoner)
{
if (summoner.IsTypeId(TypeId.Player))
{
summonerGUID = summoner.GetGUID();
_scheduler.Schedule(TimeSpan.FromSeconds(3), task =>
{
Player owner = Global.ObjAccessor.GetPlayer(me, summonerGUID);
if (owner)
Global.CreatureTextMgr.SendChat(me, 0, owner, owner.GetGroup() ? ChatMsg.MonsterParty : ChatMsg.MonsterWhisper, Language.Addon, CreatureTextRange.Normal);
});
}
}
public override void UpdateAI(uint diff)
{
_scheduler.Update(diff);
}
ObjectGuid summonerGUID;
}
struct TrainWrecker
{
public const int ActionWrecked = 1;
public const int EventDoJump = 1;
public const int EventDoFacing = 2;
public const int EventDoWreck = 3;
public const int EventDoDance = 4;
public const uint MoveidChase = 1;
public const uint MoveidJump = 2;
}
[Script]
class npc_train_wrecker : NullCreatureAI
{
public npc_train_wrecker(Creature creature) : base(creature)
{
_isSearching = true;
_nextAction = 0;
_timer = 1 * Time.InMilliseconds;
}
GameObject VerifyTarget()
{
GameObject target = ObjectAccessor.GetGameObject(me, _target);
if (target)
return target;
me.HandleEmoteCommand(Emote.OneshotRude);
me.DespawnOrUnsummon(3 * Time.InMilliseconds);
return null;
}
public override void UpdateAI(uint diff)
{
if (_isSearching)
{
if (diff < _timer)
_timer -= diff;
else
{
GameObject target = me.FindNearestGameObject(GameobjectIds.ToyTrain, 15.0f);
if (target)
{
_isSearching = false;
_target = target.GetGUID();
me.SetWalk(true);
me.GetMotionMaster().MovePoint(TrainWrecker.MoveidChase, target.GetNearPosition(3.0f, target.GetAngle(me)));
}
else
_timer = 3 * Time.InMilliseconds;
}
}
else
{
switch (_nextAction)
{
case TrainWrecker.EventDoJump:
{
GameObject target = VerifyTarget();
if (target)
me.GetMotionMaster().MoveJump(target, 5.0f, 10.0f, TrainWrecker.MoveidJump);
_nextAction = 0;
}
break;
case TrainWrecker.EventDoFacing:
{
GameObject target = VerifyTarget();
if (target)
{
me.SetFacingTo(target.GetOrientation());
me.HandleEmoteCommand(Emote.OneshotAttack1h);
_timer = (uint)(1.5 * Time.InMilliseconds);
_nextAction = TrainWrecker.EventDoWreck;
}
else
_nextAction = 0;
}
break;
case TrainWrecker.EventDoWreck:
{
if (diff < _timer)
{
_timer -= diff;
break;
}
GameObject target = VerifyTarget();
if (target)
{
me.CastSpell(target, SpellIds.WreckTrain, false);
target.GetAI().DoAction(TrainWrecker.ActionWrecked);
_timer = 2 * Time.InMilliseconds;
_nextAction = TrainWrecker.EventDoDance;
}
else
_nextAction = 0;
}
break;
case TrainWrecker.EventDoDance:
if (diff < _timer)
{
_timer -= diff;
break;
}
me.UpdateEntry(CreatureIds.ExultingWindUpTrainWrecker);
me.SetEmoteState(Emote.OneshotDance);
me.DespawnOrUnsummon(5 * Time.InMilliseconds);
_nextAction = 0;
break;
default:
break;
}
}
}
public override void MovementInform(MovementGeneratorType type, uint id)
{
if (id == TrainWrecker.MoveidChase)
_nextAction = TrainWrecker.EventDoJump;
else if (id == TrainWrecker.MoveidJump)
_nextAction = TrainWrecker.EventDoFacing;
}
bool _isSearching;
byte _nextAction;
uint _timer;
ObjectGuid _target;
}
[Script]
class npc_argent_squire_gruntling : ScriptedAI
{
public npc_argent_squire_gruntling(Creature creature) : base(creature)
{
ScheduleTasks();
}
public void ScheduleTasks()
{
_scheduler.Schedule(TimeSpan.FromSeconds(1), task =>
{
Aura ownerTired = me.GetOwner().GetAura(SpellIds.TiredPlayer);
if (ownerTired != null)
{
Aura squireTired = me.AddAura(IsArgentSquire() ? SpellIds.AuraTiredS : SpellIds.AuraTiredG, me);
if (squireTired != null)
squireTired.SetDuration(ownerTired.GetDuration());
}
});
_scheduler.Schedule(TimeSpan.FromSeconds(1), task =>
{
if ((me.HasAura(SpellIds.AuraTiredS) || me.HasAura(SpellIds.AuraTiredG)) && me.HasNpcFlag(NPCFlags.Banker | NPCFlags.Mailbox | NPCFlags.Vendor))
me.RemoveNpcFlag(NPCFlags.Banker | NPCFlags.Mailbox | NPCFlags.Vendor);
task.Repeat();
});
}
public override bool GossipSelect(Player player, uint menuId, uint gossipListId)
{
switch (gossipListId)
{
case GossipMenus.OptionIdBank:
{
me.AddNpcFlag(NPCFlags.Banker);
uint _bankAura = IsArgentSquire() ? SpellIds.AuraBankS : SpellIds.AuraBankG;
if (!me.HasAura(_bankAura))
DoCastSelf(_bankAura);
if (!player.HasAura(SpellIds.TiredPlayer))
player.CastSpell(player, SpellIds.TiredPlayer, true);
break;
}
case GossipMenus.OptionIdShop:
{
me.AddNpcFlag(NPCFlags.Vendor);
uint _shopAura = IsArgentSquire() ? SpellIds.AuraShopS : SpellIds.AuraShopG;
if (!me.HasAura(_shopAura))
DoCastSelf(_shopAura);
if (!player.HasAura(SpellIds.TiredPlayer))
player.CastSpell(player, SpellIds.TiredPlayer, true);
break;
}
case GossipMenus.OptionIdMail:
{
me.AddNpcFlag(NPCFlags.Mailbox);
player.GetSession().SendShowMailBox(me.GetGUID());
uint _mailAura = IsArgentSquire() ? SpellIds.AuraPostmanS : SpellIds.AuraPostmanG;
if (!me.HasAura(_mailAura))
DoCastSelf(_mailAura);
if (!player.HasAura(SpellIds.TiredPlayer))
player.CastSpell(player, SpellIds.TiredPlayer, true);
break;
}
case GossipMenus.OptionIdDarnassusSenjinPennant:
case GossipMenus.OptionIdExodarUndercityPennant:
case GossipMenus.OptionIdGnomereganOrgrimmarPennant:
case GossipMenus.OptionIdIronforgeSilvermoonPennant:
case GossipMenus.OptionIdStormwindThunderbluffPennant:
if (IsArgentSquire())
DoCastSelf(Misc.bannerSpells[gossipListId - 3].Item1, new CastSpellExtraArgs(true));
else
DoCastSelf(Misc.bannerSpells[gossipListId - 3].Item2, new CastSpellExtraArgs(true));
break;
}
player.PlayerTalkClass.SendCloseGossip();
return false;
}
public override void UpdateAI(uint diff)
{
_scheduler.Update(diff);
}
bool IsArgentSquire() { return me.GetEntry() == CreatureIds.ArgentSquire; }
}
[Script]
class npc_bountiful_tableAI : PassiveAI
{
public npc_bountiful_tableAI(Creature creature) : base(creature) { }
public override void PassengerBoarded(Unit who, sbyte seatId, bool apply)
{
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
float o = 0.0f;
switch ((SeatIds)seatId)
{
case SeatIds.TurkeyChair:
x = 3.87f;
y = 2.07f;
o = 3.700098f;
break;
case SeatIds.CranberryChair:
x = 3.87f;
y = -2.07f;
o = 2.460914f;
break;
case SeatIds.StuffingChair:
x = -2.52f;
break;
case SeatIds.SweetPotatoChair:
x = -0.09f;
y = -3.24f;
o = 1.186824f;
break;
case SeatIds.PieChair:
x = -0.18f;
y = 3.24f;
o = 5.009095f;
break;
case SeatIds.FoodHolder:
case SeatIds.PlateHolder:
Vehicle holders = who.GetVehicleKit();
if (holders)
holders.InstallAllAccessories(true);
return;
default:
break;
}
MoveSplineInit init = new MoveSplineInit(who);
init.DisableTransportPathTransformations();
init.MoveTo(x, y, z, false);
init.SetFacing(o);
init.Launch();
who.m_Events.AddEvent(new CastFoodSpell(who, SpellIds.ChairSpells[who.GetEntry()]), who.m_Events.CalculateTime(1000));
Creature creature = who.ToCreature();
if (creature)
creature.SetDisplayFromModel(0);
}
}
class CastFoodSpell : BasicEvent
{
Unit _owner;
uint _spellId;
public CastFoodSpell(Unit owner, uint spellId)
{
_owner = owner;
_spellId = spellId;
}
public override bool Execute(ulong execTime, uint diff)
{
_owner.CastSpell(_owner, _spellId, true);
return true;
}
}
}