From db6cfeca04f4dee65866c8c20054a13695d5d82e Mon Sep 17 00:00:00 2001 From: hondacrx Date: Thu, 5 May 2022 13:53:23 -0400 Subject: [PATCH] Core/Scripts: Added script hook to execute actions after completing an achievement Port From (https://github.com/TrinityCore/TrinityCore/commit/27cba3f52309dad5be964fec11d80cd8cad128cf) --- .../Game/Achievements/AchievementManager.cs | 43 ++++++++++++++++++- Source/Game/Scripting/CoreScripts.cs | 15 ++++++- Source/Game/Scripting/ScriptManager.cs | 9 ++++ Source/Game/Server/WorldManager.cs | 2 + Source/Scripts/World/Achievements.cs | 26 ++++++++++- 5 files changed, 92 insertions(+), 3 deletions(-) diff --git a/Source/Game/Achievements/AchievementManager.cs b/Source/Game/Achievements/AchievementManager.cs index 9093135c0..93801183f 100644 --- a/Source/Game/Achievements/AchievementManager.cs +++ b/Source/Game/Achievements/AchievementManager.cs @@ -541,6 +541,8 @@ namespace Game.Achievements UpdateCriteria(CriteriaType.EarnAchievement, achievement.Id, 0, 0, null, referencePlayer); UpdateCriteria(CriteriaType.EarnAchievementPoints, achievement.Points, 0, 0, null, referencePlayer); + Global.ScriptMgr.OnAchievementCompleted(referencePlayer, achievement); + // reward items and titles if any AchievementReward reward = Global.AchievementMgr.GetAchievementReward(achievement); @@ -1021,6 +1023,8 @@ namespace Game.Achievements UpdateCriteria(CriteriaType.EarnAchievement, achievement.Id, 0, 0, null, referencePlayer); UpdateCriteria(CriteriaType.EarnAchievementPoints, achievement.Points, 0, 0, null, referencePlayer); + + Global.ScriptMgr.OnAchievementCompleted(referencePlayer, achievement); } public override void SendCriteriaUpdate(Criteria entry, CriteriaProgress progress, TimeSpan timeElapsed, bool timedCompleted) @@ -1095,6 +1099,7 @@ namespace Game.Achievements Dictionary _achievementRewards = new(); Dictionary _achievementRewardLocales = new(); + Dictionary _achievementScripts = new(); AchievementGlobalMgr() { } @@ -1171,6 +1176,37 @@ namespace Game.Achievements Log.outInfo(LogFilter.ServerLoading, "Loaded {0} achievement references in {1} ms.", count, Time.GetMSTimeDiffToNow(oldMSTime)); } + public void LoadAchievementScripts() + { + uint oldMSTime = Time.GetMSTime(); + + _achievementScripts.Clear(); // need for reload case + + SQLResult result = DB.World.Query("SELECT AchievementId, ScriptName FROM achievement_scripts"); + if (result.IsEmpty()) + { + Log.outInfo(LogFilter.ServerLoading, "Loaded 0 achievement scripts. DB table `achievement_scripts` is empty."); + return; + } + + do + { + uint achievementId = result.Read(0); + string scriptName = result.Read(1); + + AchievementRecord achievement = CliDB.AchievementStorage.LookupByKey(achievementId); + if (achievement == null) + { + Log.outError(LogFilter.Sql, $"Table `achievement_scripts` contains non-existing Achievement (ID: {achievementId}), skipped."); + continue; + } + _achievementScripts[achievementId] = Global.ObjectMgr.GetScriptId(scriptName); + } + while (result.NextRow()); + + Log.outInfo(LogFilter.ServerLoading, $"Loaded {_achievementScripts.Count} achievement scripts in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); + } + public void LoadCompletedAchievements() { uint oldMSTime = Time.GetMSTime(); @@ -1353,7 +1389,7 @@ namespace Game.Achievements AchievementRewardLocale data = new(); Locale locale = localeName.ToEnum(); - if (!SharedConst.IsValidLocale(locale) || locale == Locale.enUS) + if (!SharedConst.IsValidLocale(locale) || locale == Locale.enUS) continue; ObjectManager.AddLocaleString(result.Read(2), locale, data.Subject); @@ -1365,6 +1401,11 @@ namespace Game.Achievements Log.outInfo(LogFilter.ServerLoading, "Loaded {0} achievement reward locale strings in {1} ms.", _achievementRewardLocales.Count, Time.GetMSTimeDiffToNow(oldMSTime)); } + + public uint GetAchievementScriptId(uint achievementId) + { + return _achievementScripts.LookupByKey(achievementId); + } } public class AchievementReward diff --git a/Source/Game/Scripting/CoreScripts.cs b/Source/Game/Scripting/CoreScripts.cs index 3bab0d2a1..637cabc55 100644 --- a/Source/Game/Scripting/CoreScripts.cs +++ b/Source/Game/Scripting/CoreScripts.cs @@ -586,6 +586,19 @@ namespace Game.Scripting public virtual void OnUpdate(Transport obj, uint diff) { } } + public class AchievementScript : ScriptObject + { + public AchievementScript(string name) : base(name) + { + Global.ScriptMgr.AddScript(this); + } + + public override bool IsDatabaseBound() { return true; } + + // Called when an achievement is completed. + public virtual void OnCompleted(Player player, AchievementRecord achievement) { } + } + public class AchievementCriteriaScript : ScriptObject { public AchievementCriteriaScript(string name) : base(name) @@ -593,7 +606,7 @@ namespace Game.Scripting Global.ScriptMgr.AddScript(this); } - public override bool IsDatabaseBound() { return false; } + public override bool IsDatabaseBound() { return true; } // Called when an additional criteria is checked. public virtual bool OnCheck(Player source, Unit target) { return false; } diff --git a/Source/Game/Scripting/ScriptManager.cs b/Source/Game/Scripting/ScriptManager.cs index 146b783df..ee66d0f38 100644 --- a/Source/Game/Scripting/ScriptManager.cs +++ b/Source/Game/Scripting/ScriptManager.cs @@ -866,6 +866,15 @@ namespace Game.Scripting RunScript(p => p.OnRelocate(transport, waypointId, mapId, x, y, z), transport.GetScriptId()); } + // Achievement + public void OnAchievementCompleted(Player player, AchievementRecord achievement) + { + Cypher.Assert(player != null); + Cypher.Assert(achievement != null); + + RunScript(p => p.OnCompleted(player, achievement), Global.AchievementMgr.GetAchievementScriptId(achievement.Id)); + } + // AchievementCriteriaScript public bool OnCriteriaCheck(uint ScriptId, Player source, Unit target) { diff --git a/Source/Game/Server/WorldManager.cs b/Source/Game/Server/WorldManager.cs index 3fa624604..8b42cae02 100644 --- a/Source/Game/Server/WorldManager.cs +++ b/Source/Game/Server/WorldManager.cs @@ -818,6 +818,8 @@ namespace Game Global.CriteriaMgr.LoadCriteriaData(); Log.outInfo(LogFilter.ServerLoading, "Loading Achievements..."); Global.AchievementMgr.LoadAchievementReferenceList(); + Log.outInfo(LogFilter.ServerLoading, "Loading Achievements Scripts..."); + Global.AchievementMgr.LoadAchievementScripts(); Log.outInfo(LogFilter.ServerLoading, "Loading Achievement Rewards..."); Global.AchievementMgr.LoadRewards(); Log.outInfo(LogFilter.ServerLoading, "Loading Achievement Reward Locales..."); diff --git a/Source/Scripts/World/Achievements.cs b/Source/Scripts/World/Achievements.cs index 713f5576f..7c50c044b 100644 --- a/Source/Scripts/World/Achievements.cs +++ b/Source/Scripts/World/Achievements.cs @@ -20,6 +20,7 @@ using Game.BattleGrounds; using Game.BattleGrounds.Zones; using Game.Entities; using Game.Scripting; +using Game.DataStorage; namespace Scripts.World.Achievements { @@ -43,7 +44,7 @@ namespace Scripts.World.Achievements } struct VehicleIds - { + { //BgSA Artillery public const uint AntiPersonnalCannon = 27894; } @@ -310,4 +311,27 @@ namespace Scripts.World.Achievements return target && player.IsHonorOrXPTarget(target); } } + + [Script] // 7433 - Newbie + class achievement_newbie : AchievementScript + { + public achievement_newbie() : base("achievement_newbie") { } + + public override void OnCompleted(Player player, AchievementRecord achievement) + { + player.GetSession().GetBattlePetMgr().UnlockSlot(BattlePetSlots.Slot1); + // TODO: Unlock trap + } + } + + [Script] // 6566 - Just a Pup + class achievement_just_a_pup : AchievementScript + { + public achievement_just_a_pup() : base("achievement_just_a_pup") { } + + public override void OnCompleted(Player player, AchievementRecord achievement) + { + player.GetSession().GetBattlePetMgr().UnlockSlot(BattlePetSlots.Slot2); + } + } } \ No newline at end of file