/// <summary> /// enter the given sapience state /// </summary> /// <param name="stateDef">The state definition.</param> /// <param name="initialLevel">The initial level.</param> public void EnterState([NotNull] SapienceStateDef stateDef, float initialLevel) { _sapienceState?.Exit(); _sapienceState = stateDef.CreateState(); //need to refresh comps and needs for pawn here Pawn.needs?.AddOrRemoveNeedsAsAppropriate(); _sapienceState.Init(this); SapienceLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(initialLevel); PawnComponentsUtility.AddAndRemoveDynamicComponents(Pawn); var sNeed = SapienceNeed; sNeed?.SetSapience(initialLevel); _sapienceState.Enter(); if (Pawn.Faction == Faction.OfPlayer) { Find.ColonistBar?.MarkColonistsDirty(); } //initialize work settings if they have it Pawn.workSettings?.EnableAndInitializeIfNotAlreadyInitialized(); //interrupts any jobs in case this changes their intelligence Pawn.jobs?.EndCurrentJob(JobCondition.InterruptForced); }
/// <summary> /// Makes the parent a former human. /// </summary> /// <returns></returns> public void MakeFormerHuman(float initialLevel) //TODO move most of FormerHumanUtilities.MakeAnimalSapient here { if (_isFormerHuman) { Log.Warning($"{nameof(MakeFormerHuman)} is being called on {parent.def}'s {nameof(FormerHumanTracker)} more then once!"); return; } _isFormerHuman = true; SapienceLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(initialLevel); }
/// <summary> /// Sets the sapience. /// </summary> /// <param name="sapience">The sapience.</param> public void SetSapience(float sapience) { _seekerLevel = Mathf.Clamp(sapience, 0, Mathf.Min(MaxLevel, Limit)); CurLevel = _seekerLevel; SapienceLevel cLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(CurLevel); if (_currentLevel != cLevel) { _currentLevel = cLevel; OnSapienceLevelChanges(); } }
/// <summary> /// Exposes the data. /// </summary> public override void ExposeData() { base.ExposeData(); Scribe_Values.Look(ref _seekerLevel, nameof(_seekerLevel), -1); if (Scribe.mode == LoadSaveMode.PostLoadInit) { if (_seekerLevel < 0) { _seekerLevel = CurLevel; } _currentLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(_seekerLevel); CurLevel = Mathf.Clamp(CurLevel, 0, MaxLevel); } }
/// <summary> /// called every so often by the need manager. /// </summary> /// <exception cref="System.NotImplementedException"></exception> public override void NeedInterval() { base.NeedInterval(); if (pawn.IsHashIntervalTick(TimeMetrics.TICKS_PER_REAL_SECOND)) //just every second or so { TrySubscribe(); CalculateCachesIfNeeded(); _seekerLevel = Mathf.Min(_seekerLevel, Limit); float instinctChange = GetInstinctChangePerTick(pawn) * TimeMetrics.TICKS_PER_REAL_SECOND; if (Mathf.Abs(instinctChange) > EPSILON) { AddInstinctChange(instinctChange); } //_maxLevelCached = null; SapienceLevel sLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(CurLevel); if (sLevel != _currentLevel) { _currentLevel = sLevel; OnSapienceLevelChanges(); } } }
/// <summary> /// called every so often by the need manager. /// </summary> /// <exception cref="System.NotImplementedException"></exception> public override void NeedInterval() { base.NeedInterval(); if (pawn.IsHashIntervalTick(TimeMetrics.TICKS_PER_REAL_SECOND)) //just every second or so { float instinctChange = GetInstinctChangePerTick(pawn) * TimeMetrics.TICKS_PER_REAL_SECOND; if (Mathf.Abs(instinctChange) > EPSILON) { AddInstinctChange(Mathf.CeilToInt(instinctChange)); } _maxLevelCached = null; SapienceLevel sLevel = FormerHumanUtilities.GetQuantizedSapienceLevel(CurLevel); if (sLevel != _currentLevel) { _currentLevel = sLevel; OnSapienceLevelChanges(); } if (_currentLevel == SapienceLevel.Feral && Rand.MTBEventOccurs(4, 60000f, 30f)) { TriggerPermanentlyFeralChange(); } } }
/// <summary> /// preform the requested transform /// </summary> /// <param name="request">The request.</param> /// <returns></returns> protected override TransformedPawnSingle TransformImpl(TransformationRequest request) { Pawn original = request.originals[0]; if (request.addMutationToOriginal) { TryAddMutationsToPawn(original, request.cause, request.outputDef); } var reactionStatus = original.GetFormerHumanReactionStatus(); float newAge = TransformerUtility.ConvertAge(original, request.outputDef.race.race); Faction faction; faction = GetFaction(request, original); Gender newGender = TransformerUtility.GetTransformedGender(original, request.forcedGender, request.forcedGenderChance); var pRequest = FormerHumanUtilities.CreateSapientAnimalRequest(request.outputDef, original, faction, fixedGender: newGender); Pawn animalToSpawn = PawnGenerator.GeneratePawn(pRequest); //make the temp pawn animalToSpawn.needs.food.CurLevel = original.needs.food.CurLevel; // Copies the original pawn's food need to the animal's. animalToSpawn.needs.rest.CurLevel = original.needs.rest.CurLevel; // Copies the original pawn's rest need to the animal's. animalToSpawn.Name = original.Name; // Copies the original pawn's name to the animal's. float sapienceLevel = request.forcedSapienceLevel ?? GetSapienceLevel(original, animalToSpawn); if (request.forcedFaction == null && original.Faction != faction && original.Faction != animalToSpawn.Faction && FormerHumanUtilities.GetQuantizedSapienceLevel(sapienceLevel) <= SapienceLevel.MostlySapient) { //set the faction to the original's if mostly sapient or above animalToSpawn.SetFaction(original.Faction); } GiveTransformedPawnSapienceState(animalToSpawn, sapienceLevel); FormerHumanUtilities.InitializeTransformedPawn(original, animalToSpawn, sapienceLevel); //use a normal distribution? Pawn spawnedAnimal = SpawnAnimal(original, animalToSpawn); // Spawns the animal into the map. ReactionsHelper.OnPawnTransforms(original, animalToSpawn, reactionStatus); //this needs to happen before MakeSapientAnimal because that removes relations var rFaction = request.factionResponsible ?? GetFactionResponsible(original); var inst = new TransformedPawnSingle { original = original, animal = spawnedAnimal, factionResponsible = rFaction, reactionStatus = reactionStatus }; if (original.Spawned) { for (var i = 0; i < 10; i++) // Create a cloud of magic. { IntermittentMagicSprayer.ThrowMagicPuffDown(spawnedAnimal.Position.ToVector3(), spawnedAnimal.MapHeld); IntermittentMagicSprayer.ThrowMagicPuffUp(spawnedAnimal.Position.ToVector3(), spawnedAnimal.MapHeld); } } if (request.tale != null) // If a tale was provided, push it to the tale recorder. { TaleRecorder.RecordTale(request.tale, original, animalToSpawn); } Faction oFaction = original.FactionOrExtraHomeFaction; Map oMap = original.Map; //apply any other post tf effects ApplyPostTfEffects(original, animalToSpawn, request); TransformerUtility .CleanUpHumanPawnPostTf(original, request.cause); //now clean up the original pawn (remove apparel, drop'em, ect) //notify the faction that their member has been transformed oFaction?.Notify_MemberTransformed(original, animalToSpawn, oMap == null, oMap); if (!request.noLetter && reactionStatus == FormerHumanReactionStatus.Colonist || reactionStatus == FormerHumanReactionStatus.Prisoner) //only send the letter for colonists and prisoners { SendLetter(request, original, spawnedAnimal); } if (original.Spawned) { original.DeSpawn(); // Remove the original pawn from the current map. } DebugLogUtils.Assert(!PrisonBreakUtility.CanParticipateInPrisonBreak(original), $"{original.Name} has been cleaned up and de-spawned but can still participate in prison breaks"); return(inst); }