diff --git a/EOLib.Localization/DialogResourceID.cs b/EOLib.Localization/DialogResourceID.cs index 0740ebc6f..462a5cf4c 100644 --- a/EOLib.Localization/DialogResourceID.cs +++ b/EOLib.Localization/DialogResourceID.cs @@ -72,8 +72,7 @@ public enum DialogResourceID TRADE_OTHER_PLAYER_TRICK_YOU = 126, GUILD_CREATE_TAG_FIELD_EMPTY = 128, GUILD_CREATE_NAME_FIELD_EMPTY = 130, - GUILD_WRONG_INPUT = 132, - GUILD_CREATE_TAG_TOO_SHORT = 133, + GUILD_CREATE_TAG_TOO_SHORT = 132, GUILD_CREATE_NAME_TOO_SHORT = 134, GUILD_CREATE_NAME_NOT_APPROVED = 136, GUILD_CREATE_NO_CANDIDATES = 138, @@ -86,7 +85,7 @@ public enum DialogResourceID GUILD_INVITATION = 152, GUILD_INVITES_YOU_TO_JOIN = 153, GUILD_TAG_NAME_LETTER_MUST_MATCH = 154, - GUILD_PROMPT_FOR_RECRUITER = 156, + GUILD_JOIN_GUILD = 156, GUILD_PROMPT_LEAVE_GUILD = 158, GUILD_RECRUITER_NOT_FOUND = 160, GUILD_RECRUITER_NOT_HERE = 162, diff --git a/EOLib.Localization/EOResourceID.cs b/EOLib.Localization/EOResourceID.cs index 66fea6a81..992068951 100644 --- a/EOLib.Localization/EOResourceID.cs +++ b/EOLib.Localization/EOResourceID.cs @@ -193,14 +193,26 @@ public enum EOResourceID GUILD_WITHDRAW_FUNDS_FROM_GUILD = 201, GUILD_REMOVE_MEMBER = 202, GUILD_REMOVE_A_MEMBER_FROM_GUILD = 203, - + GUILD_YOU_ARE_ABOUT_TO_JOIN_A_GUILD = 204, GUILD_JOINING_A_GUILD_IS_FREE = 205, GUILD_PLEASE_CONSIDER_CAREFULLY = 207, - GUILD_DESCRIPTION = 219, - + GUILD_CLICK_HERE_TO_JOIN_A_GUILD = 208, + GUILD_YOU_ARE_ABOUT_TO_LEAVE_THE_GUILD = 209, + GUILD_REMEMBER_THAT_AFTER_YOU_HAVE_LEFT_THE_GUILD = 210, + GUILD_CLICK_HERE_TO_LEAVE_YOUR_GUILD = 211, + GUILD_YOU_ARE_ABOUT_TO_CREATE_A_GUILD = 212, + GUILD_YOU_NEED_TO_HAVE_AT_LEAST_TEN_MEMBERS = 213, + GUILD_THE_GUILD_MASTER_WILL_ASK_A_FEE = 214, + GUILD_CLICK_HERE_TO_REGISTER_A_GUILD = 215, + GUILD_ENTER_YOUR_GUILD_DETAILS = 216, + GUILD_GUILD_TAG = 217, + GUILD_GUILD_NAME = 218, + GUILD_GUILD_DESCRIPTION = 219, + + GUILD_PLEASE_WAIT_FOR_ALL_MEMBERS_TO_JOIN = 222, GUILD_DO_YOU_ACCEPT = 223, - + GUILD_RECRUITER = 224, GUILD_YOUR_ACCOUNT_WILL_BE_CHARGED = 225, GUILD_PLEASE_CONSIDER_CAREFULLY_RECRUIT = 226, GUILD_TO_VIEW_INFORMATION_ABOUT_A_GUILD_ENTER_ITS_TAG = 227, diff --git a/EOLib/Domain/Interact/Guild/GuildActions.cs b/EOLib/Domain/Interact/Guild/GuildActions.cs index ca1aeab8c..9edc0b5b7 100644 --- a/EOLib/Domain/Interact/Guild/GuildActions.cs +++ b/EOLib/Domain/Interact/Guild/GuildActions.cs @@ -1,37 +1,44 @@ -using AutomaticTypeMapper; +using System.Collections.Generic; +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Notifiers; using EOLib.Net.Communication; using Moffat.EndlessOnline.SDK.Protocol.Net.Client; +using Optional; namespace EOLib.Domain.Interact.Guild { [AutoMappedType] public class GuildActions : IGuildActions { - private readonly IGuildSessionProvider _guildSessionProvider; + private readonly IGuildSessionRepository _guildSessionRepository; private readonly IPacketSendService _packetSendService; + private readonly ICharacterRepository _characterRepository; - public GuildActions(IGuildSessionProvider guildSessionProvider, - IPacketSendService packetSendService) + public GuildActions(IGuildSessionRepository guildSessionRespository, + IPacketSendService packetSendService, + ICharacterRepository characterRepository) { - _guildSessionProvider = guildSessionProvider; + _guildSessionRepository = guildSessionRespository; _packetSendService = packetSendService; + _characterRepository = characterRepository; } public void Lookup(string identity) { - _packetSendService.SendPacket(new GuildReportClientPacket { SessionId = _guildSessionProvider.SessionID, GuildIdentity = identity }); + _packetSendService.SendPacket(new GuildReportClientPacket { SessionId = _guildSessionRepository.SessionID, GuildIdentity = identity }); } public void ViewMembers(string identity) { - _packetSendService.SendPacket(new GuildTellClientPacket { SessionId = _guildSessionProvider.SessionID, GuildIdentity = identity }); + _packetSendService.SendPacket(new GuildTellClientPacket { SessionId = _guildSessionRepository.SessionID, GuildIdentity = identity }); } public void GetGuildDescription(string guildTag) { _packetSendService.SendPacket(new GuildTakeClientPacket { - SessionId = _guildSessionProvider.SessionID, + SessionId = _guildSessionRepository.SessionID, InfoType = GuildInfoType.Description, GuildTag = guildTag }); @@ -41,7 +48,7 @@ public void SetGuildDescription(string description) { _packetSendService.SendPacket(new GuildAgreeClientPacket() { - SessionId = _guildSessionProvider.SessionID, + SessionId = _guildSessionRepository.SessionID, InfoType = GuildInfoType.Description, InfoTypeData = new GuildAgreeClientPacket.InfoTypeDataDescription() { @@ -49,6 +56,55 @@ public void SetGuildDescription(string description) } }); } + + public void RequestToJoinGuild(string guildTag, string recruiterName) + { + _packetSendService.SendPacket(new GuildPlayerClientPacket { SessionId = _guildSessionRepository.SessionID, GuildTag = guildTag, RecruiterName = recruiterName }); + } + + public void LeaveGuild() + { + _packetSendService.SendPacket(new GuildRemoveClientPacket { SessionId = _guildSessionRepository.SessionID }); + _characterRepository.MainCharacter = _characterRepository.MainCharacter + .WithGuildTag(" ") + .WithGuildName(string.Empty) + .WithGuildRank(string.Empty); + } + + public void RequestToCreateGuild(string guildTag, string guildName, string guildDescription) + { + _guildSessionRepository.CreationSession = Option.Some( + new GuildCreationSession.Builder + { + Tag = guildTag, + Name = guildName, + Description = guildDescription, + Members = new HashSet() + }.ToImmutable()); + + _packetSendService.SendPacket(new GuildRequestClientPacket + { + SessionId = _guildSessionRepository.SessionID, + GuildTag = guildTag, + GuildName = guildName, + }); + } + + public void ConfirmGuildCreate(GuildCreationSession creationSession) + { + _packetSendService.SendPacket(new GuildCreateClientPacket + { + SessionId = _guildSessionRepository.SessionID, + GuildTag = creationSession.Tag, + GuildName = creationSession.Name, + Description = creationSession.Description, + }); + } + + public void CancelGuildCreate() + { + _guildSessionRepository.CreationSession = Option.None(); + } } public interface IGuildActions @@ -60,5 +116,15 @@ public interface IGuildActions void GetGuildDescription(string guildTag); void SetGuildDescription(string description); + + void RequestToJoinGuild(string guildTag, string recruiterName); + + void LeaveGuild(); + + void RequestToCreateGuild(string guildTag, string guildName, string guildDescription); + + void ConfirmGuildCreate(GuildCreationSession creationSession); + + void CancelGuildCreate(); } } diff --git a/EOLib/Domain/Interact/Guild/GuildCreationSession.cs b/EOLib/Domain/Interact/Guild/GuildCreationSession.cs new file mode 100644 index 000000000..0890a82f5 --- /dev/null +++ b/EOLib/Domain/Interact/Guild/GuildCreationSession.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using Amadevus.RecordGenerator; + +namespace EOLib.Domain.Interact.Guild +{ + [Record] + public sealed partial class GuildCreationSession + { + public string Tag { get; } + + public string Name { get; } + + public string Description { get; } + + public IReadOnlyCollection Members { get; } = new HashSet(); + + public bool Approved { get; } + } +} diff --git a/EOLib/Domain/Interact/Guild/GuildSessionRepository.cs b/EOLib/Domain/Interact/Guild/GuildSessionRepository.cs index 0279d251a..ed060c2d2 100644 --- a/EOLib/Domain/Interact/Guild/GuildSessionRepository.cs +++ b/EOLib/Domain/Interact/Guild/GuildSessionRepository.cs @@ -9,6 +9,8 @@ public interface IGuildSessionProvider { int SessionID { get; } + Option CreationSession { get; } + string GuildDescription { get; } Option GuildInfo { get; } @@ -20,9 +22,11 @@ public interface IGuildSessionRepository : IResettable { int SessionID { get; set; } + Option CreationSession { get; set; } + string GuildDescription { get; set; } - OptionGuildInfo { get; set; } + Option GuildInfo { get; set; } List GuildMembers { get; set; } } @@ -32,6 +36,8 @@ public class GuildSessionRepository : IGuildSessionRepository, IGuildSessionProv { public int SessionID { get; set; } + public Option CreationSession { get; set; } + public string GuildDescription { get; set; } public Option GuildInfo { get; set; } @@ -48,6 +54,7 @@ public GuildSessionRepository() public void ResetState() { SessionID = 0; + CreationSession = Option.None(); GuildDescription = string.Empty; GuildInfo = Option.None(); GuildMembers = new List(); diff --git a/EOLib/Domain/Notifiers/IGuildNotifier.cs b/EOLib/Domain/Notifiers/IGuildNotifier.cs index e8ca70458..26ca07adf 100644 --- a/EOLib/Domain/Notifiers/IGuildNotifier.cs +++ b/EOLib/Domain/Notifiers/IGuildNotifier.cs @@ -10,6 +10,8 @@ public interface IGuildNotifier void NotifyRequestToJoinGuild(int playerId, string name); void NotifyGuildReply(GuildReply reply); + + void NotifyConfirmCreateGuild(); } [AutoMappedType] @@ -18,5 +20,6 @@ public class NoOpGuildNotifier : IGuildNotifier public void NotifyGuildCreationRequest(int creatorPlayerID, string guildIdentity) { } public void NotifyRequestToJoinGuild(int playerId, string name) { } public void NotifyGuildReply(GuildReply reply) { } + public void NotifyConfirmCreateGuild() { } } } diff --git a/EOLib/PacketHandlers/Guild/GuildAgreeHandler.cs b/EOLib/PacketHandlers/Guild/GuildAgreeHandler.cs new file mode 100644 index 000000000..04a4ba70a --- /dev/null +++ b/EOLib/PacketHandlers/Guild/GuildAgreeHandler.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; + +namespace EOLib.PacketHandlers.Guild +{ + [AutoMappedType] + + public class GuildAgreeHandler : InGameOnlyPacketHandler + { + private const byte JoinGuildSfx = 18; + + private readonly ICharacterRepository _characterRepository; + private readonly IEnumerable _guildNotifiers; + private readonly IEnumerable _soundNotifiers; + + public override PacketFamily Family => PacketFamily.Guild; + + public override PacketAction Action => PacketAction.Agree; + + public GuildAgreeHandler(IPlayerInfoProvider playerInfoProvider, + ICharacterRepository characterRepository, + IEnumerable guildNotifiers, + IEnumerable soundNotifiers) + : base(playerInfoProvider) + { + _characterRepository = characterRepository; + _guildNotifiers = guildNotifiers; + _soundNotifiers = soundNotifiers; + } + + public override bool HandlePacket(GuildAgreeServerPacket packet) + { + _characterRepository.MainCharacter = _characterRepository.MainCharacter + .WithGuildTag(packet.GuildTag) + .WithGuildName(packet.GuildName) + .WithGuildRank(packet.RankName); + + foreach (var notifier in _soundNotifiers) + notifier.NotifySoundEffect(JoinGuildSfx); + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Guild/GuildCreateHandler.cs b/EOLib/PacketHandlers/Guild/GuildCreateHandler.cs new file mode 100644 index 000000000..89bc68a3a --- /dev/null +++ b/EOLib/PacketHandlers/Guild/GuildCreateHandler.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Interact.Guild; +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.Net.Handlers; +using Moffat.EndlessOnline.SDK.Protocol.Net; +using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using Optional; + +namespace EOLib.PacketHandlers.Guild +{ + [AutoMappedType] + + public class GuildCreateHandler : InGameOnlyPacketHandler + { + private const byte JoinGuildSfx = 18; + + private readonly ICharacterRepository _characterRepository; + private readonly IGuildSessionRepository _guildSessionRepository; + private readonly ICharacterInventoryRepository _characterInventoryRepository; + private readonly IEnumerable _soundNotifiers; + + public override PacketFamily Family => PacketFamily.Guild; + + public override PacketAction Action => PacketAction.Create; + + public GuildCreateHandler(IPlayerInfoProvider playerInfoProvider, + ICharacterRepository characterRepository, + IGuildSessionRepository guildSessionRepository, + ICharacterInventoryRepository characterInventoryRepository, + IEnumerable soundNotifiers) + : base(playerInfoProvider) + { + _characterRepository = characterRepository; + _guildSessionRepository = guildSessionRepository; + _characterInventoryRepository = characterInventoryRepository; + _soundNotifiers = soundNotifiers; + } + + public override bool HandlePacket(GuildCreateServerPacket packet) + { + var gold = new InventoryItem(1, packet.GoldAmount); + _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == 1); + _characterInventoryRepository.ItemInventory.Add(gold); + + _characterRepository.MainCharacter = _characterRepository.MainCharacter + .WithGuildTag(packet.GuildTag) + .WithGuildName(packet.GuildName) + .WithGuildRank(packet.RankName); + + _guildSessionRepository.CreationSession = Option.None(); + + foreach (var notifier in _soundNotifiers) + notifier.NotifySoundEffect(JoinGuildSfx); + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Guild/GuildReplyHandler.cs b/EOLib/PacketHandlers/Guild/GuildReplyHandler.cs index 88f388cc8..33ea4e70f 100644 --- a/EOLib/PacketHandlers/Guild/GuildReplyHandler.cs +++ b/EOLib/PacketHandlers/Guild/GuildReplyHandler.cs @@ -1,10 +1,12 @@ using System.Collections.Generic; using AutomaticTypeMapper; +using EOLib.Domain.Interact.Guild; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; using EOLib.Net.Handlers; using Moffat.EndlessOnline.SDK.Protocol.Net; using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using Optional; namespace EOLib.PacketHandlers.Guild { @@ -12,16 +14,19 @@ namespace EOLib.PacketHandlers.Guild public class GuildReplyHandler : InGameOnlyPacketHandler { private readonly IEnumerable _guildNotifiers; + private readonly IGuildSessionRepository _guildSessionRepository; public override PacketFamily Family => PacketFamily.Guild; public override PacketAction Action => PacketAction.Reply; public GuildReplyHandler(IPlayerInfoProvider playerInfoProvider, - IEnumerable guildNotifiers) + IEnumerable guildNotifiers, + IGuildSessionRepository guildSessionRepository) : base(playerInfoProvider) { _guildNotifiers = guildNotifiers; + _guildSessionRepository = guildSessionRepository; } public override bool HandlePacket(GuildReplyServerPacket packet) @@ -29,15 +34,59 @@ public override bool HandlePacket(GuildReplyServerPacket packet) switch (packet.ReplyCode) { case GuildReply.JoinRequest: - var joinRequestData = (GuildReplyServerPacket.ReplyCodeDataJoinRequest)(packet.ReplyCodeData); - foreach (var notifier in _guildNotifiers) - notifier.NotifyRequestToJoinGuild(joinRequestData.PlayerId, joinRequestData.Name); - break; + { + var data = (GuildReplyServerPacket.ReplyCodeDataJoinRequest)(packet.ReplyCodeData); + foreach (var notifier in _guildNotifiers) + notifier.NotifyRequestToJoinGuild(data.PlayerId, data.Name); + break; + } case GuildReply.Updated: case GuildReply.NotFound: - foreach (var notifier in _guildNotifiers) - notifier.NotifyGuildReply(packet.ReplyCode); - break; + case GuildReply.RecruiterOffline: + case GuildReply.RecruiterNotHere: + case GuildReply.RecruiterWrongGuild: + case GuildReply.NotRecruiter: + case GuildReply.NotApproved: + case GuildReply.Exists: + case GuildReply.NoCandidates: + case GuildReply.Busy: + { + foreach (var notifier in _guildNotifiers) + notifier.NotifyGuildReply(packet.ReplyCode); + break; + } + case GuildReply.CreateBegin: + { + _guildSessionRepository.CreationSession.MatchSome(creationSession => + { + _guildSessionRepository.CreationSession = Option.Some(creationSession.WithApproved(true)); + }); + break; + } + case GuildReply.CreateAdd: + { + _guildSessionRepository.CreationSession.MatchSome(creationSession => + { + var data = (GuildReplyServerPacket.ReplyCodeDataCreateAdd)packet.ReplyCodeData; + var updatedMemberList = new HashSet(creationSession.Members) { data.Name }; + _guildSessionRepository.CreationSession = Option.Some(creationSession.WithMembers(updatedMemberList)); + }); + + break; + } + case GuildReply.CreateAddConfirm: + { + _guildSessionRepository.CreationSession.MatchSome(creationSession => + { + var data = (GuildReplyServerPacket.ReplyCodeDataCreateAddConfirm)packet.ReplyCodeData; + var updatedMemberList = new HashSet(creationSession.Members) { data.Name }; + _guildSessionRepository.CreationSession = Option.Some(creationSession.WithMembers(updatedMemberList)); + + foreach (var notifier in _guildNotifiers) + notifier.NotifyConfirmCreateGuild(); + }); + break; + } } return true; diff --git a/EndlessClient/Audio/SoundEffectID.cs b/EndlessClient/Audio/SoundEffectID.cs index e115d387f..cfbdecfea 100644 --- a/EndlessClient/Audio/SoundEffectID.cs +++ b/EndlessClient/Audio/SoundEffectID.cs @@ -18,6 +18,7 @@ public enum SoundEffectID ServerMessage = Login, DeleteCharacter, MapMutation = DeleteCharacter, + LeaveGuild = DeleteCharacter, Banned, Reboot = Banned, ScreenCapture = 8, diff --git a/EndlessClient/Dialogs/Factories/GuildDialogFactory.cs b/EndlessClient/Dialogs/Factories/GuildDialogFactory.cs index 943713532..c7060cb8e 100644 --- a/EndlessClient/Dialogs/Factories/GuildDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/GuildDialogFactory.cs @@ -1,9 +1,11 @@ using AutomaticTypeMapper; +using EndlessClient.Audio; using EndlessClient.Content; using EndlessClient.Dialogs.Services; using EOLib.Domain.Character; using EOLib.Domain.Interact.Guild; using EOLib.Graphics; +using EOLib.IO.Repositories; using EOLib.Localization; namespace EndlessClient.Dialogs.Factories @@ -20,7 +22,11 @@ public class GuildDialogFactory : IGuildDialogFactory private readonly IGuildSessionProvider _guildSessionProvider; private readonly IGuildActions _guildActions; private readonly ITextInputDialogFactory _textInputDialogFactory; + private readonly ITextMultiInputDialogFactory _textMultiInputDialogFactory; private readonly IContentProvider _contentProvider; + private readonly ICharacterInventoryProvider _characterInventoryProvider; + private readonly IEIFFileProvider _eifFileProvider; + private readonly ISfxPlayer _sfxPlayer; public GuildDialogFactory(INativeGraphicsManager nativeGraphicsManager, IEODialogButtonService dialogButtonService, @@ -31,7 +37,11 @@ public GuildDialogFactory(INativeGraphicsManager nativeGraphicsManager, IGuildSessionProvider guildSessionProvider, IGuildActions guildActions, ITextInputDialogFactory textInputDialogFactory, - IContentProvider contentProvider) + ITextMultiInputDialogFactory textMultiInputDialogFactory, + IContentProvider contentProvider, + ICharacterInventoryProvider characterInventoryProvider, + IEIFFileProvider eifFileProvider, + ISfxPlayer sfxPlayer) { _nativeGraphicsManager = nativeGraphicsManager; _dialogButtonService = dialogButtonService; @@ -42,7 +52,11 @@ public GuildDialogFactory(INativeGraphicsManager nativeGraphicsManager, _guildSessionProvider = guildSessionProvider; _guildActions = guildActions; _textInputDialogFactory = textInputDialogFactory; + _textMultiInputDialogFactory = textMultiInputDialogFactory; _contentProvider = contentProvider; + _characterInventoryProvider = characterInventoryProvider; + _eifFileProvider = eifFileProvider; + _sfxPlayer = sfxPlayer; } public GuildDialog Create() @@ -56,7 +70,11 @@ public GuildDialog Create() _guildSessionProvider, _guildActions, _textInputDialogFactory, - _contentProvider); + _textMultiInputDialogFactory, + _contentProvider, + _characterInventoryProvider, + _eifFileProvider, + _sfxPlayer); } } diff --git a/EndlessClient/Dialogs/GuildDialog.cs b/EndlessClient/Dialogs/GuildDialog.cs index 3fb214730..69015fd90 100644 --- a/EndlessClient/Dialogs/GuildDialog.cs +++ b/EndlessClient/Dialogs/GuildDialog.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using EndlessClient.Audio; using EndlessClient.Content; using EndlessClient.Dialogs.Factories; using EndlessClient.Dialogs.Services; @@ -8,6 +9,7 @@ using EOLib.Domain.Character; using EOLib.Domain.Interact.Guild; using EOLib.Graphics; +using EOLib.IO.Repositories; using EOLib.Localization; using Microsoft.Xna.Framework; using Moffat.EndlessOnline.SDK.Protocol.Net.Server; @@ -33,6 +35,12 @@ private enum GuildDialogState Lookup, ViewMembers, + // Administration List Items + JoinGuild, + LeaveGuild, + RegisterGuild, + WaitingForMembers, + // Management List Items Modify, ManageRankings, @@ -51,12 +59,22 @@ private class State public static State Information => new(GuildDialogState.Information); + public static State Administration => new(GuildDialogState.Administration); + public static State Management => new(GuildDialogState.Management); public static State GuildLookup => new(GuildDialogState.Lookup); public static State ViewMembers => new(GuildDialogState.ViewMembers); + public static State JoinGuild => new(GuildDialogState.JoinGuild); + + public static State LeaveGuild => new(GuildDialogState.LeaveGuild); + + public static State RegisterGuild => new(GuildDialogState.RegisterGuild); + + public static State WaitingForMembers => new(GuildDialogState.WaitingForMembers); + public static State Modify => new(GuildDialogState.Modify); public static State ManageRankings => new(GuildDialogState.ManageRankings); @@ -78,6 +96,10 @@ private State(GuildDialogState dialogState) case GuildDialogState.Modify: case GuildDialogState.Lookup: case GuildDialogState.ViewMembers: + case GuildDialogState.JoinGuild: + case GuildDialogState.LeaveGuild: + case GuildDialogState.RegisterGuild: + case GuildDialogState.WaitingForMembers: ListItemStyle = ListDialogItem.ListItemStyle.Small; break; } @@ -105,12 +127,17 @@ public override int GetHashCode() private readonly IGuildSessionProvider _guildSessionProvider; private readonly IGuildActions _guildActions; private readonly ITextInputDialogFactory _textInputDialogFactory; + private readonly ITextMultiInputDialogFactory _textMultiInputDialogFactory; private readonly IContentProvider _contentProvider; + private readonly ICharacterInventoryProvider _characterInventoryProvider; + private readonly IEIFFileProvider _eifFileProvider; + private readonly ISfxPlayer _sfxPlayer; private readonly Stack _stateStack; private State _state; private HashSet _cachedMembers; + private HashSet _cachedCreationMembers; private Option _cachedGuildInfo; private Option _modifyGuildDescriptionListItem; @@ -123,7 +150,11 @@ public GuildDialog(INativeGraphicsManager nativeGraphicsManager, IGuildSessionProvider guildSessionProvider, IGuildActions guildActions, ITextInputDialogFactory textInputDialogFactory, - IContentProvider contentProvider) + ITextMultiInputDialogFactory textMultiInputDialogFactory, + IContentProvider contentProvider, + ICharacterInventoryProvider characterInventoryProvider, + IEIFFileProvider eifFileProvider, + ISfxPlayer sfxPlayer) : base(nativeGraphicsManager, dialogButtonService, DialogType.Guild) { _dialogIconService = dialogIconService; @@ -133,17 +164,27 @@ public GuildDialog(INativeGraphicsManager nativeGraphicsManager, _guildSessionProvider = guildSessionProvider; _guildActions = guildActions; _textInputDialogFactory = textInputDialogFactory; + _textMultiInputDialogFactory = textMultiInputDialogFactory; _contentProvider = contentProvider; + _characterInventoryProvider = characterInventoryProvider; + _eifFileProvider = eifFileProvider; + _sfxPlayer = sfxPlayer; _stateStack = new Stack(); _cachedMembers = new HashSet(); + _cachedCreationMembers = new HashSet(); _stateTransitions = new Dictionary { { State.Initial, SetupInitialState }, { State.Information, SetupInformationState }, + { State.Administration, SetupAdministrationState }, { State.Management, SetupManagementState }, - { State.Modify, SetupModifyState } + { State.Modify, SetupModifyState }, + { State.JoinGuild, SetupJoinGuildState }, + { State.LeaveGuild, SetupLeaveGuildState }, + { State.RegisterGuild, SetupRegisterGuildState }, + { State.WaitingForMembers, SetupWaitingForMembersState }, }; SetState(State.Initial); @@ -153,7 +194,7 @@ public GuildDialog(INativeGraphicsManager nativeGraphicsManager, Title = _localizedStringFinder.GetString(EOResourceID.GUILD_GUILD_MASTER); } - protected override void OnUpdateControl(GameTime gameTime) + protected override void OnUnconditionalUpdateControl(GameTime gameTime) { switch (_state.DialogState) { @@ -190,14 +231,41 @@ protected override void OnUpdateControl(GameTime gameTime) _cachedMembers = _guildSessionProvider.GuildMembers.ToHashSet(); AddTextAsKeyValueListItems( - _cachedMembers.Select(x => ($"{x.Rank} {x.Name}", char.ToUpper(x.RankName[0]) + x.RankName[1..])).ToArray() + _cachedMembers.Select(x => ($"{x.Rank} {x.Name}", Capitalize(x.RankName))).ToArray() ); } + break; + + case GuildDialogState.RegisterGuild: + _guildSessionProvider.CreationSession.MatchSome(creationSession => + { + if (creationSession.Approved) + { + SetState(State.WaitingForMembers); + } + }); + break; + case GuildDialogState.WaitingForMembers: + _guildSessionProvider.CreationSession.MatchSome(creationSession => + { + if (!_cachedCreationMembers.SetEquals(creationSession.Members)) + { + foreach (var member in creationSession.Members.Where(c => !_cachedCreationMembers.Contains(c))) + { + AddItemToList(new ListDialogItem(this, ListDialogItem.ListItemStyle.Small) + { + PrimaryText = member + }, + sortList: false); + } + _cachedCreationMembers = creationSession.Members.ToHashSet(); + } + }); break; } - base.OnUpdateControl(gameTime); + base.OnUnconditionalUpdateControl(gameTime); void CacheAndSetGuildInfo(GuildInfo guildInfo) { @@ -216,14 +284,14 @@ void CacheAndSetGuildInfo(GuildInfo guildInfo) _localizedStringFinder.GetString(EOResourceID.GUILD_SIGNUP_DATE), guildInfo.CreateDate.ToString("yyyy/MM/dd"), " ", - _localizedStringFinder.GetString(EOResourceID.GUILD_DESCRIPTION), + _localizedStringFinder.GetString(EOResourceID.GUILD_GUILD_DESCRIPTION), guildInfo.Description, " ", _localizedStringFinder.GetString(EOResourceID.GUILD_BANK_STATUS), guildInfo.Wealth, " ", _localizedStringFinder.GetString(EOResourceID.GUILD_RANKING_SYSTEM), - string.Join("\n", guildInfo.Ranks.Select((x, n) => $"{n + 1} {char.ToUpper(x[0]) + x[1..]}")), + string.Join("\n", guildInfo.Ranks.Select((x, n) => $"{n + 1} {Capitalize(x)}")), " ", _localizedStringFinder.GetString(EOResourceID.GUILD_LEADERS), string.Join("\n", guildInfo.Staff.Select(x => $"{x.Name}{(x.Rank == 0 ? " (founder)" : string.Empty)}")), @@ -237,7 +305,6 @@ void CacheAndSetGuildInfo(GuildInfo guildInfo) private void GoBack() { _modifyGuildDescriptionListItem = Option.None(); - SetState(_stateStack.Count > 0 ? _stateStack.Pop() : State.Initial, pushState: false); } @@ -281,6 +348,8 @@ private void SetupInitialState() SubText = _localizedStringFinder.GetString(EOResourceID.GUILD_JOIN_LEAVE_REGISTER), OffsetY = 45, }; + administrationItem.LeftClick += (_, _) => SetState(State.Administration); + administrationItem.RightClick += (_, _) => SetState(State.Administration); var managementItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 2) { @@ -346,10 +415,7 @@ void GuildLookup_Click(object sender, MouseEventArgs e) if (dlg.ResponseText.Length < 2 && !showOnce) { - var invalidGuildTag = _messageBoxFactory.CreateMessageBox( - _localizedStringFinder.GetString(DialogResourceID.GUILD_CREATE_TAG_TOO_SHORT), - _localizedStringFinder.GetString(DialogResourceID.GUILD_WRONG_INPUT), - EODialogButtons.OkCancel); + var invalidGuildTag = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_CREATE_TAG_TOO_SHORT); invalidGuildTag.ShowDialog(); showOnce = true; } @@ -372,10 +438,7 @@ void ViewMembers_Click(object sender, MouseEventArgs e) if (dlg.ResponseText.Length < 2 && !showOnce) { - var invalidGuildTag = _messageBoxFactory.CreateMessageBox( - _localizedStringFinder.GetString(DialogResourceID.GUILD_CREATE_TAG_TOO_SHORT), - _localizedStringFinder.GetString(DialogResourceID.GUILD_WRONG_INPUT), - EODialogButtons.OkCancel); + var invalidGuildTag = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_CREATE_TAG_TOO_SHORT); invalidGuildTag.ShowDialog(); showOnce = true; } @@ -388,6 +451,47 @@ void ViewMembers_Click(object sender, MouseEventArgs e) } } + private void SetupAdministrationState() + { + var joinGuildItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 0) + { + ShowIconBackGround = false, + IconGraphic = _dialogIconService.IconSheet, + IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.GuildJoin), + PrimaryText = _localizedStringFinder.GetString(EOResourceID.GUILD_JOIN_GUILD), + SubText = _localizedStringFinder.GetString(EOResourceID.GUILD_JOIN_AN_EXISTING_GUILD), + OffsetY = 45, + }; + joinGuildItem.LeftClick += (_, _) => SetStateIfNotInGuild(State.JoinGuild); + joinGuildItem.RightClick += (_, _) => SetStateIfNotInGuild(State.JoinGuild); + + var leaveGuildItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 1) + { + ShowIconBackGround = false, + IconGraphic = _dialogIconService.IconSheet, + IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.GuildLeave), + PrimaryText = _localizedStringFinder.GetString(EOResourceID.GUILD_LEAVE_GUILD), + SubText = _localizedStringFinder.GetString(EOResourceID.GUILD_LEAVE_YOUR_CURRENT_GUILD), + OffsetY = 45, + }; + leaveGuildItem.LeftClick += (_, _) => SetStateIfInGuild(State.LeaveGuild); + leaveGuildItem.RightClick += (_, _) => SetStateIfInGuild(State.LeaveGuild); + + var registerGuildItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 2) + { + ShowIconBackGround = false, + IconGraphic = _dialogIconService.IconSheet, + IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.GuildRegister), + PrimaryText = _localizedStringFinder.GetString(EOResourceID.GUILD_REGISTER_GUILD), + SubText = _localizedStringFinder.GetString(EOResourceID.GUILD_CREATE_YOUR_OWN_GUILD), + OffsetY = 45, + }; + registerGuildItem.LeftClick += (_, _) => SetStateIfNotInGuild(State.RegisterGuild); + registerGuildItem.RightClick += (_, _) => SetStateIfNotInGuild(State.RegisterGuild); + + SetItemList(new List { joinGuildItem, leaveGuildItem, registerGuildItem }); + } + private void SetupManagementState() { var modifyGuildItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 0) @@ -399,8 +503,8 @@ private void SetupManagementState() SubText = _localizedStringFinder.GetString(EOResourceID.GUILD_CHANGE_YOUR_GUILD_DETAILS), OffsetY = 45, }; - modifyGuildItem.LeftClick += (_, _) => SetStateIfGuildMember(State.Modify); - modifyGuildItem.RightClick += (_, _) => SetStateIfGuildMember(State.Modify); + modifyGuildItem.LeftClick += (_, _) => SetStateIfInGuild(State.Modify); + modifyGuildItem.RightClick += (_, _) => SetStateIfInGuild(State.Modify); var manageRankingItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 0) { @@ -411,8 +515,8 @@ private void SetupManagementState() SubText = _localizedStringFinder.GetString(EOResourceID.GUILD_MANAGE_MEMBER_RANKINGS), OffsetY = 45, }; - manageRankingItem.LeftClick += (_, _) => SetStateIfGuildMember(State.ManageRankings); - manageRankingItem.RightClick += (_, _) => SetStateIfGuildMember(State.ManageRankings); + manageRankingItem.LeftClick += (_, _) => SetStateIfInGuild(State.ManageRankings); + manageRankingItem.RightClick += (_, _) => SetStateIfInGuild(State.ManageRankings); var assignRankItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 0) { @@ -423,8 +527,8 @@ private void SetupManagementState() SubText = _localizedStringFinder.GetString(EOResourceID.GUILD_ASSIGN_RANK_TO_MEMBER), OffsetY = 45, }; - assignRankItem.LeftClick += (_, _) => SetStateIfGuildMember(State.AssignRank); - assignRankItem.RightClick += (_, _) => SetStateIfGuildMember(State.AssignRank); + assignRankItem.LeftClick += (_, _) => SetStateIfInGuild(State.AssignRank); + assignRankItem.RightClick += (_, _) => SetStateIfInGuild(State.AssignRank); var removeMemberItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 0) { @@ -435,8 +539,8 @@ private void SetupManagementState() SubText = _localizedStringFinder.GetString(EOResourceID.GUILD_REMOVE_A_MEMBER_FROM_GUILD), OffsetY = 45, }; - removeMemberItem.LeftClick += (_, _) => SetStateIfGuildMember(State.RemoveMember); - removeMemberItem.RightClick += (_, _) => SetStateIfGuildMember(State.RemoveMember); + removeMemberItem.LeftClick += (_, _) => SetStateIfInGuild(State.RemoveMember); + removeMemberItem.RightClick += (_, _) => SetStateIfInGuild(State.RemoveMember); var disbandItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 0) { @@ -447,8 +551,8 @@ private void SetupManagementState() SubText = _localizedStringFinder.GetString(EOResourceID.GUILD_DISBAND_YOUR_GUILD), OffsetY = 45, }; - disbandItem.LeftClick += (_, _) => SetStateIfGuildMember(State.Disband); - disbandItem.RightClick += (_, _) => SetStateIfGuildMember(State.Disband); + disbandItem.LeftClick += (_, _) => SetStateIfInGuild(State.Disband); + disbandItem.RightClick += (_, _) => SetStateIfInGuild(State.Disband); SetItemList(new List { modifyGuildItem, manageRankingItem, assignRankItem, removeMemberItem, disbandItem }); } @@ -471,7 +575,7 @@ private void SetupModifyState() void ShowChangeDescriptionMessageBox() { - var dlg = _textInputDialogFactory.Create(_localizedStringFinder.GetString(EOResourceID.GUILD_DESCRIPTION), 240); + var dlg = _textInputDialogFactory.Create(_localizedStringFinder.GetString(EOResourceID.GUILD_GUILD_DESCRIPTION), 240); dlg.DialogClosing += (_, e) => { if (e.Result == XNADialogResult.OK) @@ -484,7 +588,216 @@ void ShowChangeDescriptionMessageBox() } } - private void SetStateIfGuildMember(State state) + private void SetupJoinGuildState() + { + AddTextAsListItems( + _contentProvider.Fonts[Constants.FontSize08pt5], + insertLineBreaks: true, + new List { ShowJoinGuildMessageBox }, + _localizedStringFinder.GetString(EOResourceID.GUILD_JOIN_GUILD), + _localizedStringFinder.GetString(EOResourceID.GUILD_YOU_ARE_ABOUT_TO_JOIN_A_GUILD), + _localizedStringFinder.GetString(EOResourceID.GUILD_JOINING_A_GUILD_IS_FREE), + _localizedStringFinder.GetString(EOResourceID.GUILD_PLEASE_CONSIDER_CAREFULLY), + _localizedStringFinder.GetString(EOResourceID.GUILD_CLICK_HERE_TO_JOIN_A_GUILD) + ); + } + + private void SetupLeaveGuildState() + { + AddTextAsListItems( + _contentProvider.Fonts[Constants.FontSize08pt5], + insertLineBreaks: true, + new List { ShowLeaveGuildMessageBox }, + _localizedStringFinder.GetString(EOResourceID.GUILD_LEAVE_GUILD), + _localizedStringFinder.GetString(EOResourceID.GUILD_YOU_ARE_ABOUT_TO_LEAVE_THE_GUILD), + _localizedStringFinder.GetString(EOResourceID.GUILD_REMEMBER_THAT_AFTER_YOU_HAVE_LEFT_THE_GUILD), + _localizedStringFinder.GetString(EOResourceID.GUILD_CLICK_HERE_TO_LEAVE_YOUR_GUILD) + ); + } + + private void SetupRegisterGuildState() + { + AddTextAsListItems( + _contentProvider.Fonts[Constants.FontSize08pt5], + insertLineBreaks: true, + new List { ShowRegisterGuildMessageBox }, + _localizedStringFinder.GetString(EOResourceID.GUILD_REGISTER_GUILD), + _localizedStringFinder.GetString(EOResourceID.GUILD_YOU_ARE_ABOUT_TO_CREATE_A_GUILD), + _localizedStringFinder.GetString(EOResourceID.GUILD_YOU_NEED_TO_HAVE_AT_LEAST_TEN_MEMBERS), + _localizedStringFinder.GetString(EOResourceID.GUILD_THE_GUILD_MASTER_WILL_ASK_A_FEE), + _localizedStringFinder.GetString(EOResourceID.GUILD_CLICK_HERE_TO_REGISTER_A_GUILD) + ); + } + + private void SetupWaitingForMembersState() + { + AddTextAsListItems( + _contentProvider.Fonts[Constants.FontSize08pt5], + insertLineBreaks: false, + new List { }, + _localizedStringFinder.GetString(EOResourceID.GUILD_PLEASE_WAIT_FOR_ALL_MEMBERS_TO_JOIN), + " ", + Capitalize(_characterProvider.MainCharacter.Name) + ); + } + + private void ShowJoinGuildMessageBox() + { + if (_characterProvider.MainCharacter.InGuild) + { + var dlgAlreadyMember = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_ALREADY_A_MEMBER); + dlgAlreadyMember.ShowDialog(); + return; + } + + var dlgJoin = _textMultiInputDialogFactory.Create( + _localizedStringFinder.GetString(DialogResourceID.GUILD_JOIN_GUILD), + _localizedStringFinder.GetString(DialogResourceID.GUILD_JOIN_GUILD + 1), + TextMultiInputDialog.DialogSize.Two, + new TextMultiInputDialog.InputInfo { Label = _localizedStringFinder.GetString(EOResourceID.GUILD_GUILD_TAG), MaxChars = 3 }, + new TextMultiInputDialog.InputInfo { Label = _localizedStringFinder.GetString(EOResourceID.GUILD_RECRUITER), MaxChars = 12 } + ); + + dlgJoin.DialogClosing += (sender, e) => + { + if (e.Result == XNADialogResult.OK) + { + var guildTag = dlgJoin.Responses[0]; + var recruiterName = dlgJoin.Responses[1]; + + if (string.IsNullOrEmpty(guildTag)) + { + e.Cancel = true; + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_CREATE_TAG_FIELD_EMPTY); + dlg.ShowDialog(); + return; + } + + if (string.IsNullOrEmpty(recruiterName)) + { + e.Cancel = true; + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_RECRUITER_INPUT_MISSING); + dlg.ShowDialog(); + return; + } + + if (guildTag.Length == 1) + { + e.Cancel = true; + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_CREATE_TAG_TOO_SHORT); + dlg.ShowDialog(); + return; + } + + _guildActions.RequestToJoinGuild(guildTag, recruiterName); + } + }; + + dlgJoin.ShowDialog(); + } + + private void ShowLeaveGuildMessageBox() + { + if (!_characterProvider.MainCharacter.InGuild) + { + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_NOT_IN_GUILD); + dlg.ShowDialog(); + return; + } + + var dlgLeave = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_PROMPT_LEAVE_GUILD, whichButtons: EODialogButtons.OkCancel); + dlgLeave.DialogClosing += (_, e) => + { + if (e.Result == XNADialogResult.OK) + { + _sfxPlayer.PlaySfx(SoundEffectID.LeaveGuild); + _guildActions.LeaveGuild(); + } + }; + dlgLeave.ShowDialog(); + } + + private void ShowRegisterGuildMessageBox() + { + if (_characterProvider.MainCharacter.InGuild) + { + var dlgAlreadyMember = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_ALREADY_A_MEMBER); + dlgAlreadyMember.ShowDialog(); + return; + } + + var dlgRegister = _textMultiInputDialogFactory.Create( + _localizedStringFinder.GetString(EOResourceID.GUILD_REGISTER_GUILD), + _localizedStringFinder.GetString(EOResourceID.GUILD_ENTER_YOUR_GUILD_DETAILS), + TextMultiInputDialog.DialogSize.Three, + new TextMultiInputDialog.InputInfo { Label = _localizedStringFinder.GetString(EOResourceID.GUILD_GUILD_TAG), MaxChars = 3 }, + new TextMultiInputDialog.InputInfo { Label = _localizedStringFinder.GetString(EOResourceID.GUILD_GUILD_NAME), MaxChars = 24 }, + new TextMultiInputDialog.InputInfo { Label = _localizedStringFinder.GetString(EOResourceID.GUILD_GUILD_DESCRIPTION), MaxChars = 240 } + ); + + dlgRegister.DialogClosing += (_, e) => + { + if (e.Result == XNADialogResult.OK) + { + var guildTag = dlgRegister.Responses[0]; + var guildName = dlgRegister.Responses[1]; + var guildDescription = dlgRegister.Responses[2]; + + if (!_characterInventoryProvider.ItemInventory.Any(x => x.ItemID == 1 && x.Amount >= 50_000)) + { + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.WARNING_YOU_HAVE_NOT_ENOUGH, $" {_eifFileProvider.EIFFile[1].Name}"); + dlg.ShowDialog(); + return; + } + + if (string.IsNullOrEmpty(guildTag)) + { + e.Cancel = true; + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_CREATE_TAG_FIELD_EMPTY); + dlg.ShowDialog(); + return; + } + + if (string.IsNullOrEmpty(guildName)) + { + e.Cancel = true; + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_CREATE_NAME_FIELD_EMPTY); + dlg.ShowDialog(); + return; + } + + if (guildTag.Length == 1) + { + e.Cancel = true; + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_CREATE_TAG_TOO_SHORT); + dlg.ShowDialog(); + return; + } + + if (guildName.Length <= 3) + { + e.Cancel = true; + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_CREATE_NAME_TOO_SHORT); + dlg.ShowDialog(); + return; + } + + if (char.ToLower(guildTag[0]) != char.ToLower(guildName[0])) + { + e.Cancel = true; + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_TAG_NAME_LETTER_MUST_MATCH); + dlg.ShowDialog(); + return; + } + + _guildActions.RequestToCreateGuild(guildTag, guildName, guildDescription); + } + }; + + dlgRegister.ShowDialog(); + } + + private void SetStateIfInGuild(State state) { if (!_characterProvider.MainCharacter.InGuild) { @@ -495,5 +808,20 @@ private void SetStateIfGuildMember(State state) SetState(state); } + + private void SetStateIfNotInGuild(State state) + { + if (_characterProvider.MainCharacter.InGuild) + { + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_ALREADY_A_MEMBER); + dlg.ShowDialog(); + return; + } + + SetState(state); + } + + private static string Capitalize(string input) => + string.IsNullOrEmpty(input) ? string.Empty : char.ToUpper(input[0]) + input[1..].ToLower(); } } diff --git a/EndlessClient/Dialogs/TextMultiInputDialog.cs b/EndlessClient/Dialogs/TextMultiInputDialog.cs index 07ade6ec4..762920c8d 100644 --- a/EndlessClient/Dialogs/TextMultiInputDialog.cs +++ b/EndlessClient/Dialogs/TextMultiInputDialog.cs @@ -84,8 +84,26 @@ public TextMultiInputDialog(INativeGraphicsManager nativeGraphicsManager, cancelButtonPosition = new Vector2(166, 125); break; - case DialogSize.NineWithScroll: + case DialogSize.Three: + if (inputInfo.Length != 3) + { + throw new ArgumentException("Not enough input labels were provided"); + } + + _backgroundSourceRectangle = new Rectangle(0, 0, 330, 194); + + SetSize(330, 194); + _bottomOverlayDrawPosition = new Vector2(0, 134); + _bottomOverlaySource = new Rectangle(0, 240, 330, 59); + + _inputLabels = new XNALabel[3]; + _inputBoxes = new XNATextBox[3]; + okButtonPosition = new Vector2(73, 148); + cancelButtonPosition = new Vector2(166, 148); + break; + + case DialogSize.NineWithScroll: if (inputInfo.Length != 9) { throw new ArgumentException("Not enough input labels were provided"); @@ -150,7 +168,6 @@ public TextMultiInputDialog(INativeGraphicsManager nativeGraphicsManager, Text = inputInfo[i].Label, DrawPosition = new Vector2(24, yCoord), }; - _inputLabels[i].Initialize(); _inputLabels[i].SetParentControl(this); _inputBoxes[i] = new XNATextBox(new Rectangle(126, yCoord, 168, 19), Constants.FontSize08, caretTexture: contentProvider.Textures[ContentProvider.Cursor]) @@ -159,6 +176,7 @@ public TextMultiInputDialog(INativeGraphicsManager nativeGraphicsManager, LeftPadding = 4, TextColor = ColorConstants.LightBeigeText, MaxWidth = 160, + TabOrder = i, }; _inputBoxes[i].SetParentControl(this); @@ -186,6 +204,8 @@ public TextMultiInputDialog(INativeGraphicsManager nativeGraphicsManager, public override void Initialize() { + foreach (var label in _inputLabels) + label.Initialize(); foreach (var box in _inputBoxes) box.Initialize(); @@ -248,5 +268,15 @@ protected override void OnUpdateControl(GameTime gameTime) } base.OnUpdateControl(gameTime); } + + public override void CenterInGameView() + { + var viewport = Game.GraphicsDevice.Viewport; + var area = _backgroundSourceRectangle; + DrawPosition = new Vector2((viewport.Width - area.Width) / 2, (viewport.Height - area.Height) / 2); + + if (!Game.Window.AllowUserResizing) + DrawPosition = new Vector2(DrawPosition.X, (330 - DrawArea.Height) / 2f); + } } } diff --git a/EndlessClient/Subscribers/GuildEventSubscriber.cs b/EndlessClient/Subscribers/GuildEventSubscriber.cs index bbb65a01e..8045dc237 100644 --- a/EndlessClient/Subscribers/GuildEventSubscriber.cs +++ b/EndlessClient/Subscribers/GuildEventSubscriber.cs @@ -1,11 +1,14 @@ using AutomaticTypeMapper; using EndlessClient.Audio; +using EndlessClient.Dialogs; using EndlessClient.Dialogs.Factories; +using EOLib.Domain.Interact.Guild; using EOLib.Domain.Notifiers; using EOLib.Localization; using EOLib.Net.Communication; using Moffat.EndlessOnline.SDK.Protocol.Net.Client; using Moffat.EndlessOnline.SDK.Protocol.Net.Server; +using XNAControls; namespace EndlessClient.Subscribers { @@ -13,16 +16,25 @@ namespace EndlessClient.Subscribers public class GuildEventSubscriber : IGuildNotifier { private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly IGuildActions _guildActions; private readonly ILocalizedStringFinder _localizedStringFinder; private readonly IPacketSendService _packetSendService; private readonly ISfxPlayer _sfxPlayer; + private readonly IGuildSessionProvider _guildSessionProvider; - public GuildEventSubscriber(IEOMessageBoxFactory messageBoxFactory, ILocalizedStringFinder localizedStringFinder, IPacketSendService packetSendService, ISfxPlayer sfxPlayer) + public GuildEventSubscriber(IEOMessageBoxFactory messageBoxFactory, + IGuildActions guildActions, + ILocalizedStringFinder localizedStringFinder, + IPacketSendService packetSendService, + ISfxPlayer sfxPlayer, + IGuildSessionProvider guildSessionProvider) { _messageBoxFactory = messageBoxFactory; + _guildActions = guildActions; _localizedStringFinder = localizedStringFinder; _packetSendService = packetSendService; _sfxPlayer = sfxPlayer; + _guildSessionProvider = guildSessionProvider; } public void NotifyGuildCreationRequest(int creatorPlayerID, string guildIdentity) @@ -87,6 +99,14 @@ public void NotifyGuildReply(GuildReply reply) { GuildReply.Updated => DialogResourceID.GUILD_DETAILS_UPDATED, GuildReply.NotFound => DialogResourceID.GUILD_DOES_NOT_EXIST, + GuildReply.RecruiterOffline => DialogResourceID.GUILD_RECRUITER_NOT_FOUND, + GuildReply.RecruiterNotHere => DialogResourceID.GUILD_RECRUITER_NOT_HERE, + GuildReply.RecruiterWrongGuild => DialogResourceID.GUILD_RECRUITER_NOT_MEMBER, + GuildReply.NotRecruiter => DialogResourceID.GUILD_RECRUITER_RANK_TOO_LOW, + GuildReply.Busy => DialogResourceID.GUILD_MASTER_IS_BUSY, + GuildReply.NotApproved => DialogResourceID.GUILD_CREATE_NAME_NOT_APPROVED, + GuildReply.Exists => DialogResourceID.GUILD_TAG_OR_NAME_ALREADY_EXISTS, + GuildReply.NoCandidates => DialogResourceID.GUILD_CREATE_NO_CANDIDATES, _ => default }; @@ -96,5 +116,27 @@ public void NotifyGuildReply(GuildReply reply) var dlg = _messageBoxFactory.CreateMessageBox(dialogMessage); dlg.ShowDialog(); } + + public void NotifyConfirmCreateGuild() + { + _guildSessionProvider.CreationSession.MatchSome(creationSession => + { + _sfxPlayer.PlaySfx(SoundEffectID.ServerMessage); + + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.GUILD_WILL_BE_CREATED, whichButtons: EODialogButtons.OkCancel); + dlg.DialogClosing += (_, e) => + { + if (e.Result == XNADialogResult.OK) + { + _guildActions.ConfirmGuildCreate(creationSession); + } + else + { + _guildActions.CancelGuildCreate(); + } + }; + dlg.ShowDialog(); + }); + } } }