using System; using System.Collections.Generic; using System.Linq; using Nullframes.Intrigues.Utils; using UnityEngine; namespace Nullframes.Intrigues { public sealed class Clan { private readonly List policies; private readonly List members; private readonly List variables; private string _clanName { get; set; } private string _description { get; set; } /// /// Contains private variables associated with the clan. /// public IEnumerable Variables => variables; /// /// Gets the unique ID of the clan. /// public string ID { get; private set; } /// /// Gets the icon of the clan, e.g., a flag icon. /// public Sprite Icon { get; private set; } /// /// Gets the culture of the clan. /// public Culture Culture { get; private set; } /// /// Gets the members of the clan. /// public IEnumerable Members => members; /// /// Gets the policies of the clan. /// public IEnumerable Policies => policies.Where(policy => policy is { Type: PolicyType.Generic or PolicyType.Clan }); /// /// Gets the count of members in the clan. /// public int MemberCount => members.Count; /// /// Gets the name of the clan, e.g., "Arcanum." /// public string ClanName { get => _clanName.LocaliseText(); private set => _clanName = value; } /// /// Gets the description of the clan. /// public string Description { get => _description.LocaliseText(); private set => _description = value; } /// /// Gets un-localized definition of policy. /// public string DescriptionWithoutLocalisation => _description; /// /// Occurs when a policy is accepted by the clan. /// public event Action onPolicyAccepted; /// /// Occurs when a policy is no longer accepted by the clan. /// public event Action onPolicyUnaccepted; /// /// Occurs when the clan's name is changed. /// public event Action onClanNameChanged; /// /// Occurs when the clan's icon is changed. /// public event Action onClanIconChanged; /// /// Occurs when the clan's culture is changed. /// public event Action onClanCultureChanged; /// /// Occurs when a new member joins the clan. /// public Action onMemberJoin; /// /// Occurs when a member leaves the clan. /// public event Action onMemberLeave; /// /// Occurs when an actor's role within the clan changes. /// public Action onActorRoleChanged; /// /// Retrieves all members of the clan that match a specific role. /// /// The role to filter the members by, e.g., 'Engineer'. /// If true, includes passive (e.g., deceased) members in the results. /// An enumerable of members matching the role filter. public IEnumerable GetMembers(string roleFilter, bool inclusivePassive = false) { if(inclusivePassive) return Members.Where(m => m.Role?.ID == roleFilter || m.Role?.RoleName == roleFilter); return Members.Where(m => m.State == Actor.IState.Active && (m.Role?.ID == roleFilter || m.Role?.RoleName == roleFilter)); } /// /// Retrieves a member of the clan based on their role. /// /// The role to filter the members by, e.g., 'Engineer'. /// If true, includes passive (e.g., deceased) members in the search. /// The first member found matching the role filter; null if no match is found. /// /// If multiple members have the specified role, this method returns the first one in the list. /// public Actor GetMember(string roleFilter, bool inclusivePassive = false) { if(inclusivePassive) return Members.FirstOrDefault(m => m.Role?.ID == roleFilter || m.Role?.RoleName == roleFilter); return Members.FirstOrDefault(m => m.State == Actor.IState.Active && (m.Role?.ID == roleFilter || m.Role?.RoleName == roleFilter)); } /// /// Checks if the clan has accepted a specific policy. /// /// The name or ID of the policy to check. /// True if the policy is accepted by the clan; otherwise, false. public bool HasPolicy(string policyNameOrId) { return !string.IsNullOrEmpty(policyNameOrId) && Policies.Any(p => p.PolicyName == policyNameOrId || p.ID == policyNameOrId); } /// /// Checks if the clan has accepted any policy. /// /// True if the clan has any accepted policy; otherwise, false. public bool AnyPolicy() => Policies.Any(); /// /// Creates a new clan with the specified attributes and adds it to the system. /// /// The name of the clan. /// A description of the clan. /// An icon or banner representing the clan visually. /// The culture associated with the clan, defining its traditions and practices. /// A collection of policies the clan adheres to, defining its rules and governance. /// If a clan with the same name already exists within the system, the existing clan is returned; otherwise, a new Clan object is created and returned. /// /// This method first checks for the existence of a clan with the provided name to ensure uniqueness within the system. If a clan with the same name is found, /// a debug message is logged, and the existing Clan object is returned, avoiding the creation of duplicate clans. If no such clan exists, a new Clan object is instantiated /// with a generated unique ID and the specified attributes, and then added to the system. This approach ensures that each clan is uniquely identified and properly integrated into the system. /// public static Clan Create(string clanName, string description, Culture culture = null, Sprite icon = null, params Policy[] policies) { var targetClan = IM.Clans.FirstOrDefault((s) => s.ClanName == clanName); if (targetClan != null) { NDebug.Log(string.Format(STATIC.DEBUG_CLAN_SAME_TITLE, clanName)); return targetClan; } var clan = new Clan(NullUtils.GenerateID(), clanName, description, icon, culture, policies.Where(policy => policy is { Type: PolicyType.Generic or PolicyType.Clan }), null); IM.AddClan(clan); return clan; } /// /// Creates a new clan with the specified attributes and adds it to the system. /// /// The name of the clan. /// A description of the clan. /// An icon or banner representing the clan visually. /// The culture name/id associated with the clan, defining its traditions and practices. /// A collection of policies the clan adheres to, defining its rules and governance. /// If a clan with the same name already exists within the system, the existing clan is returned; otherwise, a new Clan object is created and returned. /// /// This method first checks for the existence of a clan with the provided name to ensure uniqueness within the system. If a clan with the same name is found, /// a debug message is logged, and the existing Clan object is returned, avoiding the creation of duplicate clans. If no such clan exists, a new Clan object is instantiated /// with a generated unique ID and the specified attributes, and then added to the system. This approach ensures that each clan is uniquely identified and properly integrated into the system. /// public static Clan Create(string clanName, string description, string cultureNameOrId, Sprite icon = null, params string[] policyNameOrId) { var targetClan = IM.Clans.FirstOrDefault((s) => s.ClanName == clanName); if (targetClan != null) { NDebug.Log(string.Format(STATIC.DEBUG_CLAN_SAME_TITLE, clanName)); return targetClan; } var clan = new Clan(NullUtils.GenerateID(), clanName, description, icon, IM.GetCulture(cultureNameOrId), policyNameOrId.Select(IM.GetPolicy).Where(policy => policy is { Type: PolicyType.Generic or PolicyType.Clan }).ToList(), null); IM.AddClan(clan); return clan; } public Clan(string id, string clanName, string story, Sprite icon, Culture culture, IEnumerable policies, IEnumerable vars) { ID = id; members = new List(); variables = new List(vars); this.policies = policies != null ? new List(policies) : new List(); ClanName = clanName; Description = story; Icon = icon; Culture = culture; } /// /// Checks if an actor is a member of the clan. /// /// The actor to check. /// True if the actor is a member of the clan; otherwise, false. public bool IsMember(Actor member) { return members.Contains(member); } public bool Join(Actor member, bool withoutNotification = false) { if (members.Contains(member)) return false; members.Add(member); if (withoutNotification) return true; onMemberJoin?.Invoke(member); return true; } public bool Quit(Actor member, bool showNotification = true) { if (!members.Remove(member)) return false; if(showNotification) onMemberLeave?.Invoke(member); return true; } /// /// Adds a policy to the clan. /// /// The name or ID of the policy to add. public void AddPolicy(string policyNameOrId) { var policy = IM.Policies.FirstOrDefault(p => p.PolicyName == policyNameOrId || p.ID == policyNameOrId); if (policy == null) return; if (Policies.Contains(policy)) return; policies.Add(policy); onPolicyAccepted?.Invoke(policy); } /// /// Adds a policy to the clan. /// /// The policy to add. public void AddPolicy(Policy policy) { if (policy == null) return; if (Policies.Contains(policy)) return; policies.Add(policy); onPolicyAccepted?.Invoke(policy); } /// /// Removes a policy from the clan. /// /// The name or ID of the policy to remove. public void RemovePolicy(string policyNameOrId) { var policy = Policies.FirstOrDefault(p => p.PolicyName == policyNameOrId || p.ID == policyNameOrId); if (policy == null) return; if (policies.Remove(policy)) onPolicyUnaccepted?.Invoke(policy); } /// /// Removes a policy from the clan. /// /// The policy to remove. public void RemovePolicy(Policy policy) { if (policy == null) return; if (policies.Remove(policy)) onPolicyUnaccepted?.Invoke(policy); } /// /// Sets the culture of the clan. /// /// The name or ID of the culture to set. public void SetCulture(string cultureNameOrId) { var culture = IM.Cultures.FirstOrDefault(p => p.CultureName == cultureNameOrId || p.ID == cultureNameOrId); if (culture == null) return; var oldCulture = Culture; Culture = culture; onClanCultureChanged?.Invoke(oldCulture); } /// /// Sets the culture of the clan. /// /// The culture to set. public void SetCulture(Culture culture) { if (culture == null) return; var oldCulture = Culture; Culture = culture; onClanCultureChanged?.Invoke(oldCulture); } /// /// Sets the icon of the clan. /// /// The new icon for the clan. public void SetIcon(Sprite icon) { var oldEmblem = Icon; Icon = icon; onClanIconChanged?.Invoke(oldEmblem); } /// /// Sets the name of the clan. /// /// The new name for the clan. /// If set to true, the name change does not trigger a notification event. /// /// This method changes the clan's name to the specified new name, provided no other clan already has that name. /// If 'withoutNotification' is false, and the name is successfully changed, the 'onClanNameChanged' event is invoked with the old name. /// An error log is generated if there is already another clan with the specified new name. /// It's important to ensure unique policy names within the system to avoid conflicts. /// public void SetName(string clanName, bool withoutNotification = false) { if (IM.Clans.All(c => c.ClanName != clanName)) { var oldName = ClanName; ClanName = clanName; if(!withoutNotification && oldName != ClanName) onClanNameChanged?.Invoke(oldName); return; } NDebug.Log($"There is already another clan with this name. / {clanName}", NLogType.Error); } /// /// Sets the description of the clan. /// /// The new description for the clan. public void SetDescription(string description) { Description = description; } /// /// Retrieves a private variable from the clan based on its name or ID. /// /// Name or ID of the desired variable. /// Returns the corresponding variable from the clan. public NVar GetVariable(string variableNameOrId) => variables.Find(v => v.name == variableNameOrId || v.id == variableNameOrId); /// /// Retrieves a private variable from the clan based on its name or ID and casts it to the specified type. /// /// Name or ID of the desired variable. /// Returns the corresponding variable of type T from the clan. public T GetVariable(string variableNameOrId) where T : NVar => variables.Find(v => v.name == variableNameOrId || v.id == variableNameOrId) as T; /// /// Sets the value of a private variable for the clan. /// /// Name or ID of the variable to set. /// New value for the clan's variable. public void SetVariable(string variableNameOrId, object value) { var localVariable = variables.Find(v => v.name == variableNameOrId || v.id == variableNameOrId); if (localVariable == null) return; localVariable.value = value; } /// /// Sets the value of a private variable for the clan and returns the updated value cast to the specified type. /// /// Name or ID of the variable to set. /// New value for the clan's variable. /// Returns the updated variable of type T from the clan. public T SetVariable(string variableNameOrId, object value) where T : NVar { var localVariable = variables.Find(v => v.name == variableNameOrId || v.id == variableNameOrId); if (localVariable == null) return null; localVariable.value = value; return localVariable as T; } } }