Esempio n. 1
0
        /// <summary>
        /// Update the set of recruits
        /// </summary>
        internal void CreateRecruits()
        {
            var recuritsToRemove = new List <string>();

            //remove recruits from iat and randomly select to remove them from pool of available recruits
            foreach (var member in Recruits)
            {
                var path = Path.Combine(storageLocation, member.Value.RolePlayCharacter.VoiceName + ".rpc").Replace("\\", "/");
                iat.RemoveCharacters(new List <int> {
                    iat.GetAllCharacterSources().First(c => c.Source.Replace("\\", "/") == path).Id
                });
                if (StaticRandom.Int(0, 100) % ConfigKey.RecruitChangeChance.GetIntValue() != 0)
                {
                    recuritsToRemove.Add(member.Key);
                }
            }
            foreach (var member in recuritsToRemove)
            {
                Recruits.Remove(member);
            }

            //for the amount of empty recruit spaces, create a new recruit
            var amount = ConfigKey.RecruitCount.GetIntValue() - Recruits.Count;

            for (var i = 0; i < amount; i++)
            {
                var position  = Boat.GetWeakestPosition(CrewMembers.Values.Concat(Recruits.Values).ToList());
                var newMember = new CrewMember(position, Nationality);
                UniqueNameCheck(newMember);
                Recruits.Add(newMember.Name, newMember);
            }
            var storeNum = 0;

            //set up the files for each recruit and their avatar
            foreach (var recruit in Recruits)
            {
                recruit.Value.CreateRecruitFile(iat, storageLocation, storeNum);
                storeNum++;
            }
            iat.Save();
        }
Esempio n. 2
0
 /// <summary>
 /// Create opinions for everyone included in the list for this CrewMember
 /// </summary>
 internal void CreateInitialOpinions(List <string> people, bool save = false)
 {
     foreach (var person in people)
     {
         if (person == Name)
         {
             continue;
         }
         AddOrUpdateOpinion(person, StaticRandom.Int(ConfigKey.DefaultOpinionMin.GetIntValue(), ConfigKey.DefaultOpinionMax.GetIntValue() + 1));
         //if the two people share the same last name, give the bonus stated in the config to their opinion
         if (person.GetType() == typeof(CrewMember) && LastName == person.Split(new[] { ' ' }, 2).Last())
         {
             AddOrUpdateOpinion(person, ConfigKey.LastNameBonusOpinion.GetIntValue());
         }
         AddOrUpdateRevealedOpinion(person, 0, false);
     }
     if (save)
     {
         SaveStatus();
     }
 }
Esempio n. 3
0
 /// <summary>
 /// Randomly select the gender of the CrewMember
 /// </summary>
 private string SelectGender()
 {
     return(StaticRandom.Int(0, 1000) % 2 == 0 ? "M" : "F");
 }
Esempio n. 4
0
 /// <summary>
 /// Constructor for creating a CrewMember with a random age/gender/name
 /// </summary>
 internal CrewMember(Position position, string nationality) : this()
 {
     Gender      = SelectGender();
     Age         = StaticRandom.Int(18, 45);
     Nationality = nationality;
     SelectRandomName();
     foreach (Skill skill in Enum.GetValues(typeof(Skill)))
     {
         if (position != Position.Null)
         {
             Skills[skill] = position.RequiresSkill(skill) ? StaticRandom.Int(ConfigKey.GoodPositionRating.GetIntValue(), 11) : StaticRandom.Int(1, ConfigKey.BadPositionRating.GetIntValue() + 1);
         }
         else
         {
             Skills[skill] = StaticRandom.Int(ConfigKey.RandomSkillLow.GetIntValue(), ConfigKey.RandomSkillHigh.GetIntValue() + 1);
         }
     }
 }
Esempio n. 5
0
        /// <summary>
        /// Make changes based off of post-race events
        /// </summary>
        private void PostRaceFeedback(string ev, Team team, List <string> subjects)
        {
            var spacelessName = Name.NoSpaces();
            var eventString   = EventHelper.ActionStart("Player", $"PostRace({ev})", spacelessName);

            if (ev.Contains("("))
            {
                eventString = EventHelper.ActionStart("Player", ev, spacelessName);
            }
            //event perceived to trigger any mood change events kept in the EA file
            RolePlayCharacter.Perceive(eventString);
            if (Enum.IsDefined(typeof(PostRaceEventImpact), ev))
            {
                //trigger different changes based off of what dialogue the player last picked
                switch ((PostRaceEventImpact)Enum.Parse(typeof(PostRaceEventImpact), ev))
                {
                //improve opinion of manager, crew member now expects to be picked in the selected position (subjects[0]) next race
                case PostRaceEventImpact.ExpectedPosition:
                    AddOrUpdateOpinion(team.ManagerName, 1);
                    UpdateSingleBelief(NPCBelief.ExpectedPosition, subjects[0]);
                    break;

                //improve opinion of manager, crew member now expects to be picked in the selected position (subjects[0]) in two races time
                case PostRaceEventImpact.ExpectedPositionAfter:
                    AddOrUpdateOpinion(team.ManagerName, 1);
                    UpdateSingleBelief(NPCBelief.ExpectedPositionAfter, subjects[0]);
                    break;

                //make opinion of manager worse
                case PostRaceEventImpact.ManagerOpinionWorse:
                    AddOrUpdateOpinion(team.ManagerName, -1);
                    break;

                //make all crew members' opinion of manager worse
                case PostRaceEventImpact.ManagerOpinionAllCrewWorse:
                    foreach (var cm in team.CrewMembers)
                    {
                        cm.Value.AddOrUpdateOpinion(team.ManagerName, -2);
                        cm.Value.SaveStatus();
                    }
                    break;

                //improve opinion of manager
                case PostRaceEventImpact.ManagerOpinionBetter:
                    AddOrUpdateOpinion(team.ManagerName, 1);
                    break;

                //make all crew members' opinion of manager better
                case PostRaceEventImpact.ManagerOpinionAllCrewBetter:
                    foreach (var cm in team.CrewMembers)
                    {
                        cm.Value.AddOrUpdateOpinion(team.ManagerName, 2);
                        cm.Value.SaveStatus();
                    }
                    break;

                //improve opinion of manager greatly
                case PostRaceEventImpact.ManagerOpinionMuchBetter:
                    AddOrUpdateOpinion(team.ManagerName, 5);
                    break;

                //make opinion of manager much worse
                case PostRaceEventImpact.ManagerOpinionMuchWorse:
                    AddOrUpdateOpinion(team.ManagerName, -5);
                    break;

                //reveal two random skills for this crew member (can be already revealed skills)
                case PostRaceEventImpact.RevealTwoSkills:
                    AddOrUpdateOpinion(team.ManagerName, 1);
                    for (var i = 0; i < 2; i++)
                    {
                        var randomStat = Math.Pow(2, StaticRandom.Int(0, Skills.Count));
                        var statName   = ((Skill)randomStat).ToString();
                        var statValue  = Skills[(Skill)randomStat];
                        RevealedSkills[(Skill)randomStat] = statValue;
                        UpdateSingleBelief(NPCBelief.RevealedSkill, statValue, statName);
                    }
                    break;

                //reveal four random skills for this crew member (can be already revealed skills)
                case PostRaceEventImpact.RevealFourSkills:
                    AddOrUpdateOpinion(team.ManagerName, 3);
                    for (var i = 0; i < 4; i++)
                    {
                        var randomStat = Math.Pow(2, StaticRandom.Int(0, Skills.Count));
                        var statName   = ((Skill)randomStat).ToString();
                        var statValue  = Skills[(Skill)randomStat];
                        RevealedSkills[(Skill)randomStat] = statValue;
                        UpdateSingleBelief(NPCBelief.RevealedSkill, statValue, statName);
                    }
                    break;

                //improve all crew members' opinion of the crew member who was the subject of the event (subjects[0]) greatly and reveals their opinion.
                //Regex adds spaces back before each capital letter
                case PostRaceEventImpact.ImproveConflictOpinionGreatly:
                    var subGreatHelp = Regex.Replace(subjects[0], @"((?<=\p{Ll})\p{Lu})|((?!\A)\p{Lu}(?>\p{Ll}))", " $0");
                    foreach (var cm in team.CrewMembers)
                    {
                        if (cm.Key != subGreatHelp)
                        {
                            cm.Value.AddOrUpdateOpinion(subGreatHelp, 2);
                            cm.Value.AddOrUpdateRevealedOpinion(subGreatHelp, cm.Value.CrewOpinions[subGreatHelp]);
                            cm.Value.SaveStatus();
                        }
                    }
                    break;

                //improve all crew members' opinion of the crew member who was the subject of the event (subjects[0]) and reveals their opinion.
                //Regex adds spaces back before each capital letter
                case PostRaceEventImpact.ImproveConflictTeamOpinion:
                    var subHelp = Regex.Replace(subjects[0], @"((?<=\p{Ll})\p{Lu})|((?!\A)\p{Lu}(?>\p{Ll}))", " $0");
                    foreach (var cm in team.CrewMembers)
                    {
                        if (cm.Key != subHelp)
                        {
                            cm.Value.AddOrUpdateOpinion(subHelp, 1);
                            cm.Value.AddOrUpdateRevealedOpinion(subHelp, cm.Value.CrewOpinions[subHelp]);
                            cm.Value.SaveStatus();
                        }
                    }
                    break;

                //reveals all crew members' opinion of the crew member who was the subject of the event (subjects[0]) and slightly improves this the opinion of the manager for this crew member.
                //Regex adds spaces back before each capital letter
                case PostRaceEventImpact.ImproveConflictKnowledge:
                    var subKnow = Regex.Replace(subjects[0], @"((?<=\p{Ll})\p{Lu})|((?!\A)\p{Lu}(?>\p{Ll}))", " $0");
                    AddOrUpdateOpinion(team.ManagerName, 1);
                    foreach (var cm in team.CrewMembers)
                    {
                        if (cm.Key != subKnow)
                        {
                            cm.Value.AddOrUpdateRevealedOpinion(subKnow, cm.Value.CrewOpinions[subKnow]);
                            cm.Value.SaveStatus();
                        }
                    }
                    break;

                //improve opinion of manager, expects to be placed in perferred position (subjects[0]) next race
                //other crew member involved in this event (subjects[1]) - improve opinion of manager, expects to be placed in perferred position (subjects[0]) in two races times
                //Regex adds spaces back before each capital letter
                case PostRaceEventImpact.CausesSelectionAfter:
                    AddOrUpdateOpinion(team.ManagerName, 1);
                    UpdateSingleBelief(NPCBelief.ExpectedPosition, subjects[0]);
                    var otherPlayer = Regex.Replace(subjects[1], @"((?<=\p{Ll})\p{Lu})|((?!\A)\p{Lu}(?>\p{Ll}))", " $0");
                    team.CrewMembers[otherPlayer].AddOrUpdateOpinion(team.ManagerName, 1);
                    team.CrewMembers[otherPlayer].UpdateSingleBelief(NPCBelief.ExpectedPositionAfter, subjects[0]);
                    team.CrewMembers[otherPlayer].SaveStatus();
                    break;

                //improves opinion of manager greatly, all unselected crew members' opinion of manager improves and expect to be selected next race
                case PostRaceEventImpact.WholeTeamChange:
                    AddOrUpdateOpinion(team.ManagerName, 4);
                    foreach (var cm in team.CrewMembers)
                    {
                        if (!team.PreviousSession.PositionCrew.Values.Select(v => v.Name).Contains(cm.Key))
                        {
                            cm.Value.AddOrUpdateOpinion(team.ManagerName, 1);
                            cm.Value.UpdateSingleBelief(NPCBelief.ExpectedSelection, "true");
                            cm.Value.SaveStatus();
                        }
                    }
                    break;
                }
            }
            TickUpdate(0);
        }
