Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions Maple2.Server.Game/Commands/PlayerCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<MasteryType>("mastery", "MasteryType of the player.");
Expand All @@ -45,6 +46,31 @@ public MasteryExpCommand(GameSession session) : base("exp", "Set player mastery
this.SetHandler<InvocationContext, MasteryType, int>(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;
}
}
Comment on lines +49 to +57

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

setexp cannot decrease mastery due to clamping in MasteryManager indexer.

Both addexp and setexp route through session.Mastery[...] which clamps to [current..max]; setexp cannot lower EXP/level, contrary to “Set” semantics. Provide an absolute setter or an override path for admin commands.

- session.Mastery[masteryType] = exp;
+ // Introduce an absolute setter on MasteryManager that clamps [0..max] and allows decreases:
+ // session.Mastery.SetAbsolute(masteryType, exp);

If you prefer to keep the indexer strict, inject a bool allowDecrease into the indexer (default false) and use it only from admin commands.

Also applies to: 74-82

🤖 Prompt for AI Agents
In Maple2.Server.Game/Commands/PlayerCommand.cs around lines 49-57 (and also
apply same change to 74-82): setexp currently uses session.Mastery[...] which
clamps increases only and so cannot lower mastery; change the admin command to
call an absolute setter on the MasteryManager (or add an optional bool
allowDecrease=false parameter to the MasteryManager indexer) and pass true from
admin commands so the value is applied without clamping; update the admin paths
to use the new setter/override and keep the default clamping behavior for normal
gameplay.

}

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<MasteryType>("mastery", "MasteryType of the player.");
var exp = new Argument<int>("exp", "Experience points to set to.");

AddArgument(masteryCode);
AddArgument(exp);
this.SetHandler<InvocationContext, MasteryType, int>(Handle, masteryCode, exp);
}

private void Handle(InvocationContext ctx, MasteryType masteryType, int exp) {
try {
session.Mastery[masteryType] = exp;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if its a set command we shouldn't add.

@Tandashi Tandashi Aug 28, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will change the description of the subcommand. Did forget to do that as the exp positional argument description already describes it as add.

Furthermore adding would be more inline with the other commands e.g. /home as it has exp and setexp subcommands.

If you'd like I can also introduce a setexp subcommand for the mastery command as well.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think would be better to introduce a subcommand like setexp/addexp

Expand Down
12 changes: 12 additions & 0 deletions Maple2.Server.Game/Manager/AchievementManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
66 changes: 53 additions & 13 deletions Maple2.Server.Game/Manager/MasteryManager.cs
Comment thread
Tandashi marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Comment thread
Tandashi marked this conversation as resolved.
HandleMasteryLevelChange(type, currentLevel, deltaLevel);
HandleMasteryExpIncrease(type, deltaExp);
}

}

/// <summary>
/// Handles the change of mastery level for a specified <see cref="MasteryType"/>.
/// Updates the corresponding condition based on the mastery type and level changes.
/// </summary>
/// <param name="type">The type of mastery whos level has been increased.</param>
/// <param name="currentLevel">The new current level of the mastery after the increase.</param>
/// <param name="deltaLevel">The delta by which the mastery level has changed.</param>
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;
}
}

/// <summary>
/// Handles the increase of mastery experience for a specified MasteryType.
/// Updates relevant conditions based on the mastery type and the amount of experience gained.
/// </summary>
/// <param name="type">The type of mastery for which experience is being increased.</param>
/// <param name="deltaExp">The amount of experience that has been gained for the mastery.</param>
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) {
Expand Down
2 changes: 2 additions & 0 deletions Maple2.Server.Game/Util/ConditionUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
Loading