From 291e93048ecea59ad4d54b52b6b21978d04a1771 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 8 Apr 2022 10:57:19 -0700 Subject: [PATCH] Update MapCellState to hold optinal chest key instead of chest object Client only needs to know if the chest is locked and that it is a chest - server handles spawn info --- .../Domain/Character/WalkValidationActions.cs | 1 + EOLib/Domain/Map/Chest.cs | 16 ----- EOLib/Domain/Map/IMapCellState.cs | 2 +- EOLib/Domain/Map/MapCellState.cs | 4 +- EOLib/Domain/Map/MapCellStateProvider.cs | 4 +- EOLib/Domain/Map/UnlockChestValidator.cs | 53 +++++++++++++++ .../Controllers/MapInteractionController.cs | 6 +- EndlessClient/Input/UnwalkableTileActions.cs | 68 +++++++++---------- 8 files changed, 97 insertions(+), 57 deletions(-) delete mode 100644 EOLib/Domain/Map/Chest.cs create mode 100644 EOLib/Domain/Map/UnlockChestValidator.cs diff --git a/EOLib/Domain/Character/WalkValidationActions.cs b/EOLib/Domain/Character/WalkValidationActions.cs index cf578d2a7..2377060f2 100644 --- a/EOLib/Domain/Character/WalkValidationActions.cs +++ b/EOLib/Domain/Character/WalkValidationActions.cs @@ -49,6 +49,7 @@ public bool CanMoveToCoordinates(int gridX, int gridY) var cellState = _mapCellStateProvider.GetCellStateAt(gridX, gridY); return IsCellStateWalkable(cellState); } + public bool IsCellStateWalkable(IMapCellState cellState) { var mc = _characterProvider.MainCharacter; diff --git a/EOLib/Domain/Map/Chest.cs b/EOLib/Domain/Map/Chest.cs deleted file mode 100644 index 6c3387c0b..000000000 --- a/EOLib/Domain/Map/Chest.cs +++ /dev/null @@ -1,16 +0,0 @@ -using EOLib.IO.Map; - -namespace EOLib.Domain.Map -{ - public class Chest : IChest - { - public Chest(ChestSpawnMapEntity chest) - { - } - } - - public interface IChest - { - //todo: figure out properties - } -} diff --git a/EOLib/Domain/Map/IMapCellState.cs b/EOLib/Domain/Map/IMapCellState.cs index cc7213da0..c481aef79 100644 --- a/EOLib/Domain/Map/IMapCellState.cs +++ b/EOLib/Domain/Map/IMapCellState.cs @@ -20,7 +20,7 @@ public interface IMapCellState Option Character { get; } - Option Chest { get; } + Option ChestKey { get; } Option Warp { get; } diff --git a/EOLib/Domain/Map/MapCellState.cs b/EOLib/Domain/Map/MapCellState.cs index 0497ca305..f7ef88fbb 100644 --- a/EOLib/Domain/Map/MapCellState.cs +++ b/EOLib/Domain/Map/MapCellState.cs @@ -20,7 +20,7 @@ public class MapCellState : IMapCellState public Option Character { get; set; } - public Option Chest { get; set; } + public Option ChestKey { get; set; } public Option Warp { get; set; } @@ -33,7 +33,7 @@ public MapCellState() TileSpec = TileSpec.None; NPC = Option.None(); Character = Option.None(); - Chest = Option.None(); + ChestKey = Option.None(); Warp = Option.None(); Sign = Option.None(); } diff --git a/EOLib/Domain/Map/MapCellStateProvider.cs b/EOLib/Domain/Map/MapCellStateProvider.cs index d0c7ca885..c533e7bc5 100644 --- a/EOLib/Domain/Map/MapCellStateProvider.cs +++ b/EOLib/Domain/Map/MapCellStateProvider.cs @@ -33,7 +33,7 @@ public IMapCellState GetCellStateAt(int x, int y) var tileSpec = CurrentMap.Tiles[y, x]; var warp = CurrentMap.Warps[y, x]; - var chest = CurrentMap.Chests.FirstOrDefault(c => c.X == x && c.Y == y); + var chest = CurrentMap.Chests.Where(c => c.X == x && c.Y == y && c.Key != ChestKey.None).Select(c => c.Key).FirstOrDefault(); var sign = CurrentMap.Signs.FirstOrDefault(s => s.X == x && s.Y == y); var character = _mapStateProvider.Characters.Values.Concat(new[] { _characterProvider.MainCharacter }) @@ -48,7 +48,7 @@ public IMapCellState GetCellStateAt(int x, int y) Items = items.ToList(), TileSpec = tileSpec, Warp = warp.SomeNotNull().Map(w => new Warp(w)), - Chest = chest.SomeNotNull().Map(c => new Chest(c)), + ChestKey = chest.SomeNotNull(), Sign = sign.SomeNotNull().Map(s => new Sign(s)), Character = character, NPC = npc diff --git a/EOLib/Domain/Map/UnlockChestValidator.cs b/EOLib/Domain/Map/UnlockChestValidator.cs new file mode 100644 index 000000000..576063406 --- /dev/null +++ b/EOLib/Domain/Map/UnlockChestValidator.cs @@ -0,0 +1,53 @@ +using System.Linq; +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.IO.Map; +using EOLib.IO.Repositories; +using Optional; + +namespace EOLib.Domain.Map +{ + [AutoMappedType] + public class UnlockChestValidator : IUnlockChestValidator + { + private readonly ICharacterInventoryProvider _characterInventoryProvider; + private readonly IEIFFileProvider _eifFileProvider; + + public UnlockChestValidator(ICharacterInventoryProvider characterInventoryProvider, + IEIFFileProvider eifFileProvider) + { + _characterInventoryProvider = characterInventoryProvider; + _eifFileProvider = eifFileProvider; + } + + public bool CanMainCharacterOpenChest(ChestKey requiredKey) + { + return GetRequiredKeyName(requiredKey).Match( + some: keyName => _characterInventoryProvider + .ItemInventory + .Where(x => _eifFileProvider.EIFFile[x.ItemID].Type == IO.ItemType.Key) + .Select(x => _eifFileProvider.EIFFile[x.ItemID].Name) + .Any(keyName.Equals), + none: () => true); + } + + public Option GetRequiredKeyName(ChestKey requiredKey) + { + switch (requiredKey) + { + case ChestKey.Normal: return Option.Some("Normal Key"); + case ChestKey.Silver: return Option.Some("Silver Key"); + case ChestKey.Crystal: return Option.Some("Crystal Key"); + case ChestKey.Wraith: return Option.Some("Wraith Key"); + default: return Option.None(); + } + } + } + + public interface IUnlockChestValidator + { + bool CanMainCharacterOpenChest(ChestKey requiredKey); + + Option GetRequiredKeyName(ChestKey requiredKey); + } +} diff --git a/EndlessClient/Controllers/MapInteractionController.cs b/EndlessClient/Controllers/MapInteractionController.cs index 54ffa556a..6ec8f1cc9 100644 --- a/EndlessClient/Controllers/MapInteractionController.cs +++ b/EndlessClient/Controllers/MapInteractionController.cs @@ -14,6 +14,7 @@ using EOLib.Domain.Interact; using EOLib.Domain.Item; using EOLib.Domain.Map; +using EOLib.IO.Map; using EOLib.Localization; using Optional; using Optional.Collections; @@ -92,7 +93,10 @@ public void LeftClick(IMapCellState cellState, IMouseCursorRenderer mouseRendere var messageBox = _eoMessageBoxFactory.CreateMessageBox(sign.Message, sign.Title); messageBox.ShowDialog(); } - else if (cellState.Chest.HasValue) { /* TODO: chest interaction */ } + else if (cellState.TileSpec == TileSpec.Chest) + { + // todo: chest request, show dialog + } else if (_characterProvider.MainCharacter.RenderProperties.SitState != SitState.Standing) { _characterActions.ToggleSit(); diff --git a/EndlessClient/Input/UnwalkableTileActions.cs b/EndlessClient/Input/UnwalkableTileActions.cs index a5a3faf30..b497bf276 100644 --- a/EndlessClient/Input/UnwalkableTileActions.cs +++ b/EndlessClient/Input/UnwalkableTileActions.cs @@ -1,4 +1,5 @@ using AutomaticTypeMapper; +using EndlessClient.Dialogs; using EndlessClient.Dialogs.Factories; using EndlessClient.HUD; using EOLib.Domain.Character; @@ -20,24 +21,30 @@ public class UnwalkableTileActions : IUnwalkableTileActions private readonly IStatusLabelSetter _statusLabelSetter; private readonly ICurrentMapStateRepository _currentMapStateRepository; private readonly IUnlockDoorValidator _unlockDoorValidator; + private readonly IUnlockChestValidator _unlockChestValidator; private readonly IEOMessageBoxFactory _eoMessageBoxFactory; private readonly IPacketSendService _packetSendService; + private readonly IEOMessageBoxFactory _messageBoxFactory; public UnwalkableTileActions(IMapCellStateProvider mapCellStateProvider, - ICharacterProvider characterProvider, - IStatusLabelSetter statusLabelSetter, - ICurrentMapStateRepository currentMapStateRepository, - IUnlockDoorValidator unlockDoorValidator, - IEOMessageBoxFactory eoMessageBoxFactory, - IPacketSendService packetSendService) + ICharacterProvider characterProvider, + IStatusLabelSetter statusLabelSetter, + ICurrentMapStateRepository currentMapStateRepository, + IUnlockDoorValidator unlockDoorValidator, + IUnlockChestValidator unlockChestValidator, + IEOMessageBoxFactory eoMessageBoxFactory, + IPacketSendService packetSendService, + IEOMessageBoxFactory messageBoxFactory) { _mapCellStateProvider = mapCellStateProvider; _characterProvider = characterProvider; _statusLabelSetter = statusLabelSetter; _currentMapStateRepository = currentMapStateRepository; _unlockDoorValidator = unlockDoorValidator; + _unlockChestValidator = unlockChestValidator; _eoMessageBoxFactory = eoMessageBoxFactory; _packetSendService = packetSendService; + _messageBoxFactory = messageBoxFactory; } public void HandleUnwalkableTile() @@ -116,36 +123,27 @@ private void HandleWalkToTileSpec(IMapCellState cellState) case TileSpec.ChairAll: HandleWalkToChair(); break; - case TileSpec.Chest: //todo: chests - //if (!walkValid) - //{ - // var chest = OldWorld.Instance.ActiveMapRenderer.MapRef.Chests.Single(_c => _c.X == destX && _c.Y == destY); - // if (chest != null) - // { - // string requiredKey = null; - // switch (Character.CanOpenChest(chest)) - // { - // case ChestKey.Normal: requiredKey = "Normal Key"; break; - // case ChestKey.Silver: requiredKey = "Silver Key"; break; - // case ChestKey.Crystal: requiredKey = "Crystal Key"; break; - // case ChestKey.Wraith: requiredKey = "Wraith Key"; break; - // default: - // ChestDialog.Show(((EOGame)Game).API, (byte)chest.X, (byte)chest.Y); - // break; - // } + case TileSpec.Chest: + cellState.ChestKey.Match( + some: key => + { + if (!_unlockChestValidator.CanMainCharacterOpenChest(key)) + { + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.CHEST_LOCKED); + dlg.ShowDialog(); - // if (requiredKey != null) - // { - // EOMessageBox.Show(DialogResourceID.CHEST_LOCKED, XNADialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_THE_CHEST_IS_LOCKED_EXCLAMATION, - // " - " + requiredKey); - // } - // } - // else - // { - // ChestDialog.Show(((EOGame)Game).API, destX, destY); - // } - //} + var requiredKey = _unlockChestValidator.GetRequiredKeyName(key); + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_THE_CHEST_IS_LOCKED_EXCLAMATION, " - " + requiredKey); + } + else + { + // todo: chest request, show dialog + } + }, + none: () => + { + // todo: chest request, show dialog + }); break; case TileSpec.BankVault: //todo: locker //walkValid = Renderer.NoWall;