Files
LowPolyRPG/Assets/Plugins/Nullframes/Intrigues/Scripts/Clan/Clan.cs
Caleb Sandford deQuincey 715fb68744 Initial commitment
2025-06-25 11:10:11 +01:00

398 lines
18 KiB
C#

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<Policy> policies;
private readonly List<Actor> members;
private readonly List<NVar> variables;
private string _clanName { get; set; }
private string _description { get; set; }
/// <summary>
/// Contains private variables associated with the clan.
/// </summary>
public IEnumerable<NVar> Variables => variables;
/// <summary>
/// Gets the unique ID of the clan.
/// </summary>
public string ID { get; private set; }
/// <summary>
/// Gets the icon of the clan, e.g., a flag icon.
/// </summary>
public Sprite Icon { get; private set; }
/// <summary>
/// Gets the culture of the clan.
/// </summary>
public Culture Culture { get; private set; }
/// <summary>
/// Gets the members of the clan.
/// </summary>
public IEnumerable<Actor> Members => members;
/// <summary>
/// Gets the policies of the clan.
/// </summary>
public IEnumerable<Policy> Policies => policies.Where(policy => policy is { Type: PolicyType.Generic or PolicyType.Clan });
/// <summary>
/// Gets the count of members in the clan.
/// </summary>
public int MemberCount => members.Count;
/// <summary>
/// Gets the name of the clan, e.g., "Arcanum."
/// </summary>
public string ClanName {
get => _clanName.LocaliseText();
private set => _clanName = value;
}
/// <summary>
/// Gets the description of the clan.
/// </summary>
public string Description {
get => _description.LocaliseText();
private set => _description = value;
}
/// <summary>
/// Gets un-localized definition of policy.
/// </summary>
public string DescriptionWithoutLocalisation => _description;
/// <summary>
/// Occurs when a policy is accepted by the clan.
/// </summary>
public event Action<Policy> onPolicyAccepted;
/// <summary>
/// Occurs when a policy is no longer accepted by the clan.
/// </summary>
public event Action<Policy> onPolicyUnaccepted;
/// <summary>
/// Occurs when the clan's name is changed.
/// </summary>
public event Action<string> onClanNameChanged;
/// <summary>
/// Occurs when the clan's icon is changed.
/// </summary>
public event Action<Sprite> onClanIconChanged;
/// <summary>
/// Occurs when the clan's culture is changed.
/// </summary>
public event Action<Culture> onClanCultureChanged;
/// <summary>
/// Occurs when a new member joins the clan.
/// </summary>
public Action<Actor> onMemberJoin;
/// <summary>
/// Occurs when a member leaves the clan.
/// </summary>
public event Action<Actor> onMemberLeave;
/// <summary>
/// Occurs when an actor's role within the clan changes.
/// </summary>
public Action<Actor, Role> onActorRoleChanged;
/// <summary>
/// Retrieves all members of the clan that match a specific role.
/// </summary>
/// <param name="roleFilter">The role to filter the members by, e.g., 'Engineer'.</param>
/// <param name="inclusivePassive">If true, includes passive (e.g., deceased) members in the results.</param>
/// <returns>An enumerable of members matching the role filter.</returns>
public IEnumerable<Actor> 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));
}
/// <summary>
/// Retrieves a member of the clan based on their role.
/// </summary>
/// <param name="roleFilter">The role to filter the members by, e.g., 'Engineer'.</param>
/// <param name="inclusivePassive">If true, includes passive (e.g., deceased) members in the search.</param>
/// <returns>The first member found matching the role filter; null if no match is found.</returns>
/// <remarks>
/// If multiple members have the specified role, this method returns the first one in the list.
/// </remarks>
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));
}
/// <summary>
/// Checks if the clan has accepted a specific policy.
/// </summary>
/// <param name="policyNameOrId">The name or ID of the policy to check.</param>
/// <returns>True if the policy is accepted by the clan; otherwise, false.</returns>
public bool HasPolicy(string policyNameOrId)
{
return !string.IsNullOrEmpty(policyNameOrId) && Policies.Any(p => p.PolicyName == policyNameOrId || p.ID == policyNameOrId);
}
/// <summary>
/// Checks if the clan has accepted any policy.
/// </summary>
/// <returns>True if the clan has any accepted policy; otherwise, false.</returns>
public bool AnyPolicy() => Policies.Any();
/// <summary>
/// Creates a new clan with the specified attributes and adds it to the system.
/// </summary>
/// <param name="clanName">The name of the clan.</param>
/// <param name="description">A description of the clan.</param>
/// <param name="icon">An icon or banner representing the clan visually.</param>
/// <param name="culture">The culture associated with the clan, defining its traditions and practices.</param>
/// <param name="policies">A collection of policies the clan adheres to, defining its rules and governance.</param>
/// <returns>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.</returns>
/// <remarks>
/// 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.
/// </remarks>
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;
}
/// <summary>
/// Creates a new clan with the specified attributes and adds it to the system.
/// </summary>
/// <param name="clanName">The name of the clan.</param>
/// <param name="description">A description of the clan.</param>
/// <param name="icon">An icon or banner representing the clan visually.</param>
/// <param name="cultureNameOrId">The culture name/id associated with the clan, defining its traditions and practices.</param>
/// <param name="policyNameOrId">A collection of policies the clan adheres to, defining its rules and governance.</param>
/// <returns>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.</returns>
/// <remarks>
/// 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.
/// </remarks>
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<Policy> policies, IEnumerable<NVar> vars)
{
ID = id;
members = new List<Actor>();
variables = new List<NVar>(vars);
this.policies = policies != null ? new List<Policy>(policies) : new List<Policy>();
ClanName = clanName;
Description = story;
Icon = icon;
Culture = culture;
}
/// <summary>
/// Checks if an actor is a member of the clan.
/// </summary>
/// <param name="member">The actor to check.</param>
/// <returns>True if the actor is a member of the clan; otherwise, false.</returns>
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;
}
/// <summary>
/// Adds a policy to the clan.
/// </summary>
/// <param name="policyNameOrId">The name or ID of the policy to add.</param>
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);
}
/// <summary>
/// Adds a policy to the clan.
/// </summary>
/// <param name="policy">The policy to add.</param>
public void AddPolicy(Policy policy)
{
if (policy == null) return;
if (Policies.Contains(policy)) return;
policies.Add(policy);
onPolicyAccepted?.Invoke(policy);
}
/// <summary>
/// Removes a policy from the clan.
/// </summary>
/// <param name="policyNameOrId">The name or ID of the policy to remove.</param>
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);
}
/// <summary>
/// Removes a policy from the clan.
/// </summary>
/// <param name="policy">The policy to remove.</param>
public void RemovePolicy(Policy policy)
{
if (policy == null) return;
if (policies.Remove(policy)) onPolicyUnaccepted?.Invoke(policy);
}
/// <summary>
/// Sets the culture of the clan.
/// </summary>
/// <param name="cultureNameOrId">The name or ID of the culture to set.</param>
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);
}
/// <summary>
/// Sets the culture of the clan.
/// </summary>
/// <param name="culture">The culture to set.</param>
public void SetCulture(Culture culture)
{
if (culture == null) return;
var oldCulture = Culture;
Culture = culture;
onClanCultureChanged?.Invoke(oldCulture);
}
/// <summary>
/// Sets the icon of the clan.
/// </summary>
/// <param name="icon">The new icon for the clan.</param>
public void SetIcon(Sprite icon)
{
var oldEmblem = Icon;
Icon = icon;
onClanIconChanged?.Invoke(oldEmblem);
}
/// <summary>
/// Sets the name of the clan.
/// </summary>
/// <param name="clanName">The new name for the clan.</param>
/// <param name="withoutNotification">If set to true, the name change does not trigger a notification event.</param>
/// <remarks>
/// 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.
/// </remarks>
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);
}
/// <summary>
/// Sets the description of the clan.
/// </summary>
/// <param name="description">The new description for the clan.</param>
public void SetDescription(string description)
{
Description = description;
}
/// <summary>
/// Retrieves a private variable from the clan based on its name or ID.
/// </summary>
/// <param name="variableNameOrId">Name or ID of the desired variable.</param>
/// <returns>Returns the corresponding variable from the clan.</returns>
public NVar GetVariable(string variableNameOrId) => variables.Find(v => v.name == variableNameOrId || v.id == variableNameOrId);
/// <summary>
/// Retrieves a private variable from the clan based on its name or ID and casts it to the specified type.
/// </summary>
/// <param name="variableNameOrId">Name or ID of the desired variable.</param>
/// <returns>Returns the corresponding variable of type T from the clan.</returns>
public T GetVariable<T>(string variableNameOrId) where T : NVar => variables.Find(v => v.name == variableNameOrId || v.id == variableNameOrId) as T;
/// <summary>
/// Sets the value of a private variable for the clan.
/// </summary>
/// <param name="variableNameOrId">Name or ID of the variable to set.</param>
/// <param name="value">New value for the clan's variable.</param>
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;
}
/// <summary>
/// Sets the value of a private variable for the clan and returns the updated value cast to the specified type.
/// </summary>
/// <param name="variableNameOrId">Name or ID of the variable to set.</param>
/// <param name="value">New value for the clan's variable.</param>
/// <returns>Returns the updated variable of type T from the clan.</returns>
public T SetVariable<T>(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;
}
}
}