Esempio n. 6
0
        /// <summary>
        /// Send an event to the EA/RPC to get CrewMember information
        /// </summary>
        internal List <string> SendMeetingEvent(IntegratedAuthoringToolAsset iat, string style, Team team)
        {
            var reply = new List <string>();

            switch (style)
            {
            case "StatReveal":
                //select a random skill that has not been displayed before or any random skill if all have been displayed
                var availableStats = RevealedSkills.Where(s => s.Value == 0).Select(s => s.Key).ToList();
                if (availableStats.Count == 0)
                {
                    availableStats = RevealedSkills.Where(s => s.Value != Skills[s.Key]).Select(s => s.Key).ToList();
                }
                if (availableStats.Count == 0)
                {
                    availableStats = RevealedSkills.Select(s => s.Key).ToList();
                }
                var randomStat   = StaticRandom.Int(0, availableStats.Count);
                var statName     = availableStats[randomStat].ToString();
                var selectedStat = (Skill)Enum.Parse(typeof(Skill), statName);
                var statValue    = Skills[selectedStat];
                //add this skill rating to the dictionary to revealed skills
                RevealedSkills[selectedStat] = statValue;
                //get available dialogue based off of the rating in the skill
                style += statValue <= ConfigKey.BadSkillRating.GetIntValue() ? "Bad" : statValue >= ConfigKey.GoodSkillRating.GetIntValue() ? "Good" : "Middle";
                reply.Add(statName.ToLower());
                //save that this skill has been revealed
                UpdateSingleBelief(NPCBelief.RevealedSkill, statValue, statName);
                break;

            case "RoleReveal":
                //select a random position
                var pos = team.Boat.Positions[StaticRandom.Int(0, team.Boat.PositionCount)];
                //get dialogue based on if they would be above or below mid-range in this position
                style += pos.GetPositionRating(this) <= 5 ? "Bad" : "Good";
                reply.Add(pos.ToString());
                break;

            case "OpinionRevealPositive":
                //get all opinions for active crewmembers and the manager
                var crewOpinionsPositive = CrewOpinions.Where(c => team.CrewMembers.ContainsKey(c.Key)).ToDictionary(p => p.Key, p => p.Value);
                crewOpinionsPositive.Add(team.ManagerName, CrewOpinions[team.ManagerName]);
                //get all opinions where the value is equal/greater than the OpinionLike value in the config
                var opinionsPositive = crewOpinionsPositive.Where(co => co.Value >= ConfigKey.OpinionLike.GetIntValue()).ToDictionary(o => o.Key, o => o.Value);
                //if there are any positive opinions
                if (opinionsPositive.Any())
                {
                    //select an opinion at random
                    var pickedOpinionPositive = opinionsPositive.OrderBy(o => Guid.NewGuid()).First();
                    if (pickedOpinionPositive.Value >= ConfigKey.OpinionStrongLike.GetIntValue())
                    {
                        style += "High";
                    }
                    reply.Add(pickedOpinionPositive.Key != team.ManagerName ? pickedOpinionPositive.Key : "you");
                    AddOrUpdateRevealedOpinion(pickedOpinionPositive.Key, pickedOpinionPositive.Value);
                }
                //if there are no positive opinions, get dialogue based on that
                else
                {
                    style += "None";
                }
                break;

            case "OpinionRevealNegative":
                var crewOpinionsNegative = CrewOpinions.Where(c => team.CrewMembers.ContainsKey(c.Key)).ToDictionary(p => p.Key, p => p.Value);
                crewOpinionsNegative.Add(team.ManagerName, CrewOpinions[team.ManagerName]);
                var opinionsNegative = crewOpinionsNegative.Where(co => co.Value <= ConfigKey.OpinionDislike.GetIntValue()).ToDictionary(o => o.Key, o => o.Value);
                if (opinionsNegative.Any())
                {
                    var pickedOpinionNegative = opinionsNegative.OrderBy(o => Guid.NewGuid()).First();
                    if (pickedOpinionNegative.Value >= ConfigKey.OpinionStrongDislike.GetIntValue())
                    {
                        style += "High";
                    }
                    reply.Add(pickedOpinionNegative.Key != team.ManagerName ? pickedOpinionNegative.Key : "you");
                    AddOrUpdateRevealedOpinion(pickedOpinionNegative.Key, pickedOpinionNegative.Value);
                }
                else
                {
                    style += "None";
                }
                break;
            }
            SaveStatus();
            var dialogueOptions = iat.GetDialogueActionsByState("NPC_" + style).ToList();

            if (dialogueOptions.Any())
            {
                reply.Insert(0, dialogueOptions.OrderBy(o => Guid.NewGuid()).First().Utterance);
                return(reply);
            }
            reply.Clear();
            return(reply);
        }
