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 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 #3
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);
         }
     }
 }