private void Finished()
        {
            StringBuilder attendedString = new StringBuilder();

            foreach (Pawn p in attendees)
            {
                attendedString.AppendLine(p.Name.ToString());
                if (PsycheHelper.PsychologyEnabled(p))
                {
                    ThoughtDef def = new ThoughtDef();
                    def.defName          = p.GetHashCode() + "AttendedFuneral" + dead.GetHashCode();
                    def.durationDays     = 20f;
                    def.nullifyingTraits = new List <TraitDef>();
                    def.nullifyingTraits.Add(TraitDefOf.Psychopath);
                    def.nullifyingTraits.Add(TraitDefOfPsychology.Desensitized);
                    def.thoughtClass = typeof(Thought_MemoryDynamic);
                    ThoughtStage stage = new ThoughtStage();
                    stage.label          = "AttendedFuneralThought".Translate(dead);
                    stage.baseMoodEffect = Mathf.RoundToInt((p.relations.OpinionOf(dead) / 15f) * (0.33f + PsycheHelper.Comp(p).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Nostalgic)));
                    stage.description    = "AttendedFuneralDesc".Translate().AdjustedFor(dead);
                    def.stages.Add(stage);
                    p.needs.mood.thoughts.memories.TryGainMemory(def);
                }
                else
                {
                    p.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.AttendedFuneral);
                }
            }
            if (attendees.Count == 0)
            {
                attendedString.AppendLine("No one.");
            }
            Find.LetterStack.ReceiveLetter("LetterLabelFuneralEnded".Translate(dead), "LetterFuneralEnded".Translate(dead, attendedString), LetterDefOf.NeutralEvent, null);
        }
 public override float RandomSelectionWeight(Pawn initiator, Pawn recipient)
 {
     if (!initiator.IsColonist || !recipient.IsColonist)
     {
         return(0f);
     }
     if (!RendezvousUtility.AcceptableGameConditionsToStartHangingOut(initiator.Map))
     {
         return(0f);
     }
     if (!PsycheHelper.PsychologyEnabled(initiator) || !PsycheHelper.PsychologyEnabled(recipient))
     {
         return(0f);
     }
     if (!LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient))
     {
         return(0f);
     }
     if (PsycheHelper.Comp(initiator).Psyche.lastDateTick >= Find.TickManager.TicksGame - GenDate.TicksPerDay * 7 || PsycheHelper.Comp(recipient).Psyche.lastDateTick >= Find.TickManager.TicksGame - GenDate.TicksPerDay * 7)
     {
         return(0f);
     }
     if (!GatheringsUtility.ShouldGuestKeepAttendingGathering(initiator) || !GatheringsUtility.ShouldGuestKeepAttendingGathering(recipient))
     {
         return(0f);
     }
     return(1.2f * (1f + Mathf.InverseLerp(100f, 0f, initiator.needs.mood.thoughts.TotalOpinionOffset(recipient))) * PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * (1f - PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Independent))
            * PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * (1f - PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Independent)) * RendezvousUtility.ColonySizeFactor(initiator));
 }
Пример #3
0
 public void LearnSexuality(Pawn p)
 {
     if (p != null && PsycheHelper.PsychologyEnabled(pawn) && !knownSexualities.Keys.Contains(p))
     {
         knownSexualities.Add(p, PsycheHelper.Comp(p).Sexuality.kinseyRating);
     }
 }
Пример #4
0
        protected override ThoughtState CurrentSocialStateInternal(Pawn p, Pawn otherPawn)
        {
            if (!RelationsUtility.PawnsKnowEachOther(p, otherPawn))
            {
                return(false);
            }
            if (!LovePartnerRelationUtility.LovePartnerRelationExists(p, otherPawn))
            {
                return(false);
            }
            if (!PsycheHelper.PsychologyEnabled(p))
            {
                return(false);
            }
            if (p.Map == otherPawn.Map)
            {
                PsycheHelper.Comp(p).LDRTick = Find.TickManager.TicksAbs;
                return(false);
            }
            int tickSinceLastSeen = PsycheHelper.Comp(p).LDRTick;
            int ticksApart        = Find.TickManager.TicksAbs - tickSinceLastSeen;
            int quadrumsApart     = Mathf.FloorToInt((float)ticksApart / (float)GenDate.TicksPerQuadrum);
            int maxApart          = (p.relations.GetDirectRelation(PawnRelationDefOf.Spouse, otherPawn) == null ? 7 : 6);

            if (quadrumsApart > maxApart)
            {
                quadrumsApart = maxApart;
            }
            if (quadrumsApart > 1)
            {
                return(ThoughtState.ActiveAtStage(quadrumsApart - 1));
            }
            return(false);
        }
Пример #5
0
 public static void DrawPsycheCard(Rect rect, Pawn pawn)
 {
     if (PsycheHelper.PsychologyEnabled(pawn))
     {
         GUI.BeginGroup(rect);
         Text.Font = GameFont.Small;
         Rect rect2 = new Rect(20f, 20f, rect.width - 20f, rect.height - 20f);
         Rect rect3 = rect2.ContractedBy(10f);
         Rect rect4 = rect3;
         Rect rect5 = rect3;
         rect4.width *= 0.6f;
         rect5.x      = rect4.xMax + 17f;
         rect5.xMax   = rect3.xMax;
         GUI.color    = new Color(1f, 1f, 1f, 0.5f);
         Widgets.DrawLineVertical(rect4.xMax, 0f, rect.height);
         GUI.color = Color.white;
         if (Prefs.DevMode)
         {
             Rect rect6 = new Rect(0f, 5f, rect3.width, 22f);
             PsycheCardUtility.DrawDebugOptions(rect6, pawn);
         }
         PsycheCardUtility.DrawPersonalityNodes(rect4, pawn);
         PsycheCardUtility.DrawSexuality(rect5, pawn, true);
         GUI.EndGroup();
     }
 }
Пример #6
0
 public override void PostMake()
 {
     base.PostMake();
     if (!PsycheHelper.PsychologyEnabled(this.pawn))
     {
         this.pawn.health.RemoveHediff(this);
     }
 }
Пример #7
0
 public void ExposeData()
 {
     Scribe_Values.Look(ref this.upbringing, "upbringing", 0, false);
     Scribe_Values.Look(ref this.lastDateTick, "lastDateTick", 0, false);
     PsycheHelper.Look(ref this.nodes, "nodes", LookMode.Deep, new object[] { this.pawn });
     foreach (PersonalityNode n in this.nodes)
     {
         nodeDict[n.def] = n;
     }
 }
Пример #8
0
        public override float RandomSelectionWeight(Pawn initiator, Pawn recipient)
        {
            if (!GatheringsUtility.ShouldGuestKeepAttendingGathering(initiator) || !GatheringsUtility.ShouldGuestKeepAttendingGathering(recipient))
            {
                return(0f);
            }
            if (!PsycheHelper.PsychologyEnabled(initiator) || !PsycheHelper.PsychologyEnabled(recipient))
            {
                return(0f);
            }
            if (initiator.GetLord() != null || recipient.GetLord() != null)
            {
                return(0f);
            }
            if (initiator.Drafted || recipient.Drafted)
            {
                return(0f);
            }
            if (!RendezvousUtility.AcceptableGameConditionsToStartHangingOut(initiator.Map))
            {
                return(0f);
            }
            if (initiator.Faction != recipient.Faction)
            {
                return(0f);
            }
            float initiatorFactor = 0f;
            float recipientFactor = 0f;

            if (initiator.relations.OpinionOf(recipient) > -20)
            {
                initiatorFactor = PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Extroverted) + 0.15f + Mathf.InverseLerp(0f, 100f, initiator.relations.OpinionOf(recipient));
                recipientFactor = (PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Friendly) + PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Cool)) / 2f;
            }
            else if (initiator.relations.OpinionOf(recipient) <= -20)
            {
                initiatorFactor = Mathf.InverseLerp(0.6f, 1f, PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Empathetic));
                recipientFactor = PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Trusting);
            }
            float scheduleFactor = 0f;

            if (initiator.GetTimeAssignment() == TimeAssignmentDefOf.Anything)
            {
                scheduleFactor = 0.33f;
            }
            else if (initiator.GetTimeAssignment() == TimeAssignmentDefOf.Joy)
            {
                scheduleFactor = 1f;
            }
            if (initiator.mindState.IsIdle && recipient.mindState.IsIdle && initiator.GetTimeAssignment() != TimeAssignmentDefOf.Work && recipient.GetTimeAssignment() != TimeAssignmentDefOf.Work)
            {
                scheduleFactor = 5f;
            }
            return(0.05f * initiatorFactor * recipientFactor * scheduleFactor * RendezvousUtility.ColonySizeFactor(initiator));
        }
 public override void Init()
 {
     this.topic             = def.defName;
     this.label             = def.stages[0].label;
     this.baseOpinionOffset = def.stages[0].baseOpinionOffset;
     if (PsycheHelper.PsychologyEnabled(pawn))
     {
         PsycheHelper.Comp(pawn).Psyche.OpinionCacheDirty[otherPawn.ThingID] = true;
         Pair <string, string> disagreeKey = new Pair <string, string>(otherPawn.ThingID, label);
         PsycheHelper.Comp(pawn).Psyche.DisagreementCacheDirty[disagreeKey] = true;
     }
     base.Init();
 }
Пример #10
0
        private void Finished()
        {
            List <Pair <Pawn, int> > voteTally = new List <Pair <Pawn, int> >();

            foreach (Candidate candidate in this.candidates)
            {
                IEnumerable <string> votesForMe = (from v in this.votes
                                                   where v == candidate.pawn.LabelShort
                                                   select v);
                voteTally.Add(new Pair <Pawn, int>(candidate.pawn, votesForMe.Count()));
            }
            //If there ends up being a tie, we'll just assume the least competitive candidates drop out.
            //The chances of there being a tie after that are exceedingly slim, but the result will be essentially random.
            IEnumerable <Pair <Pawn, int> > orderedTally = (from v in voteTally
                                                            orderby PsycheHelper.Comp(v.First).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Competitive) descending
                                                            orderby v.Second descending
                                                            select v);

            if (Prefs.DevMode && Prefs.LogVerbose)
            {
                foreach (Pair <Pawn, int> t in orderedTally)
                {
                    Log.Message("Psychology :: Votes for " + t.First + ": " + t.Second);
                }
            }
            Pair <Pawn, int> winningCandidate = orderedTally.First();

            if (orderedTally.Count() > 1 && orderedTally.First().Second == orderedTally.ElementAt(1).Second)
            {
                Find.LetterStack.ReceiveLetter("LetterLabelTieSettled".Translate(winningCandidate.First), "LetterTieSettled".Translate(winningCandidate.First), LetterDefOf.NeutralEvent, winningCandidate.First);
            }
            StringBuilder issuesString = new StringBuilder();

            for (int i = 0; i < candidates.Find(c => c.pawn == winningCandidate.First).nodes.Count; i++)
            {
                issuesString.AppendFormat("{0}) {1}{2}", i + 1, PsycheHelper.Comp(winningCandidate.First).Psyche.GetPersonalityNodeOfDef(candidates.Find(c => c.pawn == winningCandidate.First).nodes[i]).PlatformIssue, (i != candidates.Find(c => c.pawn == winningCandidate.First).nodes.Count - 1 ? "\n" : ""));
            }
            if (this.map == null)
            {
                this.map = winningCandidate.First.Map;
            }
            Hediff mayor = HediffMaker.MakeHediff(HediffDefOfPsychology.Mayor, winningCandidate.First);

            (mayor as Hediff_Mayor).worldTileElectedOn = map.Tile;
            (mayor as Hediff_Mayor).yearElected        = GenLocalDate.Year(map);
            winningCandidate.First.health.AddHediff(mayor);
            winningCandidate.First.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.WonElection);
            Find.LetterStack.ReceiveLetter("LetterLabelElectionWon".Translate(winningCandidate.First), "LetterElectionWon".Translate(winningCandidate.First, this.baseName, winningCandidate.Second, issuesString.ToString()), LetterDefOf.NeutralEvent, winningCandidate.First);
        }
Пример #11
0
        private static void DrawSexuality(Rect rect, Pawn pawn, bool notOnMenu)
        {
            float width = rect.width - 26f - 3f;

            GUI.color = Color.white;
            if (PsychologyBase.ActivateKinsey())
            {
                Text.Font = GameFont.Medium;
                Rect rect2 = rect;
                rect2.yMax = rect2.y + 30f;
                Widgets.Label(rect2, "Sexuality".Translate());
                Text.Font = GameFont.Small;
                Rect rect3 = rect;
                rect3.y = rect2.yMax + RowTopPadding;
                string text = "KinseyRating".Translate() + "    " + PsycheHelper.Comp(pawn).Sexuality.kinseyRating;
                float  num4 = Mathf.Max(50f, Text.CalcHeight(text, width));
                rect3.yMax = rect3.y + num4;
                Widgets.Label(rect3, text);
                bool asexual = false;
                Rect rect4   = rect;
                if (PsycheHelper.Comp(pawn).Sexuality.sexDrive < 0.1f)
                {
                    rect4.y = rect3.yMax;
                    string text2 = "Asexual".Translate();
                    float  num5  = Mathf.Max(26f, Text.CalcHeight(text2, width));
                    rect4.yMax = rect4.y + num5;
                    Widgets.Label(rect4, text2);
                    TooltipHandler.TipRegion(rect4, () => "AsexualDescription".Translate(), 613261 + (int)(100 * PsycheHelper.Comp(pawn).Sexuality.sexDrive));
                    asexual = true;
                }
                if (PsycheHelper.Comp(pawn).Sexuality.romanticDrive < 0.1f)
                {
                    Rect rect5 = rect;
                    rect5.y = (asexual ? rect4.yMax : rect3.yMax);
                    string text2 = "Aromantic".Translate();
                    float  num5  = Mathf.Max(26f, Text.CalcHeight(text2, width));
                    rect5.yMax = rect5.y + num5;
                    Widgets.Label(rect5, text2);
                    TooltipHandler.TipRegion(rect5, () => "AromanticDescription".Translate(), 613261 + (int)(100 * PsycheHelper.Comp(pawn).Sexuality.romanticDrive));
                }
            }
            else if (notOnMenu)
            {
                GUI.color = Color.red;
                string text = "SexualityDisabledWarning".Translate();
                Widgets.Label(rect, text);
                GUI.color = Color.white;
            }
        }
Пример #12
0
        private bool TryGainThought(ThoughtDef def, int opinionOffset)
        {
            ThoughtStage stage = def.stages.First();
            IEnumerable <Thought_MemorySocialDynamic> convoMemories;

            /* The more they know about someone, the less likely small thoughts are to have an impact on their opinion.
             * This helps declutter the Social card without preventing pawns from having conversations.
             * They just won't change their mind about the colonist as a result.
             */
            if (Rand.Value < Mathf.InverseLerp(0f, PsycheHelper.Comp(pawn).Psyche.TotalThoughtOpinion(this.otherPawn, out convoMemories), 250f + Mathf.Abs(opinionOffset)) && opinionOffset != 0)
            {
                this.pawn.needs.mood.thoughts.memories.TryGainMemory(def, this.otherPawn);
                return(true);
            }
            return(false);
        }
Пример #13
0
 public override void MapLoaded(Map map)
 {
     if (ModIsActive && PsychologyBase.ActivateKinsey())
     {
         /* Remove Gay trait from pawns if Kinsey scale is enabled */
         IEnumerable <Pawn> gayPawns = (from p in map.mapPawns.AllPawns
                                        where p.story != null && p.story.traits.HasTrait(TraitDefOf.Gay)
                                        select p);
         foreach (Pawn pawn in gayPawns)
         {
             RemoveTrait(pawn, TraitDefOf.Gay);
             if (PsycheHelper.PsychologyEnabled(pawn) && PsycheHelper.Comp(pawn).Sexuality.kinseyRating < 5)
             {
                 PsycheHelper.Comp(pawn).Sexuality.kinseyRating = Rand.RangeInclusive(5, 6);
             }
         }
     }
 }