Esempio n. 7
0
        /// <summary>
        /// Select event(s) to trigger post race
        /// </summary>
        internal void SelectPostRaceEvents(Team team, int chance)
        {
            //get the state of currently running events
            foreach (var crewMember in team.CrewMembers.Values)
            {
                crewMember.CurrentEventCheck(team, iat);
            }
            var selectedEvents = new List <List <PostRaceEventState> >();
            //get all possible post-race event starting dialogue
            var dialogueOptions = GetPossiblePostRaceDialogue();
            //get events that can be fired according to the game config
            var events = GetEvents(dialogueOptions, team);

            if (events.Any())
            {
                var allCrewInitial = team.CrewMembers;
                var allCrew        = new Dictionary <string, CrewMember>();
                //remove those already involved in a running event to not be selected
                foreach (var crewMember in allCrewInitial.Values)
                {
                    var expectsPos       = crewMember.LoadBelief(NPCBelief.ExpectedPosition);
                    var expectsPosAfter  = crewMember.LoadBelief(NPCBelief.ExpectedPosition);
                    var expectsSelection = crewMember.LoadBelief(NPCBelief.ExpectedSelection);
                    if (expectsPos == null && expectsPosAfter == null && expectsSelection == null)
                    {
                        allCrew.Add(crewMember.Name, crewMember);
                    }
                }
                foreach (var ev in events)
                {
                    var eventCrew = new Dictionary <string, CrewMember>(allCrew);
                    //if there is no-one to select for an event, stop looking
                    if (eventCrew.Count == 0)
                    {
                        continue;
                    }
                    var selected = dialogueOptions.Where(a => a.NextState == "Player_" + ev.EventName).OrderBy(o => Guid.NewGuid()).First();
                    if (ev.Random && StaticRandom.Int(0, (int)Math.Pow(chance, selectedEvents.Count + 1)) != 0)
                    {
                        continue;
                    }
                    var eventSelected = new List <PostRaceEventState>();
                    switch (selected.NextState.Replace("Player_", string.Empty))
                    {
                    case "PW":
                        //for this event, select a crew member who feels that they were placed in the wrong position
                        var betterPlace = new List <KeyValuePair <CrewMember, Position> >();
                        foreach (var pair in team.PreviousSession.PositionCrew)
                        {
                            var betterPosition = CrewMemberBestPosition(pair.Value, team);
                            if (betterPosition.Key != Position.Null)
                            {
                                betterPlace.Add(new KeyValuePair <CrewMember, Position>(pair.Value, betterPosition.Key));
                            }
                            eventCrew.Remove(pair.Value.Name);
                        }
                        //if nobody currently placed can be put into a better position, select a placed crew member and position at random
                        if (!betterPlace.Any())
                        {
                            var selectedCrewMember = eventCrew.OrderBy(c => Guid.NewGuid()).First().Value;
                            betterPlace.Add(new KeyValuePair <CrewMember, Position>(selectedCrewMember, CrewMemberBestPosition(selectedCrewMember, team).Key));
                        }
                        betterPlace = betterPlace.OrderBy(c => Guid.NewGuid()).ToList();
                        eventSelected.Add(new PostRaceEventState(betterPlace.First().Key, selected, new[] { betterPlace.First().Value.ToString() }.ToList()));
                        break;

                    case "OO":
                        //for this event, select a crew member who is placed with someone they do not get on with
                        var selectedAgainst = team.CrewMembers.OrderByDescending(c => c.Value.RevealedSkills.Values.Sum()).First();
                        if (eventCrew.ContainsKey(selectedAgainst.Key))
                        {
                            eventCrew.Remove(selectedAgainst.Key);
                            if (eventCrew.Count == 0)
                            {
                                continue;
                            }
                        }
                        var selectedFor = eventCrew.OrderBy(c => Guid.NewGuid()).First();
                        //make it so selectedFor has the worst possible opinion of selectedAgainst
                        selectedFor.Value.AddOrUpdateOpinion(selectedAgainst.Key, -10);
                        selectedFor.Value.AddOrUpdateRevealedOpinion(selectedAgainst.Key, selectedFor.Value.CrewOpinions[selectedAgainst.Key]);
                        selectedFor.Value.SaveStatus();
                        //randomly adjusted everyone else's opinion of selectedAgainst
                        foreach (var cm in team.CrewMembers)
                        {
                            if (cm.Key != selectedFor.Key && cm.Key != selectedAgainst.Key)
                            {
                                cm.Value.AddOrUpdateOpinion(selectedAgainst.Key, StaticRandom.Int(-3, 1));
                                cm.Value.SaveStatus();
                            }
                        }
                        eventSelected.Add(new PostRaceEventState(selectedFor.Value, selected, new[] { selectedAgainst.Key.NoSpaces() }.ToList()));
                        break;

                    case "NotPicked":
                        //for this event, select a crew member who was not selected
                        foreach (var pair in team.PreviousSession.PositionCrew)
                        {
                            eventCrew.Remove(pair.Value.Name);
                        }
                        if (eventCrew.Count == 0)
                        {
                            continue;
                        }
                        var randomCrewMember      = eventCrew.OrderBy(c => Guid.NewGuid()).First();
                        var randomBestPosition    = CrewMemberBestPosition(randomCrewMember.Value, team);
                        var randomPositionCurrent = team.PreviousSession.PositionCrew[randomBestPosition.Key].Name;
                        eventSelected.Add(new PostRaceEventState(randomCrewMember.Value, selected, new[] { randomBestPosition.Key.ToString(), randomPositionCurrent.NoSpaces() }.ToList()));
                        break;

                    case "IPC":
                        //for this event, select a crew member to have a conflict with the skipper
                        if (!team.PreviousSession.PositionCrew.ContainsKey(Position.Skipper))
                        {
                            continue;
                        }
                        var skipper = team.PreviousSession.PositionCrew[Position.Skipper].Name;
                        if (eventCrew.ContainsKey(skipper))
                        {
                            eventCrew.Remove(skipper);
                        }
                        if (eventCrew.Count == 0)
                        {
                            continue;
                        }
                        var randomAdditional = eventCrew.OrderBy(c => Guid.NewGuid()).First();
                        eventCrew.Remove(randomAdditional.Key);
                        if (eventCrew.Count == 0)
                        {
                            continue;
                        }
                        eventSelected.Add(new PostRaceEventState(eventCrew.OrderBy(c => Guid.NewGuid()).First().Value, selected, new[] { skipper.NoSpaces(), randomAdditional.Key.NoSpaces() }.ToList()));
                        break;
                    }
                    eventSelected.ForEach(es => allCrew.Remove(es.CrewMember.Name));
                    selectedEvents.Add(eventSelected);
                }
            }
            PostRaceEvents = selectedEvents;
            SaveEvents(team.Manager);
        }
