using System; using System.Collections.Generic; using System.Linq; using Nullframes.Intrigues.Utils; using UnityEngine; namespace Nullframes.Intrigues { public sealed class Family { private readonly List policies; private readonly List members; private readonly List variables; private string _familyName { get; set; } private string _description { get; set; } /// /// Contains private variables associated with the family. /// public IEnumerable Variables => variables; /// /// Gets the unique ID of the family. /// public string ID { get; private set; } /// /// Gets the name of the family. /// public string FamilyName { get => _familyName.LocaliseText(); private set => _familyName = value; } /// /// Gets the description of the family. /// public string Description { get => _description.LocaliseText(); private set => _description = value; } /// /// Gets un-localized definition of family. /// 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; /// /// Gets the emblem of the family. /// public Sprite Icon { get; private set; } /// /// Gets the culture associated with the family. /// public Culture Culture { get; private set; } /// /// Gets the members of the family. /// public IEnumerable Members => members; /// /// Gets the policies of the clan. /// public IEnumerable Policies => policies.Where(policy => policy is { Type: PolicyType.Generic or PolicyType.Family }); /// /// Gets the count of members in the family. /// public int MemberCount => members.Count; /// /// Occurs when the family's name is changed. /// public event Action onFamilyNameChanged; /// /// Occurs when the family's icon is changed. /// public event Action onFamilyIconChanged; /// /// Occurs when the family's culture is changed. /// public event Action onFamilyCultureChanged; /// /// Occurs when a new member joins the family. /// public Action onMemberJoin; /// /// Occurs when a member leaves the family. /// public event Action onMemberLeave; /// /// Checks if the family has accepted a specific policy. /// /// The name or ID of the policy to check. /// True if the policy is accepted by the family; otherwise, false. public bool HasPolicy(string policyNameOrId) { return !string.IsNullOrEmpty(policyNameOrId) && Policies.Any(p => p.PolicyName == policyNameOrId || p.ID == policyNameOrId); } /// /// Checks if the family has accepted any policy. /// /// True if the clan has any accepted policy; otherwise, false. public bool AnyPolicy() => Policies.Any(); /// /// Creates a new family with specified attributes and adds it to the system. /// /// The name of the family. /// A description of the family's history, values, or notable characteristics. /// A visual representation (banner) of the family. /// The culture associated with the family, defining its traditions and practices. /// A collection of policies the clan adheres to, defining its rules and governance. /// If a family with the same name already exists, the existing family is returned; otherwise, a new Family object is created and added to the system. /// /// Before creating a new family, this method checks for the existence of a family with the provided name to ensure that each family within the system is unique. If a matching family is found, /// a debug message is generated, and the existing Family object is returned to prevent duplication. If no matching family is found, a new Family object is instantiated with a generated unique ID and the provided attributes, then added to the system. This ensures that family names are distinct and correctly managed within the system. /// public static Family Create(string familyName, string description, Culture culture = null, Sprite icon = null, params Policy[] policies) { var targetFamily = IM.Families.FirstOrDefault((s) => s.FamilyName == familyName); if (targetFamily != null) { NDebug.Log(string.Format(STATIC.DEBUG_FAMILY_SAME_TITLE, familyName)); return targetFamily; } var family = new Family(NullUtils.GenerateID(), familyName, description, icon, culture, policies.Where(policy => policy is { Type: PolicyType.Generic or PolicyType.Family }), null); IM.AddFamily(family); return family; } /// /// Creates a new family with specified attributes and adds it to the system. /// /// The name of the family. /// A description of the family's history, values, or notable characteristics. /// A visual representation (banner) of the family. /// The culture name/id associated with the family, defining its traditions and practices. /// A collection of policies the clan adheres to, defining its rules and governance. /// If a family with the same name already exists, the existing family is returned; otherwise, a new Family object is created and added to the system. /// /// Before creating a new family, this method checks for the existence of a family with the provided name to ensure that each family within the system is unique. If a matching family is found, /// a debug message is generated, and the existing Family object is returned to prevent duplication. If no matching family is found, a new Family object is instantiated with a generated unique ID and the provided attributes, then added to the system. This ensures that family names are distinct and correctly managed within the system. /// public static Family Create(string familyName, string description, string cultureNameOrId, Sprite icon, params string[] policyNameOrId) { var targetFamily = IM.Families.FirstOrDefault((s) => s.FamilyName == familyName); if (targetFamily != null) { NDebug.Log(string.Format(STATIC.DEBUG_FAMILY_SAME_TITLE, familyName)); return targetFamily; } var family = new Family(NullUtils.GenerateID(), familyName, description, icon, IM.GetCulture(cultureNameOrId), policyNameOrId.Select(IM.GetPolicy).Where(policy => policy is { Type: PolicyType.Generic or PolicyType.Family }), null); IM.AddFamily(family); return family; } public Family(string id, string familyName, string description, Sprite icon, Culture culture, IEnumerable policies, IEnumerable vars) { members = new List(); variables = new List(vars); this.policies = policies != null ? new List(policies) : new List(); ID = id; FamilyName = familyName; Description = description; Icon = icon; Culture = culture; } /// /// Checks if an actor is a member of the family. /// /// The actor to check. /// True if the actor is a member of the family; 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 family. /// /// 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 family. /// /// The policy to remove. public void RemovePolicy(Policy policy) { if (policy == null) return; if (policies.Remove(policy)) onPolicyUnaccepted?.Invoke(policy); } /// /// Sets the name of the family. /// /// The new name for the family. /// If set to true, the name change does not trigger a notification event. /// /// This method changes the family's name to the specified new name, provided no other family already has that name. /// If 'withoutNotification' is false and the name is successfully changed, the 'onFamilyNameChanged' event is invoked with the old name. /// An error log is generated if there is already another family with the specified new name. /// Ensuring unique family names within the system is crucial to avoid conflicts. /// public void SetName(string familyName, bool withoutNotification = false) { if (IM.Families.All(c => c.FamilyName != familyName)) { var oldName = FamilyName; FamilyName = familyName; if(!withoutNotification && oldName != FamilyName) onFamilyNameChanged?.Invoke(oldName); return; } NDebug.Log($"There is already another family with this name. / {familyName}", NLogType.Error); } /// /// Sets the icon of the family. /// /// The new icon for the family. public void SetIcon(Sprite icon) { var oldEmblem = Icon; Icon = icon; onFamilyIconChanged?.Invoke(oldEmblem); } /// /// Sets the culture of the family. /// /// The new culture for the family. public void SetCulture(string cultureName) { var culture = IM.Cultures.FirstOrDefault(p => p.CultureName == cultureName); if (culture == null) return; var oldCulture = Culture; Culture = culture; onFamilyCultureChanged?.Invoke(oldCulture); } /// /// Sets the description of the family. /// /// The new description for the family. public void SetDescription(string description) { Description = description; } /// /// Retrieves a private variable from the family based on its name or ID. /// /// Name or ID of the desired variable. /// Returns the corresponding variable from the family. public NVar GetVariable(string variableNameOrId) => variables.Find(v => v.name == variableNameOrId || v.id == variableNameOrId); /// /// Retrieves a private variable from the family 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 family. 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 family. /// /// Name or ID of the variable to set. /// New value for the family'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 family and returns the updated value cast to the specified type. /// /// Name or ID of the variable to set. /// New value for the family's variable. /// Returns the updated variable of type T from the family. 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; } } }