Пример #14
0
        private bool ShouldPawnKeepVoting(Pawn p)
        {
            if (!PsycheHelper.PsychologyEnabled(p))
            {
                return(false);
            }
            bool matchingCandidates = (from c in candidates
                                       where c.pawn == p
                                       select c).Count() > 0;

            if (voters.Contains(p.GetHashCode()) && !matchingCandidates)
            {
                return(false);
            }
            bool notApathetic = PsycheHelper.Comp(p).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Passionate) > (0.6f / candidates.Count);

            return(GatheringsUtility.ShouldGuestKeepAttendingGathering(p) && (notApathetic || matchingCandidates));
        }
        public override void Interacted(Pawn initiator, Pawn recipient, List <RulePackDef> extraSentencePacks, out string letterText, out string letterLabel, out LetterDef letterDef)
        {
            letterText  = null;
            letterLabel = null;
            letterDef   = null;
            //Choose a time that works with their schedule, based on their personality
            Dictionary <int, float> possibleHours = new Dictionary <int, float>();

            for (int i = 0; i < GenDate.HoursPerDay; i++)
            {
                possibleHours.Add(i, 0f);
            }
            foreach (PersonalityNodeDef d in DefDatabase <PersonalityNodeDef> .AllDefsListForReading)
            {
                if (d.preferredDateHours != null)
                {
                    foreach (int h in d.preferredDateHours)
                    {
                        possibleHours[h] += (Mathf.Pow(Mathf.Abs(0.5f - PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(d)), 2) / (1.3f - PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Aggressive)) + Mathf.Pow(Mathf.Abs(0.5f - PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(d)), 2) / (1.3f - PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Aggressive)) / 2f);
                    }
                }
            }
            int hour = possibleHours.Keys.RandomElementByWeight(h => possibleHours[h] * RendezvousUtility.TimeAssignmentFactor(initiator, h) * RendezvousUtility.TimeAssignmentFactor(recipient, h));
            //More Spontaneous couples will plan their dates sooner; possibly even immediately!
            int day = Find.TickManager.TicksAbs + Mathf.RoundToInt(GenDate.TicksPerDay * 5 * (((1f - PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Spontaneous)) + (1f - PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Spontaneous))) / 2f));
            Hediff_PlannedDate plannedDate = HediffMaker.MakeHediff(HediffDefOfPsychology.PlannedDate, initiator) as Hediff_PlannedDate;

            plannedDate.partner = recipient;
            plannedDate.day     = day;
            plannedDate.hour    = hour;
            initiator.health.AddHediff(plannedDate);
            PsycheHelper.Comp(initiator).Psyche.lastDateTick = day;
            PsycheHelper.Comp(recipient).Psyche.lastDateTick = day;
            if (PsychologyBase.SendDateLetters())
            {
                int    hourDiscrepancy = GenDate.HourOfDay(day, Find.WorldGrid.LongLatOf(initiator.Map.Tile).x) - hour;
                int    accurateTime    = day + (Math.Abs(hourDiscrepancy) * GenDate.TicksPerHour);
                String dateTime        = GenDate.QuadrumDateStringAt(accurateTime, Find.WorldGrid.LongLatOf(initiator.Map.Tile).x);
                Letter dateLetter      = LetterMaker.MakeLetter("LetterLabelDatePlanned".Translate(), "LetterDatePlanned".Translate(initiator, recipient, dateTime, hour), LetterDefOf.PositiveEvent);
                Find.LetterStack.ReceiveLetter(dateLetter);
            }
        }
Пример #16
0
 public static void DrawPsycheMenuCard(Rect rect, Pawn pawn)
 {
     if (PsycheHelper.PsychologyEnabled(pawn))
     {
         GUI.BeginGroup(rect);
         Text.Font = GameFont.Small;
         Rect rect2 = new Rect(10f, 10f, rect.width - 10f, rect.height - 10f);
         Rect rect4 = rect2;
         Rect rect5 = rect2;
         rect4.width *= 0.6f;
         rect4.xMin  -= 20f;
         rect5.x      = rect4.xMax + 17f;
         rect5.xMax   = rect.xMax;
         GUI.color    = new Color(1f, 1f, 1f, 0.5f);
         Widgets.DrawLineVertical(rect4.xMax, 0f, rect.height);
         GUI.color = Color.white;
         PsycheCardUtility.DrawPersonalityNodes(rect4, pawn);
         PsycheCardUtility.DrawSexuality(rect5, pawn, false);
         GUI.EndGroup();
     }
 }
        public override float RandomSelectionWeight(Pawn initiator, Pawn recipient)
        {
            if (!PsycheHelper.PsychologyEnabled(initiator) || !PsycheHelper.PsychologyEnabled(recipient))
            {
                return(0f);
            }
            if (!initiator.health.capacities.CapableOf(PawnCapacityDefOf.Talking) || !recipient.health.capacities.CapableOf(PawnCapacityDefOf.Talking))
            {
                return(0f);
            }
            float baseChance = 0.45f;
            Lord  lord       = LordUtility.GetLord(initiator);

            if (lord != null && (lord.LordJob is LordJob_HangOut || lord.LordJob is LordJob_Date) && LordUtility.GetLord(recipient) == lord)
            {
                baseChance = 0.75f;
            }
            if (initiator.story.traits.HasTrait(TraitDefOfPsychology.Chatty))
            {
                baseChance *= 1.2f;
            }
            return(Mathf.Max(0f, baseChance + (PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Friendly) - 0.6f) + (PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Extroverted) - 0.5f)));
        }
        public override void Interacted(Pawn initiator, Pawn recipient, List <RulePackDef> extraSentencePacks, out string letterText, out string letterLabel, out LetterDef letterDef)
        {
            letterText  = null;
            letterLabel = null;
            letterDef   = null;
            PersonalityNode topic = (from node in PsycheHelper.Comp(initiator).Psyche.PersonalityNodes
                                     where !node.Core
                                     select node).RandomElementByWeight(node => PsycheHelper.Comp(initiator).Psyche.GetConversationTopicWeight(node.def, recipient));
            string convoTopic = topic.def.conversationTopics.RandomElement();
            Hediff_Conversation initiatorHediff = (Hediff_Conversation)HediffMaker.MakeHediff(HediffDefOfPsychology.HoldingConversation, initiator);

            initiatorHediff.otherPawn   = recipient;
            initiatorHediff.topic       = topic.def;
            initiatorHediff.waveGoodbye = true;
            initiatorHediff.convoTopic  = convoTopic;
            initiator.health.AddHediff(initiatorHediff);
            Hediff_Conversation recipientHediff = (Hediff_Conversation)HediffMaker.MakeHediff(HediffDefOfPsychology.HoldingConversation, recipient);

            recipientHediff.otherPawn   = initiator;
            recipientHediff.topic       = topic.def;
            recipientHediff.waveGoodbye = false;
            recipientHediff.convoTopic  = convoTopic;
            recipient.health.AddHediff(recipientHediff);
        }
Пример #19
0
 public Dialog_EditPsyche(Pawn editFor)
 {
     pawn = editFor;
     if (PsychologyBase.ActivateKinsey())
     {
         pawnKinseyRating  = PsycheHelper.Comp(pawn).Sexuality.kinseyRating;
         pawnSexDrive      = PsycheHelper.Comp(pawn).Sexuality.sexDrive;
         pawnRomanticDrive = PsycheHelper.Comp(pawn).Sexuality.romanticDrive;
     }
     foreach (PersonalityNode node in PsycheHelper.Comp(pawn).Psyche.PersonalityNodes)
     {
         cachedList.Add(new Pair <string, float>(node.def.label.CapitalizeFirst(), node.rawRating));
         try
         {
             descriptions.Add(node.def.label.CapitalizeFirst(), node.def.description);
         }
         catch (ArgumentException e)
         {
             Log.Error("[Psychology] " + "DuplicateDefLabel".Translate(node.def.defName));
             descriptions.Add(node.def.defName.CapitalizeFirst(), node.def.description);
         }
     }
     cachedList.SortBy(n => n.First);
 }
Пример #20
0
        public override void Notify_ReachedDutyLocation(Pawn voter)
        {
            LordJob_Joinable_Election election = voter.GetLord().LordJob as LordJob_Joinable_Election;

            if (election != null && PsycheHelper.PsychologyEnabled(voter) && !election.voters.Contains(voter.GetHashCode()))
            {
                election.voters.Add(voter.GetHashCode());
                if (election.candidates.Find(c => c.pawn == voter) == null)
                {
                    List <Pair <Pawn, float> > possibleVotes = new List <Pair <Pawn, float> >();
                    foreach (Candidate candidate in election.candidates)
                    {
                        float issueWeighting = 0f;
                        candidate.nodes.ForEach(p => issueWeighting += (4f * Mathf.Pow(1f - Mathf.Abs(PsycheHelper.Comp(candidate.pawn).Psyche.GetPersonalityRating(p) - PsycheHelper.Comp(voter).Psyche.GetPersonalityRating(p)), 5f)) * Mathf.Pow(2.5f, p.controversiality));
                        possibleVotes.Add(new Pair <Pawn, float>(candidate.pawn, issueWeighting + voter.relations.OpinionOf(candidate.pawn)));
                    }
                    IEnumerable <Pair <Pawn, float> > orderedPossibleVotes = (from v in possibleVotes
                                                                              orderby v.Second descending
                                                                              select v);
                    if (Prefs.DevMode && Prefs.LogVerbose)
                    {
                        StringBuilder voteString = new StringBuilder("Psychology :: Vote weights for " + voter.LabelShort + ": ");
                        foreach (Pair <Pawn, float> v in orderedPossibleVotes)
                        {
                            voteString.Append(v.First.LabelShort + " " + v.Second + " ");
                        }
                        Log.Message(voteString.ToString());
                    }
                    election.votes.Add(orderedPossibleVotes.First().First.LabelShort);
                }
                else
                {
                    election.votes.Add(voter.LabelShort);
                }
            }
        }
Пример #21
0
 private bool IsInvited(Pawn p)
 {
     return(p.Faction == this.lord.faction && p.needs.mood != null && p.relations.OpinionOf(dead) > 0 && (!PsycheHelper.PsychologyEnabled(p) || Mathf.Lerp(0, 100, p.relations.OpinionOf(dead)) >= (1f - PsycheHelper.Comp(p).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Nostalgic))));
 }
Пример #22
0
 private void Finished()
 {
     if (PsycheHelper.PsychologyEnabled(mayor) && PsycheHelper.PsychologyEnabled(constituent))
     {
         if (this.ticksInSameRoom > 0)
         {
             if (this.complaint)
             {
                 ThoughtDef complaintDef = new ThoughtDef();
                 complaintDef.label        = "MayorComplaint";
                 complaintDef.durationDays = 1f + 4f * this.mayor.GetStatValue(StatDefOf.SocialImpact);
                 //Constituent thought duration affected by mayor's Social stat
                 complaintDef.thoughtClass            = typeof(Thought_MemoryDynamic);
                 complaintDef.stackedEffectMultiplier = 1f;
                 complaintDef.stackLimit = 999;
                 ThoughtStage complaintStage = new ThoughtStage();
                 float        complaintMood  = 18f * (PsycheHelper.Comp(mayor).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Empathetic) - 0.33f);
                 //Base complaint mood determined by mayor's Empathetic trait
                 complaintMood *= (float)this.ticksInSameRoom / (float)GenDate.TicksPerHour;
                 //Length of meeting also affects mood
                 complaintMood *= (complaintMood < 0f ? Mathf.Lerp(1.25f, 0.75f, PsycheHelper.Comp(constituent).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Polite)) : 1f);
                 //Negative meeting thoughts (unempathetic mayors) mitigated by mayor's politeness
                 complaintMood += (BeautyUtility.AverageBeautyPerceptible(this.constituent.Position, this.constituent.Map) / 10f);
                 //Beauty of the room has a net positive effect on the thought
                 complaintMood *= 0.75f + (PsycheHelper.Comp(constituent).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Judgmental) / 2f);
                 //Constituent's Judgmental trait changes how much the thought affects them
                 complaintStage.label          = "ComplaintLabel".Translate();
                 complaintStage.description    = "ComplaintDesc".Translate();
                 complaintStage.baseMoodEffect = Mathf.RoundToInt(complaintMood);
                 complaintDef.defName          = this.constituent.GetHashCode() + "MayorComplaint" + complaintStage.baseMoodEffect;
                 complaintDef.stages.Add(complaintStage);
                 if (complaintStage.baseMoodEffect != 0)
                 {
                     this.constituent.needs.mood.thoughts.memories.TryGainMemory(complaintDef, this.mayor);
                 }
             }
             ThoughtDef visitDef = new ThoughtDef();
             visitDef.label        = "MayorVisited";
             visitDef.durationDays = 0.75f + 2f * (1f - PsycheHelper.Comp(mayor).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Independent));
             //Mayor thought duration affected by mayor's Independent trait
             visitDef.thoughtClass            = typeof(Thought_MemoryDynamic);
             visitDef.stackedEffectMultiplier = 1f;
             visitDef.stackLimit = 999;
             ThoughtStage stage = new ThoughtStage();
             float        mood  = 7f * (complaint ? -0.5f - (1f - this.constituent.needs.mood.CurLevel) : 0.1f + (this.constituent.needs.mood.CurLevel * 0.65f));
             //Base visit mood determined by the mood level of the constituent
             mood *= (float)this.ticksInSameRoom / (float)GenDate.TicksPerHour;
             //Length of meeting also affects mood
             mood *= (mood < 0f ? Mathf.Lerp(1.25f, 0.75f, PsycheHelper.Comp(constituent).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Polite)) : 1f);
             //Negative meeting thoughts (unhappy constituents) mitigated by constituent's politeness
             mood *= 0.5f + (1f - PsycheHelper.Comp(this.mayor).Psyche.GetPersonalityRating(PersonalityNodeDefOf.LaidBack));
             //Mayor's Laid-Back trait strongly impacts how much the thought affects them
             stage.label          = "VisitLabel".Translate();
             stage.description    = "VisitDesc".Translate();
             stage.baseMoodEffect = Mathf.RoundToInt(mood);
             visitDef.defName     = this.mayor.GetHashCode() + "MayorVisited" + stage.baseMoodEffect;
             visitDef.stages.Add(stage);
             if (stage.baseMoodEffect != 0)
             {
                 this.mayor.needs.mood.thoughts.memories.TryGainMemory(visitDef, this.constituent);
             }
             InteractionDef endConversation = new InteractionDef();
             endConversation.defName = "EndConversation";
             FieldInfo     RuleStrings     = typeof(RulePack).GetField("rulesStrings", BindingFlags.Instance | BindingFlags.NonPublic);
             RulePack      goodbyeTextInit = new RulePack();
             List <string> text            = new List <string>(1);
             if (complaint)
             {
                 text.Add("r_logentry->" + "Complained".Translate());
             }
             else
             {
                 text.Add("r_logentry->" + "Supported".Translate());
             }
             RuleStrings.SetValue(goodbyeTextInit, text);
             endConversation.logRulesInitiator = goodbyeTextInit;
             FieldInfo Symbol = typeof(InteractionDef).GetField("symbol", BindingFlags.Instance | BindingFlags.NonPublic);
             Symbol.SetValue(endConversation, Symbol.GetValue(InteractionDefOfPsychology.HangOut));
             PlayLogEntry_InteractionConversation log = new PlayLogEntry_InteractionConversation(endConversation, this.constituent, this.mayor, new List <RulePackDef>());
             Find.PlayLog.Add(log);
             MoteMaker.MakeInteractionBubble(this.mayor, this.constituent, InteractionDefOf.Chitchat.interactionMote, InteractionDefOf.Chitchat.Symbol);
         }
     }
 }
Пример #23
0
 public override void PostRemoved()
 {
     base.PostRemoved();
     if (this.pawn != null && this.otherPawn != null)
     {
         if (this.pawn.Dead || this.otherPawn.Dead || !PsycheHelper.PsychologyEnabled(pawn) || !PsycheHelper.PsychologyEnabled(otherPawn))
         {
             return;
         }
         Hediff_Conversation otherConvo = otherPawn.health.hediffSet.hediffs.Find(h => h is Hediff_Conversation && ((Hediff_Conversation)h).otherPawn == this.pawn) as Hediff_Conversation;
         if (otherConvo != null)
         {
             this.otherPawn.health.RemoveHediff(otherConvo);
             this.startedFight = otherConvo.startedFight;
         }
         string talkDesc;
         if (this.ageTicks < 500)
         {
             int numShortTalks = int.Parse("NumberOfShortTalks".Translate());
             talkDesc = "ShortTalk" + Rand.RangeInclusive(1, numShortTalks);
         }
         else if (this.ageTicks < GenDate.TicksPerHour / 2)
         {
             int numNormalTalks = int.Parse("NumberOfNormalTalks".Translate());
             talkDesc = "NormalTalk" + Rand.RangeInclusive(1, numNormalTalks);
         }
         else if (this.ageTicks < GenDate.TicksPerHour * 2.5)
         {
             int numLongTalks = int.Parse("NumberOfLongTalks".Translate());
             talkDesc = "LongTalk" + Rand.RangeInclusive(1, numLongTalks);
         }
         else
         {
             int numEpicTalks = int.Parse("NumberOfEpicTalks".Translate());
             talkDesc = "EpicTalk" + Rand.RangeInclusive(1, numEpicTalks);
         }
         float          opinionMod;
         ThoughtDef     def             = CreateSocialThought(out opinionMod);
         bool           mattered        = TryGainThought(def, Mathf.RoundToInt(opinionMod));
         InteractionDef endConversation = new InteractionDef();
         endConversation.socialFightBaseChance = 0.2f * PsycheHelper.Comp(pawn).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Aggressive) * PopulationModifier * Mathf.InverseLerp(0f, -80f, opinionMod);
         endConversation.defName = "EndConversation";
         endConversation.label   = def.label;
         List <RulePackDef> socialFightPacks = new List <RulePackDef>();
         if (otherConvo != null && (startedFight || (mattered && this.pawn.interactions.CheckSocialFightStart(endConversation, otherPawn))))
         {
             if (startedFight)
             {
                 socialFightPacks.Add(RulePackDefOfPsychology.Sentence_SocialFightConvoRecipientStarted);
             }
             else
             {
                 socialFightPacks.Add(RulePackDefOfPsychology.Sentence_SocialFightConvoInitiatorStarted);
             }
             this.startedFight = true;
             if (!this.waveGoodbye && otherConvo.convoLog != null && !otherConvo.startedFight)
             {
                 //The main conversation hediff was the other conversation, and didn't start a fight, so we have to add the extra sentence in after the fact.
                 Traverse.Create(otherConvo.convoLog).Field("extraSentencePacks").GetValue <List <RulePackDef> >().AddRange(socialFightPacks);
             }
         }
         if (this.waveGoodbye && this.pawn.Map != null)
         {
             RulePack      goodbyeText = new RulePack();
             FieldInfo     RuleStrings = typeof(RulePack).GetField("rulesStrings", BindingFlags.Instance | BindingFlags.NonPublic);
             List <string> text        = new List <string>(1);
             text.Add("r_logentry->" + talkDesc.Translate(convoTopic, pawn.Named("INITIATOR"), otherPawn.Named("RECIPIENT")));
             RuleStrings.SetValue(goodbyeText, text);
             endConversation.logRulesInitiator = goodbyeText;
             FieldInfo Symbol = typeof(InteractionDef).GetField("symbol", BindingFlags.Instance | BindingFlags.NonPublic);
             Symbol.SetValue(endConversation, Symbol.GetValue(InteractionDefOfPsychology.EndConversation));
             PlayLogEntry_InteractionConversation log = new PlayLogEntry_InteractionConversation(endConversation, pawn, this.otherPawn, socialFightPacks);
             Find.PlayLog.Add(log);
             convoLog = log;
             MoteMaker.MakeInteractionBubble(this.pawn, this.otherPawn, InteractionDefOf.Chitchat.interactionMote, InteractionDefOf.Chitchat.Symbol);
         }
     }
 }
Пример #24
0
 public override void Tick(int currentTick)
 {
     //Performance reporting tick
     if (EnablePerformanceTesting() && currentTick % GenDate.TicksPerDay == 0 && PerformanceSetup.performanceTotals.Keys.Count > 0)
     {
         Dictionary <string, float> averages = PerformanceSetup.performanceTotals.ToDictionary(x => x.Key, x => (float)x.Value / (float)PerformanceSetup.performanceCalls[x.Key]);
         int topAmt = Math.Min(10, averages.Count);
         List <KeyValuePair <string, float> > avgTicks = (from avg in averages orderby avg.Value descending select avg).Take(topAmt).ToList();
         List <KeyValuePair <string, float> > topTicks = (from avg in averages orderby avg.Value * PerformanceSetup.performanceCalls[avg.Key] descending select avg).Take(topAmt).ToList();
         StringBuilder avgString = new StringBuilder();
         foreach (KeyValuePair <string, float> t in avgTicks)
         {
             avgString.AppendLine(t.Key + " (" + t.Value + ")");
         }
         StringBuilder topString = new StringBuilder();
         foreach (KeyValuePair <string, float> t in topTicks)
         {
             topString.AppendLine(t.Key + " (" + avgTicks.Find(x => x.Key == t.Key).Value + ")");
         }
         Log.Message("Psychology :: Performance Report :: Top " + topAmt + " average tick consumers:\n" + avgString.ToString() + "\nTop " + topAmt + " weighted tick consumers: " + topString.ToString());
     }
     //Constituent tick
     if (currentTick % GenDate.TicksPerHour * 2 == 0)
     {
         Map playerFactionMap            = Find.WorldObjects.SettlementBases.Find(b => b.Faction.IsPlayer).Map;
         IEnumerable <Pawn> constituents = (from p in playerFactionMap.mapPawns.FreeColonistsSpawned
                                            where !p.health.hediffSet.HasHediff(HediffDefOfPsychology.Mayor) && p.GetLord() == null && p.GetTimeAssignment() != TimeAssignmentDefOf.Work && p.Awake()
                                            select p);
         if (constituents.Count() > 0)
         {
             Pawn potentialConstituent       = constituents.RandomElementByWeight(p => 0.0001f + Mathf.Pow(Mathf.Abs(0.7f - p.needs.mood.CurLevel), 2));
             IEnumerable <Pawn> activeMayors = (from m in playerFactionMap.mapPawns.FreeColonistsSpawned
                                                where !m.Dead && m.health.hediffSet.HasHediff(HediffDefOfPsychology.Mayor) && ((Hediff_Mayor)m.health.hediffSet.GetFirstHediffOfDef(HediffDefOfPsychology.Mayor)).worldTileElectedOn == potentialConstituent.Map.Tile &&
                                                m.GetTimeAssignment() != TimeAssignmentDefOf.Work && m.GetTimeAssignment() != TimeAssignmentDefOf.Sleep && m.GetLord() == null && m.Awake() && m.GetLord() == null
                                                select m);
             if (potentialConstituent != null && !potentialConstituent.Downed && !potentialConstituent.Drafted && potentialConstituent.health.summaryHealth.SummaryHealthPercent >= 1f && potentialConstituent.GetTimeAssignment() != TimeAssignmentDefOf.Work && activeMayors.Count() > 0)
             {
                 Pawn    mayor  = activeMayors.RandomElement(); //There should only be one.
                 IntVec3 gather = default(IntVec3);
                 String  found  = null;
                 if (mayor.Map.GetComponent <OfficeTableMapComponent>().officeTable != null)
                 {
                     gather = mayor.Map.GetComponent <OfficeTableMapComponent>().officeTable.parent.Position;
                     found  = "office";
                 }
                 else if (mayor.ownership != null && mayor.ownership.OwnedBed != null)
                 {
                     gather = mayor.ownership.OwnedBed.Position;
                     found  = "bed";
                 }
                 if (PsycheHelper.PsychologyEnabled(potentialConstituent) && Rand.Chance((1f - PsycheHelper.Comp(potentialConstituent).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Independent)) / 5f) && (found != null || RCellFinder.TryFindPartySpot(mayor, out gather)) &&
                     (!mayor.Drafted && !mayor.Downed && mayor.health.summaryHealth.SummaryHealthPercent >= 1f && mayor.GetTimeAssignment() != TimeAssignmentDefOf.Work && (mayor.CurJob == null || mayor.CurJob.def != JobDefOf.TendPatient)))
                 {
                     List <Pawn> pawns = new List <Pawn>();
                     pawns.Add(mayor);
                     pawns.Add(potentialConstituent);
                     Lord meeting = LordMaker.MakeNewLord(mayor.Faction, new LordJob_VisitMayor(gather, potentialConstituent, mayor, (potentialConstituent.needs.mood.CurLevel < (potentialConstituent.mindState.mentalBreaker.BreakThresholdMinor * 1.25f))), mayor.Map, pawns);
                     mayor.jobs.EndCurrentJob(Verse.AI.JobCondition.InterruptForced);
                     potentialConstituent.jobs.EndCurrentJob(Verse.AI.JobCondition.InterruptForced);
                     if (found == "bed")
                     {
                         mayor.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.MayorNoOffice);
                     }
                     else if (found == null)
                     {
                         mayor.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.MayorNoBedroom);
                     }
                 }
             }
         }
     }
     //Election tick
     if (currentTick % (GenDate.TicksPerDay / 4f) == 0)
     {
         foreach (Settlement settlement in Find.WorldObjects.Settlements)
         {
             //Self-explanatory.
             if (!PsychologyBase.ActivateElections())
             {
                 continue;
             }
             //If the base isn't owned or named by the player, no election can be held.
             if (!settlement.Faction.IsPlayer || !settlement.namedByPlayer)
             {
                 continue;
             }
             //If the base is not at least a year old, no election will be held.
             if ((Find.TickManager.TicksGame - settlement.creationGameTicks) / GenDate.TicksPerYear < 1)
             {
                 continue;
             }
             //A base must have at least 7 people in it to hold an election.
             if (settlement.Map.mapPawns.FreeColonistsSpawnedCount < 7)
             {
                 continue;
             }
             //If an election is already being held, don't start a new one.
             if (settlement.Map.gameConditionManager.ConditionIsActive(GameConditionDefOfPsychology.Election) || settlement.Map.lordManager.lords.Find(l => l.LordJob is LordJob_Joinable_Election) != null)
             {
                 continue;
             }
             //Elections are held in Septober (because I guess some maps don't have fall?) and during the day.
             if (GenDate.Quadrum(Find.TickManager.TicksAbs, Find.WorldGrid.LongLatOf(settlement.Tile).x) != Quadrum.Septober || (GenLocalDate.HourOfDay(settlement.Map) < 7 || GenLocalDate.HourOfDay(settlement.Map) > 20))
             {
                 continue;
             }
             //If an election has already been completed this year, don't start a new one.
             IEnumerable <Pawn> activeMayors = (from m in settlement.Map.mapPawns.FreeColonistsSpawned
                                                where !m.Dead && m.health.hediffSet.HasHediff(HediffDefOfPsychology.Mayor) && ((Hediff_Mayor)m.health.hediffSet.GetFirstHediffOfDef(HediffDefOfPsychology.Mayor)).worldTileElectedOn == settlement.Map.Tile && ((Hediff_Mayor)m.health.hediffSet.GetFirstHediffOfDef(HediffDefOfPsychology.Mayor)).yearElected == GenLocalDate.Year(settlement.Map.Tile)
                                                select m);
             if (activeMayors.Count() > 0)
             {
                 continue;
             }
             //Try to space out the elections so they don't all proc at once.
             if (Rand.RangeInclusive(1, 15 - GenLocalDate.DayOfQuadrum(settlement.Map.Tile)) > 1)
             {
                 continue;
             }
             IncidentParms parms = new IncidentParms();
             parms.target  = settlement.Map;
             parms.faction = settlement.Faction;
             FiringIncident fi = new FiringIncident(IncidentDefOfPsychology.Election, null, parms);
             Find.Storyteller.TryFire(fi);
         }
     }
 }
Пример #25
0
        private ThoughtDef CreateSocialThought(out float opinionMod)
        {
            //We create a dynamic def to hold this thought so that the game won't worry about it being used anywhere else.
            ThoughtDef def = new ThoughtDef();

            def.defName          = this.pawn.GetHashCode() + "Conversation" + topic.defName;
            def.label            = topic.defName;
            def.durationDays     = PsychologyBase.ConvoDuration();
            def.nullifyingTraits = new List <TraitDef>();
            def.nullifyingTraits.Add(TraitDefOf.Psychopath);
            def.thoughtClass = typeof(Thought_MemorySocialDynamic);
            ThoughtStage stage = new ThoughtStage();

            /* Base opinion mod is 5 to the power of controversiality.
             * Controversiality varies from 0.7 (~3.09) to 1.5 (~11.18).
             */
            opinionMod = Mathf.Pow(5f, topic.controversiality);

            /* That opinion mod is weighted by the difference in their personality. 1 is identical, 0 is polar opposites.
             * Here's the math on how this works:
             *
             * The weighting is on a heavily customized cubic curve. It looks like this: https://www.wolframalpha.com/input/?i=(9.5((x-0.5)%5E3))%2B(2x%2F3)%5E2-0.3+from+0+to+1
             * The maximum positive weight is 1.27x. The maximum negative weight is -1.4875x. The neutral weight (0x) is at an opinion diff of 0.706.
             * This means that to have a positive thought from a conversation, pawns need to have a <31% difference in personality on that topic.
             * However, since it's a cubic curve, the negative modifier builds gradually. Pawns will need a >79% difference in personality to have a -0.5x weight.
             * But they'll also need a <23% difference to have a 0.5x weight. Normal agreement is at ~0.962, and normal disagreement is at ~0.073.
             * Pawns are unlikely to have huge differences in opinion. There are more ways for them to be close to each other than far apart. Here's the proof: https://anydice.com/program/1177b4
             * The approximate likelihood for them to agree on something with this weighting is 49.89%.
             *
             * Pawns' differences are exacerbated when they are in a relationship, but their similarities are also magnified.
             * The neutral conversation weight (0x) moves from 0.706 to 0.759, so the threshold for agreement is ~5% higher.
             * Normal disagreement moves from 0.073 to 0.127, and normal agreement moves from 0.962 to 0.946.
             * The maximum positive weight moves from 1.27x to 1.4986x. The maximum negative weight moves from -1.425x to -1.9875x.
             * The approximate likelihood for them to agree on something with this weighting is 42.63%.
             */
            float rawOpinionDiff = 1f - Mathf.Abs(PsycheHelper.Comp(pawn).Psyche.GetPersonalityRating(topic) - PsycheHelper.Comp(otherPawn).Psyche.GetPersonalityRating(topic));

            if (LovePartnerRelationUtility.LovePartnerRelationExists(this.pawn, this.otherPawn))
            {
                opinionMod *= (13.5f * (Mathf.Pow(rawOpinionDiff - 0.5f, 3))) + Mathf.Pow(((3f * rawOpinionDiff) / 9f), 2) - 0.3f;
            }
            else
            {
                opinionMod *= (9.5f * (Mathf.Pow(rawOpinionDiff - 0.5f, 3))) + Mathf.Pow(((2f * rawOpinionDiff) / 3f), 2) - 0.3f;
            }
            //Old cubic interpolation weighting.
            //opinionMod *= Mathf.Lerp((LovePartnerRelationUtility.LovePartnerRelationExists(pawn, otherPawn) ? -2f : -1.5f), (LovePartnerRelationUtility.LovePartnerRelationExists(pawn, otherPawn) ? 1.5f : 1.25f), weightedOpinionDiff);

            /* The Cool modifier ranges from 3^(0.7) ~ 2.16 to 3^(1.5) ~ 5.2.
             * If a pawn is Cool, that modifier is a positive one added to all conversational thoughts. Otherwise, it's subtracted.
             * On average, Cool pawns will be liked better, and non-Cool pawns will be disliked more.
             */
            opinionMod += Mathf.Pow(3f, topic.controversiality) * (PsycheHelper.Comp(otherPawn).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Cool) - 0.5f);

            /* The length of the talk has a large impact on how much the pawn cares.
             * A conversation is considered "full impact" at 1,125 ticks, or less than half an hour in-game.
             * A short talk (500 ticks or less) has a maximum 0.53x impact. The max opinion this could give (for non-lovers) is 7.5/-8.8.
             * A normal talk (half an hour or less) has a maximum 1.33x impact. The max opinion this could give is 18.9/-22.1.
             * A long talk (2.5 hours or less) has a maximum 6.67x impact. The max opinion this could give is 94.7/-110.9.
             * An epic talk (2.5+ hours) has no maximum impact, but after 2 hours the MTB to end the conversation becomes half an hour, so it's unlikely they will ever have an epic talk.
             * An average conversation is 1-2 hours, so on average the max opinion (not counting Cool modifier) is 37.9/-44.3 to 75.7/-88.7.
             * Again, it's unlikely the numbers will get that high. This is assuming identical or polar opposite personalities.
             */
            opinionMod *= 6f * ((float)this.ageTicks / (float)(GenDate.TicksPerHour * 2.25f));
            // Negative opinions are tempered by how Polite the other pawn is. An extremely impolite pawn will make a bad opinion 1.5x worse. A very polite pawn will make it half as bad.
            opinionMod *= (opinionMod < 0f ? 0.5f + (1f - PsycheHelper.Comp(otherPawn).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Polite)) : 1f);
            // Positive opinions are bolstered by how Friendly the other pawn is. An extremely friendly pawn will make a positive opinion 1.5x better. A very unfriendly pawn will halve it.
            opinionMod *= (opinionMod > 0f ? 0.5f + PsycheHelper.Comp(otherPawn).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Friendly) : 1f);
            // The more Judgmental the pawn, the more they're affected by all conversations.
            opinionMod *= 0.5f + PsycheHelper.Comp(pawn).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Judgmental);
            // In low-population colonies, pawns will put aside their differences.
            if (opinionMod < 0f)
            {
                opinionMod *= PopulationModifier;
            }
            else if (LovePartnerRelationUtility.LovePartnerRelationExists(this.pawn, this.otherPawn) && this.pawn.story.traits.HasTrait(TraitDefOfPsychology.Codependent))
            {
                //If it's a positive thought about their lover, Codependent pawns are always 1.25x as affected by it.
                opinionMod *= 1.25f;
            }
            stage.label             = "ConversationStage".Translate() + " " + convoTopic;
            stage.baseOpinionOffset = Mathf.RoundToInt(opinionMod);
            def.stages.Add(stage);
            return(def);
        }
Пример #26
0
        public override void DoWindowContents(Rect inRect)
        {
            bool flag = false;

            if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
            {
                flag = true;
                Event.current.Use();
            }
            bool flag2 = false;

            if (Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Escape)
            {
                flag2 = true;
                Event.current.Use();
            }
            Rect windowRect = inRect.ContractedBy(17f);
            Rect mainRect   = new Rect(windowRect.x, windowRect.y, windowRect.width, windowRect.height - 20f);
            Rect okRect     = new Rect(inRect.width / 4 - 20f, mainRect.yMax + 10f, inRect.width / 4f, 30f);
            Rect cancelRect = new Rect(okRect.xMax + 40f, mainRect.yMax + 10f, inRect.width / 4f, 30f);

            Text.Font = GameFont.Medium;
            Widgets.Label(mainRect, "PsycheEditor".Translate(pawn.LabelShort));
            mainRect.yMin += 35f;
            Text.Font      = GameFont.Small;
            float warningSize = Mathf.Max(50f, Text.CalcHeight("PersonalityNodeWarning".Translate(), mainRect.width));

            Widgets.Label(mainRect, "PersonalityNodeWarning".Translate());
            mainRect.yMin += warningSize;
            float labelSize         = Mathf.Max(26f, Text.CalcHeight("SexDrive".Translate(), mainRect.width));
            Rect  nodeRect          = new Rect(mainRect.x, mainRect.y, mainRect.width, mainRect.height - labelSize * 3 - 20f);
            Rect  sexDriveRect      = new Rect(mainRect.x, nodeRect.yMax + 10f, mainRect.width, labelSize);
            Rect  romanticDriveRect = new Rect(mainRect.x, sexDriveRect.yMax, mainRect.width, labelSize);
            Rect  kinseyRect        = new Rect(mainRect.x, romanticDriveRect.yMax, mainRect.width, labelSize + 10f);

            Widgets.DrawLineHorizontal(nodeRect.x, nodeRect.yMax, nodeRect.width);
            float num = 0f;

            foreach (PersonalityNode node in PsycheHelper.Comp(pawn).Psyche.PersonalityNodes)
            {
                num += Mathf.Max(26f, Text.CalcHeight(node.def.label, nodeRect.width));
            }
            Rect viewRect = new Rect(0f, 0f, nodeRect.width - 20f, num);

            Widgets.BeginScrollView(nodeRect, ref nodeScrollPosition, viewRect);
            float num3 = 0f;

            for (int i = 0; i < cachedList.Count; i++)
            {
                string label = cachedList[i].First;
                float  num4  = Mathf.Max(26f, Text.CalcHeight(label, viewRect.width));
                Rect   rect  = new Rect(10f, num3, viewRect.width / 3, num4);
                Rect   rect2 = new Rect(10f + viewRect.width / 3, num3, ((2 * viewRect.width) / 3) - 20f, num4);
                Widgets.DrawHighlightIfMouseover(rect);
                Widgets.Label(rect, label);
                TooltipHandler.TipRegion(rect, () => descriptions[label], 436532 + Mathf.RoundToInt(num3));
                float newVal = Widgets.HorizontalSlider(rect2, cachedList[i].Second, 0f, 1f, true);
                cachedList[i] = new Pair <string, float>(cachedList[i].First, newVal);
                num3         += num4;
            }
            Widgets.EndScrollView();
            if (PsychologyBase.ActivateKinsey())
            {
                Rect sexDriveLabelRect  = new Rect(sexDriveRect.x, sexDriveRect.y, sexDriveRect.width / 3, sexDriveRect.height);
                Rect sexDriveSliderRect = new Rect(sexDriveRect.x + (sexDriveRect.width / 3), sexDriveRect.y, (2 * sexDriveRect.width) / 3, sexDriveRect.height);
                Widgets.Label(sexDriveLabelRect, "SexDrive".Translate());
                pawnSexDrive = Widgets.HorizontalSlider(sexDriveSliderRect, pawnSexDrive, 0f, 1f, true);
                Rect romanticDriveLabelRect  = new Rect(romanticDriveRect.x, romanticDriveRect.y, romanticDriveRect.width / 3, romanticDriveRect.height);
                Rect romanticDriveSliderRect = new Rect(romanticDriveRect.x + (romanticDriveRect.width / 3), romanticDriveRect.y, (2 * romanticDriveRect.width) / 3, romanticDriveRect.height);
                Widgets.Label(romanticDriveLabelRect, "RomanticDrive".Translate());
                pawnRomanticDrive = Widgets.HorizontalSlider(romanticDriveSliderRect, pawnRomanticDrive, 0f, 1f, true);
                Rect kinseyRatingLabelRect  = new Rect(kinseyRect.x, kinseyRect.y, kinseyRect.width / 3, kinseyRect.height);
                Rect kinseyRatingSliderRect = new Rect(kinseyRect.x + (kinseyRect.width / 3), kinseyRect.y, (2 * kinseyRect.width) / 3, kinseyRect.height);
                Widgets.Label(kinseyRatingLabelRect, "KinseyRating".Translate());
                pawnKinseyRating = Mathf.RoundToInt(Widgets.HorizontalSlider(kinseyRatingSliderRect, pawnKinseyRating, 0f, 6f, true, leftAlignedLabel: "0", rightAlignedLabel: "6"));
            }
            else
            {
                GUI.color = Color.red;
                Rect warningRect = new Rect(mainRect.x, nodeRect.yMax + 10f, mainRect.width, labelSize * 3);
                Widgets.Label(warningRect, "SexualityDisabledWarning".Translate());
                GUI.color = Color.white;
            }
            if (Widgets.ButtonText(okRect, "AcceptButton".Translate(), true, false, true) || flag)
            {
                foreach (PersonalityNode node in PsycheHelper.Comp(pawn).Psyche.PersonalityNodes)
                {
                    node.rawRating = (from n in cachedList
                                      where n.First == node.def.label.CapitalizeFirst()
                                      select n).First().Second;
                }
                if (PsychologyBase.ActivateKinsey())
                {
                    PsycheHelper.Comp(pawn).Sexuality.sexDrive      = pawnSexDrive;
                    PsycheHelper.Comp(pawn).Sexuality.romanticDrive = pawnRomanticDrive;
                    PsycheHelper.Comp(pawn).Sexuality.kinseyRating  = pawnKinseyRating;
                }
                this.Close(false);
            }
            if (Widgets.ButtonText(cancelRect, "CancelButton".Translate(), true, false, true) || flag2)
            {
                this.Close(true);
            }
        }
Пример #27
0
        public override void Init()
        {
            base.Init();
            //Make sure the election occurs during the day if possible.
            int plannedStart = GenDate.HourOfDay(this.Duration + Find.TickManager.TicksAbs, Find.WorldGrid.LongLatOf(this.SingleMap.Tile).x);

            if (plannedStart < 7)
            {
                this.Duration += (7 - plannedStart) * GenDate.TicksPerHour;
            }
            else if (plannedStart > 18)
            {
                this.Duration -= (plannedStart - 18) * GenDate.TicksPerHour;
            }
            IEnumerable <Pawn> psychologyColonists = (from p in this.SingleMap.mapPawns.FreeColonistsSpawned
                                                      where PsycheHelper.PsychologyEnabled(p)
                                                      select p);
            int   maxCandidatesThisColonySupports = Mathf.RoundToInt(psychologyColonists.Count() * 0.3f);
            float totalOutspoken = 0f;

            foreach (Pawn p in psychologyColonists)
            {
                totalOutspoken += PsycheHelper.Comp(p).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Outspoken);
            }
            int numCandidates = Rand.RangeInclusive(Mathf.Min(maxCandidatesThisColonySupports, 1 + Mathf.RoundToInt(totalOutspoken * 0.1f)), maxCandidatesThisColonySupports);
            int tries         = 0;

            while (this.candidates.Count < numCandidates && tries < 500)
            {
                Pawn candidate = psychologyColonists.RandomElementByWeight(p => (p.ageTracker.CurLifeStageIndex >= 3) ? PsycheHelper.Comp(p).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Outspoken) * 2 + (p.health.hediffSet.HasHediff(HediffDefOfPsychology.Mayor) ? p.needs.mood.CurLevel - 0.5f : 0f) : 0f);
                List <PersonalityNodeDef> issues = new List <PersonalityNodeDef>();
                int tries2 = 0;
                while (issues.Count < 5 && tries2 < 500)
                {
                    PersonalityNodeDef issue = (from node in PsycheHelper.Comp(candidate).Psyche.PersonalityNodes
                                                where !node.Core
                                                select node.def).RandomElementByWeight(n => Mathf.Pow(Mathf.Abs(0.5f - PsycheHelper.Comp(candidate).Psyche.GetPersonalityRating(n)), 4) * Mathf.Pow(2, n.controversiality));
                    if (!issues.Contains(issue))
                    {
                        issues.Add(issue);
                    }
                    else
                    {
                        tries2++;
                    }
                }
                if (issues.Count >= 5 && this.candidates.Find(c => c.pawn == candidate) == null)
                {
                    this.candidates.Add(new Candidate(candidate, issues));
                }
                else
                {
                    if (issues.Count < 5)
                    {
                        Log.Error("[Psychology] Could not find five unique issues for " + candidate.LabelShort + "'s platform.");
                    }
                    tries++;
                }
            }
            if (candidates.Count == 0)
            {
                this.End();
                Log.Error("[Psychology] Tried to start election but could not find anyone to run.");
                return;
            }
            foreach (Candidate candidate in candidates)
            {
                StringBuilder issuesString = new StringBuilder();
                for (int i = 0; i < candidate.nodes.Count; i++)
                {
                    issuesString.AppendFormat("{0}) {1}{2}", i + 1, PsycheHelper.Comp(candidate.pawn).Psyche.GetPersonalityNodeOfDef(candidate.nodes[i]).PlatformIssue, (i != candidate.nodes.Count - 1 ? "\n" : ""));
                }
                Find.LetterStack.ReceiveLetter("LetterLabelElectionCandidate".Translate(candidate.pawn.LabelShort), "LetterElectionCandidate".Translate(candidate.pawn.LabelShort, Find.WorldObjects.ObjectsAt(candidate.pawn.Map.Tile).OfType <SettlementBase>().First().Label, issuesString.ToString()).AdjustedFor(candidate.pawn), LetterDefOf.NeutralEvent, candidate.pawn, null);
            }
        }
Пример #28
0
        private static void DrawPersonalityNodes(Rect rect, Pawn pawn)
        {
            float width = rect.width - 26f - 3f;
            List <PersonalityNode> allNodes = (from n in PsycheHelper.Comp(pawn).Psyche.PersonalityNodes
                                               orderby n.AdjustedRating descending, n.def.defName
                                               select n).ToList();

            PsycheCardUtility.nodeStrings.Clear();
            float num = 0f;

            for (int i = 0; i < allNodes.Count(); i++)
            {
                float rating   = allNodes[i].AdjustedRating;
                float yAxis    = 0.5f - rating;
                float weight   = Mathf.Sqrt(Mathf.Abs(rating - 0.5f)) * (1 / Mathf.Sqrt(0.5f));
                int   category = Mathf.RoundToInt((Categories / 2) - (Categories * yAxis * weight));
                if (/*!allNodes[i].Core && */ category != 3)
                {
                    string text = (NodeDescriptions[category] == "" ? "" : ("Psyche" + NodeDescriptions[category]).Translate());
                    PsycheCardUtility.nodeStrings.Add(new Pair <string, int>(text, i));
                    num += Mathf.Max(26f, Text.CalcHeight(text, width));
                }
            }
            Rect viewRect = new Rect(0f, 0f, rect.width, num);

            viewRect.xMax *= 0.9f;
            Widgets.BeginScrollView(rect, ref PsycheCardUtility.nodeScrollPosition, viewRect);
            float num3 = 0f;

            for (int j = 0; j < PsycheCardUtility.nodeStrings.Count; j++)
            {
                string          first    = PsycheCardUtility.nodeStrings[j].First;
                PersonalityNode node     = allNodes[PsycheCardUtility.nodeStrings[j].Second];
                float           num4     = Mathf.Max(26f, Text.CalcHeight(first, width));
                Rect            rect2    = new Rect(10f, num3, width / 3, num4);
                Rect            rect3    = new Rect(10f + width / 3, num3, (2 * width) / 3, num4);
                float           rating   = node.AdjustedRating;
                float           yAxis    = 0.5f - rating;
                float           weight   = Mathf.Sqrt(Mathf.Abs(rating - 0.5f)) * (1 / Mathf.Sqrt(0.5f));
                int             category = Mathf.RoundToInt((Categories / 2) - (Categories * yAxis * weight));
                GUI.color = NodeColors[category];
                Widgets.Label(rect2, first.ToString());
                if (Prefs.DevMode && Prefs.LogVerbose)
                {
                    TooltipHandler.TipRegion(rect2, delegate { return((100f * node.AdjustedRating) + "%"); }, 693261 + j * 310);
                }
                GUI.color = Color.white;
                Widgets.DrawHighlightIfMouseover(rect3);
                Widgets.Label(rect3, node.def.label.CapitalizeFirst());
                Func <String> descriptionString = delegate
                {
                    if (node.def.conversationTopics != null)
                    {
                        return(node.def.description + "\n\n" + "ConversationTooltip".Translate(string.Join(", ", node.def.conversationTopics.Take(node.def.conversationTopics.Count - 1).ToArray()) + "ConversationAnd".Translate() + node.def.conversationTopics.Last()));
                    }
                    return(node.def.description);
                };
                TooltipHandler.TipRegion(rect3, descriptionString, 613261 + j * 612);
                num3 += num4;
            }
            Widgets.EndScrollView();
        }