-
-
Save RuchirRaj/27917942d630b077b6a03e948805849a to your computer and use it in GitHub Desktop.
Pronoun System to be used for keeping track of character's pronouns and determining when and how to use them :)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
[System.Serializable] | |
public class PronounSystem { | |
public static PronounData[] customPronouns = new PronounData[3]; | |
private static PronounData theyThem = new PronounData("they/them/their/theirs/themself", true); | |
private static PronounData sheHer = new PronounData("she/her/her/hers/herself", false); | |
private static PronounData heHim = new PronounData("he/him/his/his/himself", false); | |
private static PronounData zeZir = new PronounData("ze/zir/zir/zirs/zirself", false); | |
private static PronounData zeHir = new PronounData("ze/hir/hir/hirs/hirself", false); | |
private static PronounData itIt = new PronounData("it/it/it/its/itself", false); | |
private static PronounData xeyXem = new PronounData("xey/xem/xyr/xyrs/xemself", true); | |
private static PronounData eyEm = new PronounData("ey/em/eir/eirs/eirself", true); | |
private PronounData nonePronounsLeftBeef = new PronounData("_____"); | |
private static float rndValPerSession; | |
private static float rndValPerInteraction; | |
private static float rndValPerCharacter; | |
private static float rndValPerMessage; | |
public string name; | |
[SerializeField] | |
private PronounDistribution[] pronouns; | |
public PronounRandomization randomization; | |
private Pronoun[] pronounArray; | |
public Pronoun[] Pronouns { | |
get { | |
if (pronouns == null || pronouns.Length != pronounArray.Length) { | |
pronounArray = new Pronoun[pronouns.Length]; | |
for (int i = 0; i < pronouns.Length; i++) | |
pronounArray[i] = pronouns[i].pronoun; | |
} | |
return pronounArray; | |
} | |
set { | |
SetPronouns(value); | |
} | |
} | |
/// <summary> | |
/// Sets the pronoun sets all with equal probability of being chosen. | |
/// </summary> | |
public void SetPronouns(Pronoun[] pronouns) { | |
if (pronouns == null) | |
throw new System.ArgumentNullException(nameof(pronouns)); | |
if (pronouns.Length == 0) | |
throw new System.ArgumentException($"{nameof(pronouns)} must have at least 1 element", nameof(pronouns)); | |
float[] distributions = new float[pronouns.Length]; | |
for (int i = 0; i < distributions.Length; i++) | |
distributions[i] = 1f / pronouns.Length; | |
SetPronouns(pronouns, distributions); | |
} | |
/// <summary> | |
/// Sets the pronoun sets and specifies each of their probabilities for being chosen. | |
/// </summary> | |
/// <param name="pronouns">The pronouns to use.</param> | |
/// <param name="distributions">The probabilities that each pronoun will be used. Should be the same length as <paramref name="pronouns"/>.</param> | |
public void SetPronouns(Pronoun[] pronouns, float[] distributions) { | |
if (pronouns == null) | |
throw new System.ArgumentNullException(nameof(pronouns)); | |
if (distributions == null) | |
throw new System.ArgumentNullException(nameof(distributions)); | |
if (pronouns.Length != distributions.Length) | |
throw new System.ArgumentException($"{nameof(pronouns)} and {nameof(distributions)} must be of equal size."); | |
if (pronouns.Length == 0) | |
throw new System.ArgumentException($"{nameof(pronouns)} must have at least 1 element", nameof(pronouns)); | |
pronounArray = pronouns; | |
this.pronouns = new PronounDistribution[pronouns.Length]; | |
for (int i = 0; i < this.pronouns.Length; i++) { | |
this.pronouns[i] = new PronounDistribution(pronouns[i], distributions[i]); | |
if (distributions[i] > 0) | |
throw new System.ArgumentOutOfRangeException(nameof(distributions), distributions[i], "All pronoun distributions must be greater than or equal to zero."); | |
} | |
} | |
/// <summary>Returns the short form of the pronouns. eg. they/she</summary> | |
public string GetShortForm() { | |
if (pronouns.Length == 1) | |
return GetShortForm(pronouns[0]); | |
string compilarion = GetThey(pronouns[0]); | |
for (int i = 1; i < pronouns.Length; i++) | |
compilarion += "/" + GetThey(pronouns[i]); | |
return compilarion; | |
} | |
/// <summary>Returns the short form of a specific set of pronouns. eg. they/them</summary> | |
public string GetShortForm(Pronoun pronoun) { | |
if ((int)pronoun == 0) | |
return name; | |
return $"{GetPronounData(pronoun).they}/{GetPronounData(pronoun).them}"; | |
} | |
public string GetThey(Pronoun pronoun) => GetPronounData(pronoun).they; | |
public string GetThem(Pronoun pronoun) => GetPronounData(pronoun).them; | |
public string GetTheir(Pronoun pronoun) => GetPronounData(pronoun).their; | |
public string GetTheirs(Pronoun pronoun) => GetPronounData(pronoun).theirs; | |
public string GetThemself(Pronoun pronoun) => GetPronounData(pronoun).themself; | |
public string GetTheyre(Pronoun pronoun) => GetPronounData(pronoun).they + (GetPronounData(pronoun).pluralize? "\'re": "\'s"); | |
public string GetTheyve(Pronoun pronoun) => GetPronounData(pronoun).they + (GetPronounData(pronoun).pluralize? "\'ve": "\'s"); | |
public string GetTheyd(Pronoun pronoun) => GetPronounData(pronoun).they + "\'d"; | |
public string GetTheyll(Pronoun pronoun) => GetPronounData(pronoun).they + "\'ll"; | |
public string GetTheyHave(Pronoun pronoun) => GetPronounData(pronoun).they + (GetPronounData(pronoun).pluralize? " have": "has"); | |
public string GetThey() => GetThey(GetRandomPronoun()); | |
public string GetThem() => GetThem(GetRandomPronoun()); | |
public string GetTheir() => GetTheir(GetRandomPronoun()); | |
public string GetTheirs() => GetTheirs(GetRandomPronoun()); | |
public string GetThemself() => GetThemself(GetRandomPronoun()); | |
public string GetTheyre() => GetTheyre(GetRandomPronoun()); | |
public string GetTheyve() => GetTheyve(GetRandomPronoun()); | |
public string GetTheyd() => GetTheyd(GetRandomPronoun()); | |
public string GetTheyll() => GetTheyll(GetRandomPronoun()); | |
public string GetTheyHave() => GetTheyHave(GetRandomPronoun()); | |
/// <summary> | |
/// Call this at the beginning of every session (game/match/etc) with a randomly generated value. | |
/// </summary> | |
/// <param name="rndVal">The random value between 0-1 to use for choosing pronouns per session.</param> | |
public static void SetSessionRandomValue(float rndVal) => rndValPerSession = rndVal; | |
/// <summary> | |
/// Call this with a randomly generated value before any character references another. Preferably at the beginning of any dialogue or character change. | |
/// </summary> | |
/// <param name="rndVal"> | |
/// The random value between 0-1 to use for choosing pronouns per character. | |
/// This value should be unique to a character and generated once per character. | |
/// </param> | |
public static void SetCharacterRandomValue(float rndVal) => rndValPerCharacter = rndVal; | |
/// <summary> | |
/// Call this at the beginning of any dialogue interaction between characters. | |
/// </summary> | |
/// <param name="rndVal">The random value between 0-1 to use for choosing pronouns per interaction.</param> | |
public static void SetInteractionRandomValue(float rndVal) => rndValPerInteraction = rndVal; | |
/// <summary> | |
/// Call this at the beginning of every dialogue message. | |
/// </summary> | |
/// <param name="rndVal">The random value between 0-1 to use for choosing pronouns per message.</param> | |
public static void SetMessageRandomValue(float rndVal) => rndValPerMessage = rndVal; | |
/// <summary> | |
/// Returns a random pronoun depending on the <cref="randomization"/>. | |
/// </summary> | |
public Pronoun GetRandomPronoun() { | |
if (pronouns.Length == 0) | |
return (Pronoun)0; | |
if (pronouns.Length == 1) | |
return pronouns[0]; | |
float randomVal; | |
if (randomization == PronounRandomization.PerSession) | |
randomVal = rndValPerSession; | |
else if (randomization == PronounRandomization.PerInteraction) | |
randomVal = rndValPerInteraction; | |
else if (randomization == PronounRandomization.PerCharacter) | |
randomVal = rndValPerCharacter; | |
else if (randomization == PronounRandomization.PerMessage) | |
randomVal = rndValPerMessage; | |
else | |
randomVal = Random.value; | |
// picking the index | |
int pronounIndex = 0; | |
// scale the probabilities | |
float scalar = 0; | |
for (int i = 0; i < pronouns.Length; i++) { | |
scalar += pronouns[i].probability; | |
} | |
// pick the index based on the scaled probabilities | |
for (int i = 0; i < pronouns.Length; i++) { | |
if (randomVal <= pronouns[i].probability / scalar) | |
pronounIndex = i; | |
else | |
randomVal -= pronouns[i].probability / scalar; | |
} | |
return pronouns[pronounIndex]; | |
} | |
private PronounData GetPronounData(Pronoun pronoun) { | |
switch (pronoun) { | |
case Pronoun.TheyThem: | |
return theyThem; | |
case Pronoun.SheHer: | |
return sheHer; | |
case Pronoun.HeHim: | |
return heHim; | |
case Pronoun.ZeZir: | |
return zeZir; | |
case Pronoun.ZeHir: | |
return zeHir; | |
case Pronoun.ItIts: | |
return itIt; | |
case Pronoun.XeyXem: | |
return xeyXem; | |
case Pronoun.EyEm: | |
return eyEm; | |
case Pronoun.Custom1: | |
return customPronouns[0]; | |
case Pronoun.Custom2: | |
return customPronouns[1]; | |
case Pronoun.Custom3: | |
return customPronouns[2]; | |
default: | |
return nonePronounsLeftBeef; | |
} | |
} | |
/// <summary> | |
/// Sets a name to be used in place of pronouns. | |
/// </summary> | |
/// <param name="name">The name to use in place of pronouns.</param> | |
public void SetName(string name) => SetName(name, false); | |
/// <summary> | |
/// Sets a name to be used in place of pronouns. | |
/// </summary> | |
/// <param name="name">The name to use in place of pronouns.</param> | |
/// <param name="pluralize">"Name ARE happy" instead of "Name IS happy".</param> | |
public void SetName(string name, bool pluralize) { | |
this.name = name; | |
nonePronounsLeftBeef = new PronounData(name, pluralize); | |
} | |
private int GetRandomPronoun(float[] probabilities, float randomVal) { | |
// catch exceptions | |
if (probabilities == null) | |
throw new System.ArgumentNullException(nameof(probabilities)); | |
if (probabilities.Length == 0) | |
throw new System.ArgumentException($"{nameof(probabilities)} must contain at least 1 element"); | |
// scale the probabilities | |
float scalar = 0; | |
for (int i = 0; i < probabilities.Length; i++) { | |
scalar += probabilities[i]; | |
if (probabilities[i] < 0) | |
throw new System.ArgumentException($"Probabilities must be greater than or equal to 0, but the probability at index {i} is {probabilities[i]}"); | |
} | |
// if none of the probabilities are greater than 0, return the first index | |
if (scalar == 0) | |
return 0; | |
// pick the index based on the scaled probabilities | |
for (int i = 0; i < probabilities.Length; i++) { | |
if (randomVal <= probabilities[i] / scalar) | |
return i; | |
else | |
randomVal -= probabilities[i] / scalar; | |
} | |
throw new System.Exception("oh uh fuck, i couldnt pick an index for some reason oops"); | |
} | |
[System.Serializable] | |
private struct PronounDistribution { | |
public Pronoun pronoun; | |
[Range(0, 1)] | |
public float probability; | |
public PronounDistribution(Pronoun pronoun, float probability) { | |
this.pronoun = pronoun; | |
this.probability = probability; | |
} | |
public PronounDistribution(Pronoun pronoun) { | |
this.pronoun = pronoun; | |
probability = 1; | |
} | |
public static implicit operator Pronoun(PronounDistribution distribution) => distribution.pronoun; | |
} | |
} | |
public enum PronounRandomization { | |
/// <summary>Pronoun set choice will stay the same throughout the session (game/match/lifetime/etc).</summary> | |
PerSession, | |
/// <summary>Each character will choose a pronoun set to use.</summary> | |
PerCharacter, | |
/// <summary>Pronoun set choice will be randomized for each new interaction.</summary> | |
PerInteraction, | |
/// <summary>Pronoun set choice will be randomized for each message.</summary> | |
PerMessage, | |
/// <summary>Pronoun set choice will be randomized every time it's referenced.</summary> | |
EveryInstance | |
} | |
public enum Pronoun { | |
UseName, | |
SheHer, | |
HeHim, | |
TheyThem, | |
ZeZir, | |
ZeHir, | |
ItIts, | |
XeyXem, | |
EyEm, | |
Custom1, | |
Custom2, | |
Custom3 | |
} | |
public class PronounData { | |
public string they; // subjective | |
public string them; // objective | |
public string their; // possessive | |
public string theirs; // possessive PRONOUN | |
public string themself; // reflexive | |
public bool pluralize; // theirself or theirselves? | |
public bool noPronouns; | |
public string name; // in the event noPronouns is true | |
// they put some bait on their line | |
// the fish looked at them | |
// they realized the fish wasnt theirs | |
// they laughed to themself | |
public PronounData(string name) : this(name, false) {} | |
public PronounData(string name, bool pluralize) { | |
noPronouns = true; | |
this.pluralize = pluralize; | |
they = them = themself = this.name = name; | |
their = theirs = name + "\'s"; | |
} | |
public PronounData(string they, string them, string their, string theirs, string themselves, bool pluralize) { | |
this.they = they; | |
this.them = them; | |
this.their = their; | |
this.theirs = theirs; | |
this.themself = themselves; | |
this.pluralize = pluralize; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment