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
30 changes: 30 additions & 0 deletions Maple2.Server.Game/Commands/DebugCommand.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,6 +33,7 @@ public DebugCommand(GameSession session, NpcMetadataStorage npcStorage, MapDataS
AddCommand(new DebugQueryCommand(session, mapDataStorage));
AddCommand(new LogoutCommand(session));
AddCommand(new ReloadCommandsCommand(session));
AddCommand(new PrintInventoryCommand(session));
}

private class ReloadCommandsCommand : Command {
Expand DownExpand Up@@ -398,4 +399,33 @@ private void Handle(InvocationContext ctx) {
session.Disconnect();
}
}

private class PrintInventoryCommand : Command {
private readonly GameSession session;

public PrintInventoryCommand(GameSession session) : base("print-inventory", "Print player inventory items.") {
this.session = session;

var tab = new Argument<string>("tab", $"Inventory tab to print. One of: {string.Join(", ", Enum.GetNames(typeof(InventoryType)))}");

AddArgument(tab);
this.SetHandler<InvocationContext, string>(Handle, tab);
}

private void Handle(InvocationContext ctx, string tab) {
try {
if (!Enum.TryParse(tab, true, out InventoryType inventoryType)) {
ctx.Console.Error.WriteLine($"Invalid inventory tab: {tab}. Must be one of: {string.Join(", ", Enum.GetNames(typeof(InventoryType)))}");
ctx.ExitCode = 1;
return;
}

ctx.Console.Out.WriteLine(session.Item.Inventory.Print(inventoryType));
ctx.ExitCode = 0;
} catch (SystemException ex) {
ctx.Console.Error.WriteLine(ex.Message);
ctx.ExitCode = 1;
}
}
}
}
17 changes: 8 additions & 9 deletions Maple2.Server.Game/Manager/ItemEnchantManager.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,13 +14,11 @@ public class ItemEnchantManager {
private const int MAX_EXP = 10000;
private const int CHARGE_RATE = 1;

// ReSharper disable RedundantExplicitArraySize
private static readonly int[] RequireFodder = new int[15] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 3, 4 };
private static readonly int[] GainExp = new int[15] { 10000, 10000, 10000, 5000, 5000, 5000, 2500, 2500, 2500, 2000, 3334, 2000, 2000, 1250, 1250 };
private static readonly int[] SuccessRate = new int[15] { 100, 100, 100, 95, 90, 80, 70, 60, 50, 40, 30, 20, 15, 10, 5 };
private static readonly int[] FodderRate = new int[15] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 5, 4, 2 };
private static readonly int[] FailCharge = new int[15] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 4, 5 };
// ReSharper restore RedundantExplicitArraySize
private static readonly int[] RequireFodder = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 3, 4];
private static readonly int[] GainExp = [10000, 10000, 10000, 5000, 5000, 5000, 2500, 2500, 2500, 2000, 3334, 2000, 2000, 1250, 1250];
private static readonly int[] SuccessRate = [100, 100, 100, 95, 90, 80, 70, 60, 50, 40, 30, 20, 15, 10, 5];
private static readonly int[] FodderRate = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 5, 4, 2];
private static readonly int[] FailCharge = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 4, 5];

private static readonly IngredientInfo[][] PeachyCost = new IngredientInfo[15][];

