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)); }
public void LearnSexuality(Pawn p) { if (p != null && PsycheHelper.PsychologyEnabled(pawn) && !knownSexualities.Keys.Contains(p)) { knownSexualities.Add(p, PsycheHelper.Comp(p).Sexuality.kinseyRating); } }
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); }
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(); }
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); }
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; } }
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); }
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 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); } } } }
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); } }
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 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); }
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); }
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); } }
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.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); } } }
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); } } }
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); }
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); }
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)))); }
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); } } }
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); } }
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(); }