diff --git a/Source/Framework/Constants/ObjectConst.cs b/Source/Framework/Constants/ObjectConst.cs index a7354f6c7..267e0b7ed 100644 --- a/Source/Framework/Constants/ObjectConst.cs +++ b/Source/Framework/Constants/ObjectConst.cs @@ -122,7 +122,7 @@ namespace Framework.Constants TimedOrDeadDespawn = 1, // despawns after a specified time OR when the creature disappears TimedOrCorpseDespawn = 2, // despawns after a specified time OR when the creature dies TimedDespawn = 3, // despawns after a specified time - TimedDespawnOOC = 4, // despawns after a specified time after the creature is out of combat + TimedDespawnOutOfCombat = 4, // despawns after a specified time after the creature is out of combat CorpseDespawn = 5, // despawns instantly after death CorpseTimedDespawn = 6, // despawns after a specified time after death DeadDespawn = 7, // despawns when the creature disappears diff --git a/Source/Game/AI/AISelector.cs b/Source/Game/AI/AISelector.cs index 3874dd72b..7a33e75d9 100644 --- a/Source/Game/AI/AISelector.cs +++ b/Source/Game/AI/AISelector.cs @@ -119,11 +119,11 @@ namespace Game.AI switch (go.GetAIName()) { case "GameObjectAI": + default: return new GameObjectAI(go); case "SmartGameObjectAI": return new SmartGameObjectAI(go); } - return new NullGameObjectAI(go); } } } diff --git a/Source/Game/AI/CoreAI/GameObjectAI.cs b/Source/Game/AI/CoreAI/GameObjectAI.cs index c1111f3cb..4af884941 100644 --- a/Source/Game/AI/CoreAI/GameObjectAI.cs +++ b/Source/Game/AI/CoreAI/GameObjectAI.cs @@ -99,11 +99,4 @@ namespace Game.AI public GameObject me; } - - public class NullGameObjectAI : GameObjectAI - { - public NullGameObjectAI(GameObject g) : base(g) { } - - public override void UpdateAI(uint diff) { } - } } diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index ac96bcb7d..a6653e072 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -2812,7 +2812,7 @@ namespace Game.Entities stmt.AddValue(5, GetGUID().GetCounter()); DB.Characters.Execute(stmt); } - void SetBindPoint(ObjectGuid guid) + public void SetBindPoint(ObjectGuid guid) { BinderConfirm packet = new BinderConfirm(guid); SendPacket(packet); diff --git a/Source/Game/Entities/TemporarySummon.cs b/Source/Game/Entities/TemporarySummon.cs index e86e5b627..19d33a8be 100644 --- a/Source/Game/Entities/TemporarySummon.cs +++ b/Source/Game/Entities/TemporarySummon.cs @@ -69,7 +69,7 @@ namespace Game.Entities m_timer -= diff; break; } - case TempSummonType.TimedDespawnOOC: + case TempSummonType.TimedDespawnOutOfCombat: { if (!IsInCombat()) { diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index f7542ef61..897bdb6c1 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -1872,7 +1872,7 @@ namespace Game creature.FlagsExtra = (CreatureFlagsExtra)fields.Read(75); creature.ScriptID = GetScriptId(fields.Read(76)); - _creatureTemplateStorage.Add(entry, creature); + _creatureTemplateStorage[entry] = creature; } void LoadCreatureTemplateModels() diff --git a/Source/Game/Scripting/CoreScripts.cs b/Source/Game/Scripting/CoreScripts.cs index 5c8577c8b..62932a62b 100644 --- a/Source/Game/Scripting/CoreScripts.cs +++ b/Source/Game/Scripting/CoreScripts.cs @@ -340,6 +340,24 @@ namespace Game.Scripting public virtual CreatureAI GetAI(Creature creature) { return null; } } + public class GenericGameObjectScript : GameObjectScript where AI : GameObjectAI + { + public GenericGameObjectScript(string name, object[] args) : base(name) + { + _args = args; + } + + public override GameObjectAI GetAI(GameObject me) + { + if (me.GetInstanceScript() != null) + return GetInstanceAI(me); + else + return (AI)Activator.CreateInstance(typeof(AI), new object[] { me }.Combine(_args)); + } + + object[] _args; + } + public class GameObjectScript : ScriptObject { public GameObjectScript(string name) : base(name) diff --git a/Source/Game/Scripting/ScriptManager.cs b/Source/Game/Scripting/ScriptManager.cs index a41f0eec6..30ad48e8b 100644 --- a/Source/Game/Scripting/ScriptManager.cs +++ b/Source/Game/Scripting/ScriptManager.cs @@ -79,21 +79,7 @@ namespace Game.Scripting foreach (var type in assembly.GetTypes()) { var attributes = (ScriptAttribute[])type.GetCustomAttributes(); - if (attributes.Empty()) - { - var baseType = type.BaseType; - while (baseType != null) - { - if (baseType == typeof(ScriptObject)) - { - Log.outWarn(LogFilter.Server, "Script {0} does not have ScriptAttribute", type.Name); - continue; - } - - baseType = baseType.BaseType; - } - } - else + if (!attributes.Empty()) { var constructors = type.GetConstructors(); if (constructors.Length == 0) @@ -136,14 +122,17 @@ namespace Game.Scripting switch (type.BaseType.Name) { - case "SpellScript": + case nameof(SpellScript): genericType = typeof(GenericSpellScriptLoader<>).MakeGenericType(type); name = name.Replace("_SpellScript", ""); break; - case "AuraScript": + case nameof(AuraScript): genericType = typeof(GenericAuraScriptLoader<>).MakeGenericType(type); name = name.Replace("_AuraScript", ""); break; + case nameof(GameObjectAI): + genericType = typeof(GenericGameObjectScript<>).MakeGenericType(type); + break; case "SpellScriptLoader": case "AuraScriptLoader": case "WorldScript": @@ -177,7 +166,6 @@ namespace Game.Scripting Activator.CreateInstance(genericType); else Activator.CreateInstance(genericType, new object[] { name }.Combine(attribute.Args)); - continue; default: genericType = typeof(GenericCreatureScript<>).MakeGenericType(type); diff --git a/Source/Scripts/World/Achievements.cs b/Source/Scripts/World/Achievements.cs index 992095372..fa0dbb9c4 100644 --- a/Source/Scripts/World/Achievements.cs +++ b/Source/Scripts/World/Achievements.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2012-2020 CypherCore * * This program is free software: you can redistribute it and/or modify @@ -21,9 +21,9 @@ using Game.BattleGrounds.Zones; using Game.Entities; using Game.Scripting; -namespace Scripts.World +namespace Scripts.World.Achievements { - struct AchievementConst + struct AreaIds { //Tilted public const uint AreaArgentTournamentFields = 4658; @@ -32,12 +32,18 @@ namespace Scripts.World public const uint AreaRingOfAllianceValiants = 4672; public const uint AreaRingOfHordeValiants = 4673; public const uint AreaRingOfChampions = 4669; + } + struct AuraIds + { //Flirt With Disaster public const uint AuraPerfumeForever = 70235; public const uint AuraPerfumeEnchantress = 70234; public const uint AuraPerfumeVictory = 70233; + } + struct VehicleIds + { //BgSA Artillery public const uint AntiPersonnalCannon = 27894; } @@ -147,7 +153,7 @@ namespace Scripts.World Creature vehicle = source.GetVehicleCreatureBase(); if (vehicle) { - if (vehicle.GetEntry() == AchievementConst.AntiPersonnalCannon) + if (vehicle.GetEntry() == VehicleIds.AntiPersonnalCannon) return true; } @@ -160,6 +166,8 @@ namespace Scripts.World [Script("achievement_arena_5v5_kills", ArenaTypes.Team5v5)] class achievement_arena_kills : AchievementCriteriaScript { + ArenaTypes _arenaType; + public achievement_arena_kills(string name, ArenaTypes arenaType) : base(name) { _arenaType = arenaType; @@ -167,14 +175,12 @@ namespace Scripts.World public override bool OnCheck(Player source, Unit target) { - // this checks GetBattleground() for NULL already + // this checks GetBattleground() for Null already if (!source.InArena()) return false; return source.GetBattleground().GetArenaType() == _arenaType; } - - ArenaTypes _arenaType; } [Script] @@ -251,12 +257,12 @@ namespace Scripts.World if (!player) return false; - bool checkArea = player.GetAreaId() == AchievementConst.AreaArgentTournamentFields || - player.GetAreaId() == AchievementConst.AreaRingOfAspirants || - player.GetAreaId() == AchievementConst.AreaRingOfArgentValiants || - player.GetAreaId() == AchievementConst.AreaRingOfAllianceValiants || - player.GetAreaId() == AchievementConst.AreaRingOfHordeValiants || - player.GetAreaId() == AchievementConst.AreaRingOfChampions; + bool checkArea = player.GetAreaId() == AreaIds.AreaArgentTournamentFields || + player.GetAreaId() == AreaIds.AreaRingOfAspirants || + player.GetAreaId() == AreaIds.AreaRingOfArgentValiants || + player.GetAreaId() == AreaIds.AreaRingOfAllianceValiants || + player.GetAreaId() == AreaIds.AreaRingOfHordeValiants || + player.GetAreaId() == AreaIds.AreaRingOfChampions; return checkArea && player.duel != null && player.duel.isMounted; } @@ -287,7 +293,7 @@ namespace Scripts.World if (!player) return false; - if (player.HasAura(AchievementConst.AuraPerfumeForever) || player.HasAura(AchievementConst.AuraPerfumeEnchantress) || player.HasAura(AchievementConst.AuraPerfumeVictory)) + if (player.HasAura(AuraIds.AuraPerfumeForever) || player.HasAura(AuraIds.AuraPerfumeEnchantress) || player.HasAura(AuraIds.AuraPerfumeVictory)) return true; return false; diff --git a/Source/Scripts/World/AreaTrigger.cs b/Source/Scripts/World/AreaTrigger.cs index a69aefe77..a8fab07ca 100644 --- a/Source/Scripts/World/AreaTrigger.cs +++ b/Source/Scripts/World/AreaTrigger.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2012-2020 CypherCore * * This program is free software: you can redistribute it and/or modify @@ -21,75 +21,114 @@ using Game.Entities; using Game.Scripting; using System.Collections.Generic; -namespace Scripts.World +namespace Scripts.World.Areatriggers { - struct AreaTriggerConst + struct TextIds { - //Coilfang Waterfall - public const uint GoCoilfangWaterfall = 184212; + //Brewfest + public const uint SayWelcome = 4; + } + struct SpellIds + { //Legion Teleporter - public const uint SpellTeleATo = 37387; - public const uint QuestGainingAccessA = 10589; - - public const uint SpellTeleHTo = 37389; - public const uint QuestGainingAccessH = 10604; + public const uint TeleATo = 37387; + public const uint TeleHTo = 37389; //Stormwright Shelf - public const uint QuestStrengthOfTheTempest = 12741; - public const uint SpellCreateTruePowerOfTheTempest = 53067; - - //Scent Larkorwi - public const uint QuestScentOfLarkorwi = 4291; - public const uint NpcLarkorwiMate = 9683; - - //Last Rites - public const uint QuestLastRites = 12019; - public const uint QuestBreakingThrough = 11898; + public const uint CreateTruePowerOfTheTempest = 53067; //Sholazar Waygate - public const uint SpellSholazarToUngoroTeleport = 52056; - public const uint SpellUngoroToSholazarTeleport = 52057; - - public const uint AtSholazar = 5046; - public const uint AtUngoro = 5047; - - public const uint QuestTheMakersOverlook = 12613; - public const uint QuestTheMakersPerch = 12559; - public const uint QuestMeetingAGreatOne = 13956; + public const uint SholazarToUngoroTeleport = 52056; + public const uint UngoroToSholazarTeleport = 52057; //Nats Landing - public const uint QuestNatsBargain = 11209; - public const uint SpellFishPaste = 42644; - public const uint NpcLurkingShark = 23928; + public const uint FishPaste = 42644; + + //Area 52 + public const uint A52Neuralyzer = 34400; + } + + struct QuestIds + { + //Legion Teleporter + public const uint GainingAccessA = 10589; + public const uint GainingAccessH = 10604; + + //Stormwright Shelf + public const uint StrengthOfTheTempest = 12741; + + //Scent Larkorwi + public const uint ScentOfLarkorwi = 4291; + + //Last Rites + public const uint LastRites = 12019; + public const uint BreakingThrough = 11898; + + //Sholazar Waygate + public const uint TheMakersOverlook = 12613; + public const uint TheMakersPerch = 12559; + public const uint MeetingAGreatOne = 13956; + + //Nats Landing + public const uint NatsBargain = 11209; + + //Frostgrips Hollow + public const uint TheLonesomeWatcher = 12877; + } + + struct CreatureIds + { + //Scent Larkorwi + public const uint LarkorwiMate = 9683; + + //Nats Landing + public const uint LurkingShark = 23928; //Brewfest - public const uint NpcTapperSwindlekeg = 24711; - public const uint NpcIpfelkoferIronkeg = 24710; + public const uint TapperSwindlekeg = 24711; + public const uint IpfelkoferIronkeg = 24710; - public const uint AtBrewfestDurotar = 4829; - public const uint AtBrewfestDunMorogh = 4820; + //Area 52 + public const uint Spotlight = 19913; - public const uint SayWelcome = 4; + //Frostgrips Hollow + public const uint StormforgedMonitor = 29862; + public const uint StormforgedEradictor = 29861; + } + struct GameObjectIds + { + //Coilfang Waterfall + public const uint CoilfangWaterfall = 184212; + } + + struct AreaTriggerIds + { + //Sholazar Waygate + public const uint Sholazar = 5046; + public const uint Ungoro = 5047; + + //Brewfest + public const uint BrewfestDurotar = 4829; + public const uint BrewfestDunMorogh = 4820; + + //Area 52 + public const uint Area52South = 4472; + public const uint Area52North = 4466; + public const uint Area52West = 4471; + public const uint Area52East = 4422; + } + + struct Misc + { + //Brewfest public const uint AreatriggerTalkCooldown = 5; // In Seconds //Area 52 - public const uint SpellA52Neuralyzer = 34400; - public const uint NpcSpotlight = 19913; public const uint SummonCooldown = 5; - public const uint AtArea52South = 4472; - public const uint AtArea52North = 4466; - public const uint AtArea52West = 4471; - public const uint AtArea52East = 4422; - //Frostgrips Hollow - public const uint QuestTheLonesomeWatcher = 12877; - - public const uint NpcStormforgedMonitor = 29862; - public const uint NpcStormforgedEradictor = 29861; - public const uint TypeWaypoint = 0; public const uint DataStart = 0; @@ -102,9 +141,9 @@ namespace Scripts.World { public AreaTrigger_at_coilfang_waterfall() : base("at_coilfang_waterfall") { } - public override bool OnTrigger(Player player, AreaTriggerRecord trigger, bool entered) + public override bool OnTrigger(Player player, AreaTriggerRecord areaTrigger, bool entered) { - GameObject go = player.FindNearestGameObject(AreaTriggerConst.GoCoilfangWaterfall, 35.0f); + GameObject go = player.FindNearestGameObject(GameObjectIds.CoilfangWaterfall, 35.0f); if (go) if (go.GetLootState() == LootState.Ready) go.UseDoorOrButton(); @@ -118,19 +157,19 @@ namespace Scripts.World { public AreaTrigger_at_legion_teleporter() : base("at_legion_teleporter") { } - public override bool OnTrigger(Player player, AreaTriggerRecord trigger, bool entered) + public override bool OnTrigger(Player player, AreaTriggerRecord areaTrigger, bool entered) { if (player.IsAlive() && !player.IsInCombat()) { - if (player.GetTeam() == Team.Alliance && player.GetQuestRewardStatus(AreaTriggerConst.QuestGainingAccessA)) + if (player.GetTeam() == Team.Alliance && player.GetQuestRewardStatus(QuestIds.GainingAccessA)) { - player.CastSpell(player, AreaTriggerConst.SpellTeleATo, false); + player.CastSpell(player, SpellIds.TeleATo, false); return true; } - if (player.GetTeam() == Team.Horde && player.GetQuestRewardStatus(AreaTriggerConst.QuestGainingAccessH)) + if (player.GetTeam() == Team.Horde && player.GetQuestRewardStatus(QuestIds.GainingAccessH)) { - player.CastSpell(player, AreaTriggerConst.SpellTeleHTo, false); + player.CastSpell(player, SpellIds.TeleHTo, false); return true; } @@ -145,10 +184,10 @@ namespace Scripts.World { public AreaTrigger_at_stormwright_shelf() : base("at_stormwright_shelf") { } - public override bool OnTrigger(Player player, AreaTriggerRecord trigger, bool entered) + public override bool OnTrigger(Player player, AreaTriggerRecord areaTrigger, bool entered) { - if (!player.IsDead() && player.GetQuestStatus(AreaTriggerConst.QuestStrengthOfTheTempest) == QuestStatus.Incomplete) - player.CastSpell(player, AreaTriggerConst.SpellCreateTruePowerOfTheTempest, false); + if (!player.IsDead() && player.GetQuestStatus(QuestIds.StrengthOfTheTempest) == QuestStatus.Incomplete) + player.CastSpell(player, SpellIds.CreateTruePowerOfTheTempest, false); return true; } @@ -159,12 +198,12 @@ namespace Scripts.World { public AreaTrigger_at_scent_larkorwi() : base("at_scent_larkorwi") { } - public override bool OnTrigger(Player player, AreaTriggerRecord trigger, bool entered) + public override bool OnTrigger(Player player, AreaTriggerRecord areaTrigger, bool entered) { - if (!player.IsDead() && player.GetQuestStatus(AreaTriggerConst.QuestScentOfLarkorwi) == QuestStatus.Incomplete) + if (!player.IsDead() && player.GetQuestStatus(QuestIds.ScentOfLarkorwi) == QuestStatus.Incomplete) { - if (!player.FindNearestCreature(AreaTriggerConst.NpcLarkorwiMate, 15)) - player.SummonCreature(AreaTriggerConst.NpcLarkorwiMate, player.GetPositionX() + 5, player.GetPositionY(), player.GetPositionZ(), 3.3f, TempSummonType.TimedDespawnOOC, 100000); + if (!player.FindNearestCreature(CreatureIds.LarkorwiMate, 15)) + player.SummonCreature(CreatureIds.LarkorwiMate, player.GetPositionX() + 5, player.GetPositionY(), player.GetPositionZ(), 3.3f, TempSummonType.TimedDespawnOutOfCombat, 100000); } return false; @@ -176,17 +215,17 @@ namespace Scripts.World { public AreaTrigger_at_last_rites() : base("at_last_rites") { } - public override bool OnTrigger(Player player, AreaTriggerRecord trigger, bool entered) + public override bool OnTrigger(Player player, AreaTriggerRecord areaTrigger, bool entered) { - if (!(player.GetQuestStatus(AreaTriggerConst.QuestLastRites) == QuestStatus.Incomplete || - player.GetQuestStatus(AreaTriggerConst.QuestLastRites) == QuestStatus.Complete || - player.GetQuestStatus(AreaTriggerConst.QuestBreakingThrough) == QuestStatus.Incomplete || - player.GetQuestStatus(AreaTriggerConst.QuestBreakingThrough) == QuestStatus.Complete)) + if (!(player.GetQuestStatus(QuestIds.LastRites) == QuestStatus.Incomplete || + player.GetQuestStatus(QuestIds.LastRites) == QuestStatus.Complete || + player.GetQuestStatus(QuestIds.BreakingThrough) == QuestStatus.Incomplete || + player.GetQuestStatus(QuestIds.BreakingThrough) == QuestStatus.Complete)) return false; WorldLocation pPosition; - switch (trigger.Id) + switch (areaTrigger.Id) { case 5332: case 5338: @@ -196,8 +235,8 @@ namespace Scripts.World pPosition = new WorldLocation(571, 3802.38f, 3585.95f, 49.5765f, 0.0f); break; case 5340: - if (player.GetQuestStatus(AreaTriggerConst.QuestLastRites) == QuestStatus.Incomplete || - player.GetQuestStatus(AreaTriggerConst.QuestLastRites) == QuestStatus.Complete) + if (player.GetQuestStatus(QuestIds.LastRites) == QuestStatus.Incomplete || + player.GetQuestStatus(QuestIds.LastRites) == QuestStatus.Complete) pPosition = new WorldLocation(571, 3687.91f, 3577.28f, 473.342f); else pPosition = new WorldLocation(571, 3739.38f, 3567.09f, 341.58f); @@ -217,19 +256,19 @@ namespace Scripts.World { public AreaTrigger_at_sholazar_waygate() : base("at_sholazar_waygate") { } - public override bool OnTrigger(Player player, AreaTriggerRecord trigger, bool entered) + public override bool OnTrigger(Player player, AreaTriggerRecord areaTrigger, bool entered) { - if (!player.IsDead() && (player.GetQuestStatus(AreaTriggerConst.QuestMeetingAGreatOne) != QuestStatus.None || - (player.GetQuestStatus(AreaTriggerConst.QuestTheMakersOverlook) == QuestStatus.Rewarded && player.GetQuestStatus(AreaTriggerConst.QuestTheMakersPerch) == QuestStatus.Rewarded))) + if (!player.IsDead() && (player.GetQuestStatus(QuestIds.MeetingAGreatOne) != QuestStatus.None || + (player.GetQuestStatus(QuestIds.TheMakersOverlook) == QuestStatus.Rewarded && player.GetQuestStatus(QuestIds.TheMakersPerch) == QuestStatus.Rewarded))) { - switch (trigger.Id) + switch (areaTrigger.Id) { - case AreaTriggerConst.AtSholazar: - player.CastSpell(player, AreaTriggerConst.SpellSholazarToUngoroTeleport, true); + case AreaTriggerIds.Sholazar: + player.CastSpell(player, SpellIds.SholazarToUngoroTeleport, true); break; - case AreaTriggerConst.AtUngoro: - player.CastSpell(player, AreaTriggerConst.SpellUngoroToSholazarTeleport, true); + case AreaTriggerIds.Ungoro: + player.CastSpell(player, SpellIds.UngoroToSholazarTeleport, true); break; } } @@ -243,16 +282,16 @@ namespace Scripts.World { public AreaTrigger_at_nats_landing() : base("at_nats_landing") { } - public override bool OnTrigger(Player player, AreaTriggerRecord trigger, bool entered) + public override bool OnTrigger(Player player, AreaTriggerRecord areaTrigger, bool entered) { - if (!player.IsAlive() || !player.HasAura(AreaTriggerConst.SpellFishPaste)) + if (!player.IsAlive() || !player.HasAura(SpellIds.FishPaste)) return false; - if (player.GetQuestStatus(AreaTriggerConst.QuestNatsBargain) == QuestStatus.Incomplete) + if (player.GetQuestStatus(QuestIds.NatsBargain) == QuestStatus.Incomplete) { - if (!player.FindNearestCreature(AreaTriggerConst.NpcLurkingShark, 20.0f)) + if (!player.FindNearestCreature(CreatureIds.LurkingShark, 20.0f)) { - Creature shark = player.SummonCreature(AreaTriggerConst.NpcLurkingShark, -4246.243f, -3922.356f, -7.488f, 5.0f, TempSummonType.TimedDespawnOOC, 100000); + Creature shark = player.SummonCreature(CreatureIds.LurkingShark, -4246.243f, -3922.356f, -7.488f, 5.0f, TempSummonType.TimedDespawnOutOfCombat, 100000); if (shark) shark.GetAI().AttackStart(player); @@ -266,30 +305,36 @@ namespace Scripts.World [Script] class AreaTrigger_at_brewfest : AreaTriggerScript { + Dictionary _triggerTimes; + public AreaTrigger_at_brewfest() : base("at_brewfest") { // Initialize for cooldown - _triggerTimes[AreaTriggerConst.AtBrewfestDurotar] = _triggerTimes[AreaTriggerConst.AtBrewfestDunMorogh] = 0; + _triggerTimes = new Dictionary() + { + { AreaTriggerIds.BrewfestDurotar, 0 }, + { AreaTriggerIds.BrewfestDunMorogh,0 }, + }; } - public override bool OnTrigger(Player player, AreaTriggerRecord trigger, bool entered) + public override bool OnTrigger(Player player, AreaTriggerRecord areaTrigger, bool entered) { - uint triggerId = trigger.Id; + uint triggerId = areaTrigger.Id; // Second trigger happened too early after first, skip for now - if (GameTime.GetGameTime() - _triggerTimes[triggerId] < AreaTriggerConst.AreatriggerTalkCooldown) + if (GameTime.GetGameTime() - _triggerTimes[triggerId] < Misc.AreatriggerTalkCooldown) return false; switch (triggerId) { - case AreaTriggerConst.AtBrewfestDurotar: - Creature tapper = player.FindNearestCreature(AreaTriggerConst.NpcTapperSwindlekeg, 20.0f); + case AreaTriggerIds.BrewfestDurotar: + Creature tapper = player.FindNearestCreature(CreatureIds.TapperSwindlekeg, 20.0f); if (tapper) - tapper.GetAI().Talk(AreaTriggerConst.SayWelcome, player); + tapper.GetAI().Talk(TextIds.SayWelcome, player); break; - case AreaTriggerConst.AtBrewfestDunMorogh: - Creature ipfelkofer = player.FindNearestCreature(AreaTriggerConst.NpcIpfelkoferIronkeg, 20.0f); + case AreaTriggerIds.BrewfestDunMorogh: + Creature ipfelkofer = player.FindNearestCreature(CreatureIds.IpfelkoferIronkeg, 20.0f); if (ipfelkofer) - ipfelkofer.GetAI().Talk(AreaTriggerConst.SayWelcome, player); + ipfelkofer.GetAI().Talk(TextIds.SayWelcome, player); break; default: break; @@ -298,70 +343,80 @@ namespace Scripts.World _triggerTimes[triggerId] = GameTime.GetGameTime(); return false; } - - Dictionary _triggerTimes = new Dictionary(); } [Script] class AreaTrigger_at_area_52_entrance : AreaTriggerScript { + Dictionary _triggerTimes; + public AreaTrigger_at_area_52_entrance() : base("at_area_52_entrance") { - _triggerTimes[AreaTriggerConst.AtArea52South] = _triggerTimes[AreaTriggerConst.AtArea52North] = _triggerTimes[AreaTriggerConst.AtArea52West] = _triggerTimes[AreaTriggerConst.AtArea52East] = 0; + _triggerTimes = new Dictionary() + { + { AreaTriggerIds.Area52South, 0 }, + { AreaTriggerIds.Area52North,0 }, + { AreaTriggerIds.Area52West,0}, + { AreaTriggerIds.Area52East,0}, + }; } - public override bool OnTrigger(Player player, AreaTriggerRecord trigger, bool entered) + public override bool OnTrigger(Player player, AreaTriggerRecord areaTrigger, bool entered) { float x = 0.0f, y = 0.0f, z = 0.0f; if (!player.IsAlive()) return false; - uint triggerId = trigger.Id; - if (GameTime.GetGameTime() - _triggerTimes[trigger.Id] < AreaTriggerConst.SummonCooldown) + if (GameTime.GetGameTime() - _triggerTimes[areaTrigger.Id] < Misc.SummonCooldown) return false; - switch (triggerId) + switch (areaTrigger.Id) { - case AreaTriggerConst.AtArea52East: + case AreaTriggerIds.Area52East: x = 3044.176f; y = 3610.692f; z = 143.61f; break; - case AreaTriggerConst.AtArea52North: + case AreaTriggerIds.Area52North: x = 3114.87f; y = 3687.619f; z = 143.62f; break; - case AreaTriggerConst.AtArea52West: + case AreaTriggerIds.Area52West: x = 3017.79f; y = 3746.806f; z = 144.27f; break; - case AreaTriggerConst.AtArea52South: + case AreaTriggerIds.Area52South: x = 2950.63f; y = 3719.905f; z = 143.33f; break; } - player.SummonCreature(AreaTriggerConst.NpcSpotlight, x, y, z, 0.0f, TempSummonType.TimedDespawn, 5000); - player.AddAura(AreaTriggerConst.SpellA52Neuralyzer, player); - _triggerTimes[trigger.Id] = GameTime.GetGameTime(); + player.SummonCreature(CreatureIds.Spotlight, x, y, z, 0.0f, TempSummonType.TimedDespawn, 5000); + player.AddAura(SpellIds.A52Neuralyzer, player); + _triggerTimes[areaTrigger.Id] = GameTime.GetGameTime(); return false; } - - Dictionary _triggerTimes = new Dictionary(); } [Script] class AreaTrigger_at_frostgrips_hollow : AreaTriggerScript { - public AreaTrigger_at_frostgrips_hollow() : base("at_frostgrips_hollow") { } + ObjectGuid stormforgedMonitorGUID; + ObjectGuid stormforgedEradictorGUID; - public override bool OnTrigger(Player player, AreaTriggerRecord trigger, bool entered) + public AreaTrigger_at_frostgrips_hollow() : base("at_frostgrips_hollow") { - if (player.GetQuestStatus(AreaTriggerConst.QuestTheLonesomeWatcher) != QuestStatus.Incomplete) + stormforgedMonitorGUID.Clear(); + stormforgedEradictorGUID.Clear(); + } + + public override bool OnTrigger(Player player, AreaTriggerRecord areaTrigger, bool entered) + { + if (player.GetQuestStatus(QuestIds.TheLonesomeWatcher) != QuestStatus.Incomplete) return false; Creature stormforgedMonitor = ObjectAccessor.GetCreature(player, stormforgedMonitorGUID); @@ -372,27 +427,24 @@ namespace Scripts.World if (stormforgedEradictor) return false; - stormforgedMonitor = player.SummonCreature(AreaTriggerConst.NpcStormforgedMonitor, AreaTriggerConst.StormforgedMonitorPosition, TempSummonType.TimedDespawnOOC, 60000); + stormforgedMonitor = player.SummonCreature(CreatureIds.StormforgedMonitor, Misc.StormforgedMonitorPosition, TempSummonType.TimedDespawnOutOfCombat, 60000); if (stormforgedMonitor) { stormforgedMonitorGUID = stormforgedMonitor.GetGUID(); stormforgedMonitor.SetWalk(false); - // The npc would search an alternative way to get to the last waypoint without this unit state. + /// The npc would search an alternative way to get to the last waypoint without this unit state. stormforgedMonitor.AddUnitState(UnitState.IgnorePathfinding); - stormforgedMonitor.GetMotionMaster().MovePath(AreaTriggerConst.NpcStormforgedMonitor * 100, false); + stormforgedMonitor.GetMotionMaster().MovePath(CreatureIds.StormforgedMonitor * 100, false); } - stormforgedEradictor = player.SummonCreature(AreaTriggerConst.NpcStormforgedEradictor, AreaTriggerConst.StormforgedEradictorPosition, TempSummonType.TimedDespawnOOC, 60000); + stormforgedEradictor = player.SummonCreature(CreatureIds.StormforgedEradictor, Misc.StormforgedEradictorPosition, TempSummonType.TimedDespawnOutOfCombat, 60000); if (stormforgedEradictor) { stormforgedEradictorGUID = stormforgedEradictor.GetGUID(); - stormforgedEradictor.GetMotionMaster().MovePath(AreaTriggerConst.NpcStormforgedEradictor * 100, false); + stormforgedEradictor.GetMotionMaster().MovePath(CreatureIds.StormforgedEradictor * 100, false); } return true; } - - ObjectGuid stormforgedMonitorGUID; - ObjectGuid stormforgedEradictorGUID; } -} +} \ No newline at end of file diff --git a/Source/Scripts/World/DuelReset.cs b/Source/Scripts/World/DuelReset.cs index 53fd7802f..00f5da09e 100644 --- a/Source/Scripts/World/DuelReset.cs +++ b/Source/Scripts/World/DuelReset.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2012-2020 CypherCore * * This program is free software: you can redistribute it and/or modify @@ -22,17 +22,21 @@ using Game.Scripting; using Game.Spells; using System; -namespace Scripts.World +namespace Scripts.World.DuelReset { [Script] class DuelResetScript : PlayerScript { + bool _resetCooldowns; + bool _resetHealthMana; + public DuelResetScript() : base("DuelResetScript") { _resetCooldowns = WorldConfig.GetBoolValue(WorldCfg.ResetDuelCooldowns); _resetHealthMana = WorldConfig.GetBoolValue(WorldCfg.ResetDuelHealthMana); } + // Called when a duel starts (after 3s countdown) public override void OnDuelStart(Player player1, Player player2) { // Cooldowns reset @@ -58,9 +62,10 @@ namespace Scripts.World } } + // Called when a duel ends public override void OnDuelEnd(Player winner, Player loser, DuelCompleteType type) { - // do not reset anything if DUEL_INTERRUPTED or DUEL_FLED + // do not reset anything if DuelInterrupted or DuelFled if (type == DuelCompleteType.Won) { // Cooldown restore @@ -90,17 +95,18 @@ namespace Scripts.World } } - void ResetSpellCooldowns(Player player, bool onStartDuel) + static void ResetSpellCooldowns(Player player, bool onStartDuel) { - // Remove cooldowns on spells that have < 10 min CD > 30 sec and has no onHold - player.GetSpellHistory().ResetCooldowns(itr => + // remove cooldowns on spells that have < 10 min Cd > 30 sec and has no onHold + player.GetSpellHistory().ResetCooldowns(pair => { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(itr.Key, Difficulty.None); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key, Difficulty.None); uint remainingCooldown = player.GetSpellHistory().GetRemainingCooldown(spellInfo); uint totalCooldown = spellInfo.RecoveryTime; uint categoryCooldown = spellInfo.CategoryRecoveryTime; player.ApplySpellMod(spellInfo.Id, SpellModOp.Cooldown, ref totalCooldown, null); + int cooldownMod = player.GetTotalAuraModifier(AuraType.ModCooldown); if (cooldownMod != 0) totalCooldown += (uint)(cooldownMod * Time.InMilliseconds); @@ -109,12 +115,12 @@ namespace Scripts.World player.ApplySpellMod(spellInfo.Id, SpellModOp.Cooldown, ref categoryCooldown, null); return remainingCooldown > 0 - && !itr.Value.OnHold - && TimeSpan.FromMilliseconds(totalCooldown) < TimeSpan.FromMinutes(10) - && TimeSpan.FromMilliseconds(categoryCooldown) < TimeSpan.FromMinutes(10) - && TimeSpan.FromMilliseconds(remainingCooldown) < TimeSpan.FromMinutes(10) - && (onStartDuel ? TimeSpan.FromMilliseconds(totalCooldown - remainingCooldown) > TimeSpan.FromSeconds(30) : true) - && (onStartDuel ? TimeSpan.FromMilliseconds(categoryCooldown - remainingCooldown) > TimeSpan.FromSeconds(30) : true); + && !pair.Value.OnHold + && TimeSpan.FromMilliseconds(totalCooldown) < TimeSpan.FromMinutes(10) + && TimeSpan.FromMilliseconds(categoryCooldown) < TimeSpan.FromMinutes(10) + && TimeSpan.FromMilliseconds(remainingCooldown) < TimeSpan.FromMinutes(10) + && (onStartDuel ? TimeSpan.FromMilliseconds(totalCooldown - remainingCooldown) > TimeSpan.FromSeconds(30) : true) + && (onStartDuel ? TimeSpan.FromMilliseconds(categoryCooldown - remainingCooldown) > TimeSpan.FromSeconds(30) : true); }, true); // pet cooldowns @@ -122,8 +128,5 @@ namespace Scripts.World if (pet) pet.GetSpellHistory().ResetAllCooldowns(); } - - bool _resetCooldowns; - bool _resetHealthMana; } -} +} \ No newline at end of file diff --git a/Source/Scripts/World/EmeraldDragons.cs b/Source/Scripts/World/EmeraldDragons.cs index 99794c160..579b59322 100644 --- a/Source/Scripts/World/EmeraldDragons.cs +++ b/Source/Scripts/World/EmeraldDragons.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2012-2020 CypherCore * * This program is free software: you can redistribute it and/or modify @@ -23,7 +23,7 @@ using Game.Spells; using System; using System.Collections.Generic; -namespace Scripts.World.BossEmeraldDragons +namespace Scripts.World.EmeraldDragons { struct CreatureIds { @@ -75,23 +75,23 @@ namespace Scripts.World.BossEmeraldDragons public static uint[] TaerarShadeSpells = new uint[] { 24841, 24842, 24843 }; } - struct Texts + struct TextIds { //Ysondre - public const uint YsondreAggro = 0; - public const uint YsondreSummonDruids = 1; + public const uint SayYsondreAggro = 0; + public const uint SayYsondreSummonDruids = 1; //Lethon - public const uint LethonAggro = 0; - public const uint LethonDrawSpirit = 1; + public const uint SayLethonAggro = 0; + public const uint SayLethonDrawSpirit = 1; //Emeriss - public const uint EmerissAggro = 0; - public const uint EmerissCastCorruption = 1; + public const uint SayEmerissAggro = 0; + public const uint SayEmerissCastCorruption = 1; //Taerar - public const uint TaerarAggro = 0; - public const uint TaerarSummonShades = 1; + public const uint SayTaerarAggro = 0; + public const uint SayTaerarSummonShades = 1; } class emerald_dragonAI : WorldBossAI @@ -157,6 +157,8 @@ namespace Scripts.World.BossEmeraldDragons [Script] class npc_dream_fog : ScriptedAI { + uint _roamTimer; + public npc_dream_fog(Creature creature) : base(creature) { Initialize(); @@ -200,13 +202,13 @@ namespace Scripts.World.BossEmeraldDragons else _roamTimer -= diff; } - - uint _roamTimer; } [Script] class boss_ysondre : emerald_dragonAI { + byte _stage; + public boss_ysondre(Creature creature) : base(creature) { Initialize(); @@ -221,6 +223,7 @@ namespace Scripts.World.BossEmeraldDragons { Initialize(); base.Reset(); + _scheduler.Schedule(TimeSpan.FromSeconds(12), task => { DoCastVictim(SpellIds.LightningWave); @@ -230,7 +233,7 @@ namespace Scripts.World.BossEmeraldDragons public override void EnterCombat(Unit who) { - Talk(Texts.YsondreAggro); + Talk(TextIds.SayYsondreAggro); base.EnterCombat(who); } @@ -239,20 +242,20 @@ namespace Scripts.World.BossEmeraldDragons { if (!HealthAbovePct(100 - 25 * _stage)) { - Talk(Texts.YsondreSummonDruids); + Talk(TextIds.SayYsondreSummonDruids); for (byte i = 0; i < 10; ++i) DoCast(me, SpellIds.SummonDruidSpirits, true); ++_stage; } } - - byte _stage; } [Script] class boss_lethon : emerald_dragonAI { + byte _stage; + public boss_lethon(Creature creature) : base(creature) { Initialize(); @@ -277,7 +280,7 @@ namespace Scripts.World.BossEmeraldDragons public override void EnterCombat(Unit who) { - Talk(Texts.LethonAggro); + Talk(TextIds.SayLethonAggro); base.EnterCombat(who); } @@ -285,7 +288,7 @@ namespace Scripts.World.BossEmeraldDragons { if (!HealthAbovePct(100 - 25 * _stage)) { - Talk(Texts.LethonDrawSpirit); + Talk(TextIds.SayLethonDrawSpirit); DoCast(me, SpellIds.DrawSpirit); ++_stage; } @@ -296,16 +299,16 @@ namespace Scripts.World.BossEmeraldDragons if (spell.Id == SpellIds.DrawSpirit && target.IsTypeId(TypeId.Player)) { Position targetPos = target.GetPosition(); - me.SummonCreature(CreatureIds.SpiritShade, targetPos, TempSummonType.TimedDespawnOOC, 50000); + me.SummonCreature(CreatureIds.SpiritShade, targetPos, TempSummonType.TimedDespawnOutOfCombat, 50000); } } - - byte _stage; } [Script] class npc_spirit_shade : PassiveAI { + ObjectGuid _summonerGuid; + public npc_spirit_shade(Creature creature) : base(creature) { } public override void IsSummonedBy(Unit summoner) @@ -322,13 +325,13 @@ namespace Scripts.World.BossEmeraldDragons me.DespawnOrUnsummon(1000); } } - - ObjectGuid _summonerGuid; } [Script] class boss_emeriss : emerald_dragonAI { + byte _stage; + public boss_emeriss(Creature creature) : base(creature) { Initialize(); @@ -360,7 +363,7 @@ namespace Scripts.World.BossEmeraldDragons public override void EnterCombat(Unit who) { - Talk(Texts.EmerissAggro); + Talk(TextIds.SayEmerissAggro); base.EnterCombat(who); } @@ -368,18 +371,21 @@ namespace Scripts.World.BossEmeraldDragons { if (!HealthAbovePct(100 - 25 * _stage)) { - Talk(Texts.EmerissCastCorruption); + Talk(TextIds.SayEmerissCastCorruption); DoCast(me, SpellIds.CorruptionOfEarth, true); ++_stage; } } - - byte _stage; } [Script] class boss_taerar : emerald_dragonAI { + bool _banished; // used for shades activation testing + uint _banishedTimer; // counter for banishment timeout + byte _shades; // keep track of how many shades are dead + byte _stage; // check which "shade phase" we're at (75-50-25 percentage counters) + public boss_taerar(Creature creature) : base(creature) { Initialize(); @@ -398,7 +404,6 @@ namespace Scripts.World.BossEmeraldDragons me.RemoveAurasDueToSpell(SpellIds.Shade); Initialize(); - base.Reset(); _scheduler.Schedule(TimeSpan.FromSeconds(12), task => @@ -416,7 +421,7 @@ namespace Scripts.World.BossEmeraldDragons public override void EnterCombat(Unit who) { - Talk(Texts.TaerarAggro); + Talk(TextIds.SayTaerarAggro); base.EnterCombat(who); } @@ -437,7 +442,7 @@ namespace Scripts.World.BossEmeraldDragons me.InterruptNonMeleeSpells(false); DoStopAttack(); - Talk(Texts.TaerarSummonShades); + Talk(TextIds.SayTaerarSummonShades); foreach (var spell in SpellIds.TaerarShadeSpells) DoCastVictim(spell, true); @@ -458,7 +463,7 @@ namespace Scripts.World.BossEmeraldDragons if (_banished) { - // If all three shades are dead, OR it has taken too long, end the current event and get Taerar back into business + // If all three shades are dead, Or it has taken too long, end the current event and get Taerar back into business if (_banishedTimer <= diff || _shades == 0) { _banished = false; @@ -471,7 +476,7 @@ namespace Scripts.World.BossEmeraldDragons else _banishedTimer -= diff; - // Update the scheduler before we return (handled under emerald_dragonAI.UpdateAI(diff); if we're not inside this check) + // Update the _scheduler before we return (handled under emerald_dragonAI.UpdateAI(diff); if we're not inside this check) _scheduler.Update(diff); return; @@ -479,15 +484,10 @@ namespace Scripts.World.BossEmeraldDragons base.UpdateAI(diff); } - - bool _banished; // used for shades activation testing - uint _banishedTimer; // counter for banishment timeout - byte _shades; // keep track of how many shades are dead - byte _stage; // check which "shade phase" we're at (75-50-25 percentage counters) } [Script] - class spell_dream_fog_sleep : SpellScript + class spell_dream_fog_sleep_SpellScript : SpellScript { void FilterTargets(List targets) { @@ -507,7 +507,7 @@ namespace Scripts.World.BossEmeraldDragons } [Script] - class spell_mark_of_nature : SpellScript + class spell_mark_of_nature_SpellScript : SpellScript { public override bool Validate(SpellInfo spellInfo) { @@ -522,6 +522,7 @@ namespace Scripts.World.BossEmeraldDragons Unit unit = obj.ToUnit(); if (unit) return !(unit.HasAura(SpellIds.MarkOfNature) && !unit.HasAura(SpellIds.AuraOfNature)); + return true; }); } @@ -538,4 +539,4 @@ namespace Scripts.World.BossEmeraldDragons OnEffectHitTarget.Add(new EffectHandler(HandleEffect, 0, SpellEffectName.ApplyAura)); } } -} +} \ No newline at end of file diff --git a/Source/Scripts/World/GameObject.cs b/Source/Scripts/World/GameObject.cs new file mode 100644 index 000000000..5f1bbb2c3 --- /dev/null +++ b/Source/Scripts/World/GameObject.cs @@ -0,0 +1,1314 @@ +/* + * Copyright (C) 2012-2020 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.DataStorage; +using Game.Entities; +using Game.Scripting; +using System; +using System.Collections.Generic; + +namespace Scripts.World.GameObjects +{ + struct SpellIds + { + //CatFigurine + public const uint SummonGhostSaber = 5968; + + //EthereumPrison + public const uint RepLc = 39456; + public const uint RepShat = 39457; + public const uint RepCe = 39460; + public const uint RepCon = 39474; + public const uint RepKt = 39475; + public const uint RepSpor = 39476; + + //Southfury + public const uint Blackjack = 39865; //Stuns Player + public const uint SummonRizzle = 39866; + + //Felcrystalforge + public const uint Create1FlaskOfBeast = 40964; + public const uint Create5FlaskOfBeast = 40965; + + //Bashircrystalforge + public const uint Create1FlaskOfSorcerer = 40968; + public const uint Create5FlaskOfSorcerer = 40970; + + //Matrixpunchograph + public const uint YellowPunchCard = 11512; + public const uint BluePunchCard = 11525; + public const uint RedPunchCard = 11528; + public const uint PrismaticPunchCard = 11545; + + //Arcaneprison + public const uint ArcanePrisonerKillCredit = 45456; + + //Jotunheimcage + public const uint SummonBladeKnightH = 56207; + public const uint SummonBladeKnightNe = 56209; + public const uint SummonBladeKnightOrc = 56212; + public const uint SummonBladeKnightTroll = 56214; + + //Inconspicuouslandmark + public const uint SummonPiratesTreasureAndTriggerMob = 11462; + + //Amberpineouthouse + public const uint Indisposed = 53017; + public const uint IndisposedIii = 48341; + public const uint CreateAmberseeds = 48330; + + //Thecleansing + public const uint CleansingSoul = 43351; + public const uint RecentMeditation = 61720; + + //Midsummerbonfire + public const uint StampOutBonfireQuestComplete = 45458; + + //MidsummerPoleRibbon + public static uint[] RibbonPoleSpells = { 29705, 29726, 29727 }; + + //Toy Train Set + public const uint ToyTrainPulse = 61551; + } + + struct CreatureIds + { + //GildedBrazier + public const uint Stillblade = 17716; + + //EthereumPrison + public static uint[] PrisonEntry = + { + 22810, 22811, 22812, 22813, 22814, 22815, //Good Guys + 20783, 20784, 20785, 20786, 20788, 20789, 20790 //Bad Guys + }; + + //Ethereum Stasis + public static uint[] StasisEntry = + { + 22825, 20888, 22827, 22826, 22828 + }; + + //ResoniteCask + public const uint Goggeroc = 11920; + + //Sacredfireoflife + public const uint Arikara = 10882; + + //Shrineofthebirds + public const uint HawkGuard = 22992; + public const uint EagleGuard = 22993; + public const uint FalconGuard = 22994; + + //Southfury + public const uint Rizzle = 23002; + + //Scourgecage + public const uint ScourgePrisoner = 25610; + + //Bloodfilledorb + public const uint Zelemar = 17830; + + //Jotunheimcage + public const uint EbonBladePrisonerHuman = 30186; + public const uint EbonBladePrisonerNe = 30194; + public const uint EbonBladePrisonerTroll = 30196; + public const uint EbonBladePrisonerOrc = 30195; + + //Prisonersofwyrmskull + public const uint PrisonerPriest = 24086; + public const uint PrisonerMage = 24088; + public const uint PrisonerWarrior = 24089; + public const uint PrisonerPaladin = 24090; + public const uint CapturedValgardePrisonerProxy = 24124; + + //Tadpoles + public const uint WinterfinTadpole = 25201; + + //Amberpineouthouse + public const uint OuthouseBunny = 27326; + + //Hives + public const uint HiveAmbusher = 13301; + + //Missingfriends + public const uint CaptiveChild = 22314; + + //MidsummerPoleRibbon + public const uint PoleRibbonBunny = 17066; + } + + struct GameObjectIds + { + //Shrineofthebirds + public const uint ShrineHawk = 185551; + public const uint ShrineEagle = 185547; + public const uint ShrineFalcon = 185553; + + //Bellhourlyobjects + public const uint HordeBell = 175885; + public const uint AllianceBell = 176573; + public const uint KharazhanBell = 182064; + } + + struct ItemIds + { + //Matrixpunchograph + public const uint WhitePunchCard = 9279; + public const uint YellowPunchCard = 9280; + public const uint BluePunchCard = 9282; + public const uint RedPunchCard = 9281; + public const uint PrismaticPunchCard = 9316; + public const uint MatrixPunchograph3005A = 142345; + public const uint MatrixPunchograph3005B = 142475; + public const uint MatrixPunchograph3005C = 142476; + public const uint MatrixPunchograph3005D = 142696; + + //Inconspicuouslandmark + public const uint CuergosKey = 9275; + + //Amberpineouthouse + public const uint AnderholsSliderCider = 37247; + } + + struct QuestIds + { + //GildedBrazier + public const uint TheFirstTrial = 9678; + + //Dalarancrystal + public const uint LearnLeaveReturn = 12790; + public const uint TeleCrystalFlag = 12845; + + //Arcaneprison + public const uint PrisonBreak = 11587; + + //Tabletheka + public const uint SpiderGold = 2936; + + //Prisonersofwyrmskull + public const uint PrisonersOfWyrmskull = 11255; + + //Tadpoles + public const uint OhNoesTheTadpoles = 11560; + + //Amberpineouthouse + public const uint DoingYourDuty = 12227; + + //Hives + public const uint HiveInTheTower = 9544; + + //Missingfriends + public const uint MissingFriends = 10852; + + //Thecleansing + public const uint TheCleansingHorde = 11317; + public const uint TheCleansingAlliance = 11322; + } + + struct TextIds + { + //Missingfriends + public const uint SayFree0 = 0; + } + + struct GossipConst + { + //Dalarancrystal + public const string GoTeleToDalaranCrystalFailed = "This Teleport Crystal Cannot Be Used Until The Teleport Crystal In Dalaran Has Been Used At Least Once."; + + //Felcrystalforge + public const uint GossipFelCrystalforgeText = 31000; + public const uint GossipFelCrystalforgeItemTextReturn = 31001; + public const string GossipFelCrystalforgeItem1 = "Purchase 1 Unstable Flask Of The Beast For The Cost Of 10 Apexis Shards"; + public const string GossipFelCrystalforgeItem5 = "Purchase 5 Unstable Flask Of The Beast For The Cost Of 50 Apexis Shards"; + public const string GossipFelCrystalforgeItemReturn = "Use The Fel Crystalforge To Make Another Purchase."; + + //Bashircrystalforge + public const uint GossipBashirCrystalforgeText = 31100; + public const uint GossipBashirCrystalforgeItemTextReturn = 31101; + public const string GossipBashirCrystalforgeItem1 = "Purchase 1 Unstable Flask Of The Sorcerer For The Cost Of 10 Apexis Shards"; + public const string GossipBashirCrystalforgeItem5 = "Purchase 5 Unstable Flask Of The Sorcerer For The Cost Of 50 Apexis Shards"; + public const string GossipBashirCrystalforgeItemReturn = "Use The Bashir Crystalforge To Make Another Purchase."; + + //Tabletheka + public const uint GossipTableTheka = 1653; + + //Amberpineouthouse + public const uint GossipOuthouseInuse = 12775; + public const uint GossipOuthouseVacant = 12779; + + public const string GossipUseOuthouse = "Use The Outhouse."; + public const string AnderholsSliderCiderNotFound = "Quest Item Anderhol'S Slider Cider Not Found."; + } + + struct SoundIds + { + //BrewfestMusic + public const uint EventBrewfestdwarf01 = 11810; // 1.35 Min + public const uint EventBrewfestdwarf02 = 11812; // 1.55 Min + public const uint EventBrewfestdwarf03 = 11813; // 0.23 Min + public const uint EventBrewfestgoblin01 = 11811; // 1.08 Min + public const uint EventBrewfestgoblin02 = 11814; // 1.33 Min + public const uint EventBrewfestgoblin03 = 11815; // 0.28 Min + + //Brewfestmusicevents + public const uint EventBmSelectMusic = 1; + public const uint EventBmStartMusic = 2; + + //Bells + //BellHourlySoundFX + public const uint BellTollHorde = 6595; // Horde + public const uint BellTollTribal = 6675; + public const uint BellTollAlliance = 6594; // Alliance + public const uint BellTollNightelf = 6674; + public const uint BellTolldwarfgnome = 7234; + public const uint BellTollKharazhan = 9154; // Kharazhan + } + + struct AreaIds + { + public const uint Silvermoon = 3430; // Horde + public const uint Undercity = 1497; + public const uint Orgrimmar1 = 1296; + public const uint Orgrimmar2 = 14; + public const uint Thunderbluff = 1638; + public const uint Ironforge1 = 809; // Alliance + public const uint Ironforge2 = 1; + public const uint Stormwind = 12; + public const uint Exodar = 3557; + public const uint Darnassus = 1657; + public const uint Shattrath = 3703; // General + public const uint TeldrassilZone = 141; + public const uint KharazhanMapid = 532; + } + + struct Misc + { + // These Are In Seconds + //Brewfestmusictime + public const uint EventBrewfestdwarf01Time = 95000; + public const uint EventBrewfestdwarf02Time = 155000; + public const uint EventBrewfestdwarf03Time = 23000; + public const uint EventBrewfestgoblin01Time = 68000; + public const uint EventBrewfestgoblin02Time = 93000; + public const uint EventBrewfestgoblin03Time = 28000; + + //Bellhourlymisc + public const uint GameEventHourlyBells = 73; + public const uint EventRingBell = 1; + } + + [Script] + class go_cat_figurine : GameObjectAI + { + public go_cat_figurine(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + player.CastSpell(player, SpellIds.SummonGhostSaber, true); + return false; + } + } + + [Script] + class go_barov_journal : GameObjectAI + { + public go_barov_journal(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (player.HasSkill(SkillType.Tailoring) && player.GetBaseSkillValue(SkillType.Tailoring) >= 280 && !player.HasSpell(26086)) + player.CastSpell(player, 26095, false); + + return true; + } + } + + [Script] + class go_gilded_brazier : GameObjectAI + { + public go_gilded_brazier(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (me.GetGoType() == GameObjectTypes.Goober) + { + if (player.GetQuestStatus(QuestIds.TheFirstTrial) == QuestStatus.Incomplete) + { + Creature Stillblade = player.SummonCreature(CreatureIds.Stillblade, 8106.11f, -7542.06f, 151.775f, 3.02598f, TempSummonType.DeadDespawn, 60000); + if (Stillblade) + Stillblade.GetAI().AttackStart(player); + } + } + return true; + } + } + + [Script] + class go_orb_of_command : GameObjectAI + { + public go_orb_of_command(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (player.GetQuestRewardStatus(7761)) + player.CastSpell(player, 23460, true); + + return true; + } + } + + [Script] + class go_tablet_of_madness : GameObjectAI + { + public go_tablet_of_madness(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (player.HasSkill(SkillType.Alchemy) && player.GetSkillValue(SkillType.Alchemy) >= 300 && !player.HasSpell(24266)) + player.CastSpell(player, 24267, false); + + return true; + } + } + + [Script] + class go_tablet_of_the_seven : GameObjectAI + { + public go_tablet_of_the_seven(GameObject go) : base(go) { } + + /// @todo use gossip option ("Transcript the Tablet") instead, if Trinity adds support. + public override bool GossipHello(Player player) + { + if (me.GetGoType() != GameObjectTypes.QuestGiver) + return true; + + if (player.GetQuestStatus(4296) == QuestStatus.Incomplete) + player.CastSpell(player, 15065, false); + + return true; + } + } + + [Script] + class go_jump_a_tron : GameObjectAI + { + public go_jump_a_tron(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (player.GetQuestStatus(10111) == QuestStatus.Incomplete) + player.CastSpell(player, 33382, true); + + return true; + } + } + + [Script] + class go_ethereum_prison : GameObjectAI + { + public go_ethereum_prison(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + me.UseDoorOrButton(); + int Random = (int)(RandomHelper.Rand32() % (CreatureIds.PrisonEntry.Length / sizeof(uint))); + + Creature creature = player.SummonCreature(CreatureIds.PrisonEntry[Random], me.GetPositionX(), me.GetPositionY(), me.GetPositionZ(), me.GetAngle(player), TempSummonType.TimedDespawnOutOfCombat, 30000); + if (creature) + { + if (!creature.IsHostileTo(player)) + { + FactionTemplateRecord pFaction = creature.GetFactionTemplateEntry(); + if (pFaction != null) + { + uint spellId = 0; + + switch (pFaction.Faction) + { + case 1011: + spellId = SpellIds.RepLc; + break; + case 935: + spellId = SpellIds.RepShat; + break; + case 942: + spellId = SpellIds.RepCe; + break; + case 933: + spellId = SpellIds.RepCon; + break; + case 989: + spellId = SpellIds.RepKt; + break; + case 970: + spellId = SpellIds.RepSpor; + break; + } + + if (spellId != 0) + creature.CastSpell(player, spellId, false); + else + Log.outError(LogFilter.Scripts, $"go_ethereum_prison summoned Creature (entry {creature.GetEntry()}) but faction ({creature.GetFaction()}) are not expected by script."); + } + } + } + + return false; + } + } + + [Script] + class go_ethereum_stasis : GameObjectAI + { + public go_ethereum_stasis(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + me.UseDoorOrButton(); + int Random = (int)(RandomHelper.Rand32() % CreatureIds.StasisEntry.Length / sizeof(uint)); + + player.SummonCreature(CreatureIds.StasisEntry[Random], me.GetPositionX(), me.GetPositionY(), me.GetPositionZ(), me.GetAngle(player), TempSummonType.TimedDespawnOutOfCombat, 30000); + + return false; + } + } + + [Script] + class go_resonite_cask : GameObjectAI + { + public go_resonite_cask(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (me.GetGoType() == GameObjectTypes.Goober) + me.SummonCreature(CreatureIds.Goggeroc, 0.0f, 0.0f, 0.0f, 0.0f, TempSummonType.TimedDespawnOutOfCombat, 300000); + + return false; + } + } + + [Script] + class go_sacred_fire_of_life : GameObjectAI + { + public go_sacred_fire_of_life(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (me.GetGoType() == GameObjectTypes.Goober) + player.SummonCreature(CreatureIds.Arikara, -5008.338f, -2118.894f, 83.657f, 0.874f, TempSummonType.TimedDespawnOutOfCombat, 30000); + + return true; + } + } + + [Script] + class go_shrine_of_the_birds : GameObjectAI + { + public go_shrine_of_the_birds(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + uint birdEntryId = 0; + + me.GetClosePoint(out float fX, out float fY, out float fZ, me.GetCombatReach(), SharedConst.InteractionDistance); + + switch (me.GetEntry()) + { + case GameObjectIds.ShrineHawk: + birdEntryId = CreatureIds.HawkGuard; + break; + case GameObjectIds.ShrineEagle: + birdEntryId = CreatureIds.EagleGuard; + break; + case GameObjectIds.ShrineFalcon: + birdEntryId = CreatureIds.FalconGuard; + break; + } + + if (birdEntryId != 0) + player.SummonCreature(birdEntryId, fX, fY, fZ, me.GetOrientation(), TempSummonType.TimedDespawnOutOfCombat, 60000); + + return false; + } + } + + [Script] + class go_southfury_moonstone : GameObjectAI + { + public go_southfury_moonstone(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + //implicitTarget=48 not implemented as of writing this code, and manual summon may be just ok for our purpose + //player.CastSpell(player, SpellSummonRizzle, false); + + Creature creature = player.SummonCreature(CreatureIds.Rizzle, 0.0f, 0.0f, 0.0f, 0.0f, TempSummonType.DeadDespawn, 0); + if (creature) + creature.CastSpell(player, SpellIds.Blackjack, false); + + return false; + } + } + + [Script] + class go_tele_to_dalaran_crystal : GameObjectAI + { + public go_tele_to_dalaran_crystal(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (player.GetQuestRewardStatus(QuestIds.TeleCrystalFlag)) + return false; + + player.GetSession().SendNotification(GossipConst.GoTeleToDalaranCrystalFailed); + return true; + } + } + + [Script] + class go_tele_to_violet_stand : GameObjectAI + { + public go_tele_to_violet_stand(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (player.GetQuestRewardStatus(QuestIds.LearnLeaveReturn) || player.GetQuestStatus(QuestIds.LearnLeaveReturn) == QuestStatus.Incomplete) + return false; + + return true; + } + } + + [Script] + class go_fel_crystalforge : GameObjectAI + { + public go_fel_crystalforge(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (me.GetGoType() == GameObjectTypes.QuestGiver) /* != GAMEOBJECT_TYPE_QUESTGIVER) */ + player.PrepareQuestMenu(me.GetGUID()); /* return true*/ + + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipFelCrystalforgeItem1, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef); + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipFelCrystalforgeItem5, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 1); + + player.SendGossipMenu(GossipConst.GossipFelCrystalforgeText, me.GetGUID()); + + return true; + } + + public override bool GossipSelect(Player player, uint menuId, uint gossipListId) + { + uint action = player.PlayerTalkClass.GetGossipOptionAction(gossipListId); + player.ClearGossipMenu(); + switch (action) + { + case eTradeskill.GossipActionInfoDef: + player.CastSpell(player, SpellIds.Create1FlaskOfBeast, false); + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipFelCrystalforgeItemReturn, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 2); + player.SendGossipMenu(GossipConst.GossipFelCrystalforgeItemTextReturn, me.GetGUID()); + break; + case eTradeskill.GossipActionInfoDef + 1: + player.CastSpell(player, SpellIds.Create5FlaskOfBeast, false); + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipFelCrystalforgeItemReturn, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 2); + player.SendGossipMenu(GossipConst.GossipFelCrystalforgeItemTextReturn, me.GetGUID()); + break; + case eTradeskill.GossipActionInfoDef + 2: + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipFelCrystalforgeItem1, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef); + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipFelCrystalforgeItem5, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 1); + player.SendGossipMenu(GossipConst.GossipFelCrystalforgeText, me.GetGUID()); + break; + } + return true; + } + } + + [Script] + class go_bashir_crystalforge : GameObjectAI + { + public go_bashir_crystalforge(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (me.GetGoType() == GameObjectTypes.QuestGiver) /* != GAMEOBJECT_TYPE_QUESTGIVER) */ + player.PrepareQuestMenu(me.GetGUID()); /* return true*/ + + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipBashirCrystalforgeItem1, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef); + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipBashirCrystalforgeItem5, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 1); + + player.SendGossipMenu(GossipConst.GossipBashirCrystalforgeText, me.GetGUID()); + + return true; + } + + public override bool GossipSelect(Player player, uint menuId, uint gossipListId) + { + uint action = player.PlayerTalkClass.GetGossipOptionAction(gossipListId); + player.ClearGossipMenu(); + switch (action) + { + case eTradeskill.GossipActionInfoDef: + player.CastSpell(player, SpellIds.Create1FlaskOfSorcerer, false); + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipBashirCrystalforgeItemReturn, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 2); + player.SendGossipMenu(GossipConst.GossipBashirCrystalforgeItemTextReturn, me.GetGUID()); + break; + case eTradeskill.GossipActionInfoDef + 1: + player.CastSpell(player, SpellIds.Create5FlaskOfSorcerer, false); + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipBashirCrystalforgeItemReturn, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 2); + player.SendGossipMenu(GossipConst.GossipBashirCrystalforgeItemTextReturn, me.GetGUID()); + break; + case eTradeskill.GossipActionInfoDef + 2: + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipBashirCrystalforgeItem1, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef); + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipBashirCrystalforgeItem5, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 1); + player.SendGossipMenu(GossipConst.GossipBashirCrystalforgeText, me.GetGUID()); + break; + } + return true; + } + } + + [Script] + class go_matrix_punchograph : GameObjectAI + { + public go_matrix_punchograph(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + switch (me.GetEntry()) + { + case ItemIds.MatrixPunchograph3005A: + if (player.HasItemCount(ItemIds.WhitePunchCard)) + { + player.DestroyItemCount(ItemIds.WhitePunchCard, 1, true); + player.CastSpell(player, SpellIds.YellowPunchCard, true); + } + break; + case ItemIds.MatrixPunchograph3005B: + if (player.HasItemCount(ItemIds.YellowPunchCard)) + { + player.DestroyItemCount(ItemIds.YellowPunchCard, 1, true); + player.CastSpell(player, SpellIds.BluePunchCard, true); + } + break; + case ItemIds.MatrixPunchograph3005C: + if (player.HasItemCount(ItemIds.BluePunchCard)) + { + player.DestroyItemCount(ItemIds.BluePunchCard, 1, true); + player.CastSpell(player, SpellIds.RedPunchCard, true); + } + break; + case ItemIds.MatrixPunchograph3005D: + if (player.HasItemCount(ItemIds.RedPunchCard)) + { + player.DestroyItemCount(ItemIds.RedPunchCard, 1, true); + player.CastSpell(player, SpellIds.PrismaticPunchCard, true); + } + break; + default: + break; + } + return false; + } + } + + [Script] + class go_scourge_cage : GameObjectAI + { + public go_scourge_cage(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + me.UseDoorOrButton(); + Creature pNearestPrisoner = me.FindNearestCreature(CreatureIds.ScourgePrisoner, 5.0f, true); + if (pNearestPrisoner) + { + player.KilledMonsterCredit(CreatureIds.ScourgePrisoner, pNearestPrisoner.GetGUID()); + pNearestPrisoner.DisappearAndDie(); + } + + return true; + } + } + + [Script] + class go_arcane_prison : GameObjectAI + { + public go_arcane_prison(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (player.GetQuestStatus(QuestIds.PrisonBreak) == QuestStatus.Incomplete) + { + me.SummonCreature(25318, 3485.089844f, 6115.7422188f, 70.966812f, 0, TempSummonType.TimedDespawn, 60000); + player.CastSpell(player, SpellIds.ArcanePrisonerKillCredit, true); + return true; + } + return false; + } + } + + [Script] + class go_blood_filled_orb : GameObjectAI + { + public go_blood_filled_orb(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (me.GetGoType() == GameObjectTypes.Goober) + player.SummonCreature(CreatureIds.Zelemar, -369.746f, 166.759f, -21.50f, 5.235f, TempSummonType.TimedDespawnOutOfCombat, 30000); + + return true; + } + } + + [Script] + class go_jotunheim_cage : GameObjectAI + { + public go_jotunheim_cage(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + me.UseDoorOrButton(); + Creature pPrisoner = me.FindNearestCreature(CreatureIds.EbonBladePrisonerHuman, 5.0f, true); + if (!pPrisoner) + { + pPrisoner = me.FindNearestCreature(CreatureIds.EbonBladePrisonerTroll, 5.0f, true); + if (!pPrisoner) + { + pPrisoner = me.FindNearestCreature(CreatureIds.EbonBladePrisonerOrc, 5.0f, true); + if (!pPrisoner) + pPrisoner = me.FindNearestCreature(CreatureIds.EbonBladePrisonerNe, 5.0f, true); + } + } + if (!pPrisoner || !pPrisoner.IsAlive()) + return false; + + pPrisoner.DisappearAndDie(); + player.KilledMonsterCredit(CreatureIds.EbonBladePrisonerHuman); + switch (pPrisoner.GetEntry()) + { + case CreatureIds.EbonBladePrisonerHuman: + player.CastSpell(player, SpellIds.SummonBladeKnightH, true); + break; + case CreatureIds.EbonBladePrisonerNe: + player.CastSpell(player, SpellIds.SummonBladeKnightNe, true); + break; + case CreatureIds.EbonBladePrisonerTroll: + player.CastSpell(player, SpellIds.SummonBladeKnightTroll, true); + break; + case CreatureIds.EbonBladePrisonerOrc: + player.CastSpell(player, SpellIds.SummonBladeKnightOrc, true); + break; + } + return true; + } + } + + [Script] + class go_table_theka : GameObjectAI + { + public go_table_theka(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (player.GetQuestStatus(QuestIds.SpiderGold) == QuestStatus.Incomplete) + player.AreaExploredOrEventHappens(QuestIds.SpiderGold); + + player.SendGossipMenu(GossipConst.GossipTableTheka, me.GetGUID()); + return true; + } + } + + [Script] + class go_inconspicuous_landmark : GameObjectAI + { + public go_inconspicuous_landmark(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + if (player.HasItemCount(ItemIds.CuergosKey)) + return false; + + player.CastSpell(player, SpellIds.SummonPiratesTreasureAndTriggerMob, true); + return true; + } + } + + [Script] + class go_soulwell : GameObjectAI + { + public go_soulwell(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + Unit owner = me.GetOwner(); + if (!owner || !owner.IsTypeId(TypeId.Player) || !player.IsInSameRaidWith(owner.ToPlayer())) + return true; + return false; + } + } + + [Script] + class go_dragonflayer_cage : GameObjectAI + { + public go_dragonflayer_cage(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + me.UseDoorOrButton(); + if (player.GetQuestStatus(QuestIds.PrisonersOfWyrmskull) != QuestStatus.Incomplete) + return true; + + Creature pPrisoner = me.FindNearestCreature(CreatureIds.PrisonerPriest, 2.0f); + if (!pPrisoner) + { + pPrisoner = me.FindNearestCreature(CreatureIds.PrisonerMage, 2.0f); + if (!pPrisoner) + { + pPrisoner = me.FindNearestCreature(CreatureIds.PrisonerWarrior, 2.0f); + if (!pPrisoner) + pPrisoner = me.FindNearestCreature(CreatureIds.PrisonerPaladin, 2.0f); + } + } + + if (!pPrisoner || !pPrisoner.IsAlive()) + return true; + + /// @todo prisoner should help player for a short period of time + player.KilledMonsterCredit(CreatureIds.CapturedValgardePrisonerProxy); + pPrisoner.DespawnOrUnsummon(); + return true; + } + } + + [Script] + class go_amberpine_outhouse : GameObjectAI + { + public go_amberpine_outhouse(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + QuestStatus status = player.GetQuestStatus(QuestIds.DoingYourDuty); + if (status == QuestStatus.Incomplete || status == QuestStatus.Complete || status == QuestStatus.Rewarded) + { + player.AddGossipItem(GossipOptionIcon.Chat, GossipConst.GossipUseOuthouse, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 1); + player.SendGossipMenu(GossipConst.GossipOuthouseVacant, me.GetGUID()); + } + else + player.SendGossipMenu(GossipConst.GossipOuthouseInuse, me.GetGUID()); + + return true; + } + + public override bool GossipSelect(Player player, uint menuId, uint gossipListId) + { + uint action = player.PlayerTalkClass.GetGossipOptionAction(gossipListId); + player.ClearGossipMenu(); + if (action == eTradeskill.GossipActionInfoDef + 1) + { + player.CloseGossipMenu(); + Creature target = ScriptedAI.GetClosestCreatureWithEntry(player, CreatureIds.OuthouseBunny, 3.0f); + if (target) + { + target.GetAI().SetData(1, (uint)player.GetGender()); + me.CastSpell(target, SpellIds.IndisposedIii); + } + me.CastSpell(player, SpellIds.Indisposed); + if (player.HasItemCount(ItemIds.AnderholsSliderCider)) + me.CastSpell(player, SpellIds.CreateAmberseeds); + return true; + } + else + { + player.CloseGossipMenu(); + player.GetSession().SendNotification(GossipConst.AnderholsSliderCiderNotFound); + return false; + } + } + } + + [Script] + class go_hive_pod : GameObjectAI + { + public go_hive_pod(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + player.SendLoot(me.GetGUID(), LootType.Corpse); + me.SummonCreature(CreatureIds.HiveAmbusher, me.GetPositionX() + 1, me.GetPositionY(), me.GetPositionZ(), me.GetAngle(player), TempSummonType.TimedOrDeadDespawn, 60000); + me.SummonCreature(CreatureIds.HiveAmbusher, me.GetPositionX(), me.GetPositionY() + 1, me.GetPositionZ(), me.GetAngle(player), TempSummonType.TimedOrDeadDespawn, 60000); + return true; + } + } + + [Script] + class go_massive_seaforium_charge : GameObjectAI + { + public go_massive_seaforium_charge(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + me.SetLootState(LootState.JustDeactivated); + return true; + } + } + + [Script] + class go_veil_skith_cage : GameObjectAI + { + public go_veil_skith_cage(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + me.UseDoorOrButton(); + if (player.GetQuestStatus(QuestIds.MissingFriends) == QuestStatus.Incomplete) + { + List childrenList = new List(); + me.GetCreatureListWithEntryInGrid(childrenList, CreatureIds.CaptiveChild, SharedConst.InteractionDistance); + foreach (Creature creature in childrenList) + { + player.KilledMonsterCredit(CreatureIds.CaptiveChild, creature.GetGUID()); + creature.DespawnOrUnsummon(5000); + creature.GetMotionMaster().MovePoint(1, me.GetPositionX() + 5, me.GetPositionY(), me.GetPositionZ()); + creature.GetAI().Talk(TextIds.SayFree0); + creature.GetMotionMaster().Clear(); + } + } + return false; + } + } + + [Script] + class go_frostblade_shrine : GameObjectAI + { + public go_frostblade_shrine(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + me.UseDoorOrButton(10); + if (!player.HasAura(SpellIds.RecentMeditation)) + { + if (player.GetQuestStatus(QuestIds.TheCleansingHorde) == QuestStatus.Incomplete || player.GetQuestStatus(QuestIds.TheCleansingAlliance) == QuestStatus.Incomplete) + { + player.CastSpell(player, SpellIds.CleansingSoul); + player.SetStandState(UnitStandStateType.Sit); + } + } + return true; + } + } + + [Script] + class go_midsummer_bonfire : GameObjectAI + { + public go_midsummer_bonfire(GameObject go) : base(go) { } + + public override bool GossipSelect(Player player, uint menuId, uint ssipListId) + { + player.CastSpell(player, SpellIds.StampOutBonfireQuestComplete, true); + player.CloseGossipMenu(); + return false; + } + } + + [Script] + class go_midsummer_ribbon_pole : GameObjectAI + { + public go_midsummer_ribbon_pole(GameObject go) : base(go) { } + + public override bool GossipHello(Player player) + { + Creature creature = me.FindNearestCreature(CreatureIds.PoleRibbonBunny, 10.0f); + if (creature) + { + creature.GetAI().DoAction(0); + player.CastSpell(player, SpellIds.RibbonPoleSpells[RandomHelper.IRand(0, 2)], true); + } + return true; + } + } + + [Script] + class go_toy_train_set : GameObjectAI + { + uint _pulseTimer; + + public go_toy_train_set(GameObject go) : base(go) + { + _pulseTimer = 3 * Time.InMilliseconds; + } + + public override void UpdateAI(uint diff) + { + if (diff < _pulseTimer) + _pulseTimer -= diff; + else + { + me.CastSpell(null, SpellIds.ToyTrainPulse, true); + _pulseTimer = 6 * Time.InMilliseconds; + } + } + + // triggered on wrecker'd + public override void DoAction(int action) + { + me.Delete(); + } + } + + [Script] + class go_brewfest_music : GameObjectAI + { + uint rnd = 0; + uint musicTime = 1000; + + public go_brewfest_music(GameObject go) : base(go) + { + _scheduler.Schedule(TimeSpan.FromSeconds(1), task => + { + if (Global.GameEventMgr.IsHolidayActive(HolidayIds.Brewfest)) // Check if Brewfest is active + { + rnd = RandomHelper.URand(0, 2); // Select random music sample + task.Repeat(TimeSpan.FromMilliseconds(musicTime)); // Select new song music after play time is over + } + }); + _scheduler.Schedule(TimeSpan.FromSeconds(2), task => + { + if (Global.GameEventMgr.IsHolidayActive(HolidayIds.Brewfest)) // Check if Brewfest is active + { + switch (me.GetAreaId()) + { + case AreaIds.Silvermoon: + case AreaIds.Undercity: + case AreaIds.Orgrimmar1: + case AreaIds.Orgrimmar2: + case AreaIds.Thunderbluff: + switch (rnd) + { + case 0: + me.PlayDirectMusic(SoundIds.EventBrewfestgoblin01); + musicTime = Misc.EventBrewfestgoblin01Time; + break; + case 1: + me.PlayDirectMusic(SoundIds.EventBrewfestgoblin02); + musicTime = Misc.EventBrewfestgoblin02Time; + break; + default: + me.PlayDirectMusic(SoundIds.EventBrewfestgoblin03); + musicTime = Misc.EventBrewfestgoblin03Time; + break; + } + break; + case AreaIds.Ironforge1: + case AreaIds.Ironforge2: + case AreaIds.Stormwind: + case AreaIds.Exodar: + case AreaIds.Darnassus: + switch (rnd) + { + case 0: + me.PlayDirectMusic(SoundIds.EventBrewfestdwarf01); + musicTime = Misc.EventBrewfestdwarf01Time; + break; + case 1: + me.PlayDirectMusic(SoundIds.EventBrewfestdwarf02); + musicTime = Misc.EventBrewfestdwarf02Time; + break; + default: + me.PlayDirectMusic(SoundIds.EventBrewfestdwarf03); + musicTime = Misc.EventBrewfestdwarf03Time; + break; + } + break; + case AreaIds.Shattrath: + List playersNearby = me.GetPlayerListInGrid(me.GetVisibilityRange()); + foreach (Player player in playersNearby) + { + if (player.GetTeamId() == TeamId.Horde) + { + switch (rnd) + { + case 0: + me.PlayDirectMusic(SoundIds.EventBrewfestgoblin01); + musicTime = Misc.EventBrewfestgoblin01Time; + break; + case 1: + me.PlayDirectMusic(SoundIds.EventBrewfestgoblin02); + musicTime = Misc.EventBrewfestgoblin02Time; + break; + default: + me.PlayDirectMusic(SoundIds.EventBrewfestgoblin03); + musicTime = Misc.EventBrewfestgoblin03Time; + break; + } + } + else + { + switch (rnd) + { + case 0: + me.PlayDirectMusic(SoundIds.EventBrewfestdwarf01); + musicTime = Misc.EventBrewfestdwarf01Time; + break; + case 1: + me.PlayDirectMusic(SoundIds.EventBrewfestdwarf02); + musicTime = Misc.EventBrewfestdwarf02Time; + break; + default: + me.PlayDirectMusic(SoundIds.EventBrewfestdwarf03); + musicTime = Misc.EventBrewfestdwarf03Time; + break; + } + } + } + break; + } + task.Repeat(TimeSpan.FromSeconds(5)); // Every 5 second's SMSG_PLAY_MUSIC packet (PlayDirectMusic) is pushed to the client + } + }); + } + + public override void UpdateAI(uint diff) + { + _scheduler.Update(diff); + } + } + + [Script] + class go_midsummer_music : GameObjectAI + { + public go_midsummer_music(GameObject go) : base(go) + { + _scheduler.Schedule(TimeSpan.FromSeconds(1), task => + { + if (!Global.GameEventMgr.IsHolidayActive(HolidayIds.MidsummerFireFestival)) + return; + + var playersNearby = me.GetPlayerListInGrid(me.GetMap().GetVisibilityRange()); + foreach (Player player in playersNearby) + { + if (player.GetTeam() == Team.Horde) + me.PlayDirectMusic(12325, player); + else + me.PlayDirectMusic(12319, player); + } + + task.Repeat(TimeSpan.FromSeconds(5)); // Every 5 second's SMSG_PLAY_MUSIC packet (PlayDirectMusic) is pushed to the client (sniffed value) + }); + } + + public override void UpdateAI(uint diff) + { + _scheduler.Update(diff); + } + } + + [Script] + class go_darkmoon_faire_music : GameObjectAI + { + public go_darkmoon_faire_music(GameObject go) : base(go) + { + _scheduler.Schedule(TimeSpan.FromSeconds(1), task => + { + if (Global.GameEventMgr.IsHolidayActive(HolidayIds.DarkmoonFaire)) + { + me.PlayDirectMusic(8440); + task.Repeat(TimeSpan.FromSeconds(5)); // Every 5 second's SMSG_PLAY_MUSIC packet (PlayDirectMusic) is pushed to the client (sniffed value) + } + }); + } + + public override void UpdateAI(uint diff) + { + _scheduler.Update(diff); + } + } + + [Script] + class go_pirate_day_music : GameObjectAI + { + public go_pirate_day_music(GameObject go) : base(go) + { + _scheduler.Schedule(TimeSpan.FromSeconds(1), task => + { + if (!Global.GameEventMgr.IsHolidayActive(HolidayIds.PiratesDay)) + return; + me.PlayDirectMusic(12845); + task.Repeat(TimeSpan.FromSeconds(5)); // Every 5 second's SMSG_PLAY_MUSIC packet (PlayDirectMusic) is pushed to the client (sniffed value) + }); + } + + public override void UpdateAI(uint diff) + { + _scheduler.Update(diff); + } + } + + [Script] + class go_bells : GameObjectAI + { + uint _soundId; + + public go_bells(GameObject go) : base(go) { } + + public override void InitializeAI() + { + switch (me.GetEntry()) + { + case GameObjectIds.HordeBell: + _soundId = me.GetAreaId() == AreaIds.Undercity ? SoundIds.BellTollHorde : SoundIds.BellTollTribal; + break; + case GameObjectIds.AllianceBell: + { + if (me.GetAreaId() == AreaIds.Ironforge1 || me.GetAreaId() == AreaIds.Ironforge2) + _soundId = SoundIds.BellTolldwarfgnome; + else if (me.GetAreaId() == AreaIds.Darnassus || me.GetZoneId() == AreaIds.TeldrassilZone) + _soundId = SoundIds.BellTollNightelf; + else + _soundId = SoundIds.BellTollAlliance; + + break; + } + case GameObjectIds.KharazhanBell: + _soundId = SoundIds.BellTollKharazhan; + break; + } + } + + public override void OnGameEvent(bool start, ushort eventId) + { + if (eventId == Misc.GameEventHourlyBells && start) + { + var localTm = Time.UnixTimeToDateTime(GameTime.GetGameTime()).ToLocalTime(); + int _rings = (localTm.Hour - 1) % 12 + 1; + + for (var i = 0; i < _rings; ++i) + _scheduler.Schedule(TimeSpan.FromSeconds(i * 4 + 1), task => me.PlayDirectSound(_soundId)); + } + } + + public override void UpdateAI(uint diff) + { + _scheduler.Update(diff); + } + } +} + diff --git a/Source/Scripts/World/Guards.cs b/Source/Scripts/World/Guards.cs deleted file mode 100644 index abaeedc63..000000000 --- a/Source/Scripts/World/Guards.cs +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (C) 2012-2020 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 : GuardAI - { - public guard_generic(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; - } - - [Script] - class guard_shattrath_scryer : GuardAI - { - public guard_shattrath_scryer(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; - } - - [Script] - class guard_shattrath_aldor : GuardAI - { - public guard_shattrath_aldor(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; - } -} diff --git a/Source/Scripts/World/ItemScripts.cs b/Source/Scripts/World/ItemScripts.cs index 87c84f2a0..2372534a0 100644 --- a/Source/Scripts/World/ItemScripts.cs +++ b/Source/Scripts/World/ItemScripts.cs @@ -1,19 +1,19 @@ -/* -* Copyright (C) 2012-2020 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 . -*/ +/* + * Copyright (C) 2012-2020 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 Framework.GameMath; @@ -22,86 +22,71 @@ using Game.Scripting; using Game.Spells; using System.Collections.Generic; -namespace Scripts.World +namespace Scripts.World.ItemScripts { - struct ItemScriptConst - { + struct SpellIds + { //Onlyforflight - public const uint SpellArcaneCharges = 45072; - - //Pilefakefur - public const uint GoCaribouTrap1 = 187982; - public const uint GoCaribouTrap2 = 187995; - public const uint GoCaribouTrap3 = 187996; - public const uint GoCaribouTrap4 = 187997; - public const uint GoCaribouTrap5 = 187998; - public const uint GoCaribouTrap6 = 187999; - public const uint GoCaribouTrap7 = 188000; - public const uint GoCaribouTrap8 = 188001; - public const uint GoCaribouTrap9 = 188002; - public const uint GoCaribouTrap10 = 188003; - public const uint GoCaribouTrap11 = 188004; - public const uint GoCaribouTrap12 = 188005; - public const uint GoCaribouTrap13 = 188006; - public const uint GoCaribouTrap14 = 188007; - public const uint GoCaribouTrap15 = 188008; - public const uint GoHighQualityFur = 187983; - public const uint NpcNesingwaryTrapper = 25835; - - public static uint[] CaribouTraps = - { - GoCaribouTrap1, GoCaribouTrap2, GoCaribouTrap3, GoCaribouTrap4, GoCaribouTrap5, - GoCaribouTrap6, GoCaribouTrap7, GoCaribouTrap8, GoCaribouTrap9, GoCaribouTrap10, - GoCaribouTrap11, GoCaribouTrap12, GoCaribouTrap13, GoCaribouTrap14, GoCaribouTrap15, - }; + public const uint ArcaneCharges = 45072; //Petrovclusterbombs - public const uint SpellPetrovBomb = 42406; - public const uint AreaIdShatteredStraits = 4064; - public const uint ZoneIdHowling = 495; + public const uint PetrovBomb = 42406; + } + + struct CreatureIds + { + //Pilefakefur + public const uint NesingwaryTrapper = 25835; //Helpthemselves - public const uint QuestCannotHelpThemselves = 11876; - public const uint NpcTrappedMammothCalf = 25850; - public const uint GoMammothTrap1 = 188022; - public const uint GoMammothTrap2 = 188024; - public const uint GoMammothTrap3 = 188025; - public const uint GoMammothTrap4 = 188026; - public const uint GoMammothTrap5 = 188027; - public const uint GoMammothTrap6 = 188028; - public const uint GoMammothTrap7 = 188029; - public const uint GoMammothTrap8 = 188030; - public const uint GoMammothTrap9 = 188031; - public const uint GoMammothTrap10 = 188032; - public const uint GoMammothTrap11 = 188033; - public const uint GoMammothTrap12 = 188034; - public const uint GoMammothTrap13 = 188035; - public const uint GoMammothTrap14 = 188036; - public const uint GoMammothTrap15 = 188037; - public const uint GoMammothTrap16 = 188038; - public const uint GoMammothTrap17 = 188039; - public const uint GoMammothTrap18 = 188040; - public const uint GoMammothTrap19 = 188041; - public const uint GoMammothTrap20 = 188042; - public const uint GoMammothTrap21 = 188043; - public const uint GoMammothTrap22 = 188044; - - public static uint[] MammothTraps = - { - GoMammothTrap1, GoMammothTrap2, GoMammothTrap3, GoMammothTrap4, GoMammothTrap5, - GoMammothTrap6, GoMammothTrap7, GoMammothTrap8, GoMammothTrap9, GoMammothTrap10, - GoMammothTrap11, GoMammothTrap12, GoMammothTrap13, GoMammothTrap14, GoMammothTrap15, - GoMammothTrap16, GoMammothTrap17, GoMammothTrap18, GoMammothTrap19, GoMammothTrap20, - GoMammothTrap21, GoMammothTrap22 - }; + public const uint TrappedMammothCalf = 25850; //Theemissary - public const uint QuestTheEmissary = 11626; - public const uint NpcLeviroth = 26452; + public const uint Leviroth = 26452; //Capturedfrog - public const uint QuestThePerfectSpies = 25444; - public const uint NpcVanirasSentryTotem = 40187; + public const uint VanirasSentryTotem = 40187; + } + + struct GameObjectIds + { + //Pilefakefur + public const uint HighQualityFur = 187983; + public static uint[] CaribouTraps = + { + 187982, 187995, 187996, 187997, 187998, + 187999, 188000, 188001, 188002, 188003, + 188004, 188005, 188006, 188007, 188008, + }; + + //Helpthemselves + public static uint[] MammothTraps = + { + 188022, 188024, 188025, 188026, 188027, + 188028, 188029, 188030, 188031, 188032, + 188033, 188034, 188035, 188036, 188037, + 188038, 188039, 188040, 188041, 188042, + 188043, 188044 + }; + } + + struct QuestIds + { + //Helpthemselves + public const uint CannotHelpThemselves = 11876; + + //Theemissary + public const uint TheEmissary = 11626; + + //Capturedfrog + public const uint ThePerfectSpies = 25444; + } + + struct Misc + { + //Petrovclusterbombs + public const uint AreaIdShatteredStraits = 4064; + public const uint ZoneIdHowling = 495; } [Script] @@ -126,7 +111,7 @@ namespace Scripts.World disabled = true; break; case 34475: - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(ItemScriptConst.SpellArcaneCharges, player.GetMap().GetDifficultyID()); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.ArcaneCharges, player.GetMap().GetDifficultyID()); if (spellInfo != null) Spell.SendCastResult(player, spellInfo, default, castId, SpellCastResult.NotOnGround); break; @@ -142,7 +127,7 @@ namespace Scripts.World } } - [Script] //item_nether_wraith_beacon + [Script] class item_nether_wraith_beacon : ItemScript { public item_nether_wraith_beacon() : base("item_nether_wraith_beacon") { } @@ -155,15 +140,15 @@ namespace Scripts.World if (nether) nether.GetAI().AttackStart(player); - Creature nether1 = player.SummonCreature(22408, player.GetPositionX(), player.GetPositionY() - 20, player.GetPositionZ(), 0, TempSummonType.TimedDespawn, 180000); - if (nether1) - nether1.GetAI().AttackStart(player); + nether = player.SummonCreature(22408, player.GetPositionX(), player.GetPositionY() - 20, player.GetPositionZ(), 0, TempSummonType.TimedDespawn, 180000); + if (nether) + nether.GetAI().AttackStart(player); } return false; } } - [Script] //item_gor_dreks_ointment + [Script] class item_gor_dreks_ointment : ItemScript { public item_gor_dreks_ointment() : base("item_gor_dreks_ointment") { } @@ -179,7 +164,7 @@ namespace Scripts.World } } - [Script] //item_incendiary_explosives + [Script] class item_incendiary_explosives : ItemScript { public item_incendiary_explosives() : base("item_incendiary_explosives") { } @@ -196,7 +181,7 @@ namespace Scripts.World } } - [Script] //item_mysterious_egg + [Script] class item_mysterious_egg : ItemScript { public item_mysterious_egg() : base("item_mysterious_egg") { } @@ -212,7 +197,7 @@ namespace Scripts.World } } - [Script] //item_disgusting_jar + [Script] class item_disgusting_jar : ItemScript { public item_disgusting_jar() : base("item_disgusting_jar") { } @@ -228,7 +213,7 @@ namespace Scripts.World } } - [Script] //item_pile_fake_furs + [Script] class item_pile_fake_furs : ItemScript { public item_pile_fake_furs() : base("item_pile_fake_furs") { } @@ -236,9 +221,9 @@ namespace Scripts.World public override bool OnUse(Player player, Item item, SpellCastTargets targets, ObjectGuid castId) { GameObject go = null; - for (byte i = 0; i < ItemScriptConst.CaribouTraps.Length; ++i) + foreach (var id in GameObjectIds.CaribouTraps) { - go = player.FindNearestGameObject(ItemScriptConst.CaribouTraps[i], 5.0f); + go = player.FindNearestGameObject(id, 5.0f); if (go) break; } @@ -246,13 +231,12 @@ namespace Scripts.World if (!go) return false; - if (go.FindNearestCreature(ItemScriptConst.NpcNesingwaryTrapper, 10.0f, true) || go.FindNearestCreature(ItemScriptConst.NpcNesingwaryTrapper, 10.0f, false) || go.FindNearestGameObject(ItemScriptConst.GoHighQualityFur, 2.0f)) + if (go.FindNearestCreature(CreatureIds.NesingwaryTrapper, 10.0f, true) || go.FindNearestCreature(CreatureIds.NesingwaryTrapper, 10.0f, false) || go.FindNearestGameObject(GameObjectIds.HighQualityFur, 2.0f)) return true; - float x, y, z; - go.GetClosePoint(out x, out y, out z, go.GetCombatReach() / 3, 7.0f); - go.SummonGameObject(ItemScriptConst.GoHighQualityFur, go, Quaternion.fromEulerAnglesZYX(go.GetOrientation(), 0.0f, 0.0f), 1); - TempSummon summon = player.SummonCreature(ItemScriptConst.NpcNesingwaryTrapper, x, y, z, go.GetOrientation(), TempSummonType.DeadDespawn, 1000); + go.GetClosePoint(out float x, out float y, out float z, go.GetCombatReach() / 3, 7.0f); + go.SummonGameObject(GameObjectIds.HighQualityFur, go, Quaternion.fromEulerAnglesZYX(go.GetOrientation(), 0.0f, 0.0f), 1); + TempSummon summon = player.SummonCreature(CreatureIds.NesingwaryTrapper, x, y, z, go.GetOrientation(), TempSummonType.DeadDespawn, 1000); if (summon) { summon.SetVisible(false); @@ -263,19 +247,19 @@ namespace Scripts.World } } - [Script] //item_petrov_cluster_bombs + [Script] class item_petrov_cluster_bombs : ItemScript { public item_petrov_cluster_bombs() : base("item_petrov_cluster_bombs") { } public override bool OnUse(Player player, Item item, SpellCastTargets targets, ObjectGuid castId) { - if (player.GetZoneId() != ItemScriptConst.ZoneIdHowling) + if (player.GetZoneId() != Misc.ZoneIdHowling) return false; - if (!player.GetTransport() || player.GetAreaId() != ItemScriptConst.AreaIdShatteredStraits) + if (!player.GetTransport() || player.GetAreaId() != Misc.AreaIdShatteredStraits) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(ItemScriptConst.SpellPetrovBomb, Difficulty.None); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.PetrovBomb, Difficulty.None); if (spellInfo != null) Spell.SendCastResult(player, spellInfo, default, castId, SpellCastResult.NotHere); @@ -286,30 +270,28 @@ namespace Scripts.World } } - //item_dehta_trap_smasher - [Script] //For quest 11876, Help Those That Cannot Help Themselves + [Script] class item_dehta_trap_smasher : ItemScript { public item_dehta_trap_smasher() : base("item_dehta_trap_smasher") { } public override bool OnUse(Player player, Item item, SpellCastTargets targets, ObjectGuid castId) { - if (player.GetQuestStatus(ItemScriptConst.QuestCannotHelpThemselves) != QuestStatus.Incomplete) + if (player.GetQuestStatus(QuestIds.CannotHelpThemselves) != QuestStatus.Incomplete) return false; - Creature pMammoth = player.FindNearestCreature(ItemScriptConst.NpcTrappedMammothCalf, 5.0f); + Creature pMammoth = player.FindNearestCreature(CreatureIds.TrappedMammothCalf, 5.0f); if (!pMammoth) return false; - GameObject pTrap = null; - for (byte i = 0; i < ItemScriptConst.MammothTraps.Length; ++i) + foreach (var id in GameObjectIds.MammothTraps) { - pTrap = player.FindNearestGameObject(ItemScriptConst.MammothTraps[i], 11.0f); + GameObject pTrap = player.FindNearestGameObject(id, 11.0f); if (pTrap) { pMammoth.GetAI().DoAction(1); pTrap.SetGoState(GameObjectState.Ready); - player.KilledMonsterCredit(ItemScriptConst.NpcTrappedMammothCalf); + player.KilledMonsterCredit(CreatureIds.TrappedMammothCalf); return true; } } @@ -324,9 +306,9 @@ namespace Scripts.World public override bool OnUse(Player player, Item item, SpellCastTargets targets, ObjectGuid castId) { - if (player.GetQuestStatus(ItemScriptConst.QuestThePerfectSpies) == QuestStatus.Incomplete) + if (player.GetQuestStatus(QuestIds.ThePerfectSpies) == QuestStatus.Incomplete) { - if (player.FindNearestCreature(ItemScriptConst.NpcVanirasSentryTotem, 10.0f)) + if (player.FindNearestCreature(CreatureIds.VanirasSentryTotem, 10.0f)) return false; else player.SendEquipError(InventoryResult.OutOfRange, item, null); @@ -337,8 +319,8 @@ namespace Scripts.World } } - // Only used currently for - [Script]// 19169: Nightfall + [Script] // Only used currently for + // 19169: Nightfall class item_generic_limit_chance_above_60 : ItemScript { public item_generic_limit_chance_above_60() : base("item_generic_limit_chance_above_60") { } @@ -360,3 +342,4 @@ namespace Scripts.World } } } + diff --git a/Source/Scripts/World/MobGenericCreature.cs b/Source/Scripts/World/MobGenericCreature.cs index 383adf799..b17e1c1b7 100644 --- a/Source/Scripts/World/MobGenericCreature.cs +++ b/Source/Scripts/World/MobGenericCreature.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2012-2020 CypherCore * * This program is free software: you can redistribute it and/or modify @@ -40,4 +40,4 @@ namespace Scripts.World _scheduler.Update(); } } -} +} \ No newline at end of file diff --git a/Source/Scripts/World/NpcGuard.cs b/Source/Scripts/World/NpcGuard.cs new file mode 100644 index 000000000..7dfcbb9e3 --- /dev/null +++ b/Source/Scripts/World/NpcGuard.cs @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2012-2020 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 Framework.Dynamic; +using Game.AI; +using Game.Entities; +using Game.Scripting; +using Game.Spells; +using System; + +namespace Scripts.World.NpcGuard +{ + struct SpellIds + { + public const uint BanishedShattrathA = 36642; + public const uint BanishedShattrathS = 36671; + public const uint BanishTeleport = 36643; + public const uint Exile = 39533; + } + + struct TextIds + { + public const uint SayGuardSilAggro = 0; + } + + + struct CreatureIds + { + public const uint CenarionHoldInfantry = 15184; + public const uint StormwindCityGuard = 68; + public const uint StormwindCityPatroller = 1976; + public const uint OrgrimmarGrunt = 3296; + public const uint AldorVindicator = 18549; + } + + [Script] + class npc_guard_generic : GuardAI + { + TaskScheduler _combatScheduler; + + public npc_guard_generic(Creature creature) : base(creature) + { + _scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting) && !me.IsInEvadeMode() && me.IsAlive()); + _combatScheduler = new TaskScheduler(); + _combatScheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting)); + } + + public override void Reset() + { + _scheduler.CancelAll(); + _combatScheduler.CancelAll(); + _scheduler.Schedule(TimeSpan.FromSeconds(1), task => + { + // Find a spell that targets friendly and applies an aura (these are generally buffs) + SpellInfo spellInfo = SelectSpell(me, 0, 0, SelectTargetType.AnyFriend, 0, 0, SelectEffect.Aura); + if (spellInfo != null) + DoCast(me, spellInfo.Id); + + task.Repeat(TimeSpan.FromMinutes(10)); + }); + } + + 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; + default: + break; + } + } + + public override void ReceiveEmote(Player player, TextEmotes textEmote) + { + switch (me.GetEntry()) + { + case CreatureIds.StormwindCityGuard: + case CreatureIds.StormwindCityPatroller: + case CreatureIds.OrgrimmarGrunt: + break; + default: + return; + } + + if (!me.IsFriendlyTo(player)) + return; + + DoReplyToTextEmote(textEmote); + } + + public override void EnterCombat(Unit who) + { + if (me.GetEntry() == CreatureIds.CenarionHoldInfantry) + Talk(TextIds.SayGuardSilAggro, who); + + _combatScheduler.Schedule(TimeSpan.FromSeconds(1), task => + { + Unit victim = me.GetVictim(); + if (!me.IsAttackReady() || !me.IsWithinMeleeRange(victim)) + { + task.Repeat(); + return; + } + if (RandomHelper.randChance(20)) + { + SpellInfo spellInfo = SelectSpell(me.GetVictim(), 0, 0, SelectTargetType.AnyEnemy, 0, SharedConst.NominalMeleeRange, SelectEffect.DontCare); + if (spellInfo != null) + { + me.ResetAttackTimer(); + DoCastVictim(spellInfo.Id); + task.Repeat(); + return; + } + } + if (ShouldSparWith(victim)) + me.FakeAttackerStateUpdate(victim); + else + me.AttackerStateUpdate(victim); + me.ResetAttackTimer(); + task.Repeat(); + }); + _combatScheduler.Schedule(TimeSpan.FromSeconds(5), task => + { + bool healing = false; + SpellInfo spellInfo = null; + + // Select a healing spell if less than 30% hp and Only 33% of the time + if (me.HealthBelowPct(30) && RandomHelper.randChance(33)) + spellInfo = SelectSpell(me, 0, 0, SelectTargetType.AnyFriend, 0, 0, SelectEffect.Healing); + + // No healing spell available, check if we can cast a ranged spell + if (spellInfo != null) + healing = true; + else + spellInfo = SelectSpell(me.GetVictim(), 0, 0, SelectTargetType.AnyEnemy, SharedConst.NominalMeleeRange, 0, SelectEffect.DontCare); + + // Found a spell + if (spellInfo != null) + { + if (healing) + DoCast(me, spellInfo.Id); + else + DoCastVictim(spellInfo.Id); + task.Repeat(TimeSpan.FromSeconds(5)); + } + else + task.Repeat(TimeSpan.FromSeconds(1)); + }); + } + + public override void UpdateAI(uint diff) + { + _scheduler.Update(diff); + + if (!UpdateVictim()) + return; + + _combatScheduler.Update(diff); + } + } + + [Script] + class npc_guard_shattrath_faction : GuardAI + { + public npc_guard_shattrath_faction(Creature creature) : base(creature) + { + _scheduler.SetValidator(() => !me.HasUnitState(UnitState.Casting)); + } + + public override void Reset() + { + _scheduler.CancelAll(); + } + + public override void EnterCombat(Unit who) + { + ScheduleVanish(); + } + + public override void UpdateAI(uint diff) + { + if (!UpdateVictim()) + return; + + _scheduler.Update(diff, base.DoMeleeAttackIfReady); + } + + void ScheduleVanish() + { + _scheduler.Schedule(TimeSpan.FromSeconds(5), task => + { + Unit temp = me.GetVictim(); + if (temp && temp.IsTypeId(TypeId.Player)) + { + DoCast(temp, me.GetEntry() == CreatureIds.AldorVindicator ? SpellIds.BanishedShattrathS : SpellIds.BanishedShattrathA); + ObjectGuid playerGUID = temp.GetGUID(); + task.Schedule(TimeSpan.FromSeconds(9), task => + { + Unit temp = Global.ObjAccessor.GetUnit(me, playerGUID); + if (temp) + { + temp.CastSpell(temp, SpellIds.Exile, true); + temp.CastSpell(temp, SpellIds.BanishTeleport, true); + } + ScheduleVanish(); + }); + } + else + task.Repeat(); + }); + } + } +} \ No newline at end of file diff --git a/Source/Scripts/World/NpcInnkeeper.cs b/Source/Scripts/World/NpcInnkeeper.cs new file mode 100644 index 000000000..c41c223a7 --- /dev/null +++ b/Source/Scripts/World/NpcInnkeeper.cs @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2012-2020 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 Game.Entities; +using Game.Scripting; +using Game.AI; +using Framework.Constants; + +namespace Scripts.World.NpcInnkeeper +{ + struct SpellIds + { + public const uint TrickOrTreated = 24755; + public const uint Treat = 24715; + } + + struct Gossip + { + public const string LocaleTrickOrTreat0 = "Trick or Treat!"; + public const string LocaleTrickOrTreat2 = "Des bonbons ou des blagues!"; + public const string LocaleTrickOrTreat3 = "Süßes oder Saures!"; + public const string LocaleTrickOrTreat6 = "¡Truco o trato!"; + + public const string LocaleInnkeeper0 = "Make this inn my home."; + public const string LocaleInnkeeper2 = "Faites de cette auberge votre foyer."; + public const string LocaleInnkeeper3 = "Ich möchte dieses Gasthaus zu meinem Heimatort machen."; + public const string LocaleInnkeeper6 = "Fija tu hogar en esta taberna."; + + public const string LocaleVendor0 = "I want to browse your goods."; + public const string LocaleVendor2 = "Je voudrais regarder vos articles."; + public const string LocaleVendor3 = "Ich sehe mich nur mal um."; + public const string LocaleVendor6 = "Quiero ver tus mercancías."; + } + + [Script] + class npc_innkeeper : ScriptedAI + { + public npc_innkeeper(Creature creature) : base(creature) { } + + public override bool GossipHello(Player player) + { + if (Global.GameEventMgr.IsHolidayActive(HolidayIds.HallowsEnd) && !player.HasAura(SpellIds.TrickOrTreated)) + { + string localizedEntry; + switch (player.GetSession().GetSessionDbcLocale()) + { + case Locale.frFR: + localizedEntry = Gossip.LocaleTrickOrTreat2; + break; + case Locale.deDE: + localizedEntry = Gossip.LocaleTrickOrTreat3; + break; + case Locale.esES: + localizedEntry = Gossip.LocaleTrickOrTreat6; + break; + case Locale.enUS: + default: + localizedEntry = Gossip.LocaleTrickOrTreat0; + break; + } + player.AddGossipItem(GossipOptionIcon.Chat, localizedEntry, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInfoDef + 1); + } + + if (me.IsQuestGiver()) + + if (me.IsVendor()) + { + string localizedEntry; + switch (player.GetSession().GetSessionDbcLocale()) + { + case Locale.frFR: + localizedEntry = Gossip.LocaleVendor2; + break; + case Locale.deDE: + localizedEntry = Gossip.LocaleVendor3; + break; + case Locale.esES: + localizedEntry = Gossip.LocaleVendor6; + break; + case Locale.enUS: + default: localizedEntry = Gossip.LocaleVendor0; + break; + } + player.AddGossipItem(GossipOptionIcon.Vendor, localizedEntry, eTradeskill.GossipSenderMain, eTradeskill.GossipActionTrade); + } + + if (me.IsInnkeeper()) + { + string localizedEntry; + switch (player.GetSession().GetSessionDbcLocale()) + { + case Locale.frFR: + localizedEntry = Gossip.LocaleInnkeeper2; + break; + case Locale.deDE: + localizedEntry = Gossip.LocaleInnkeeper3; + break; + case Locale.esES: + localizedEntry = Gossip.LocaleInnkeeper6; + break; + case Locale.enUS: + default: localizedEntry = Gossip.LocaleInnkeeper0; + break; + } + player.AddGossipItem(GossipOptionIcon.Interact1, localizedEntry, eTradeskill.GossipSenderMain, eTradeskill.GossipActionInn); + } + + player.TalkedToCreature(me.GetEntry(), me.GetGUID()); + player.SendGossipMenu(player.GetGossipTextId(me), me.GetGUID()); + return true; + } + + public override bool GossipSelect(Player player, uint menuId, uint gossipListId) + { + uint action = player.PlayerTalkClass.GetGossipOptionAction(gossipListId); + player.ClearGossipMenu(); + if (action == eTradeskill.GossipActionInfoDef + 1 && Global.GameEventMgr.IsHolidayActive(HolidayIds.HallowsEnd) && !player.HasAura(SpellIds.TrickOrTreated)) + { + player.CastSpell(player, SpellIds.TrickOrTreated, true); + + if (RandomHelper.IRand(0, 1) != 0) + player.CastSpell(player, SpellIds.Treat, true); + else + { + uint trickspell = 0; + switch (RandomHelper.IRand(0, 13)) + { + case 0: + trickspell = 24753; + break; // cannot cast, random 30sec + case 1: + trickspell = 24713; + break; // lepper gnome costume + case 2: + trickspell = 24735; + break; // male ghost costume + case 3: + trickspell = 24736; + break; // female ghostcostume + case 4: + trickspell = 24710; + break; // male ninja costume + case 5: + trickspell = 24711; + break; // female ninja costume + case 6: + trickspell = 24708; + break; // male pirate costume + case 7: + trickspell = 24709; + break; // female pirate costume + case 8: + trickspell = 24723; + break; // skeleton costume + case 9: + trickspell = 24753; + break; // Trick + case 10: + trickspell = 24924; + break; // Hallow's End Candy + case 11: + trickspell = 24925; + break; // Hallow's End Candy + case 12: + trickspell = 24926; + break; // Hallow's End Candy + case 13: + trickspell = 24927; + break; // Hallow's End Candy + } + player.CastSpell(player, trickspell, true); + } + player.CloseGossipMenu(); + return true; + } + + player.CloseGossipMenu(); + + switch (action) + { + case eTradeskill.GossipActionTrade: + player.GetSession().SendListInventory(me.GetGUID()); + break; + case eTradeskill.GossipActionInn: + player.SetBindPoint(me.GetGUID()); + break; + } + return true; + } + } +} + diff --git a/Source/Scripts/World/SceneScripts.cs b/Source/Scripts/World/SceneScripts.cs index dd9ac5046..e47bf0671 100644 --- a/Source/Scripts/World/SceneScripts.cs +++ b/Source/Scripts/World/SceneScripts.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2012-2020 CypherCore * * This program is free software: you can redistribute it and/or modify @@ -19,9 +19,9 @@ using Game; using Game.Entities; using Game.Scripting; -namespace Scripts.World +namespace Scripts.World.SceneScripts { - struct SceneSpells + struct SpellIds { public const uint DeathwingSimulator = 201184; } @@ -34,8 +34,8 @@ namespace Scripts.World // Called when a player receive trigger from scene public override void OnSceneTriggerEvent(Player player, uint sceneInstanceID, SceneTemplate sceneTemplate, string triggerName) { - if (triggerName == "BURN PLAYER") - player.CastSpell(player, SceneSpells.DeathwingSimulator, true); // Deathwing Simulator Burn player + if (triggerName == "Burn Player") + player.CastSpell(player, SpellIds.DeathwingSimulator, true); // Deathwing Simulator Burn player } } -} +} \ No newline at end of file