private void SubtypeButton_Click(object sender, RoutedEventArgs e) { CharacterRelationshipOption selectedRelationship = CollectionControl.SelectedItem as CharacterRelationshipOption; if (selectedRelationship?.ChildOptions?.Count > 0) { CollectionControl.Items.Clear(); ItemsSource = selectedRelationship.ChildOptions; } }
private bool CheckForLover(CharacterRelationshipOption relationship, int numAlready) { if (numAlready >= relationship.Max) return false; if (AgeYears < relationship?.MinAge) return false; if (AgeYears > relationship?.MaxAge) return false; if (HasAnyRelationships(relationship.IncompatibleRelationships) || !HasAllRelationships(relationship.RequiredRelationships)) return false; bool force = false; int weight; if (numAlready > 1 && relationship.SecondWeight.HasValue) weight = relationship.SecondWeight.Value; else if (numAlready > 2 && relationship.ThirdWeight.HasValue) weight = relationship.ThirdWeight.Value; else weight = relationship.GetEffectiveWeight(out force); NoteOption orientationOption = Traits.FindOption("Personality\\Orientation"); CharacterOrientationOption orientation = orientationOption.LowestCheckedChild as CharacterOrientationOption; if (orientation != null) { // An orientation which includes any gender is somewhat more likely than usual to have a lover // (of a different gender than their spouse). if (orientation?.IncludesAny == true) weight = (int)Math.Round(weight * bisexualLoverChanceMultiplier); else { List<CharacterNote> spouses = GetSpouses(); bool orientationSatisfied = false; CharacterGenderOption gender = EffectiveGender; foreach (CharacterNote spouse in spouses) { CharacterGenderOption partnerGender = spouse.EffectiveGender; if (gender == null || partnerGender == null) continue; if (orientation.IncludesSame && gender.Archetype == partnerGender.Name) { orientationSatisfied = true; break; } if (orientation.IncludesSimilar && gender.Archetype == partnerGender.Archetype) { orientationSatisfied = true; break; } if (orientation.IncludesOpposite && gender.Opposite != null && gender.Opposite == partnerGender.Name) { orientationSatisfied = true; break; } if (orientation.IncludesSimilarToOpposite && gender.Opposite != null && gender.Opposite == partnerGender.Archetype) { orientationSatisfied = true; break; } } // There is an even higher chance that a character who is married to someone // of a gender that does not match their preference will take a lover (of a preferred gender). if (!orientationSatisfied) weight = (int)Math.Round(weight * homosexualLoverChanceMultiplier); } } bool chosen = random.Next(1, 101) <= weight * Math.Pow(multipleRelationshipMultiplier, numAlready); return force || chosen; }
public static void AddDefaultRelationships(IdeaTreeTemplate defaultTemplate) { CharacterRelationshipOption relationship = new CharacterRelationshipOption("Significant Other") { MinAgeOffset = -20, MaxAgeOffset = 20, RequiresOrientationMatch = true }; CharacterRelationshipOption subRelationship = new CharacterRelationshipOption("Spouse") { IsChoice = true, Weight = 75, Max = 1, MinAge = 18, SharesMasculineSurname = true, ReciprocalRelationship = "Significant Other\\Spouse", IncompatibleRelationships = new ObservableCollection<string>() { "Significant Other\\Betrothed", "Significant Other\\Sweetheart" } }; subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 1, MaxAge = 24 }); subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 7, MinAge = 25, MaxAge = 29 }); subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 50, MinAge = 36, MaxAge = 39 }); subRelationship.AddChild(new CharacterRelationshipOption("Husband") { Genders = new ObservableCollection<string>() { CharacterGenderOption.manArchetype } }); subRelationship.AddChild(new CharacterRelationshipOption("Wife") { Genders = new ObservableCollection<string>() { CharacterGenderOption.womanArchetype } }); relationship.AddChild(subRelationship); subRelationship = new CharacterRelationshipOption("Betrothed") { IsChoice = true, Weight = 7, Max = 1, MinAge = 18, ReciprocalRelationship = "Significant Other\\Betrothed", IncompatibleRelationships = new ObservableCollection<string>() { "Significant Other\\Spouse", "Significant Other\\Sweetheart" } }; subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 1, MaxAge = 24 }); subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 2, MinAge = 25, MaxAge = 29 }); subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 5, MinAge = 36, MaxAge = 39 }); subRelationship.AddChild(new CharacterRelationshipOption("Fiancé") { Genders = new ObservableCollection<string>() { CharacterGenderOption.manArchetype } }); subRelationship.AddChild(new CharacterRelationshipOption("Fiancée") { Genders = new ObservableCollection<string>() { CharacterGenderOption.womanArchetype } }); relationship.AddChild(subRelationship); subRelationship = new CharacterRelationshipOption("Sweetheart") { IsChoice = true, Weight = 5, Max = 1, MinAge = 13, ReciprocalRelationship = "Significant Other\\Sweetheart", IncompatibleRelationships = new ObservableCollection<string>() { "Significant Other\\Spouse", "Significant Other\\Betrothed" } }; subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 0, MaxAge = 13 }); subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 20, MinAge = 16, MaxAge = 29 }); subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 10, MinAge = 30, MaxAge = 49 }); subRelationship.AddChild(new CharacterRelationshipOption("Boyfriend") { Genders = new ObservableCollection<string>() { CharacterGenderOption.manArchetype } }); subRelationship.AddChild(new CharacterRelationshipOption("Girlfriend") { Genders = new ObservableCollection<string>() { CharacterGenderOption.womanArchetype } }); relationship.AddChild(subRelationship); subRelationship = new CharacterRelationshipOption("Lover") { IsChoice = true, Weight = 2, ReciprocalRelationship = "Significant Other\\Lover", RequiredRelationships = new ObservableCollection<string>() { "Significant Other\\Spouse" } }; subRelationship.AddChild(new CharacterRelationshipOption("Paramour") { Genders = new ObservableCollection<string>() { CharacterGenderOption.manArchetype } }); subRelationship.AddChild(new CharacterRelationshipOption("Mistress") { Genders = new ObservableCollection<string>() { CharacterGenderOption.womanArchetype } }); relationship.AddChild(subRelationship); defaultTemplate.CharacterTemplate.Relationships.AddChild(relationship); relationship = new CharacterRelationshipOption("Ex") { MinAgeOffset = -15, MaxAgeOffset = 15 }; subRelationship = new CharacterRelationshipOption("Ex-Spouse") { IsChoice = true, Weight = 50, SecondWeight = 5, Max = 2, MinAge = 18, ReciprocalRelationship = "Ex\\Ex-Spouse"}; subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 1, MaxAge = 24 }); subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 3, MinAge = 25, MaxAge = 29 }); subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 10, MinAge = 30, MaxAge = 35 }); subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 20, MinAge = 35, MaxAge = 44 }); subRelationship.AddChild(new CharacterRelationshipOption("Ex-Husband") { Genders = new ObservableCollection<string>() { CharacterGenderOption.manArchetype } }); subRelationship.AddChild(new CharacterRelationshipOption("Ex-Wife") { Genders = new ObservableCollection<string>() { CharacterGenderOption.womanArchetype } }); relationship.AddChild(subRelationship); subRelationship = new CharacterRelationshipOption("Ex-Sweetheart") { IsChoice = true, Weight = 5, ReciprocalRelationship = "Ex\\Ex-Sweetheart"}; subRelationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 0, MaxAge = 13 }); subRelationship.AddChild(new CharacterRelationshipOption("Ex-Boyfriend") { Genders = new ObservableCollection<string>() { CharacterGenderOption.manArchetype } }); subRelationship.AddChild(new CharacterRelationshipOption("Ex-Girlfriend") { Genders = new ObservableCollection<string>() { CharacterGenderOption.womanArchetype } }); relationship.AddChild(subRelationship); defaultTemplate.CharacterTemplate.Relationships.AddChild(relationship); relationship = new CharacterRelationshipOption("Child") { IsChoice = true, Weight = 2, MinAgeOffset = -45, MaxAgeOffset = -18, IsBloodRelative = true, AlwaysSharesSurname = true, ReciprocalRelationship = "Parent" }; relationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 0, MaxAge = 29 }); relationship.Modifiers.Add(new NoteOptionCharacterModifier() { Weight = 85, MinAge = 61 }); relationship.AddChild(new CharacterRelationshipOption("Son") { Genders = new ObservableCollection<string>() { CharacterGenderOption.manArchetype } }); relationship.AddChild(new CharacterRelationshipOption("Daughter") { Genders = new ObservableCollection<string>() { CharacterGenderOption.womanArchetype } }); defaultTemplate.CharacterTemplate.Relationships.AddChild(relationship); relationship = new CharacterRelationshipOption("Parent") { IsChoice = true, MinAgeOffset = 18, MaxAgeOffset = 45, Max = 2, IsBloodRelative = true, SharesFamilySurname = true, ReciprocalRelationship = "Child" }; relationship.AddChild(new CharacterRelationshipOption("Father") { Genders = new ObservableCollection<string>() { CharacterGenderOption.manArchetype } }); relationship.AddChild(new CharacterRelationshipOption("Mother") { Genders = new ObservableCollection<string>() { CharacterGenderOption.womanArchetype } }); defaultTemplate.CharacterTemplate.Relationships.AddChild(relationship); relationship = new CharacterRelationshipOption("Sibling") { IsChoice = true, MaxAgeOffset = 27, MinAgeOffset = -27, IsBloodRelative = true, SharesFamilySurname = true }; relationship.AddChild(new CharacterRelationshipOption("Brother") { Genders = new ObservableCollection<string>() { CharacterGenderOption.manArchetype } }); relationship.AddChild(new CharacterRelationshipOption("Sister") { Genders = new ObservableCollection<string>() { CharacterGenderOption.womanArchetype } }); defaultTemplate.CharacterTemplate.Relationships.AddChild(relationship); relationship = new CharacterRelationshipOption("Colleague") { IsFamily = false, Weight = 60, MinAge = 18, MaxAge = 65 }; relationship.AddChild(new CharacterRelationshipOption("Boss") { IsFamily = false, Max = 2, Weight = 40, SecondWeight = 20, MinAge = 25, MaxAge = 65, ReciprocalRelationship = "Colleague\\Employee" }); relationship.AddChild(new CharacterRelationshipOption("Employee") { IsFamily = false, Weight = 10, SecondWeight = 20, ThirdWeight = 50, MinAge = 18, MaxAge = 65, ReciprocalRelationship = "Colleague\\Boss" }); defaultTemplate.CharacterTemplate.Relationships.AddChild(relationship); defaultTemplate.CharacterTemplate.Relationships.AddChild(new CharacterRelationshipOption("Friend") { IsFamily = false, Weight = 80, MinAgeOffset = -5, MaxAgeOffset = 5 }); defaultTemplate.CharacterTemplate.Relationships.AddChild(new CharacterRelationshipOption("Neighbor") { IsFamily = false, Max = 5, Weight = 60, MinAge = 18 }); defaultTemplate.CharacterTemplate.Relationships.AddChild(new CharacterRelationshipOption("Roommate") { IsFamily = false, Max = 3, Weight = 20, MinAge = 18, MinAgeOffset = -5, MaxAgeOffset = 5 }); defaultTemplate.CharacterTemplate.Relationships.AddChild(new CharacterRelationshipOption("Student") { IsFamily = false, Max = 24, Weight = 5, SecondWeight = 75, ThirdWeight = 100, MinAge = 5, MaxAge = 25, MaxAgeOffset = -6, ReciprocalRelationship = "Teacher", IncompatibleRelationships = new ObservableCollection<string>() { "Teacher" } }); defaultTemplate.CharacterTemplate.Relationships.AddChild(new CharacterRelationshipOption("Teacher") { IsFamily = false, Max = 6, Weight = 5, SecondWeight = 80, MinAge = 26, MaxAge = 65, MinAgeOffset = 6, ReciprocalRelationship = "Student", IncompatibleRelationships = new ObservableCollection<string>() { "Student" } }); }
private bool CheckForSpouse(CharacterRelationshipOption relationship, int numAlready) { // Parents' spouses (or lack thereof) are determined by their relative, and not generated at this level. if (Relationship?.IsInPath("Parent") == true) return false; if (relationship != null) return CheckForRelationship(relationship, numAlready); else return false; }
private bool CheckForExSpouse(CharacterRelationshipOption relationship, int numAlready) { // The character must be at least the minimum age for a spouse, plus 3 years for every ex // (including the proposed new one) and also including an additional 3 years if the // character is currently married. This allows for a reasonable amount of time for each // marriage, divorce, and remarriage. if (AgeYears < (18 + (3 * (numAlready + (IsMarried() ? 2 : 1))))) return false; if (relationship != null) return CheckForRelationship(relationship, numAlready); else return false; }
private int CountRelationship(CharacterRelationshipOption relationship) { int count = 0; if (Relationship?.Path.StartsWith(relationship.ReciprocalRelationship) == true) count++; count += Ideas.Count(i => i.IdeaNoteType == nameof(CharacterNote) && ((CharacterNote)i).Relationship.Path.StartsWith(relationship.Path)); return count; }
private bool CheckForRelationship(CharacterRelationshipOption relationship, int numAlready) { if (numAlready >= relationship.Max) return false; if (AgeYears < relationship?.MinAge) return false; if (AgeYears > relationship?.MaxAge) return false; if (HasAnyRelationships(relationship.IncompatibleRelationships) || !HasAllRelationships(relationship.RequiredRelationships)) return false; bool force = false; int weight; if (numAlready > 1 && relationship.SecondWeight.HasValue) weight = relationship.SecondWeight.Value; else if (numAlready > 2 && relationship.ThirdWeight.HasValue) weight = relationship.ThirdWeight.Value; else weight = relationship.GetEffectiveWeight(out force); bool chosen = random.Next(1, 101) <= (weight * Math.Pow(multipleRelationshipMultiplier, numAlready)); return force || chosen; }
private void SetRelationshipMatchingGender(CharacterNote partner, CharacterRelationshipOption relationship) { // If the relationship is orientation-specific, pick an appropriate gender. bool choseGender = false; if (relationship.RequiresOrientationMatch) { NoteOption orientationOptions = partner.Traits.FindOption("Personality\\Orientation"); CharacterOrientationOption partnerOrientation = orientationOptions.LowestCheckedChild as CharacterOrientationOption; choseGender = SetOrientationMatchedGender(partner, partnerOrientation); // A choice must only be forced if the partner has an orientation, and it is gender-specific. if (partnerOrientation != null && !partnerOrientation.IncludesAny) { // Ensure gender options are up to date. if (RootSaveFile?.Template?.CharacterTemplate?.Genders != null) Genders.MergeWithOption(RootSaveFile.Template.CharacterTemplate.Genders, false); List<CharacterGenderOption> genders = new List<CharacterGenderOption>(); if (partnerOrientation.IncludesSimilarToOpposite) genders.AddRange(Genders.GetArchetypeClone(partner.EffectiveGender.Opposite).ChildOptions.Cast<CharacterGenderOption>()); else if (partnerOrientation.IncludesOpposite) genders.AddRange(Genders.FindOptionsByName(new List<NoteOption>(), partner.EffectiveGender.Opposite).Cast<CharacterGenderOption>()); if (partnerOrientation.IncludesSimilar) genders.AddRange(Genders.GetArchetypeClone(partner.EffectiveGender.Archetype).ChildOptions.Cast<CharacterGenderOption>()); else if (partnerOrientation.IncludesSame) genders.AddRange(Genders.FindOptionsByName(new List<NoteOption>(), partner.EffectiveGender.Archetype).Cast<CharacterGenderOption>()); if (genders.Count > 0) { // Use a dummy NoteOption so that the weighted choice algorithms may be leveraged. NoteOption genderOptions = new NoteOption() { RootIdea = this, ChildOptions = new ObservableCollection<NoteOption>(genders), IsChoice = true }; genderOptions.Choose(); Genders.FindOption(genderOptions.LowestCheckedChild.Path).IsChecked = true; choseGender = true; } } } // Otherwise, choose one at random. if (!choseGender) ChooseGender(); foreach (CharacterRelationshipOption childRelationship in relationship.ChildOptions) { if (childRelationship.Genders.Any(g => g == EffectiveGender.Archetype)) { Relationship = childRelationship; return; } } return; }
private bool ShouldHaveChildren(CharacterRelationshipOption relationship, bool woman, bool married, bool divorced) { bool force; int weight = relationship.GetEffectiveWeight(out force); if (force) return true; // Certain situations will override the usual weight. if (married) { if (random.Next(1, 101) > chanceToHaveKidsWhenMarried) return false; } else if (divorced && woman) // 50% chance of being a single divorced mom. { if (random.Next(1, 101) > chanceToHaveKids_SingleDivorcedMom) return false; } else if (AgeYears >= 30 && AgeYears <= 60) { if (woman) // 10% chance of being a single mom (not divorced) between ages 30 and 60. { if (random.Next(1, 101) > chanceToHaveKids_SingleUndivorcedMom_30to60) return false; } else if (divorced) // 10% chance of being a single divorced dad between ages 30 and 60. { if (random.Next(1, 101) > chanceToHaveKids_SingleDivorcedDad_30to60) return false; } } // In other situations, the usual weight is used. else if (random.Next(101) > weight) return false; return true; }
private void CalculateChildAgeRange(CharacterRelationshipOption childRelationship, out int minChildAge, out int maxChildAge) { minChildAge = int.MinValue; maxChildAge = int.MaxValue; if (childRelationship == null) return; if (childRelationship.MinAgeOffset.HasValue) minChildAge = AgeYears + childRelationship.MinAgeOffset.Value; if (childRelationship.MaxAgeOffset.HasValue) maxChildAge = AgeYears + childRelationship.MaxAgeOffset.Value; if (!EffectiveGender.IsFeminine) // Non-women determine their children's possible ages from their female spouse, if possible. { IEnumerable<CharacterNote> wives = GetSpouses().Where(s => s.EffectiveGender.IsFeminine).Cast<CharacterNote>(); if (wives.Count() > 0) { if (childRelationship.MinAgeOffset.HasValue) minChildAge = wives.Min(w => w.AgeYears) + childRelationship.MinAgeOffset.Value; if (childRelationship.MaxAgeOffset.HasValue) maxChildAge = wives.Max(w => w.AgeYears) + childRelationship.MaxAgeOffset.Value; } else // If no female spouses are found, adjust the range already set from this character by the likely offsets for the missing mother. { CharacterRelationshipOption wifeRelationship = RootSaveFile.Template.CharacterTemplate.Relationships.FindOption("Wife") as CharacterRelationshipOption; if (wifeRelationship != null) { minChildAge += wifeRelationship.MinAgeOffset ?? 0; maxChildAge += wifeRelationship.MaxAgeOffset ?? 0; } } } }
private void ReconcileOrientation(CharacterNote partner, CharacterRelationshipOption relationship) { NoteOption orientationOptions = Traits.FindOption("Personality\\Orientation"); if (orientationOptions == null) return; // No adjustment necessary/possible without any orientation traits. CharacterOrientationOption orientation = orientationOptions.LowestCheckedChild as CharacterOrientationOption; if (orientation == null || orientation.IncludesAny == true) return; // No adjustment necessary; any gender is accepted. CharacterGenderOption gender = EffectiveGender; CharacterGenderOption partnerGender = partner.EffectiveGender; if (gender == null || partnerGender == null) return; // No adjustment possible without gender information. List<NoteOption> candidateOrientations = new List<NoteOption>(); if (gender.Opposite == partnerGender.Archetype && !orientation.IncludesOpposite && !orientation.IncludesSimilarToOpposite) candidateOrientations.AddRange(orientationOptions.ChildOptions.Cast<CharacterOrientationOption>().Where(o => o.IncludesOpposite || o.IncludesSimilarToOpposite || o.IncludesAny)); else if (gender.Archetype == partnerGender.Archetype && !orientation.IncludesSame && !orientation.IncludesSimilar) candidateOrientations.AddRange(orientationOptions.ChildOptions.Cast<CharacterOrientationOption>().Where(o => o.IncludesSame || o.IncludesSimilar || o.IncludesAny)); else if (gender.Opposite == partnerGender.Name && !orientation.IncludesOpposite) candidateOrientations.AddRange(orientationOptions.ChildOptions.Cast<CharacterOrientationOption>().Where(o => o.IncludesOpposite || o.IncludesAny)); else if (gender.Archetype == partnerGender.Name && !orientation.IncludesSame) candidateOrientations.AddRange(orientationOptions.ChildOptions.Cast<CharacterOrientationOption>().Where(o => o.IncludesSame || o.IncludesAny)); if (candidateOrientations.Count > 0) { // Use a dummy NoteOption so that the weighted choice algorithms may be leveraged. NoteOption options = new NoteOption() { RootIdea = this, ChildOptions = new ObservableCollection<NoteOption>(candidateOrientations), IsChoice = true }; orientationOptions.DeselectAllChildren(); options.Choose(); } }
public CharacterNote AddNewFamilyMember(CharacterRelationshipOption relationship, bool manual) { if (relationship == null) return null; CharacterNote newNote = new CharacterNote(); AddChild(newNote); // First see if the relationship specified is a gender-neutral option with gender-specific child options. // If so, choose a gender first, then select the appropriate child relationship. bool genderChosen = false; if (relationship.Genders?.Count == 0 && relationship.ChildOptions.Cast<CharacterRelationshipOption>().Count(c => c.Genders?.Count > 0) > 1) { newNote.SetRelationshipMatchingGender(this, relationship); genderChosen = true; } // If no gender-specific options were selected, the choice will // fall back on the gender-neutral original below. if (newNote.Relationship == null) newNote.Relationship = relationship; // False return means no valid age range exists for the relationship (min > max). // Ignored when adding manually. if (!newNote.ChooseAge() && !manual) { Ideas.Remove(newNote); return null; } if (!genderChosen) newNote.ChooseGender(); newNote.SetInheritedRaces(); newNote.AssignFamilySurname(); newNote.AssignFamilyFirstName(); if (RootSaveFile?.Template?.CharacterTemplate?.Traits != null) newNote.Traits.MergeWithOption(RootSaveFile.Template.CharacterTemplate.Traits, true); newNote.Traits.Choose(); if (newNote.Relationship.RequiresOrientationMatch) { newNote.ReconcileOrientation(this, newNote.Relationship); CharacterRelationshipOption reciprocalRelationship = RootSaveFile.Template.CharacterTemplate.Relationships.FindOption(newNote.Relationship.ReciprocalRelationship) as CharacterRelationshipOption; ReconcileOrientation(newNote, reciprocalRelationship); } return newNote; }
private void GenerateSignificantOthers(CharacterRelationshipOption relationship) { int numAlready = CountRelationship(relationship); while (GenerateSignificantOther(relationship, numAlready)) numAlready++; }
private bool GenerateSignificantOther(CharacterRelationshipOption relationship, int numAlready) { if (relationship.IsInPath("Spouse")) { if (!CheckForSpouse(relationship, numAlready)) return false; } else if (relationship.IsInPath("Ex-Spouse")) { if (!CheckForExSpouse(relationship, numAlready)) return false; } else if (relationship.IsInPath("Lover")) { if (!CheckForLover(relationship, numAlready)) return false; } else if (!CheckForRelationship(relationship, numAlready)) return false; CharacterNote newNote = new CharacterNote(); AddChild(newNote); newNote.Relationship = relationship; if (!relationship.RequiresOrientationMatch || !newNote.SetSignificantOtherGender(this, relationship)) newNote.ChooseGender(); int? minimum, maximum; GetSignificantOtherAgeRange(newNote.EffectiveGender, out minimum, out maximum); if (!newNote.ChooseAge(false, minimum, maximum)) // False return means no valid age range exists for the relationship (min > max). { Ideas.Remove(newNote); return false; } newNote.SetInheritedRaces(); newNote.AssignFamilySurname(); newNote.AssignFamilyFirstName(); if (RootSaveFile?.Template?.CharacterTemplate?.Traits != null) newNote.Traits.MergeWithOption(RootSaveFile.Template.CharacterTemplate.Traits, true); newNote.Traits.Choose(); // There is a chance that a character of any orientation will be in a // heterosexual marriage (or ex-marriage), due to societal pressure. // Otherwise, the new character's orientation will be adjusted, if necessary, to // fit the relationship. if (relationship.RequiresOrientationMatch && (!relationship.Path.Contains("Spouse") || random.Next(101) > chanceOfForcedHeteroMarriage || EffectiveGender?.Archetype != newNote.EffectiveGender?.Opposite)) newNote.ReconcileOrientation(this, newNote.Relationship); return true; }
private bool SetSignificantOtherGender(CharacterNote partner, CharacterRelationshipOption relationship) { // Ensure gender options are up to date. if (RootSaveFile?.Template?.CharacterTemplate?.Genders != null) Genders.MergeWithOption(RootSaveFile.Template.CharacterTemplate.Genders, false); // There is a chance that any character, regardless of actual orientation, will be in // a hetero marriage (or ex-marriage), due to the pressure of social conventions. if (relationship.Path.Contains("Spouse") && random.Next(101) <= chanceOfForcedHeteroMarriage) { CharacterGenderOption gender = Genders.FindOptionsByName(new List<NoteOption>(), partner.EffectiveGender?.Opposite).FirstOrDefault() as CharacterGenderOption; if (gender != null) { gender.IsChecked = true; return true; } } // Otherwise, select a gender that corresponds to the character's orientation. NoteOption orientationOption = partner.Traits.FindOption("Personality\\Orientation"); CharacterOrientationOption partnerOrientation = orientationOption.LowestCheckedChild as CharacterOrientationOption; if (partnerOrientation != null) { // When selecting a lover, a character whose orientation includes multiple genders // has a high chance that their extra-marital relationship will be with someone of // a gender not represented in their marriage. if (relationship.IsInPath("Lover") && partnerOrientation.IncludesMultiple && random.Next(101) <= chanceOfAlternateGenderLoverForBisexual) { IEnumerable<CharacterGenderOption> spouseGenders = partner.GetSpouses().Select(s => s.EffectiveGender); List<CharacterGenderOption> candidateGenders = Genders.ChildOptions.Cast<CharacterGenderOption>().Where(g => !spouseGenders.Any(s => s.Archetype == g.Archetype)).ToList(); if (candidateGenders.Count > 0) { // Use a dummy NoteOption so that the weighted choice algorithms may be leveraged. NoteOption genderOptions = new NoteOption() { RootIdea = this, ChildOptions = new ObservableCollection<NoteOption>(candidateGenders), IsChoice = true }; genderOptions.Choose(); return true; } } return SetOrientationMatchedGender(partner, partnerOrientation); } return false; }
public void AddFamilyMember(CharacterRelationshipOption relationship) { if (CurrentIdeaNote?.IdeaNoteType != nameof(CharacterNote) || relationship == null) return; CharacterNote newNote = CurrentCharacterNote.AddNewFamilyMember(relationship, true); CurrentCharacterNote.IsExpanded = true; newNote.IsSelected = true; }