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);
        }
Example #2
0
        private static void AddBrokeUpMood(Pawn lover, Pawn ex, float intensity = 1f)
        {
            ThoughtDef brokeUpMoodDef = new ThoughtDef();

            brokeUpMoodDef.defName = "BrokeUpWithMeMood" + lover.LabelShort + Find.TickManager.TicksGame;
            if (intensity < 1f)
            {
                brokeUpMoodDef.durationDays = 10f;
            }
            else
            {
                brokeUpMoodDef.durationDays = 40f;
            }
            brokeUpMoodDef.thoughtClass            = typeof(Thought_MemoryDynamic);
            brokeUpMoodDef.stackedEffectMultiplier = 1f;
            brokeUpMoodDef.stackLimit = 999;
            ThoughtStage brokeUpStage = new ThoughtStage();

            brokeUpStage.label          = "Broke up with {0}";
            brokeUpStage.baseMoodEffect = Mathf.RoundToInt(-4f * intensity * Mathf.InverseLerp(0.25f, 0.75f, PsycheHelper.Comp(lover).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic)) * Mathf.InverseLerp(-20f, 100f, lover.relations.OpinionOf(ex)));
            if (brokeUpStage.baseMoodEffect < -5f)
            {
                brokeUpStage.description = "{0} and I parted ways amicably, but it's still a little sad.";
            }
            else
            {
                brokeUpStage.description = "I'm going through a bad break-up right now.";
            }
            brokeUpMoodDef.stages.Add(brokeUpStage);
            if (brokeUpStage.baseMoodEffect > 0f)
            {
                lover.needs.mood.thoughts.memories.TryGainMemory(brokeUpMoodDef, ex);
            }
        }
        public override void ExposeData()
        {
            if (this.def != null)
            {
                this.def.defName = "Dynamic";
            }
            base.ExposeData();
            Scribe_Values.Look(ref this.topic, "topic", "Dynamic");
            Scribe_Values.Look(ref this.label, "label", "dynamic thought");
            Scribe_Values.Look(ref this.description, "description", "a dynamic thought.");
            Scribe_Values.Look(ref this.duration, "duration", 5f);
            Scribe_Values.Look(ref this.baseMoodEffect, "realMoodEffect", 5f);
            ThoughtDef def = new ThoughtDef();

            def.defName                 = this.topic;
            def.label                   = "dynamic thought";
            def.description             = this.description;
            def.durationDays            = this.duration;
            def.thoughtClass            = typeof(Thought_MemoryDynamic);
            def.stackedEffectMultiplier = 1f;
            def.stackLimit              = 999;
            ThoughtStage stage = new ThoughtStage();

            stage.label          = this.label;
            stage.baseMoodEffect = this.baseMoodEffect;
            def.stages.Add(stage);
            this.def = def;
        }
        public ThoughtStageWidget(ThoughtStage stage)
        {
            this.stage = stage;

            this.inputWidgets = new List <IInputWidget>()
            {
                new FloatInputWidget <ThoughtStage>(this.stage, "Base Mood Effect", s => s.baseMoodEffect, (s, v) => s.baseMoodEffect          = v),
                new FloatInputWidget <ThoughtStage>(this.stage, "Base Opinion Offset", s => s.baseOpinionOffset, (s, v) => s.baseOpinionOffset = v),
                new BoolInputWidget <ThoughtStage>(this.stage, "Visible", s => s.visible, (s, v) => s.visible = v)
            };
        }
Example #5
0
        public static void Thoughts()
        {
            Func <ThoughtDef, string> stagesText = delegate(ThoughtDef t)
            {
                string text = "";
                if (t.stages == null)
                {
                    return(null);
                }
                for (int i = 0; i < t.stages.Count; i++)
                {
                    ThoughtStage thoughtStage = t.stages[i];
                    text = text + "[" + i + "] ";
                    if (thoughtStage == null)
                    {
                        text += "null";
                    }
                    else
                    {
                        if (thoughtStage.label != null)
                        {
                            text += thoughtStage.label;
                        }
                        if (thoughtStage.labelSocial != null)
                        {
                            if (thoughtStage.label != null)
                            {
                                text += "/";
                            }
                            text += thoughtStage.labelSocial;
                        }
                        text += " ";
                        if (thoughtStage.baseMoodEffect != 0f)
                        {
                            text = text + "[" + thoughtStage.baseMoodEffect.ToStringWithSign() + " Mo]";
                        }
                        if (thoughtStage.baseOpinionOffset != 0f)
                        {
                            text = text + "(" + thoughtStage.baseOpinionOffset.ToStringWithSign() + " Op)";
                        }
                    }
                    if (i < t.stages.Count - 1)
                    {
                        text += "\n";
                    }
                }
                return(text);
            };

            DebugTables.MakeTablesDialog(DefDatabase <ThoughtDef> .AllDefs, new TableDataGetter <ThoughtDef>("defName", (ThoughtDef d) => d.defName), new TableDataGetter <ThoughtDef>("type", (ThoughtDef d) => (!d.IsMemory) ? "situ" : "mem"), new TableDataGetter <ThoughtDef>("social", (ThoughtDef d) => (!d.IsSocial) ? "mood" : "soc"), new TableDataGetter <ThoughtDef>("stages", (ThoughtDef d) => stagesText(d)), new TableDataGetter <ThoughtDef>("best\nmood", (ThoughtDef d) => d.stages.Where((ThoughtStage st) => st != null).Max((ThoughtStage st) => st.baseMoodEffect)), new TableDataGetter <ThoughtDef>("worst\nmood", (ThoughtDef d) => d.stages.Where((ThoughtStage st) => st != null).Min((ThoughtStage st) => st.baseMoodEffect)), new TableDataGetter <ThoughtDef>("stack\nlimit", (ThoughtDef d) => d.stackLimit.ToString()), new TableDataGetter <ThoughtDef>("stack\nlimit\nper o. pawn", (ThoughtDef d) => (d.stackLimitForSameOtherPawn >= 0) ? d.stackLimitForSameOtherPawn.ToString() : ""), new TableDataGetter <ThoughtDef>("stacked\neffect\nmultiplier", (ThoughtDef d) => (d.stackLimit != 1) ? d.stackedEffectMultiplier.ToStringPercent() : ""), new TableDataGetter <ThoughtDef>("duration\n(days)", (ThoughtDef d) => d.durationDays.ToString()), new TableDataGetter <ThoughtDef>("effect\nmultiplying\nstat", (ThoughtDef d) => (d.effectMultiplyingStat != null) ? d.effectMultiplyingStat.defName : ""), new TableDataGetter <ThoughtDef>("game\ncondition", (ThoughtDef d) => (d.gameCondition != null) ? d.gameCondition.defName : ""), new TableDataGetter <ThoughtDef>("hediff", (ThoughtDef d) => (d.hediff != null) ? d.hediff.defName : ""), new TableDataGetter <ThoughtDef>("lerp opinion\nto zero\nafter duration pct", (ThoughtDef d) => d.lerpOpinionToZeroAfterDurationPct.ToStringPercent()), new TableDataGetter <ThoughtDef>("max cumulated\nopinion\noffset", (ThoughtDef d) => (!(d.maxCumulatedOpinionOffset > 99999f)) ? d.maxCumulatedOpinionOffset.ToString() : ""), new TableDataGetter <ThoughtDef>("next\nthought", (ThoughtDef d) => (d.nextThought != null) ? d.nextThought.defName : ""), new TableDataGetter <ThoughtDef>("nullified\nif not colonist", (ThoughtDef d) => d.nullifiedIfNotColonist.ToStringCheckBlank()), new TableDataGetter <ThoughtDef>("show\nbubble", (ThoughtDef d) => d.showBubble.ToStringCheckBlank()));
        }
        public static void AddBrokeUpOpinion(PsychologyPawn lover, PsychologyPawn ex)
        {
            ThoughtDef brokeUpDef = new ThoughtDef();

            brokeUpDef.defName      = "BrokeUpWithMe" + lover.LabelShort + Find.TickManager.TicksGame;
            brokeUpDef.durationDays = 40f;
            brokeUpDef.thoughtClass = typeof(Thought_MemorySocialDynamic);
            ThoughtStage brokeUpStage = new ThoughtStage();

            brokeUpStage.label             = "broke up with me";
            brokeUpStage.baseOpinionOffset = Mathf.RoundToInt(-50f * lover.psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * Mathf.InverseLerp(5f, 100f, lover.relations.OpinionOf(ex)));
            brokeUpDef.stages.Add(brokeUpStage);
            lover.needs.mood.thoughts.memories.TryGainMemory(brokeUpDef, ex);
        }
 public ThoughtStageStats(ThoughtStage ts)
 {
     if (ts != null)
     {
         this.label             = ts.label;
         this.baseMoodEffect    = ts.baseMoodEffect;
         this.baseOpinionOffset = ts.baseOpinionOffset;
         this.visible           = ts.visible;
         this.isNull            = false;
     }
     else
     {
         this.isNull = true;
     }
 }
Example #8
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);
        }
Example #9
0
 private static void RenderThoughtStage(ThoughtStage stg)
 {
     CONS.WriteLine("      li");
     CONS.WriteLine($"        label: {stg.Label.ToStringOrDefault()}");
     if (stg.LabelSocial != null)
     {
         CONS.WriteLine($"        labelSocial: {stg.LabelSocial.ToStringOrDefault()}");
     }
     CONS.WriteLine($"        description: {stg.Description.ToStringOrDefault()}");
     if (stg.BaseMoodEffect.HasValue)
     {
         CONS.WriteLine($"        baseMoodEffect: {stg.BaseMoodEffect.Value}");
     }
     if (stg.BaseOpinionOffset.HasValue)
     {
         CONS.WriteLine($"        baseOpinionOffset: {stg.BaseOpinionOffset.Value}");
     }
 }
Example #10
0
        //Modified directly from Psychology.
        private static void AddBrokeUpOpinion(Pawn lover, Pawn ex, float intensity = 1f)
        {
            ThoughtDef brokeUpDef = new ThoughtDef();

            brokeUpDef.defName = "BrokeUpWithMe" + lover.LabelShort + Find.TickManager.TicksGame;
            if (intensity < 1f)
            {
                brokeUpDef.durationDays = 10f;
            }
            else
            {
                brokeUpDef.durationDays = 40f;
            }
            brokeUpDef.thoughtClass = typeof(Thought_MemorySocialDynamic);
            ThoughtStage brokeUpStage = new ThoughtStage();

            brokeUpStage.label             = "broke up with me";
            brokeUpStage.baseOpinionOffset = Mathf.RoundToInt(-10 * intensity * PsycheHelper.Comp(lover).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * Mathf.InverseLerp(5f, 100f, lover.relations.OpinionOf(ex)));
            brokeUpDef.stages.Add(brokeUpStage);
            lover.needs.mood.thoughts.memories.TryGainMemory(brokeUpDef, ex);
        }
Example #11
0
        public static void FindAllTODOThoughts()
        {
            var builder  = new StringBuilder();
            var defNames = new List <string>();

            foreach (ThoughtDef thoughtDef in DefDatabase <ThoughtDef> .AllDefs)
            {
                var addedHeader = false;
                for (var index = 0; index < (thoughtDef?.stages?.Count ?? 0); index++)
                {
                    ThoughtStage stage = thoughtDef?.stages?[index];
                    if (stage == null)
                    {
                        continue;
                    }
                    if (string.IsNullOrEmpty(stage.label) || string.IsNullOrEmpty(stage.description))
                    {
                        continue;
                    }
                    if (stage.label == "TODO" ||
                        stage.description == "TODO" ||
                        stage.description.StartsWith("!!!") ||
                        stage.label.StartsWith("!!!"))
                    {
                        if (!addedHeader)
                        {
                            builder.AppendLine($"In {thoughtDef.defName}:");
                            addedHeader = true;
                        }

                        defNames.Add(thoughtDef.defName);
                        builder.AppendLine($"{index}) label:{stage.label} description:\"{stage.description}\"".Indented());
                    }
                }
            }

            builder.AppendLine(defNames.Distinct().Join(d => d, "\n"));

            Log.Message(builder.ToString());
        }
