From 77a6879b239bb36775dbe64ac60420d31b502ce3 Mon Sep 17 00:00:00 2001 From: Tandashi <18377875+Tandashi@users.noreply.github.com> Date: Wed, 27 Aug 2025 10:52:56 +0200 Subject: [PATCH] Handling for `music_play_instrument_mastery` condition type Handling of mastery updates has been changed to properly update the `music_play_instrument_mastery`. This now enables the following Trophies to work properly: - https://handbook.tadeucci.dev/trophies/23100142 - https://handbook.tadeucci.dev/trophies/23100143 - https://handbook.tadeucci.dev/trophies/23100144 - https://handbook.tadeucci.dev/trophies/23100168 - https://handbook.tadeucci.dev/trophies/23100169 - https://handbook.tadeucci.dev/trophies/23100170 - https://handbook.tadeucci.dev/trophies/23100178 - https://handbook.tadeucci.dev/trophies/23100179 - https://handbook.tadeucci.dev/trophies/23100180 - https://handbook.tadeucci.dev/trophies/23100197 - https://handbook.tadeucci.dev/trophies/23100198 - https://handbook.tadeucci.dev/trophies/23100199 - https://handbook.tadeucci.dev/trophies/23100224 - https://handbook.tadeucci.dev/trophies/23100225 - https://handbook.tadeucci.dev/trophies/23100226 - https://handbook.tadeucci.dev/trophies/23100232 - https://handbook.tadeucci.dev/trophies/23100233 - https://handbook.tadeucci.dev/trophies/23100234 - https://handbook.tadeucci.dev/trophies/23100235 - https://handbook.tadeucci.dev/trophies/23100236 - https://handbook.tadeucci.dev/trophies/23100237 - https://handbook.tadeucci.dev/trophies/23100254 - https://handbook.tadeucci.dev/trophies/23100255 - https://handbook.tadeucci.dev/trophies/23100256 - https://handbook.tadeucci.dev/trophies/23100277 - https://handbook.tadeucci.dev/trophies/23100278 - https://handbook.tadeucci.dev/trophies/23100310 - https://handbook.tadeucci.dev/trophies/23100311 - https://handbook.tadeucci.dev/trophies/23100353 - https://handbook.tadeucci.dev/trophies/23100354 - https://handbook.tadeucci.dev/trophies/23100355 - https://handbook.tadeucci.dev/trophies/23100410 - https://handbook.tadeucci.dev/trophies/23100411 - https://handbook.tadeucci.dev/trophies/23100412 - https://handbook.tadeucci.dev/trophies/23100413 Furthermore the `/player mastery exp` command has been updated to now add exp rather then set the mastery value to the specified exp value as this causes issues for trophy tracking and is now more inline with the actual description. Additionally the `RewardGrade` for Trophies has been miscalculated if they had no reward but had more additional grades that needed completing. Previously the `RewardGrade` had been increased past the actual `Grade` of the Trophy to mark it as completed. This was only correct for trophies that did not have additional `Grades` like e.g. music performance trophies causing the UI to skip to the next `Grade` for display. Refs: #484 --- Maple2.Server.Game/Commands/PlayerCommand.cs | 32 ++++++++- .../Manager/AchievementManager.cs | 12 ++++ Maple2.Server.Game/Manager/MasteryManager.cs | 66 +++++++++++++++---- Maple2.Server.Game/Util/ConditionUtil.cs | 2 + 4 files changed, 96 insertions(+), 16 deletions(-) diff --git a/Maple2.Server.Game/Commands/PlayerCommand.cs b/Maple2.Server.Game/Commands/PlayerCommand.cs index d8d3889a8..6fe44f7eb 100644 --- a/Maple2.Server.Game/Commands/PlayerCommand.cs +++ b/Maple2.Server.Game/Commands/PlayerCommand.cs @@ -27,14 +27,15 @@ public PlayerCommand(GameSession session, AchievementMetadataStorage achievement private class MasteryCommand : Command { public MasteryCommand(GameSession session) : base("mastery", "Set player mastery.") { - AddCommand(new MasteryExpCommand(session)); + AddCommand(new MasteryAddExpCommand(session)); + AddCommand(new MasterySetExpCommand(session)); AddCommand(new MasteryLevelCommand(session)); } - private class MasteryExpCommand : Command { + private class MasteryAddExpCommand : Command { private readonly GameSession session; - public MasteryExpCommand(GameSession session) : base("exp", "Set player mastery experience.") { + public MasteryAddExpCommand(GameSession session) : base("addexp", "Add player mastery experience.") { this.session = session; var masteryCode = new Argument("mastery", "MasteryType of the player."); @@ -45,6 +46,31 @@ public MasteryExpCommand(GameSession session) : base("exp", "Set player mastery this.SetHandler(Handle, masteryCode, exp); } + private void Handle(InvocationContext ctx, MasteryType masteryType, int exp) { + try { + session.Mastery[masteryType] = session.Mastery[masteryType] + exp; + ctx.ExitCode = 0; + } catch (SystemException ex) { + ctx.Console.Error.WriteLine(ex.Message); + ctx.ExitCode = 1; + } + } + } + + private class MasterySetExpCommand : Command { + private readonly GameSession session; + + public MasterySetExpCommand(GameSession session) : base("setexp", "Set player mastery experience.") { + this.session = session; + + var masteryCode = new Argument("mastery", "MasteryType of the player."); + var exp = new Argument("exp", "Experience points to set to."); + + AddArgument(masteryCode); + AddArgument(exp); + this.SetHandler(Handle, masteryCode, exp); + } + private void Handle(InvocationContext ctx, MasteryType masteryType, int exp) { try { session.Mastery[masteryType] = exp; diff --git a/Maple2.Server.Game/Manager/AchievementManager.cs b/Maple2.Server.Game/Manager/AchievementManager.cs index f6327c1e2..72e184367 100644 --- a/Maple2.Server.Game/Manager/AchievementManager.cs +++ b/Maple2.Server.Game/Manager/AchievementManager.cs @@ -166,6 +166,18 @@ private void GiveReward(Achievement achievement, bool manualClaim = false) { return; } + bool hasMoreGrades = achievement.Metadata.Grades.Count > achievement.CurrentGrade; + // If an achievement has still more grade then we need to make sure the reward grade + // does not exceed the current grade. Else it will not show the correct trophy in + // the UI but rather the one past. + if (grade.Reward == null && hasMoreGrades) { + achievement.RewardGrade = Math.Min(achievement.RewardGrade + 1, achievement.CurrentGrade); + return; + } + + // If an achievement has no reward and no further grade we need to push the reward grade + // past the current grade to mark it as fully completed. Else it will not show the crown + // and completion date for the trophy but rather the claim button which is not correct. if (grade.Reward == null) { achievement.RewardGrade++; return; diff --git a/Maple2.Server.Game/Manager/MasteryManager.cs b/Maple2.Server.Game/Manager/MasteryManager.cs index b71c01d25..b0b154b42 100644 --- a/Maple2.Server.Game/Manager/MasteryManager.cs +++ b/Maple2.Server.Game/Manager/MasteryManager.cs @@ -9,6 +9,7 @@ using Maple2.Server.Game.Model; using Maple2.Server.Game.Packets; using Maple2.Server.Game.Session; +using Serilog; namespace Maple2.Server.Game.Manager; @@ -80,21 +81,60 @@ public int this[MasteryType type] { session.Send(MasteryPacket.UpdateMastery(type, session.Mastery[type])); int currentLevel = GetLevel(type); - if (startLevel < currentLevel || startValue == 0) { - if (type == MasteryType.Fishing) { - session.ConditionUpdate(ConditionType.fisher_grade, codeLong: currentLevel); - } else { - session.ConditionUpdate(ConditionType.mastery_grade, codeLong: (int) type); - } - } - if (startLevel > currentLevel) { - session.ConditionUpdate(ConditionType.set_mastery_grade, codeLong: (int) type); - if (type == MasteryType.Music) { - session.ConditionUpdate(ConditionType.music_play_grade); - } - } + int deltaLevel = currentLevel - startLevel + (startValue == 0 ? 1 : 0); + int deltaExp = value - startValue; + Log.Logger.Debug("[Mastery] {type} changed from {startValue} to {value} (Level {startLevel} -> {currentLevel}), ΔLevel: {deltaLevel}, ΔExp: {deltaExp}", type, startValue, value, startLevel, currentLevel, deltaLevel, deltaExp); + + HandleMasteryLevelChange(type, currentLevel, deltaLevel); + HandleMasteryExpIncrease(type, deltaExp); + } + + } + + /// + /// Handles the change of mastery level for a specified . + /// Updates the corresponding condition based on the mastery type and level changes. + /// + /// The type of mastery whos level has been increased. + /// The new current level of the mastery after the increase. + /// The delta by which the mastery level has changed. + private void HandleMasteryLevelChange(MasteryType type, int currentLevel, int deltaLevel) { + if (deltaLevel == 0) { + return; } + if (deltaLevel < 0) { + session.ConditionUpdate(ConditionType.set_mastery_grade, codeLong: (int) type); + return; + } + + switch (type) { + case MasteryType.Fishing: + session.ConditionUpdate(ConditionType.fisher_grade, codeLong: currentLevel); + return; + case MasteryType.Music: + session.ConditionUpdate(ConditionType.music_play_grade, counter: deltaLevel); + return; + default: + session.ConditionUpdate(ConditionType.mastery_grade, codeLong: (int) type); + return; + } + } + + /// + /// Handles the increase of mastery experience for a specified MasteryType. + /// Updates relevant conditions based on the mastery type and the amount of experience gained. + /// + /// The type of mastery for which experience is being increased. + /// The amount of experience that has been gained for the mastery. + private void HandleMasteryExpIncrease(MasteryType type, int deltaExp) { + switch (type) { + case MasteryType.Music: + session.ConditionUpdate(ConditionType.music_play_instrument_mastery, counter: deltaExp, codeLong: session.Instrument?.Value.Category ?? 0); + return; + default: + return; + } } public short GetLevel(MasteryType type) { diff --git a/Maple2.Server.Game/Util/ConditionUtil.cs b/Maple2.Server.Game/Util/ConditionUtil.cs index fb753fb6c..580cde349 100644 --- a/Maple2.Server.Game/Util/ConditionUtil.cs +++ b/Maple2.Server.Game/Util/ConditionUtil.cs @@ -110,6 +110,7 @@ private static bool CheckCode(this ConditionMetadata.Parameters code, GameSessio case ConditionType.holdtime: case ConditionType.riding: case ConditionType.fish_big: + case ConditionType.music_play_instrument_mastery: case ConditionType.music_play_instrument_time: case ConditionType.music_play_ensemble_in: case ConditionType.music_play_score: @@ -271,6 +272,7 @@ private static bool CheckTarget(this ConditionMetadata.Parameters target, GameSe case ConditionType.set_mastery_grade: case ConditionType.music_play_grade: case ConditionType.music_play_ensemble: + case ConditionType.music_play_instrument_mastery: case ConditionType.item_add: case ConditionType.item_pickup: case ConditionType.item_destroy: