diff --git a/Maple2.Server.Game/Manager/Field/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager.State.cs index 9a78d4b71..8e7b046fd 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager.State.cs @@ -31,6 +31,7 @@ public partial class FieldManager { private readonly ConcurrentDictionary fieldInteracts = new(); private readonly ConcurrentDictionary fieldFunctionInteracts = new(); private readonly ConcurrentDictionary fieldAdBalloons = new(); + private readonly ConcurrentDictionary fieldInstruments = new(); private readonly ConcurrentDictionary fieldItems = new(); private readonly ConcurrentDictionary fieldMobSpawns = new(); private readonly ConcurrentDictionary fieldSkills = new(); @@ -499,6 +500,8 @@ public FieldInstrument SpawnInstrument(IActor owner, InstrumentMetadata Rotation = owner.Rotation, }; + fieldInstruments[fieldInstrument.ObjectId] = fieldInstrument; + return fieldInstrument; } @@ -637,6 +640,15 @@ public bool RemovePortal(int objectId) { Broadcast(PortalPacket.Remove(portal.Value.Id)); return true; } + + public bool RemoveInstrument(int objectId) { + if (!fieldInstruments.TryRemove(objectId, out FieldInstrument? instrument)) { + return false; + } + + Broadcast(InstrumentPacket.StopScore(instrument)); + return true; + } #endregion #region Events @@ -649,6 +661,11 @@ public void OnAddPlayer(FieldPlayer added) { foreach (FieldInteract fieldInteract in fieldAdBalloons.Values) { added.Session.Send(InteractObjectPacket.Add(fieldInteract.Object)); } + foreach (FieldInstrument fieldInstrument in fieldInstruments.Values) { + if (fieldInstrument.Score != null) { + added.Session.Send(InstrumentPacket.StartScore(fieldInstrument, fieldInstrument.Score)); + } + } if (MapId is Constant.DefaultHomeMapId) { IEnumerable interactCubes = Plots.FirstOrDefault().Value.Cubes.Values .Where(x => x.ItemType.IsInteractFurnishing && x.HousingCategory is not HousingCategory.Ranching and not HousingCategory.Farming); diff --git a/Maple2.Server.Game/Manager/ShopManager.cs b/Maple2.Server.Game/Manager/ShopManager.cs index 153987f8d..13d0982c3 100644 --- a/Maple2.Server.Game/Manager/ShopManager.cs +++ b/Maple2.Server.Game/Manager/ShopManager.cs @@ -436,7 +436,7 @@ public void Buy(int shopItemId, int quantity) { } } - if (quantity > shopItem.StockCount - shopItem.StockPurchased) { + if (shopItem.StockCount != 0 && quantity > shopItem.StockCount - shopItem.StockPurchased) { session.Send(ShopPacket.Error(ShopError.s_err_lack_shopitem)); return; } diff --git a/Maple2.Server.Game/Model/Field/Entity/FieldInstrument.cs b/Maple2.Server.Game/Model/Field/Entity/FieldInstrument.cs index 3ac84ac3b..2f3bdd722 100644 --- a/Maple2.Server.Game/Model/Field/Entity/FieldInstrument.cs +++ b/Maple2.Server.Game/Model/Field/Entity/FieldInstrument.cs @@ -1,4 +1,5 @@ -using Maple2.Model.Metadata; +using Maple2.Model.Game; +using Maple2.Model.Metadata; using Maple2.Server.Game.Manager.Field; namespace Maple2.Server.Game.Model; @@ -8,5 +9,6 @@ public class FieldInstrument(FieldManager field, int objectId, InstrumentMetadat public bool Improvising { get; set; } public long StartTick { get; set; } public bool Ensemble { get; set; } + public Item? Score { get; set; } } diff --git a/Maple2.Server.Game/PacketHandlers/InstrumentHandler.cs b/Maple2.Server.Game/PacketHandlers/InstrumentHandler.cs index b5a421c33..956382a96 100644 --- a/Maple2.Server.Game/PacketHandlers/InstrumentHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/InstrumentHandler.cs @@ -138,6 +138,7 @@ private void HandleStartScore(GameSession session, IByteReader packet) { if (!TryUseInstrument(session, itemUid, Environment.TickCount64, false, out session.Instrument)) { return; } + session.Instrument.Score = score; score.RemainUses--; session.Field.Broadcast(InstrumentPacket.StartScore(session.Instrument, score)); @@ -168,7 +169,7 @@ private void HandleStopScore(GameSession session) { // Modifier is the number of 500ms ticks that have passed. session.Exp.AddExp(expType, (totalTickTime - 500) / 500); - session.Field.Broadcast(InstrumentPacket.StopScore(session.Instrument)); + session.Field.RemoveInstrument(session.Instrument.ObjectId); session.Instrument = null; } @@ -333,7 +334,7 @@ private bool TryUseInstrument(GameSession session, long itemUid, long startTick, return false; } - fieldInstrument = session.Field!.SpawnInstrument(session.Player, metadata); + fieldInstrument = session.Field.SpawnInstrument(session.Player, metadata); fieldInstrument.StartTick = startTick; fieldInstrument.Ensemble = ensemble; return true; diff --git a/Maple2.Server.World/Migrations/20250207213214_HomeDecoration.cs b/Maple2.Server.World/Migrations/20250207213214_HomeDecoration.cs index 8df76b2f8..8b829bc21 100644 --- a/Maple2.Server.World/Migrations/20250207213214_HomeDecoration.cs +++ b/Maple2.Server.World/Migrations/20250207213214_HomeDecoration.cs @@ -32,6 +32,7 @@ protected override void Up(MigrationBuilder migrationBuilder) { name: "InteriorRewardsClaimed", table: "home", type: "json", + defaultValue: "[]", nullable: false) .Annotation("MySql:CharSet", "utf8mb4"); }