Expand DownExpand Up@@ -73,7 +71,7 @@ IngredientInfo[] Build(int onyx, int chaosOnyx, int crystalFragment) {
public ItemEnchantManager(GameSession session) {
this.session = session;

catalysts = new List<IngredientInfo>();
catalysts = [];
fodders = new Dictionary<long, Item>();
attributeDeltas = new Dictionary<BasicAttribute, BasicOption>();
rates = new EnchantRates();
Expand DownExpand Up@@ -147,7 +145,8 @@ public bool UpdateFodder(long itemUid, bool add) {

if (add) {
// Prevent adding more fodder if it won't help.
if (Type is EnchantType.Ophelia && rates.Total >= MAX_RATE) {
// Can't go over 30% rate with fodders
if (Type is EnchantType.Ophelia && rates.Total >= MAX_RATE || rates.Fodder + FodderRate[enchants] > 30) {
NpcTalkEvent(ScriptEventType.EnchantFail, ItemEnchantError.max_fodder);
return false;
}
Expand Down
29 changes: 22 additions & 7 deletions Maple2.Server.Game/Manager/Items/InventoryManager.cs
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Maple2.Database.Storage;
using Maple2.Model;
using Maple2.Model.Enum;
Expand DownExpand Up@@ -34,13 +35,11 @@ public InventoryManager(GameStorage.Request db, GameSession session) {

delete = [];
foreach ((InventoryType type, List<Item> load) in db.GetInventory(session.CharacterId)) {
if (tabs.TryGetValue(type, out ItemCollection? items)) {
foreach (Item item in load) {
if (items.Add(item).Count == 0) {
Log.Error("Failed to add item:{Uid} to ItemCollection (Size:{Size}, OpenSlots:{OpenSlots}, Count:{Count})",
item.Uid, items.Size, items.OpenSlots, items.Count);
}
}
if (!tabs.TryGetValue(type, out ItemCollection? items)) continue;
foreach (Item item in load) {
if (items.Add(item).Count != 0) continue;
Discard(item);
Log.Warning("Deleted item {ItemUid} from inventory {InventoryType} due to overflow", item.Uid, type);
}
}
}
Expand DownExpand Up@@ -736,4 +735,20 @@ public void Save(GameStorage.Request db) {
}
}
}

public string Print(InventoryType type) {
lock (session.Item) {
if (!tabs.TryGetValue(type, out ItemCollection? items)) {
return $"Inventory {type} not found.";
}

var sb = new StringBuilder();
sb.AppendLine($"Inventory {type}:");
foreach (Item item in items) {
sb.AppendLine($"- {item.Id} [{item.Metadata.Name}] (Amount: {item.Amount}, Slot: {item.Slot}, Expiry: {item.ExpiryTime}, Rarity: {item.Rarity}, Tag: {item.Metadata.Property.Tag})");
}
sb.AppendLine($"Total Items: {items.Count}, Open Slots: {items.OpenSlots}, Size: {items.Size}");
return sb.ToString();
}
}
}
4 changes: 3 additions & 1 deletion Maple2.Server.Game/Manager/Items/StorageManager.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,10 +21,12 @@ public sealed class StorageManager : IDisposable {

public StorageManager(GameSession session) {
this.session = session;
items = new ItemCollection(Constant.BaseStorageCount);

using GameStorage.Request db = session.GameStorage.Context();
(mesos, expand) = db.GetStorageInfo(session.AccountId);

items = new ItemCollection((short) (Constant.BaseStorageCount + expand));

foreach (Item item in db.GetStorage(session.AccountId)) {
if (items.Add(item).Count == 0) {
Log.Error("Failed to add storage item:{Uid}", item.Uid);
Expand Down
6 changes: 4 additions & 2 deletions Maple2.Server.Game/Manager/QuestManager.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -218,8 +218,7 @@ public void Update(ConditionType type, long counter = 1, string targetString = "
condition.Counter = (int) Math.Min(condition.Metadata.Value, condition.Counter + counter);

session.Send(QuestPacket.Update(quest));
if (quest.Metadata.Basic.Type == QuestType.FieldMission &&
CanComplete(quest)) {
if (quest.Metadata.Basic.Type == QuestType.FieldMission && CanComplete(quest)) {
Complete(quest);
}
}
Expand DownExpand Up@@ -370,6 +369,9 @@ public bool Complete(Quest quest, bool bypassConditions = false) {
session.ConditionUpdate(ConditionType.quest_clear_by_chapter, codeLong: quest.Metadata.Basic.ChapterId);
session.ConditionUpdate(ConditionType.quest, codeLong: quest.Metadata.Id);
session.ConditionUpdate(ConditionType.quest_clear, codeLong: quest.Metadata.Id);
if (quest.Metadata.Basic.Type == QuestType.FieldMission) {
session.ConditionUpdate(ConditionType.field_mission);
}

quest.EndTime = DateTime.Now.ToEpochSeconds();
quest.State = QuestState.Completed;
Expand Down