Beispiel #1
0
        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;
            }
        }
Beispiel #2
0
        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;
        }
Beispiel #3
0
        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" }
            });
        }
Beispiel #4
0
 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;
 }
Beispiel #5
0
        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;
        }
Beispiel #6
0
        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;
        }
Beispiel #7
0
        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;
        }
Beispiel #8
0
        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;
        }
Beispiel #9
0
        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;
        }
Beispiel #10
0
        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;
                    }
                }
            }
        }
Beispiel #11
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();
            }
        }
Beispiel #12
0
        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;
        }
Beispiel #13
0
 private void GenerateSignificantOthers(CharacterRelationshipOption relationship)
 {
     int numAlready = CountRelationship(relationship);
     while (GenerateSignificantOther(relationship, numAlready)) numAlready++;
 }
Beispiel #14
0
        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;
        }
Beispiel #15
0
        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;
        }
Beispiel #16
0
 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;
 }