diff --git a/EOLib.Localization/EOResourceID.cs b/EOLib.Localization/EOResourceID.cs index 9a840a464..2eb7e9a70 100644 --- a/EOLib.Localization/EOResourceID.cs +++ b/EOLib.Localization/EOResourceID.cs @@ -152,8 +152,13 @@ public enum EOResourceID DIALOG_SHOP_CRAFT_MISSING_INGREDIENTS = 158, DIALOG_SHOP_CRAFT_PUT_INGREDIENTS_TOGETHER = 159, + DIALOG_BARBER_CHANGE_MODAL = 160, + DIALOG_BARBER_CHANGE_HAIR_COLOR = 161, + DIALOG_BARBER_BUY_HAIRSTYLE = 162, DIALOG_WORD_CURRENT = 163, - + DIALOG_BARBER_DO_YOU_WANT_TO_BUY_A_NEW_HAIRSTYLE = 164, + + DIALOG_TRADE_BOTH_PLAYERS_OFFER_ONE_ITEM = 165, DIALOG_TRANSFER_TRANSFER = 176, @@ -342,6 +347,6 @@ public enum EOResourceID STATUS_LABEL_IS_ONLINE_NOT_FOUND = 430, DIALOG_BANK_LOCKER_UPGRADE = 431, DIALOG_BANK_MORE_SPACE = 432, - STATUS_LABEL_LOCKER_SPACE_INCREASED = 433 + STATUS_LABEL_LOCKER_SPACE_INCREASED = 433, } } diff --git a/EOLib/Domain/Interact/Barber/BarberActions.cs b/EOLib/Domain/Interact/Barber/BarberActions.cs new file mode 100644 index 000000000..ac7415a3d --- /dev/null +++ b/EOLib/Domain/Interact/Barber/BarberActions.cs @@ -0,0 +1,37 @@ +using AutomaticTypeMapper; +using EOLib.Net; +using EOLib.Net.Communication; +using System.Diagnostics; +using EOLib.Domain.Character; +namespace EOLib.Domain.Interact.Barber +{ + [AutoMappedType] + public class BarberActions : IBarberActions + { + private readonly IPacketSendService _packetSendService; + private readonly IBarberDataRepository _barberDataRepository; + + public BarberActions(IPacketSendService packetSendService, + IBarberDataRepository barberDataRepository) + { + _packetSendService = packetSendService; + _barberDataRepository = barberDataRepository; + } + + public void Purchase(int hairStyle, int hairColor) + { + var packet = new PacketBuilder(PacketFamily.Barber, PacketAction.Buy) + .AddChar((char)hairStyle) + .AddChar((char)hairColor) + .AddInt(_barberDataRepository.SessionID) + .Build(); + + _packetSendService.SendPacket(packet); + } + } + + public interface IBarberActions + { + void Purchase(int hairStyle, int hairColor); + } +} \ No newline at end of file diff --git a/EOLib/Domain/Interact/Barber/BarberDataRepository.cs b/EOLib/Domain/Interact/Barber/BarberDataRepository.cs new file mode 100644 index 000000000..d88e0a335 --- /dev/null +++ b/EOLib/Domain/Interact/Barber/BarberDataRepository.cs @@ -0,0 +1,30 @@ +using AutomaticTypeMapper; + +namespace EOLib.Domain.Interact.Barber +{ + public interface IBarberDataRepository : IResettable + { + int SessionID { get; set; } + } + + public interface IBarberDataProvider : IResettable + { + int SessionID { get; } + } + + [AutoMappedType(IsSingleton = true)] + public class BarberDataRepository : IBarberDataRepository, IBarberDataProvider + { + public int SessionID { get; set; } + + public BarberDataRepository() + { + ResetState(); + } + + public void ResetState() + { + SessionID = 0; + } + } +} diff --git a/EOLib/Domain/Interact/MapNPCActions.cs b/EOLib/Domain/Interact/MapNPCActions.cs index f8749d39c..64971f16a 100644 --- a/EOLib/Domain/Interact/MapNPCActions.cs +++ b/EOLib/Domain/Interact/MapNPCActions.cs @@ -90,22 +90,27 @@ public void RequestPriest(NPC.NPC npc) _packetSendService.SendPacket(packet); } + + public void RequestBarber(NPC.NPC npc) + { + var packet = new PacketBuilder(PacketFamily.Barber, PacketAction.Open) + .AddInt(npc.Index) + .Build(); + + _packetSendService.SendPacket(packet); + } } public interface IMapNPCActions { void RequestShop(NPC.NPC npc); - void RequestQuest(NPC.NPC npc); - void RequestBank(NPC.NPC npc); - void RequestSkillmaster(NPC.NPC npc); - void RequestInnkeeper(NPC.NPC npc); - void RequestLaw(NPC.NPC npc); - void RequestPriest(NPC.NPC npc); + void RequestBarber(NPC.NPC npc); // Corrected here } + } diff --git a/EOLib/PacketHandlers/Barber/BarberAgreeHandler.cs b/EOLib/PacketHandlers/Barber/BarberAgreeHandler.cs new file mode 100644 index 000000000..087ec4e0a --- /dev/null +++ b/EOLib/PacketHandlers/Barber/BarberAgreeHandler.cs @@ -0,0 +1,97 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Interact; +using EOLib.Net; +using EOLib.Net.Handlers; +using System.Collections.Generic; +using EOLib.Domain.Interact.Barber; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Map; +using EOLib.Domain.Notifiers; + +namespace EOLib.PacketHandlers.Barber +{ + [AutoMappedType] + public class BarberAgreeHandler : InGameOnlyPacketHandler + { + private readonly IBarberDataRepository _barberDataRepository; + private readonly IEnumerable _npcInteractionNotifiers; + private readonly ICharacterRepository _characterRepository; + private readonly ICurrentMapStateRepository _currentMapStateRepository; + private readonly ICharacterInventoryRepository _characterInventoryRepository; + + public override PacketFamily Family => PacketFamily.Barber; + public override PacketAction Action => PacketAction.Agree; + + public BarberAgreeHandler( + IPlayerInfoProvider playerInfoProvider, + IEnumerable npcInteractionNotifiers, + IBarberDataRepository barberDataRepository, + ICharacterRepository characterRepository, + ICurrentMapStateRepository currentMapStateRepository, + ICharacterInventoryRepository characterInventoryRepository) + : base(playerInfoProvider) + { + _npcInteractionNotifiers = npcInteractionNotifiers; + _barberDataRepository = barberDataRepository; + _characterRepository = characterRepository; + _currentMapStateRepository = currentMapStateRepository; + _characterInventoryRepository = characterInventoryRepository; + } + + public override bool HandlePacket(IPacket packet) + { + var amount = packet.ReadInt(); + var gold = new InventoryItem(1, amount); + var playerID = packet.ReadShort(); + + _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == 1); + _characterInventoryRepository.ItemInventory.Add(gold); + + var currentCharacter = _characterRepository.MainCharacter.ID == playerID + ? _characterRepository.MainCharacter + : null; + + if (currentCharacter == null) + { + return false; + } + + var currentRenderProps = currentCharacter.RenderProperties; + var slot = (AvatarSlot)packet.ReadChar(); + + switch (slot) + { + case AvatarSlot.Hair: + if (packet.ReadChar() != 0) + throw new MalformedPacketException("Missing expected 0 byte in updating hair packet", packet); + + currentRenderProps = currentRenderProps + .WithHairStyle(packet.ReadChar()) + .WithHairColor(packet.ReadChar()); + break; + + case AvatarSlot.HairColor: + if (packet.ReadChar() != 0) + throw new MalformedPacketException("Missing expected 0 byte in updating hair color packet", packet); + + currentRenderProps = currentRenderProps + .WithHairColor(packet.ReadChar()); + break; + } + + var updatedCharacter = currentCharacter.WithRenderProperties(currentRenderProps); + + if (_characterRepository.MainCharacter.ID == playerID) + { + _characterRepository.MainCharacter = updatedCharacter; + } + else + { + _currentMapStateRepository.Characters.Update(currentCharacter, updatedCharacter); + } + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Barber/BarberOpenHandler.cs b/EOLib/PacketHandlers/Barber/BarberOpenHandler.cs new file mode 100644 index 000000000..70cbba4f3 --- /dev/null +++ b/EOLib/PacketHandlers/Barber/BarberOpenHandler.cs @@ -0,0 +1,44 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Interact; +using EOLib.Net; +using EOLib.Net.Handlers; +using System.Collections.Generic; +using EOLib.Domain.Interact.Barber; +using EOLib.Domain.Character; +using EOLib.Domain.Login; + +namespace EOLib.PacketHandlers.Barber +{ + [AutoMappedType] + public class BarberOpenHandler : InGameOnlyPacketHandler + { + private readonly IBarberDataRepository _barberDataRepository; + private readonly IEnumerable _npcInteractionNotifiers; + + public override PacketFamily Family => PacketFamily.Barber; + public override PacketAction Action => PacketAction.Open; + + public BarberOpenHandler( + IPlayerInfoProvider playerInfoProvider, + IEnumerable npcInteractionNotifiers, + IBarberDataRepository barberDataRepository) + : base(playerInfoProvider) + { + _npcInteractionNotifiers = npcInteractionNotifiers; + _barberDataRepository = barberDataRepository; + } + + public override bool HandlePacket(IPacket packet) + { + var sessionId = packet.ReadInt(); + _barberDataRepository.SessionID = sessionId; + + foreach (var notifier in _npcInteractionNotifiers) + { + notifier.NotifyInteractionFromNPC(IO.NPCType.Barber); + } + + return true; + } + } +} diff --git a/EndlessClient/Controllers/NPCInteractionController.cs b/EndlessClient/Controllers/NPCInteractionController.cs index 34f86eb74..2731d4d04 100644 --- a/EndlessClient/Controllers/NPCInteractionController.cs +++ b/EndlessClient/Controllers/NPCInteractionController.cs @@ -70,6 +70,9 @@ public void ShowNPCDialog(NPC npc) case EOLib.IO.NPCType.Priest: _mapNpcActions.RequestPriest(npc); break; + case EOLib.IO.NPCType.Barber: + _mapNpcActions.RequestBarber(npc); + break; } } } diff --git a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs index ed3a8ae48..765fa3da4 100644 --- a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs @@ -44,6 +44,7 @@ public class InGameDialogActions : IInGameDialogActions private readonly IStatusLabelSetter _statusLabelSetter; private readonly IShopDialogFactory _shopDialogFactory; private readonly IQuestDialogFactory _questDialogFactory; + private readonly IBarberDialogFactory _barberDialogFactory; public InGameDialogActions(IFriendIgnoreListDialogFactory friendIgnoreListDialogFactory, IPaperdollDialogFactory paperdollDialogFactory, @@ -69,7 +70,8 @@ public InGameDialogActions(IFriendIgnoreListDialogFactory friendIgnoreListDialog ILawDialogFactory lawDialogFactory, IHelpDialogFactory helpDialogFactory, ISfxPlayer sfxPlayer, - IStatusLabelSetter statusLabelSetter) + IStatusLabelSetter statusLabelSetter, + IBarberDialogFactory barberDialogFactory) { _friendIgnoreListDialogFactory = friendIgnoreListDialogFactory; _paperdollDialogFactory = paperdollDialogFactory; @@ -96,6 +98,7 @@ public InGameDialogActions(IFriendIgnoreListDialogFactory friendIgnoreListDialog _statusLabelSetter = statusLabelSetter; _shopDialogFactory = shopDialogFactory; _questDialogFactory = questDialogFactory; + _barberDialogFactory = barberDialogFactory; } public void ShowFriendListDialog() @@ -449,6 +452,23 @@ public void ShowHelpDialog() UseDefaultDialogSounds(dlg); }); } + + public void ShowBarberDialog() + { + _activeDialogRepository.BarberDialog.MatchNone(() => + { + var dlg = _barberDialogFactory.Create(); + dlg.DialogClosed += (_, _) => + { + _activeDialogRepository.BarberDialog = Option.None(); + }; + _activeDialogRepository.BarberDialog = Option.Some(dlg); + + UseDefaultDialogSounds(dlg); + + dlg.Show(); + }); + } private void UseDefaultDialogSounds(ScrollingListDialog dialog) { @@ -522,5 +542,7 @@ public interface IInGameDialogActions void ShowLawDialog(); void ShowHelpDialog(); + + void ShowBarberDialog(); } } diff --git a/EndlessClient/Dialogs/Actions/NpcInteractionActions.cs b/EndlessClient/Dialogs/Actions/NpcInteractionActions.cs index 3c683d8cf..f110ec531 100644 --- a/EndlessClient/Dialogs/Actions/NpcInteractionActions.cs +++ b/EndlessClient/Dialogs/Actions/NpcInteractionActions.cs @@ -12,6 +12,7 @@ using System; using XNAControls; + namespace EndlessClient.Dialogs.Actions { [AutoMappedType] @@ -58,6 +59,7 @@ public void NotifyInteractionFromNPC(NPCType npcType) case NPCType.Skills: _inGameDialogActions.ShowSkillmasterDialog(); break; case NPCType.Inn: _inGameDialogActions.ShowInnkeeperDialog(); break; case NPCType.Law: _inGameDialogActions.ShowLawDialog(); break; + case NPCType.Barber: _inGameDialogActions.ShowBarberDialog(); break; case NPCType.Priest: ShowPriestDialog(); break; } } diff --git a/EndlessClient/Dialogs/ActiveDialogRepository.cs b/EndlessClient/Dialogs/ActiveDialogRepository.cs index b2e298b02..d0764cd7d 100644 --- a/EndlessClient/Dialogs/ActiveDialogRepository.cs +++ b/EndlessClient/Dialogs/ActiveDialogRepository.cs @@ -47,6 +47,8 @@ public interface IActiveDialogProvider : IDisposable Option LawDialog { get; } + Option BarberDialog { get; } + Option HelpDialog { get; } IReadOnlyList> ActiveDialogs { get; } @@ -92,6 +94,8 @@ public interface IActiveDialogRepository : IDisposable Option LawDialog { get; set; } + Option BarberDialog { get; set; } + Option HelpDialog { get; set; } IReadOnlyList> ActiveDialogs { get; } @@ -138,6 +142,8 @@ public class ActiveDialogRepository : IActiveDialogRepository, IActiveDialogProv public Option LawDialog { get; set; } + public Option BarberDialog { get; set; } + public Option HelpDialog { get; set; } IReadOnlyList> ActiveDialogs @@ -165,6 +171,7 @@ IReadOnlyList> ActiveDialogs JukeboxDialog.Map(Map), InnkeeperDialog.Map(Map), LawDialog.Map(Map), + BarberDialog.Map(Map), HelpDialog.Map(Map), }.ToList(); @@ -203,6 +210,7 @@ public void Dispose() JukeboxDialog = Option.None(); InnkeeperDialog = Option.None(); LawDialog = Option.None(); + BarberDialog = Option.None(); HelpDialog = Option.None(); } } diff --git a/EndlessClient/Dialogs/BarberDialog.cs b/EndlessClient/Dialogs/BarberDialog.cs new file mode 100644 index 000000000..d29a13c52 --- /dev/null +++ b/EndlessClient/Dialogs/BarberDialog.cs @@ -0,0 +1,197 @@ +using System; +using EndlessClient.Dialogs.Services; +using EOLib.Graphics; +using EndlessClient.UIControls; +using EndlessClient.Rendering.Factories; +using Microsoft.Xna.Framework; +using XNAControls; +using EOLib.Domain.Character; +using EOLib.Localization; +using EOLib.Domain.Interact.Barber; +using EndlessClient.Dialogs.Factories; +using Optional.Collections; +using EOLib.IO.Repositories; +using EndlessClient.Audio; + +namespace EndlessClient.Dialogs +{ + public class BarberDialog : BaseEODialog + { + private const int AdjustedWidth = 175; + private const int AdjustedHighlightXOffset = 3; + private readonly string[] _hairColorNames = { "brown", "green", "pink", "red", "blonde", "blue", "purple", "luna", "white", "black" }; + private readonly CreateCharacterControl _characterControl; + private readonly ICharacterRepository _characterRepository; + private readonly IEODialogIconService _dialogIconService; + private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly IBarberActions _barberActions; + private readonly ICharacterInventoryProvider _characterInventoryProvider; + private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly IEIFFileProvider _eifFileProvider; + private readonly ISfxPlayer _sfxPlayer; + + private CharacterRenderProperties RenderProperties => _characterControl.RenderProperties; + private ListDialogItem _changeHairItem, _changeHairColor, _changeBuyHairStyleOrColor; + + public BarberDialog(INativeGraphicsManager nativeGraphicsManager, + ICharacterRendererFactory rendererFactory, + IEODialogButtonService dialogButtonService, + ICharacterRepository characterLvRepository, + IEODialogIconService dialogIconService, + ILocalizedStringFinder localizedStringFinder, + IBarberActions barberActions, + ICharacterInventoryProvider characterInventoryProvider, + IEOMessageBoxFactory messageBoxFactory, + IEIFFileProvider eifFileProvider, + ISfxPlayer sfxPlayer) + : base(nativeGraphicsManager, isInGame: true) + { + _characterRepository = characterLvRepository; + _dialogIconService = dialogIconService; + _localizedStringFinder = localizedStringFinder; + _barberActions = barberActions; + _characterInventoryProvider = characterInventoryProvider; + _messageBoxFactory = messageBoxFactory; + _eifFileProvider = eifFileProvider; + _sfxPlayer = sfxPlayer; + + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 56); + + var mainCharacterRenderProperties = _characterRepository.MainCharacter.RenderProperties; + _characterControl = new CreateCharacterControl(mainCharacterRenderProperties, rendererFactory) + { + DrawPosition = new Vector2(210, 19), + }; + + InitializeCharacterControl(); + InitializeDialogItems(dialogButtonService); + CenterInGameView(); + } + + private void InitializeCharacterControl() + { + _characterControl.SetParentControl(this); + } + + private void InitializeDialogItems(IEODialogButtonService dialogButtonService) + { + var cancel = CreateButton(dialogButtonService, new Vector2(215, 151), SmallButton.Cancel); + cancel.OnClick += (_, _) => Close(XNADialogResult.Cancel); + + _changeHairItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 0) + { + IconGraphic = _dialogIconService.IconSheet, + IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.BarberHairModel), + ShowIconBackGround = false, + OffsetX = AdjustedHighlightXOffset, + }; + _changeHairItem.DrawArea = _changeHairItem.DrawArea.WithSize(AdjustedWidth, _changeHairItem.DrawArea.Size.Y); + _changeHairItem.LeftClick += ChangeHairStyle_Click; + + _changeHairColor = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 1) + { + IconGraphic = _dialogIconService.IconSheet, + IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.BarberChangeHairColor), + ShowIconBackGround = false, + OffsetX = AdjustedHighlightXOffset, + }; + _changeHairColor.DrawArea = _changeHairColor.DrawArea.WithSize(AdjustedWidth, _changeHairColor.DrawArea.Size.Y); + _changeHairColor.LeftClick += ChangeHairColor_Click; + + _changeBuyHairStyleOrColor = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 2) + { + IconGraphic = _dialogIconService.IconSheet, + IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.BarberOk), + ShowIconBackGround = false, + OffsetX = AdjustedHighlightXOffset, + }; + _changeBuyHairStyleOrColor.DrawArea = _changeBuyHairStyleOrColor.DrawArea.WithSize(AdjustedWidth, _changeBuyHairStyleOrColor.DrawArea.Size.Y); + _changeBuyHairStyleOrColor.LeftClick += BuyHair_Click; + } + + public override void Initialize() + { + base.Initialize(); + _characterControl.Initialize(); + UpdateListItems(_characterRepository.MainCharacter.RenderProperties); + } + + private void UpdateListItems(CharacterRenderProperties currentProperties) + { + _changeHairItem.PrimaryText = _localizedStringFinder.GetString(EOResourceID.DIALOG_BARBER_CHANGE_MODAL); + _changeHairItem.SubText = GetCurrentHairStyleText(currentProperties.HairStyle); + + _changeHairColor.PrimaryText = _localizedStringFinder.GetString(EOResourceID.DIALOG_BARBER_CHANGE_HAIR_COLOR); + _changeHairColor.SubText = GetCurrentHairColorText(currentProperties.HairColor); + + _changeBuyHairStyleOrColor.PrimaryText = _localizedStringFinder.GetString(EOResourceID.DIALOG_BARBER_BUY_HAIRSTYLE); + _changeBuyHairStyleOrColor.SubText = GetCostText(); + } + + private string GetCurrentHairStyleText(int hairStyle) => $"{_localizedStringFinder.GetString(EOResourceID.DIALOG_WORD_CURRENT)}: {hairStyle}"; + private string GetCurrentHairColorText(int hairColor) => $"{_localizedStringFinder.GetString(EOResourceID.DIALOG_WORD_CURRENT)}: {_hairColorNames[hairColor % _hairColorNames.Length]}"; + private string GetCostText() => $"{_localizedStringFinder.GetString(EOResourceID.DIALOG_WORD_CURRENT)}: {CalculateCost()} gold"; + + private int CalculateCost() + { + var level = (int)_characterRepository.MainCharacter.Stats[CharacterStat.Level]; + return 200 + Math.Max(level - 1, 0) * 200; + } + + private void ChangeHairStyle_Click(object sender, MonoGame.Extended.Input.InputListeners.MouseEventArgs e) + { + _characterControl.NextHairStyle(); + _changeHairItem.SubText = GetCurrentHairStyleText(_characterControl.RenderProperties.HairStyle); + } + + private void ChangeHairColor_Click(object sender, MonoGame.Extended.Input.InputListeners.MouseEventArgs e) + { + _characterControl.NextHairColor(); + _changeHairColor.SubText = GetCurrentHairColorText(_characterControl.RenderProperties.HairColor); + } + + private void BuyHair_Click(object sender, MonoGame.Extended.Input.InputListeners.MouseEventArgs e) + { + int hairStyle = _characterControl.RenderProperties.HairStyle; + int hairColor = _characterControl.RenderProperties.HairColor; + + int totalCost = CalculateCost(); + int currentGold = _characterInventoryProvider.ItemInventory.SingleOrNone(i => i.ItemID == 1) + .Map(i => i.Amount) + .ValueOr(0); + + if (currentGold >= totalCost) + { + var message = $"{_localizedStringFinder.GetString(EOResourceID.DIALOG_BARBER_DO_YOU_WANT_TO_BUY_A_NEW_HAIRSTYLE)}, {totalCost} {_eifFileProvider.EIFFile[1].Name}"; + var title = _localizedStringFinder.GetString(EOResourceID.DIALOG_BARBER_BUY_HAIRSTYLE); + var msgBox = _messageBoxFactory.CreateMessageBox(message, title, EODialogButtons.OkCancel); + + msgBox.DialogClosing += (_, e) => + { + if (e.Result == XNADialogResult.OK) + { + _barberActions.Purchase(hairStyle, hairColor); + _sfxPlayer.PlaySfx(SoundEffectID.BuySell); + } + }; + + msgBox.ShowDialog(); + } + else + { + var msgBox = _messageBoxFactory.CreateMessageBox(DialogResourceID.WARNING_YOU_HAVE_NOT_ENOUGH, $" {_eifFileProvider.EIFFile[1].Name}"); + msgBox.ShowDialog(); + } + } + + private XNAButton CreateButton(IEODialogButtonService dialogButtonService, Vector2 position, SmallButton buttonType) + { + var button = new XNAButton(dialogButtonService.SmallButtonSheet, position, + dialogButtonService.GetSmallDialogButtonOutSource(buttonType), + dialogButtonService.GetSmallDialogButtonOverSource(buttonType)); + button.Initialize(); + button.SetParentControl(this); + return button; + } + } +} diff --git a/EndlessClient/Dialogs/Factories/BarberDialogFactory.cs b/EndlessClient/Dialogs/Factories/BarberDialogFactory.cs new file mode 100644 index 000000000..a446b06d7 --- /dev/null +++ b/EndlessClient/Dialogs/Factories/BarberDialogFactory.cs @@ -0,0 +1,78 @@ +using AutomaticTypeMapper; +using EndlessClient.Controllers; +using EndlessClient.Dialogs.Services; +using EndlessClient.Rendering.Character; +using EOLib.Graphics; +using EndlessClient.Content; +using EndlessClient.Rendering.Factories; +using EOLib.Domain.Character; +using EOLib.Localization; +using EOLib.Domain.Interact.Barber; +using EOLib.IO.Repositories; +using EOLib.Domain.Notifiers; +using System.Collections.Generic; +using EndlessClient.Audio; + +namespace EndlessClient.Dialogs.Factories +{ + [AutoMappedType] + public class BarberDialogFactory : IBarberDialogFactory + { + private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly ICharacterRendererFactory _characterRendererFactory; + private readonly IEODialogButtonService _dialogButtonService; + private readonly ICharacterRepository _characterRepository; + private readonly IEODialogIconService _dialogIconService; + private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly IBarberActions _barberActions; + private readonly ICharacterInventoryProvider _characterInventoryProvider; + private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly IEIFFileProvider _eifFileProvider; + private readonly ISfxPlayer _sfxPlayer; + + public BarberDialogFactory(INativeGraphicsManager nativeGraphicsManager, + ICharacterRendererFactory characterRendererFactory, + IEODialogButtonService dialogButtonService, + ICharacterRepository characterRepository, + IEODialogIconService dialogIconService, + ILocalizedStringFinder localizedStringFinder, + IBarberActions barberActions, + ICharacterInventoryProvider characterInventoryProvider, + IEOMessageBoxFactory messageBoxFactory, + IEIFFileProvider eifFileProvider, + ISfxPlayer sfxPlayer) + { + _nativeGraphicsManager = nativeGraphicsManager; + _characterRendererFactory = characterRendererFactory; + _dialogButtonService = dialogButtonService; + _characterRepository = characterRepository; + _dialogIconService = dialogIconService; + _localizedStringFinder = localizedStringFinder; + _barberActions = barberActions; + _characterInventoryProvider = characterInventoryProvider; + _messageBoxFactory = messageBoxFactory; + _eifFileProvider = eifFileProvider; + _sfxPlayer = sfxPlayer; + } + + public BarberDialog Create() + { + return new BarberDialog(_nativeGraphicsManager, + _characterRendererFactory, + _dialogButtonService, + _characterRepository, + _dialogIconService, + _localizedStringFinder, + _barberActions, + _characterInventoryProvider, + _messageBoxFactory, + _eifFileProvider, + _sfxPlayer); + } + } + + public interface IBarberDialogFactory + { + BarberDialog Create(); + } +} \ No newline at end of file diff --git a/EndlessClient/Dialogs/Services/EODialogIconService.cs b/EndlessClient/Dialogs/Services/EODialogIconService.cs index 9466aebcc..f5a1072bb 100644 --- a/EndlessClient/Dialogs/Services/EODialogIconService.cs +++ b/EndlessClient/Dialogs/Services/EODialogIconService.cs @@ -15,6 +15,10 @@ public enum DialogIcon Craft, BankLockerUpgrade, + BarberHairModel = 6, + BarberChangeHairColor = 7, + BarberOk = 8, + JukeboxPlay = 8, Registration = 9, diff --git a/EndlessClient/Rendering/Character/CharacterRenderer.cs b/EndlessClient/Rendering/Character/CharacterRenderer.cs index 897d7f222..807918a9e 100644 --- a/EndlessClient/Rendering/Character/CharacterRenderer.cs +++ b/EndlessClient/Rendering/Character/CharacterRenderer.cs @@ -35,7 +35,6 @@ public class CharacterRenderer : DrawableGameComponent, ICharacterRenderer private readonly IRenderOffsetCalculator _renderOffsetCalculator; private readonly ICharacterPropertyRendererBuilder _characterPropertyRendererBuilder; private readonly ICharacterTextures _characterTextures; - private readonly IGameStateProvider _gameStateProvider; private readonly ICurrentMapProvider _currentMapProvider; private readonly IUserInputProvider _userInputProvider; private readonly IMetadataProvider _hatMetadataProvider; @@ -44,6 +43,8 @@ public class CharacterRenderer : DrawableGameComponent, ICharacterRenderer private readonly IClientWindowSizeRepository _clientWindowSizeRepository; private readonly IEffectRenderer _effectRenderer; + private readonly bool _isUiControl; + private EOLib.Domain.Character.Character _character; private bool _textureUpdateRequired, _positionIsRelative = true; @@ -94,15 +95,15 @@ public CharacterRenderer(Game game, IRenderOffsetCalculator renderOffsetCalculator, ICharacterPropertyRendererBuilder characterPropertyRendererBuilder, ICharacterTextures characterTextures, - EOLib.Domain.Character.Character character, - IGameStateProvider gameStateProvider, ICurrentMapProvider currentMapProvider, IUserInputProvider userInputProvider, IEffectRendererFactory effectRendererFactory, IMetadataProvider hatMetadataProvider, IMetadataProvider weaponMetadataProvider, ISfxPlayer sfxPlayer, - IClientWindowSizeRepository clientWindowSizeRepository) + IClientWindowSizeRepository clientWindowSizeRepository, + EOLib.Domain.Character.Character character, + bool isUiControl) : base(game) { _renderTargetFactory = renderTargetFactory; @@ -112,8 +113,6 @@ public CharacterRenderer(Game game, _renderOffsetCalculator = renderOffsetCalculator; _characterPropertyRendererBuilder = characterPropertyRendererBuilder; _characterTextures = characterTextures; - _character = character; - _gameStateProvider = gameStateProvider; _currentMapProvider = currentMapProvider; _userInputProvider = userInputProvider; _hatMetadataProvider = hatMetadataProvider; @@ -121,6 +120,8 @@ public CharacterRenderer(Game game, _effectRenderer = effectRendererFactory.Create(); _sfxPlayer = sfxPlayer; _clientWindowSizeRepository = clientWindowSizeRepository; + _character = character; + _isUiControl = isUiControl; _chatBubble = new Lazy(() => _chatBubbleFactory.CreateChatBubble(this)); @@ -146,7 +147,7 @@ public override void Initialize() _sb = new SpriteBatch(Game.GraphicsDevice); - if (_gameStateProvider.CurrentState == GameStates.PlayingTheGame) + if (!_isUiControl) { _nameLabel = new BlinkingLabel(Constants.FontSize08pt5) { @@ -202,7 +203,7 @@ public override void Update(GameTime gameTime) _textureUpdateRequired = false; } - if (_gameStateProvider.CurrentState == GameStates.PlayingTheGame) + if (!_isUiControl) { UpdateNameLabel(); @@ -271,7 +272,7 @@ public void DrawToSpriteBatch(SpriteBatch spriteBatch) _effectRenderer.DrawInFrontOfTarget(spriteBatch); - if (_gameStateProvider.CurrentState == GameStates.PlayingTheGame) + if (!_isUiControl) _healthBarRenderer?.DrawToSpriteBatch(spriteBatch); } @@ -299,15 +300,15 @@ private void DrawToRenderTarget() foreach (var renderer in characterPropertyRenderers) renderer.Render(_sb, DrawArea, weaponMetadata); - if (_gameStateProvider.CurrentState == GameStates.None) - { - _sb.Draw(_outline, DrawArea.WithSize(DrawArea.Width, 1), Color.Black); - _sb.Draw(_outline, DrawArea.WithPosition(new Vector2(DrawArea.X + DrawArea.Width, DrawArea.Y)).WithSize(1, DrawArea.Height), Color.Black); - _sb.Draw(_outline, DrawArea.WithPosition(new Vector2(DrawArea.X, DrawArea.Y + DrawArea.Height)).WithSize(DrawArea.Width, 1), Color.Black); - _sb.Draw(_outline, DrawArea.WithSize(1, DrawArea.Height), Color.Black); + //if (_gameStateProvider.CurrentState == GameStates.None) + //{ + // _sb.Draw(_outline, DrawArea.WithSize(DrawArea.Width, 1), Color.Black); + // _sb.Draw(_outline, DrawArea.WithPosition(new Vector2(DrawArea.X + DrawArea.Width, DrawArea.Y)).WithSize(1, DrawArea.Height), Color.Black); + // _sb.Draw(_outline, DrawArea.WithPosition(new Vector2(DrawArea.X, DrawArea.Y + DrawArea.Height)).WithSize(DrawArea.Width, 1), Color.Black); + // _sb.Draw(_outline, DrawArea.WithSize(1, DrawArea.Height), Color.Black); - _sb.Draw(_outline, DrawArea, Color.FromNonPremultiplied(255, 0, 0, 64)); - } + // _sb.Draw(_outline, DrawArea, Color.FromNonPremultiplied(255, 0, 0, 64)); + //} _sb.End(); GraphicsDevice.SetRenderTarget(null); @@ -362,9 +363,7 @@ private int GetMainCharacterOffsetY() private void UpdateNameLabel() { - if (_gameStateProvider.CurrentState != GameStates.PlayingTheGame || - _healthBarRenderer == null || - _nameLabel == null) + if (_isUiControl || _healthBarRenderer == null || _nameLabel == null) return; if (_healthBarRenderer.Visible) @@ -404,7 +403,7 @@ private Vector2 GetNameLabelPosition() private bool GetIsSteppingStone(CharacterRenderProperties renderProps) { - if (_gameStateProvider.CurrentState != GameStates.PlayingTheGame) + if (_isUiControl) return false; return _currentMapProvider.CurrentMap.Tiles[renderProps.MapY, renderProps.MapX] == TileSpec.Jump diff --git a/EndlessClient/Rendering/Character/CharacterRendererUpdater.cs b/EndlessClient/Rendering/Character/CharacterRendererUpdater.cs index 405a077da..219739c6f 100644 --- a/EndlessClient/Rendering/Character/CharacterRendererUpdater.cs +++ b/EndlessClient/Rendering/Character/CharacterRendererUpdater.cs @@ -177,7 +177,7 @@ private void UpdateDeadCharacters() private ICharacterRenderer InitializeRendererForCharacter(EOLib.Domain.Character.Character character) { - var renderer = _characterRendererFactory.CreateCharacterRenderer(character); + var renderer = _characterRendererFactory.CreateCharacterRenderer(character, isUiControl: false); renderer.Initialize(); return renderer; } diff --git a/EndlessClient/Rendering/Factories/CharacterRendererFactory.cs b/EndlessClient/Rendering/Factories/CharacterRendererFactory.cs index 7f99c0ecf..c7ee761b9 100644 --- a/EndlessClient/Rendering/Factories/CharacterRendererFactory.cs +++ b/EndlessClient/Rendering/Factories/CharacterRendererFactory.cs @@ -25,7 +25,6 @@ public class CharacterRendererFactory : ICharacterRendererFactory private readonly IRenderOffsetCalculator _renderOffsetCalculator; private readonly ICharacterPropertyRendererBuilder _characterPropertyRendererBuilder; private readonly ICharacterTextures _characterTextures; - private readonly IGameStateProvider _gameStateProvider; private readonly ICurrentMapProvider _currentMapProvider; private readonly IUserInputProvider _userInputProvider; private readonly IEffectRendererFactory _effectRendererFactory; @@ -42,7 +41,6 @@ public CharacterRendererFactory(IEndlessGameProvider gameProvider, IRenderOffsetCalculator renderOffsetCalculator, ICharacterPropertyRendererBuilder characterPropertyRendererBuilder, ICharacterTextures characterTextures, - IGameStateProvider gameStateProvider, ICurrentMapProvider currentMapProvider, IUserInputProvider userInputProvider, IEffectRendererFactory effectRendererFactory, @@ -59,7 +57,6 @@ public CharacterRendererFactory(IEndlessGameProvider gameProvider, _renderOffsetCalculator = renderOffsetCalculator; _characterPropertyRendererBuilder = characterPropertyRendererBuilder; _characterTextures = characterTextures; - _gameStateProvider = gameStateProvider; _currentMapProvider = currentMapProvider; _userInputProvider = userInputProvider; _effectRendererFactory = effectRendererFactory; @@ -69,7 +66,7 @@ public CharacterRendererFactory(IEndlessGameProvider gameProvider, _clientWindowSizeRepository = clientWindowSizeRepository; } - public ICharacterRenderer CreateCharacterRenderer(EOLib.Domain.Character.Character character) + public ICharacterRenderer CreateCharacterRenderer(EOLib.Domain.Character.Character character, bool isUiControl) { return new CharacterRenderer( (Game) _gameProvider.Game, @@ -80,15 +77,15 @@ public ICharacterRenderer CreateCharacterRenderer(EOLib.Domain.Character.Charact _renderOffsetCalculator, _characterPropertyRendererBuilder, _characterTextures, - character, - _gameStateProvider, _currentMapProvider, _userInputProvider, _effectRendererFactory, _hatMetadataProvider, _weaponMetadataProvider, _sfxPlayer, - _clientWindowSizeRepository); + _clientWindowSizeRepository, + character, + isUiControl); } } } \ No newline at end of file diff --git a/EndlessClient/Rendering/Factories/ICharacterRendererFactory.cs b/EndlessClient/Rendering/Factories/ICharacterRendererFactory.cs index f79dd0852..4ceaec244 100644 --- a/EndlessClient/Rendering/Factories/ICharacterRendererFactory.cs +++ b/EndlessClient/Rendering/Factories/ICharacterRendererFactory.cs @@ -4,6 +4,6 @@ namespace EndlessClient.Rendering.Factories { public interface ICharacterRendererFactory { - ICharacterRenderer CreateCharacterRenderer(EOLib.Domain.Character.Character character); + ICharacterRenderer CreateCharacterRenderer(EOLib.Domain.Character.Character character, bool isUiControl); } } diff --git a/EndlessClient/Test/CharacterStateTest.cs b/EndlessClient/Test/CharacterStateTest.cs index ef96f552d..6e35812ce 100644 --- a/EndlessClient/Test/CharacterStateTest.cs +++ b/EndlessClient/Test/CharacterStateTest.cs @@ -79,7 +79,7 @@ public override void Initialize() foreach (var displayState in _allDisplayStates) { var props = GetRenderPropertiesForState(displayState); - _renderersForDifferentStates.Add(_characterRendererFactory.CreateCharacterRenderer(Character.Default.WithRenderProperties(props))); + _renderersForDifferentStates.Add(_characterRendererFactory.CreateCharacterRenderer(Character.Default.WithRenderProperties(props), isUiControl: false)); _renderersForDifferentStates.OfType().Last().DrawOrder = 10; } diff --git a/EndlessClient/UIControls/CharacterControl.cs b/EndlessClient/UIControls/CharacterControl.cs index 96765a509..11d7c7a0f 100644 --- a/EndlessClient/UIControls/CharacterControl.cs +++ b/EndlessClient/UIControls/CharacterControl.cs @@ -23,7 +23,7 @@ protected set public CharacterControl(Character character, ICharacterRendererFactory characterRendererFactory) { - _characterRenderer = characterRendererFactory.CreateCharacterRenderer(character); + _characterRenderer = characterRendererFactory.CreateCharacterRenderer(character, isUiControl: true); } public override void Initialize() diff --git a/EndlessClient/UIControls/CreateCharacterControl.cs b/EndlessClient/UIControls/CreateCharacterControl.cs index de1f64668..7dfae3d85 100644 --- a/EndlessClient/UIControls/CreateCharacterControl.cs +++ b/EndlessClient/UIControls/CreateCharacterControl.cs @@ -1,21 +1,27 @@ -using EndlessClient.Rendering.Factories; -using EOLib; -using EOLib.Domain.Character; +using System; using Microsoft.Xna.Framework; using MonoGame.Extended.Input.InputListeners; -using System; using XNAControls; +using EndlessClient.Rendering.Factories; +using EOLib; +using EOLib.Domain.Character; namespace EndlessClient.UIControls { public class CreateCharacterControl : CharacterControl { private Vector2 _lastPosition; + public event EventHandler Clicked; + // default properties public CreateCharacterControl(ICharacterRendererFactory characterRendererFactory) - : base(Character.Default.WithRenderProperties(GetDefaultProperties()), characterRendererFactory) + : this(GetDefaultProperties(), characterRendererFactory) { } + + // custom render properties + public CreateCharacterControl(CharacterRenderProperties renderProperties, ICharacterRendererFactory characterRendererFactory) + : base(Character.Default.WithRenderProperties(renderProperties.WithDirection(EODirection.Down)), characterRendererFactory) { SetSize(99, 123); _lastPosition = Vector2.Zero;