protected override Job TryGiveJob(Pawn pawn) { if (Find.TickManager.TicksGame - pawn.mindState.lastDisturbanceTick < 400) { return(null); } AIPawn aiPawn = pawn as AIPawn; Building_AIPawnRechargeStation rechargeStation = HelperAIPawn.FindRechargeStationFor(aiPawn); if (rechargeStation == null) { return(null); } if (rechargeStation.owners != null && !rechargeStation.owners.Contains(aiPawn) && !rechargeStation.Medical) { aiPawn.ownership.ClaimBedIfNonMedical(rechargeStation); } if (aiPawn.ownership.OwnedBed == null || aiPawn.ownership.OwnedBed != rechargeStation) { return(null); } Job job = new Job(JobDefOf.LayDown, rechargeStation); return(job); }
public static AIPawn CreateAIPawn(string pawnDefName, IntVec3 position, Map map, Faction faction, Gender gender) { AIPawn pawn = AIPawnGenerator.GenerateAIPawn(pawnDefName, faction, map, gender); //// Old: //IntVec3 spawnPos = position; // GenCellFinder.RandomStandableClosewalkCellNear(position, 1); // New: Find empty position in adjacent cell IntVec3 spawnPos = IntVec3.Invalid; if (map.thingGrid.ThingAt(position, ThingCategory.Building) != null || map.thingGrid.ThingAt(position, ThingCategory.Pawn) != null) { foreach (IntVec3 c in GenAdjFast.AdjacentCells8Way(position)) { if (map.thingGrid.ThingAt(c, ThingCategory.Building) == null && map.thingGrid.ThingAt(c, ThingCategory.Pawn) == null) { spawnPos = c; break; } } } if (spawnPos == IntVec3.Invalid) { spawnPos = position; } AIPawn newPawn = (AIPawn)Spawn(pawn, spawnPos, map); // Notify the Storyteller Find.StoryWatcher.watcherPopAdaptation.Notify_PawnEvent(newPawn, PopAdaptationEvent.GainedColonist); return(newPawn); }
public static AIPawn CreateAIPawn(string pawnDefName, IntVec3 position, Map map, Faction faction, Gender gender) { AIPawn pawn = AIPawnGenerator.GenerateAIPawn(pawnDefName, faction, map, gender); //// Old: //IntVec3 spawnPos = position; // GenCellFinder.RandomStandableClosewalkCellNear(position, 1); // New: Find empty position in adjacent cell IntVec3 spawnPos = IntVec3.Invalid; if (map.thingGrid.ThingAt(position, ThingCategory.Building) != null || map.thingGrid.ThingAt(position, ThingCategory.Pawn) != null) { foreach (IntVec3 c in GenAdjFast.AdjacentCells8Way(position)) { if (map.thingGrid.ThingAt(c, ThingCategory.Building) == null && map.thingGrid.ThingAt(c, ThingCategory.Pawn) == null) { spawnPos = c; break; } } } if (spawnPos == IntVec3.Invalid) { spawnPos = position; } return((AIPawn)Spawn(pawn, spawnPos, map)); }
private static void GetXMLData(AIPawn pawn) { ThingDef_AIPawn def2 = (ThingDef_AIPawn)pawn.def; passionLevel = def2.passionLevel; startingSkillLevel = def2.startingSkillLevel; enhancedAI = def2.enhancedAI; }
public static void MakeSkillsFromBackstory(AIPawn pawn) { IEnumerator <SkillDef> enumerator = DefDatabase <SkillDef> .AllDefs.GetEnumerator(); try { while (enumerator.MoveNext()) { SkillDef current = enumerator.Current; int num = FinalLevelOfSkill(current); SkillRecord skill = pawn.skills.GetSkill(current); skill.levelInt = num; if (skill.TotallyDisabled) { continue; } skill.xpSinceLastLevel = 0; switch (passionLevel) { case 1: skill.passion = Passion.Minor; break; case 2: skill.passion = Passion.Major; break; default: skill.passion = Passion.None; break; } } } finally { enumerator.Dispose(); } }
// ================== Ticks ================== public override void Tick() { base.Tick(); // Do init work after spawning if (!init) { HelperAIPawn.ReApplyThingToListerThings(this.Position, this); Drawer.renderer.graphics.ResolveAllGraphics(); //Causes errors! UpdateGraphics(); initTicks--; if (initTicks <= 0) { // Replace invalid Mai with valid Mai if (!story.childhood.identifier.Contains(BackstoryHelper.BackstoryDefNameIdentifier)) { string savedDefName = def.defName; IntVec3 savedPosition = Position; Map savedMap = Map; Gender savedGender = this.gender; // Destroy me destroyMeWithoutExplosion = true; Destroy(DestroyMode.Vanish); // Create a new me AIPawn mai = Building_AIPawnCreator.CreateAIPawn(savedDefName, savedPosition, savedMap, savedGender); return; } BackstoryHelper.RemoveNewBackstoriesFromDatabase(); init = true; } return; } //// To circumvent the strange pathing error! //if ((this.CurJob == null || this.CurJob != curJobOld) && Map != null) //{ // HelperAIPawn.ReApplyThingToListerThings(this.Position, this); // curJobOld = this.CurJob; //} // To circumvent the destroy apparel error if (this.CurJob != null && this.CurJob.def.defName == "Wear" && this.CurJob.targetA.Cell == this.Position) { AIPawnGenerator.DestroyBaseShielding(this); } // Update drafted graphics if (draftedActiveOld != this.Drafted) { UpdateGraphics(); draftedActiveOld = this.Drafted; } // When AIPawn is in a Container, do nothing if (this.InContainerEnclosed) { return; } // When AIPawn is in a bed, fix rest value to prevent explosions in the hospital room if (Find.TickManager.TicksGame % fixRestWhenInBedCounter == 0) { Building_AIPawnRechargeStation rechargeStation; if (this.InBed() && !this.IsInAIRechargeStation(Map, out rechargeStation)) { needs.rest.CurLevel = fixRestWhenInBedFixedValue; } else { fixRestWhenInBedFixedValue = needs.rest.CurLevel; } } // Disable food reduction <-- Food is needed or some errors are thrown if (needs != null && needs.food != null && needs.food.CurLevel <= 0.95f) { needs.food.CurLevel = 1.0f; } //// Disable joy reduction //if (needs != null && needs.joy != null && needs.joy.CurLevel <= 0.95f) // needs.joy.CurLevel = 1.0f; //// Disable beauty reduction //if (needs != null && needs.beauty != null && needs.beauty.CurLevel <= 0.95f) // needs.beauty.CurLevel = 1.0f; //// Disable comfort reduction //if (needs != null && needs.comfort != null && needs.comfort.CurLevel <= 0.95f) // needs.comfort.CurLevel = 1.0f; //// Disable rest reduction when traveling in a caravan! //if (needs != null && needs.rest != null && needs.rest.CurLevel <= 0.95f && !Destroyed && !Downed && Map == null) // needs.rest.CurLevel += 0.01f / 60f; // If in bed, slowly increase rest (to circumvent bed problems) if (IsInBed(Map)) { needs.rest.CurLevel += 0.025f / 60f; } // Self healing ability (Nanobots) healDamagedPartsCounter -= 1; if (healDamagedPartsCounter <= 0) { DoHealDamagedBodyPart(enhancedAI); healDamagedPartsCounter = healDamagedPartsCounterStartValue; } refreshQuickCount += 1; if (refreshQuickCount >= refreshQuickMax) { refreshQuickCount = 0; } if (refreshQuickCount == 0) { // Add thought when health < x if (this.health.summaryHealth.SummaryHealthPercent < 0.75) { this.needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("AIShieldingError")); } // disable diseases DoDiseaseHandling(); if (Destroyed) { destroyMeWithoutExplosion = true; Destroy(DestroyMode.Vanish); return; } // Do explosion when downed, dead or incapable of moving if (Dead || (!isAnestheticIncap && !IsInBed(Map) && (Downed || health.capacities.GetLevel(PawnCapacityDefOf.Moving) < 0.1f))) { incapToExplosionCounter -= refreshQuickMax; if (incapToExplosionCounter <= 0) { Destroy(DestroyMode.KillFinalize); return; } } // Reset counter when health is rising -- Not working right now if ((Downed && this.health.summaryHealth.SummaryHealthPercent > incapHealthOld) || !Downed && (incapToExplosionCounter < incapToExplosionCounterStartValue)) { incapToExplosionCounter = incapToExplosionCounterStartValue; } incapHealthOld = this.health.summaryHealth.SummaryHealthPercent; //// Add thought when rested //if (rest.Rest.CurLevel >= 98.9f) // psychology.thoughts.memories.TryGainMemoryThought(ThoughtDef.Named("AIBatteriesRefilled")); // Change color when near exhausted float levelLowBatterie = 0.25f; float levelLowCriticalBatterie = 0.15f; if (needs.rest.CurLevel <= levelLowCriticalBatterie && !graphicHueActive) { // Switch to alternate graphic graphicHueActive = true; UpdateGraphics(); } else if (needs.rest.CurLevel > levelLowCriticalBatterie && graphicHueActive) { // Switch back to normal graphic graphicHueActive = false; UpdateGraphics(); } // Add thought when rest(batteries) < x if (needs.rest.CurLevel < levelLowCriticalBatterie) { needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("AILowCriticalBattery")); } // Add thought when rest(batteries) < x else if (needs.rest.CurLevel < levelLowBatterie) { needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("AILowBattery")); } // Explosion when exhausted if (needs.rest.CurLevel <= 0.011f) { if (!Downed) { HealthUtility.DamageUntilDowned(this, false); } } else if (needs.rest.CurLevel < 0.2f) { TryGoRecharging(); } // unclaim bed when fully rested // Activate? Don't Activate? //if (ownership != null && (rest.Rest.CurLevel >= 94.8f || rest.DoneResting)) // ownership.UnclaimBed(); } // Update base AI thought every x refreshBaseInfosCount += 1; if (refreshBaseInfosCount >= refreshBaseInfosMax || refreshBaseInfosCount < 0) { refreshBaseInfosCount = 0; this.mindState.canFleeIndividual = false; DoRelationHandling(); //Base thought is only available after save/load (why?) so it needs to be set this.needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("AIBaseThought")); // Rebuild Base Shielding if needed Building_AIPawnRechargeStation rs2; AIPawnGenerator.GiveBaseApparelWhileInBed(this, IsInAIRechargeStation(Map, out rs2)); } }
//public static AIPawn GeneratePawn(PawnKindDef kindDef, Faction faction, Map map, Gender gender = Gender.Female, int tries = 0) public static AIPawn GenerateAIPawn(ref PawnGenerationRequest request, Map map, int tries = 0) { BackstoryHelper.AddNewBackstoriesToDatabase(); // First add the new backstories to the database //Log.Error("0"); AIPawn pawnAI = (AIPawn)ThingMaker.MakeThing(request.KindDef.race, null); //Log.Error("1"); GetXMLData(pawnAI); //request.EnsureNonNullFaction(); pawnAI.kindDef = request.KindDef; pawnAI.SetFactionDirect(request.Faction); PawnComponentsUtility.CreateInitialComponents(pawnAI); //Log.Error("2"); // Needs to be set because of not flesh user if (pawnAI.ownership == null) { pawnAI.ownership = new Pawn_Ownership(pawnAI); } pawnAI.relations = new Pawn_RelationsTracker(pawnAI); pawnAI.guest = new Pawn_GuestTracker(pawnAI); pawnAI.guilt = new Pawn_GuiltTracker(pawnAI); pawnAI.royalty = new Pawn_RoyaltyTracker(pawnAI); pawnAI.abilities = new Pawn_AbilityTracker(pawnAI); pawnAI.relations = new Pawn_RelationsTracker(pawnAI); if (request.FixedGender.HasValue) { pawnAI.gender = request.FixedGender.Value; } else if (pawnAI.RaceProps.hasGenders) { if (Rand.Value < 0.5f) { pawnAI.gender = Gender.Male; } else { pawnAI.gender = Gender.Female; } } else { pawnAI.gender = Gender.Female; } SetBirthday(pawnAI); pawnAI.needs.SetInitialLevels(); //Log.Error("3"); AIPawnGenerator.GenerateInitialHediffs(pawnAI); if (pawnAI.RaceProps.Humanlike) { pawnAI.story.melanin = 0.1f; pawnAI.story.crownType = CrownType.Average; pawnAI.story.hairColor = PawnHairColors.RandomHairColor(pawnAI.story.SkinColor, pawnAI.ageTracker.AgeBiologicalYears); pawnAI.story.childhood = GetBackstory(); //pawnAI.story.adulthood = GetBackstory(); string headGraphicPath = GraphicDatabaseHeadRecords.GetHeadRandom(pawnAI.gender, pawnAI.story.SkinColor, pawnAI.story.crownType, false).GraphicPath; // With this Reflection you can access a private variable! Here: The private string "headGraphicPath" is set System.Reflection.FieldInfo fi = typeof(Pawn_StoryTracker).GetField("headGraphicPath", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); fi.SetValue(pawnAI.story, headGraphicPath); pawnAI.story.hairDef = GetHair(); pawnAI.story.bodyType = ((pawnAI.gender != Gender.Female) ? BodyTypeDefOf.Male : BodyTypeDefOf.Female); MakeSkillsFromBackstory(pawnAI); GiveTraitsTo(pawnAI); if (pawnAI.workSettings != null && (request.Faction == Faction.OfPlayer)) { pawnAI.workSettings.EnableAndInitialize(); } } if (pawnAI.RaceProps.ToolUser) { GenerateBaseApparel(pawnAI); } pawnAI.Name = GetName(pawnAI.def, map); pawnAI.royalty = null; //Log.Error("4"); //PawnGenerationRequest request = new PawnGenerationRequest(pawnAI.kindDef , Faction.OfPlayer, PawnGenerationContext.All, true, true, false,false, false, false, 0, false, false, false,null, 0,0, pawnAI.gender, null, null); //PawnInventoryGenerator.GenerateInventoryFor(pawnAI, request); if (!pawnAI.Dead) { return(pawnAI); } if (tries < 10) { return(GenerateAIPawn(ref request, map, tries + 1)); } return(null); }
public static Building_AIPawnRechargeStation FindRechargeStationFor(AIPawn sleeper, AIPawn traveler, bool sleeperWillBePrisoner, bool checkSocialProperness, bool forceCheckMedBed = false) { Predicate <Thing> bedValidator = (Thing t) => { Building_AIPawnRechargeStation foundRechargeStation = t as Building_AIPawnRechargeStation; if (foundRechargeStation == null) { return(false); } if (!traveler.CanReserveAndReach(t, PathEndMode.OnCell, Danger.Some, foundRechargeStation.SleepingSlotsCount)) { return(false); } if (!foundRechargeStation.AnyUnoccupiedSleepingSlot && (!sleeper.InBed() || sleeper.CurrentBed() != foundRechargeStation)) { foreach (Pawn owner in foundRechargeStation.owners) { if (owner as AIPawn != null) { return(false); } } } if (sleeperWillBePrisoner) { if (!foundRechargeStation.ForPrisoners) { return(false); } if (!foundRechargeStation.Position.IsInPrisonCell(sleeper.Map)) { return(false); } } else { if (foundRechargeStation.Faction != traveler.Faction) { return(false); } if (foundRechargeStation.ForPrisoners) { return(false); } } if (foundRechargeStation.Medical) { if (!HealthAIUtility.ShouldEverReceiveMedicalCare(sleeper)) { return(false); } if (!HealthAIUtility.ShouldSeekMedicalRest(sleeper)) { return(false); } if (!foundRechargeStation.AnyUnoccupiedSleepingSlot && (!sleeper.InBed() || sleeper.CurrentBed() != foundRechargeStation)) { return(false); } } else if (foundRechargeStation.owners.Any <Pawn>() && !foundRechargeStation.owners.Contains(sleeper)) { // The pawn in the recharge station is not an AIPawn. UnassignPawn! foreach (Pawn owner in foundRechargeStation.owners) { if (owner as AIPawn == null) { if (foundRechargeStation.owners.Find((Pawn x) => LovePartnerRelationUtility.LovePartnerRelationExists(sleeper, x)) == null) { foundRechargeStation.TryUnassignPawn(owner); break; } } } // Now recheck if there is a free place if (!foundRechargeStation.AnyUnownedSleepingSlot) { return(false); } } return((!checkSocialProperness || foundRechargeStation.IsSociallyProper(sleeper, sleeperWillBePrisoner, false)) && !foundRechargeStation.IsForbidden(traveler) && !foundRechargeStation.IsBurning()); }; if (sleeper.ownership != null && sleeper.ownership.OwnedBed != null && bedValidator(sleeper.ownership.OwnedBed)) { Building_AIPawnRechargeStation rStation = sleeper.ownership.OwnedBed as Building_AIPawnRechargeStation; if (rStation != null) { return(rStation); } else { sleeper.ownership.UnclaimBed(); } } DirectPawnRelation directPawnRelation = LovePartnerRelationUtility.ExistingMostLikedLovePartnerRel(sleeper, false); if (directPawnRelation != null) { Building_AIPawnRechargeStation ownedBed = directPawnRelation.otherPawn.ownership.OwnedBed as Building_AIPawnRechargeStation; if (ownedBed != null && bedValidator(ownedBed)) { return(ownedBed); } } for (int j = 0; j < RestUtility.AllBedDefBestToWorst.Count; j++) { ThingDef thingDef = RestUtility.AllBedDefBestToWorst[j]; if (RestUtility.CanUseBedEver(sleeper, thingDef)) { Predicate <Thing> validator = (Thing b) => bedValidator(b) && (b as Building_AIPawnRechargeStation != null) && !((Building_AIPawnRechargeStation)b).Medical; Building_AIPawnRechargeStation building_Bed2 = GenClosest.ClosestThingReachable(sleeper.Position, sleeper.Map, ThingRequest.ForDef(thingDef), PathEndMode.OnCell, TraverseParms.For(traveler, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null, 0, -1, false) as Building_AIPawnRechargeStation; if (building_Bed2 != null) { if (sleeper.ownership != null) { sleeper.ownership.UnclaimBed(); } return(building_Bed2); } } } return(null); }
public static Building_AIPawnRechargeStation FindMedicalRechargeStationFor(AIPawn p) { return(FindRechargeStationFor(p, p, false, false, true)); //FindBedFor(p, p, p.IsPrisonerOfColony, true); }