using System; using System.Collections.Generic; using System.Linq; namespace Nox.Game { public interface IPartyFactory { PartyDefinition Create(CharacterDefinition protagonist, IEnumerable companions = null); } public sealed class PartyFactoryOptions { public int minPartySize = 1; public int maxPartySize = 4; public bool enforceUniqueCharacterIds = true; } public sealed class PartyFactory : IPartyFactory { private readonly PartyFactoryOptions options; public PartyFactory(PartyFactoryOptions options = null) { this.options = options ?? new PartyFactoryOptions(); } public PartyDefinition Create(CharacterDefinition protagonist, IEnumerable companions = null) { if(protagonist == null) { throw new ArgumentNullException(nameof(protagonist)); } PartyDefinition party = new PartyDefinition { maxPartySize = options.maxPartySize <= 0 ? int.MaxValue : options.maxPartySize }; CharacterDefinition protagonistClone = protagonist.Clone(); protagonistClone.role = CharacterRole.Protagonist; party.members.Add(protagonistClone); if(companions != null) { foreach(CharacterDefinition companion in companions.Where(c => c != null)) { CharacterDefinition companionClone = companion.Clone(); companionClone.role = CharacterRole.Companion; party.members.Add(companionClone); } } ValidateParty(party); return party; } private void ValidateParty(PartyDefinition party) { if(party.members.Count < options.minPartySize) { throw new ArgumentException($"Party size {party.members.Count} is below minimum {options.minPartySize}."); } if(party.members.Count > party.maxPartySize) { throw new ArgumentException($"Party size {party.members.Count} exceeds max {party.maxPartySize}."); } int protagonistCount = party.members.Count(m => m.role == CharacterRole.Protagonist); if(protagonistCount != 1) { throw new ArgumentException($"Party must contain exactly one protagonist, found {protagonistCount}."); } if(options.enforceUniqueCharacterIds) { int uniqueIds = party.members .Where(m => !string.IsNullOrWhiteSpace(m.ID)) .Select(m => m.ID) .Distinct() .Count(); if(uniqueIds != party.members.Count) { throw new ArgumentException("Party contains duplicate or missing character ids."); } } } } }