Example #12
0
        private static void Postfix(IngestionOutcomeDoer_GiveHediff __instance, Pawn pawn, Thing ingested)
        {
            ThoughtStage ts = new ThoughtStage()
            {
                label          = "took antidepressants",
                description    = "I feel calm. LOL",
                baseMoodEffect = -50,
            };
            ThoughtDef td = new ThoughtDef()
            {
                defName      = "AteAntiDepressant",
                durationDays = 0.5f,
                stackLimit   = 1,
                stages       = new List <ThoughtStage>()
                {
                    ts
                },
            };

            pawn.needs.mood.thoughts.memories.TryGainMemory(td, null);
            Debug.Log("debug : " + ingested.def.defName + " " + pawn.Name);
        }
        public override void ExposeData()
        {
            if (this.def != null)
            {
                this.def.defName = "DynamicSocial";
            }
            base.ExposeData();
            Scribe_Values.Look(ref this.topic, "topic", "DynamicSocial");
            Scribe_Values.Look(ref this.label, "label", "conversation");
            Scribe_Values.Look(ref this.baseOpinionOffset, "realOpinionOffset", 5);
            ThoughtDef def = new ThoughtDef();

            def.defName      = this.topic;
            def.label        = "conversation";
            def.durationDays = 60f;
            def.thoughtClass = typeof(Thought_MemorySocialDynamic);
            ThoughtStage stage = new ThoughtStage();

            stage.label             = this.label;
            stage.baseOpinionOffset = this.baseOpinionOffset;
            def.stages.Add(stage);
            this.def = def;
        }
        public override void PostRemoved()
        {
            base.PostRemoved();
            if (this.realPawn == null)
            {
                this.realPawn = this.pawn as PsychologyPawn;
            }
            if (this.realPawn != null && this.otherPawn != null)
            {
                Hediff otherConvo = otherPawn.health.hediffSet.hediffs.Find(h => h is Hediff_Conversation && ((Hediff_Conversation)h).otherPawn == this.realPawn);
                if (otherConvo != null)
                {
                    this.otherPawn.health.RemoveHediff(otherConvo);
                }
                string talkDesc;
                if (this.ageTicks < 500)
                {
                    int numShortTalks = int.Parse("NumberOfShortTalks".Translate());
                    talkDesc = "ShortTalk" + Rand.RangeInclusive(1, numShortTalks);
                }
                else if (this.ageTicks < 1500)
                {
                    int numNormalTalks = int.Parse("NumberOfNormalTalks".Translate());
                    talkDesc = "NormalTalk" + Rand.RangeInclusive(1, numNormalTalks);
                }
                else if (this.ageTicks < 5000)
                {
                    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);
                }
                //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     = 60f;
                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.
                float opinionMod = Mathf.Pow(5f, topic.controversiality);
                //Multiplied by difference between their personality ratings, on an exponential scale.
                opinionMod *= Mathf.Lerp(-1.25f, 1.25f, Mathf.Pow(1f - Mathf.Abs(this.realPawn.psyche.GetPersonalityRating(topic) - this.otherPawn.psyche.GetPersonalityRating(topic)), 3));
                //Cool pawns are liked more.
                opinionMod += Mathf.Pow(2f, topic.controversiality) * (0.5f - this.otherPawn.psyche.GetPersonalityRating(PersonalityNodeDefOf.Cool));
                //The length of the talk has a large impact on how much the pawn cares.
                opinionMod *= 5f * (this.ageTicks / (GenDate.TicksPerHour * 2.25f)); //talkModifier[talkLength]
                //If they had a bad experience, the more polite the pawn is, the less they're bothered by it.
                opinionMod *= (opinionMod < 0f ? 0.5f + (1f - this.otherPawn.psyche.GetPersonalityRating(PersonalityNodeDefOf.Polite)) : 1f);
                //The more judgmental the pawn, the more they're affected by all conversations.
                opinionMod *= 0.5f + this.realPawn.psyche.GetPersonalityRating(PersonalityNodeDefOf.Judgmental);
                if (opinionMod < 0f)
                {
                    opinionMod *= PopulationModifier;
                }
                stage.label             = "ConversationStage".Translate() + " " + topic.conversationTopic;
                stage.baseOpinionOffset = Mathf.RoundToInt(opinionMod);
                def.stages.Add(stage);

                /* 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, this.realPawn.psyche.TotalThoughtOpinion(this.otherPawn), 250f + Mathf.Abs(stage.baseOpinionOffset)) && stage.baseOpinionOffset != 0)
                {
                    this.pawn.needs.mood.thoughts.memories.TryGainMemory(def, this.otherPawn);
                }
                if (this.waveGoodbye && this.pawn.Map != null)
                {
                    InteractionDef endConversation = new InteractionDef();
                    endConversation.defName = "EndConversation";
                    RulePack      goodbyeText = new RulePack();
                    FieldInfo     RuleStrings = typeof(RulePack).GetField("rulesStrings", BindingFlags.Instance | BindingFlags.NonPublic);
                    List <string> text        = new List <string>(1);
                    text.Add("logentry->" + talkDesc.Translate(topic.conversationTopic));
                    RuleStrings.SetValue(goodbyeText, text);
                    endConversation.logRulesInitiator = goodbyeText;
                    endConversation.logRulesRecipient = goodbyeText;
                    FieldInfo Symbol = typeof(InteractionDef).GetField("symbol", BindingFlags.Instance | BindingFlags.NonPublic);
                    Symbol.SetValue(endConversation, Symbol.GetValue(InteractionDefOf.DeepTalk));
                    PlayLogEntry_InteractionConversation log = new PlayLogEntry_InteractionConversation(endConversation, realPawn, this.otherPawn, new List <RulePackDef>());
                    Find.PlayLog.Add(log);
                    MoteMaker.MakeInteractionBubble(this.pawn, this.otherPawn, InteractionDefOf.Chitchat.interactionMote, InteractionDefOf.Chitchat.Symbol);
                }
            }
        }
Example #15
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);
         }
     }
 }
 public static void AddPsychRejectedThoughts(Pawn initiator, Pawn recipient)
 {
     if (PsycheHelper.PsychologyEnabled(initiator))
     {
         ThoughtDef rejectedProposalDef = new ThoughtDef();
         rejectedProposalDef.defName      = "RejectedMyProposal" + initiator.LabelShort + Find.TickManager.TicksGame;
         rejectedProposalDef.durationDays = 60f * PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic);
         rejectedProposalDef.thoughtClass = typeof(Thought_MemorySocialDynamic);
         ThoughtStage rejectedProposalStage = new ThoughtStage();
         rejectedProposalStage.label             = "rejected my proposal";
         rejectedProposalStage.baseOpinionOffset = Mathf.RoundToInt(-40f * PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * (PsychologyBase.ActivateKinsey() ? PsycheHelper.Comp(initiator).Sexuality.AdjustedRomanticDrive : 1f));
         rejectedProposalDef.stages.Add(rejectedProposalStage);
         ThoughtDef rejectedProposalMoodDef = new ThoughtDef();
         rejectedProposalMoodDef.defName                 = "RejectedMyProposalMood" + initiator.LabelShort + Find.TickManager.TicksGame;
         rejectedProposalMoodDef.durationDays            = 25f;
         rejectedProposalMoodDef.thoughtClass            = typeof(Thought_MemoryDynamic);
         rejectedProposalMoodDef.stackLimit              = 999;
         rejectedProposalMoodDef.stackedEffectMultiplier = 1f;
         ThoughtStage rejectedProposalMoodStage = new ThoughtStage();
         rejectedProposalMoodStage.label          = "proposal rejected by {0}";
         rejectedProposalMoodStage.baseMoodEffect = Mathf.RoundToInt(-25f * PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * Mathf.InverseLerp(100f, 5f, initiator.relations.OpinionOf(recipient)));
         if (rejectedProposalMoodStage.baseMoodEffect < -5f)
         {
             rejectedProposalMoodStage.description = "My lover isn't ready for that kind of commitment right now, and I understand, but rejection is hard to take.";
         }
         else
         {
             rejectedProposalMoodStage.description = "I can't believe I got turned down. Maybe we're not meant to be together after all?";
         }
         rejectedProposalMoodDef.stages.Add(rejectedProposalMoodStage);
         if (rejectedProposalMoodStage.baseMoodEffect < 0f)
         {
             initiator.needs.mood.thoughts.memories.TryGainMemory(rejectedProposalMoodDef, recipient);
         }
         initiator.needs.mood.thoughts.memories.TryGainMemory(rejectedProposalDef, recipient);
     }
     else
     {
         initiator.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.RejectedMyProposal, recipient);
     }
     if (PsycheHelper.PsychologyEnabled(recipient))
     {
         ThoughtDef rejectedTheirProposalDef = new ThoughtDef();
         rejectedTheirProposalDef.defName      = "IRejectedTheirProposal" + recipient.LabelShort + Find.TickManager.TicksGame;
         rejectedTheirProposalDef.durationDays = 60f * PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic);
         rejectedTheirProposalDef.thoughtClass = typeof(Thought_MemorySocialDynamic);
         ThoughtStage rejectedTheirProposalStage = new ThoughtStage();
         rejectedTheirProposalStage.label             = "I rejected their proposal";
         rejectedTheirProposalStage.baseOpinionOffset = Mathf.RoundToInt(-30f * PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * (PsychologyBase.ActivateKinsey() ? 1.75f - PsycheHelper.Comp(recipient).Sexuality.AdjustedRomanticDrive : 1f));
         rejectedTheirProposalDef.stages.Add(rejectedTheirProposalStage);
         ThoughtDef rejectedTheirProposalMoodDef = new ThoughtDef();
         rejectedTheirProposalMoodDef.defName                 = "IRejectedTheirProposalMood" + recipient.LabelShort + Find.TickManager.TicksGame;
         rejectedTheirProposalMoodDef.durationDays            = 25f;
         rejectedTheirProposalMoodDef.thoughtClass            = typeof(Thought_MemoryDynamic);
         rejectedTheirProposalMoodDef.stackLimit              = 999;
         rejectedTheirProposalMoodDef.stackedEffectMultiplier = 1f;
         ThoughtStage rejectedTheirProposalMoodStage = new ThoughtStage();
         rejectedTheirProposalMoodStage.label          = "rejected {0}'s proposal";
         rejectedTheirProposalMoodStage.baseMoodEffect = Mathf.RoundToInt(-25f * PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * Mathf.InverseLerp(100f, 5f, recipient.relations.OpinionOf(initiator)));
         if (rejectedTheirProposalMoodStage.baseMoodEffect < -5f)
         {
             rejectedTheirProposalMoodStage.description = "I wish they wouldn't spring something like that on me.";
         }
         else
         {
             rejectedTheirProposalMoodStage.description = "I'm not ready for that kind of commitment. If they don't know that, maybe we're not meant to be together after all?";
         }
         rejectedTheirProposalMoodDef.stages.Add(rejectedTheirProposalMoodStage);
         if (rejectedTheirProposalMoodStage.baseMoodEffect < 0f)
         {
             recipient.needs.mood.thoughts.memories.TryGainMemory(rejectedTheirProposalMoodDef, initiator);
         }
         recipient.needs.mood.thoughts.memories.TryGainMemory(rejectedTheirProposalDef, initiator);
     }
     else
     {
         recipient.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.IRejectedTheirProposal, initiator);
     }
 }
Example #17
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);
        }
Example #18
0
 static void ListThoughtStageInfo([NotNull] ThoughtStage stage, [NotNull] StringBuilder builder)
 {
     builder.AppendLine($"{nameof(stage.label)}:{stage.label}\t{nameof(stage.labelSocial)}:{stage.labelSocial}");
     builder.AppendLine($"{nameof(stage.visible)}:{stage.visible}\t{nameof(stage.baseMoodEffect)}:{stage.baseMoodEffect}\t{nameof(stage.baseOpinionOffset)}:{stage.baseOpinionOffset}");
     builder.AppendLine($"description:\t{stage.description}");
 }
Example #19
0
        public static bool NewInteracted(InteractionWorker_MarriageProposal __instance, Pawn initiator, Pawn recipient, List <RulePackDef> extraSentencePacks)
        {
            //TODO: Turn this into a transpihahaha no.
            float num     = __instance.AcceptanceChance(initiator, recipient);
            bool  flag    = Rand.Value < num;
            bool  brokeUp = false;

            if (flag)
            {
                initiator.relations.RemoveDirectRelation(PawnRelationDefOf.Lover, recipient);
                initiator.relations.AddDirectRelation(PawnRelationDefOf.Fiance, recipient);
                initiator.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(ThoughtDefOf.RejectedMyProposal, recipient);
                recipient.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(ThoughtDefOf.RejectedMyProposal, initiator);
                /* Remove custom Psychology rejection thoughts */
                foreach (ThoughtDef d in (from tgt in initiator.needs.mood.thoughts.memories.Memories
                                          where tgt.def.defName.Contains("RejectedMyProposal")
                                          select tgt.def))
                {
                    initiator.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(d, recipient);
                }
                foreach (ThoughtDef d in (from tgt in recipient.needs.mood.thoughts.memories.Memories
                                          where tgt.def.defName.Contains("RejectedMyProposal")
                                          select tgt.def))
                {
                    recipient.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(d, initiator);
                }
                initiator.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(ThoughtDefOf.IRejectedTheirProposal, recipient);
                recipient.needs.mood.thoughts.memories.RemoveMemoriesOfDefWhereOtherPawnIs(ThoughtDefOf.IRejectedTheirProposal, initiator);
                extraSentencePacks.Add(RulePackDefOf.Sentence_MarriageProposalAccepted);
            }
            else
            {
                PsychologyPawn realInitiator = initiator as PsychologyPawn;
                PsychologyPawn realRecipient = recipient as PsychologyPawn;
                if (realInitiator != null)
                {
                    ThoughtDef rejectedProposalDef = new ThoughtDef();
                    rejectedProposalDef.defName      = "RejectedMyProposal" + realInitiator.LabelShort + Find.TickManager.TicksGame;
                    rejectedProposalDef.durationDays = 40f;
                    rejectedProposalDef.thoughtClass = typeof(Thought_MemorySocialDynamic);
                    ThoughtStage rejectedProposalStage = new ThoughtStage();
                    rejectedProposalStage.label             = "rejected my proposal";
                    rejectedProposalStage.baseOpinionOffset = Mathf.RoundToInt(-30f * realInitiator.psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * Mathf.InverseLerp(100f, 5f, realInitiator.relations.OpinionOf(realRecipient)));
                    rejectedProposalDef.stages.Add(rejectedProposalStage);
                    ThoughtDef rejectedProposalMoodDef = new ThoughtDef();
                    rejectedProposalMoodDef.defName                 = "RejectedMyProposalMood" + realInitiator.LabelShort + Find.TickManager.TicksGame;
                    rejectedProposalMoodDef.durationDays            = 25f;
                    rejectedProposalMoodDef.thoughtClass            = typeof(Thought_MemoryDynamic);
                    rejectedProposalMoodDef.stackedEffectMultiplier = 1f;
                    ThoughtStage rejectedProposalMoodStage = new ThoughtStage();
                    rejectedProposalMoodStage.label          = "proposal rejected by {0}";
                    rejectedProposalMoodStage.baseMoodEffect = Mathf.RoundToInt(-25f * realInitiator.psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * Mathf.InverseLerp(100f, 5f, realInitiator.relations.OpinionOf(realRecipient)));
                    if (rejectedProposalMoodStage.baseMoodEffect < -5f)
                    {
                        rejectedProposalMoodStage.description = "My lover isn't ready for that kind of commitment right now, and I understand, but rejection is hard to take.";
                    }
                    else
                    {
                        rejectedProposalMoodStage.description = "I can't believe I got turned down. Maybe we're not meant to be together after all?";
                    }
                    rejectedProposalMoodDef.stages.Add(rejectedProposalMoodStage);
                    if (rejectedProposalMoodStage.baseMoodEffect > 0)
                    {
                        realInitiator.needs.mood.thoughts.memories.TryGainMemory(rejectedProposalMoodDef, realRecipient);
                    }
                    realInitiator.needs.mood.thoughts.memories.TryGainMemory(rejectedProposalDef, realRecipient);
                }
                else
                {
                    initiator.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.RejectedMyProposal, recipient);
                }
                recipient.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.IRejectedTheirProposal, initiator);
                extraSentencePacks.Add(RulePackDefOf.Sentence_MarriageProposalRejected);
                if (realRecipient != null && !recipient.story.traits.HasTrait(TraitDefOfPsychology.Codependent) && Rand.Value > 2f * realRecipient.psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic))
                {
                    recipient.interactions.TryInteractWith(initiator, DefDatabase <InteractionDef> .GetNamed("Breakup"));
                }
                else if (realRecipient == null && !recipient.story.traits.HasTrait(TraitDefOfPsychology.Codependent) && Rand.Value < 0.4f)
                {
                    initiator.relations.RemoveDirectRelation(PawnRelationDefOf.Lover, recipient);
                    initiator.relations.AddDirectRelation(PawnRelationDefOf.ExLover, recipient);
                    brokeUp = true;
                    extraSentencePacks.Add(RulePackDefOf.Sentence_MarriageProposalRejectedBrokeUp);
                }
            }
            if (initiator.IsColonist || recipient.IsColonist)
            {
                Traverse.Create(__instance).Method("SendLetter", new[] { typeof(Pawn), typeof(Pawn), typeof(bool), typeof(bool) }).GetValue(new object[] { initiator, recipient, flag, brokeUp });
            }
            return(false);
        }