Example #1
0
        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));
        }
        // ================== 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);
        }