Esempio n. 8
0
        /// <summary>
        /// Create a new Avatar based on randomness and this Crew Member's best skill or load the existing Avatar for this Crew Member
        /// </summary>
        private void CreateAvatar(CrewMember crewMember)
        {
            //Get Best Skill
            var currentBestSkill = crewMember.LoadBelief(NPCBelief.AvatarBestSkill);

            _bestSkill = Enum.TryParse <Skill>(currentBestSkill, out var loadedBestSkill) ? loadedBestSkill : GetBestSkill(crewMember);
            _bodyType  = GetBodyType();

            //Set Skin Color
            var loadedMouthColor = crewMember.LoadBelief(NPCBelief.AvatarMouthColor);

            if (loadedMouthColor != null &&
                byte.TryParse(crewMember.LoadBelief(NPCBelief.AvatarSkinColorRed), out var skinColorRed) &&
                byte.TryParse(crewMember.LoadBelief(NPCBelief.AvatarSkinColorGreen), out var skinColorGreen) &&
                byte.TryParse(crewMember.LoadBelief(NPCBelief.AvatarSkinColorBlue), out var skinColorBlue))
            {
                SkinColor  = new Color(skinColorRed, skinColorGreen, skinColorBlue);
                MouthColor = loadedMouthColor;
            }
            else
            {
                SkinColor = GetRandomSkinColor();
            }

            //Set Hair Color
            if (byte.TryParse(crewMember.LoadBelief(NPCBelief.AvatarHairColorRed), out var hairColorRed) &&
                byte.TryParse(crewMember.LoadBelief(NPCBelief.AvatarHairColorGreen), out var hairColorGreen) &&
                byte.TryParse(crewMember.LoadBelief(NPCBelief.AvatarHairColorBlue), out var hairColorBlue))
            {
                HairColor = new Color(hairColorRed, hairColorGreen, hairColorBlue);
            }
            else
            {
                HairColor = Config.RandomHairColor ? GetRandomHairColor() : GetHairColorForSkin(SkinColor);
            }

            //Set Body Type
            BodyType = crewMember.LoadBelief(NPCBelief.AvatarBodyType) ?? $"Body{_gender}_{_bodyType}";

            //Set Hair Type
            HairType = crewMember.LoadBelief(NPCBelief.AvatarHairType) ?? $"Hair{StaticRandom.Int(1, Config.HairTypesCount + 1):00}{_gender}";

            //Set Eye Type
            EyeType = crewMember.LoadBelief(NPCBelief.AvatarEyeType) ?? $"Eye{_gender}_{_bestSkill}";

            //Set Eye Color
            var textEyeColor = crewMember.LoadBelief(NPCBelief.AvatarEyeColor);

            if (textEyeColor != null)
            {
                EyeColor = GetEyeColorFromText(textEyeColor);
            }
            else
            {
                if (byte.TryParse(crewMember.LoadBelief(NPCBelief.AvatarEyeColorRed), out var eyeColorRed) &&
                    byte.TryParse(crewMember.LoadBelief(NPCBelief.AvatarEyeColorGreen), out var eyeColorGreen) &&
                    byte.TryParse(crewMember.LoadBelief(NPCBelief.AvatarEyeColorBlue), out var eyeColorBlue))
                {
                    EyeColor = new Color(eyeColorRed, eyeColorGreen, eyeColorBlue);
                }
                else
                {
                    EyeColor = GetRandomEyeColor();
                }
            }

            //Set Face type
            EyebrowType = crewMember.LoadBelief(NPCBelief.AvatarEyebrowType) ?? $"Face{_gender}_{_bestSkill}_Eyebrows";
            NoseType    = crewMember.LoadBelief(NPCBelief.AvatarNoseType) ?? $"Face{_gender}_{_bestSkill}_Nose";

            //Specify the teeth for male avatars
            if (IsMale)
            {
                TeethType = crewMember.LoadBelief(NPCBelief.AvatarTeethType) ?? $"Face{_gender}_{_bestSkill}_Teeth";
            }

            //Set Mouth Type
            MouthType = crewMember.LoadBelief(NPCBelief.AvatarMouthType) ?? $"Face{_gender}_{_bestSkill}_Mouth";

            // Set Height and Width (Weight)
            if (float.TryParse(crewMember.LoadBelief(NPCBelief.AvatarHeight), out var loadedHeight))
            {
                Height = loadedHeight;
            }
            else
            {
                Height = 1 + StaticRandom.Float(-0.075f, 0.075f);
            }

            if (float.TryParse(crewMember.LoadBelief(NPCBelief.AvatarWeight), out var loadedWeight))
            {
                Weight = loadedWeight;
            }
            else
            {
                Weight = 1 + StaticRandom.Float(-0.075f, 0.075f);
            }

            //Save attributes
            UpdateAvatarBeliefs(crewMember);
        }