private void updateViewBlockerCells(bool blockView)
        {
#if InternalProfile
            ProfilingUtils.startProfiling("CompViewBlockerWatcher.updateViewBlockerCells");
#endif
            bool[] viewBlockerCells = mapCompSeenFog.viewBlockerCells;

            int mapSizeZ = map.Size.z;
            int mapSizeX = map.Size.x;

            CellRect occupiedRect = parent.OccupiedRect();
            for (int x = occupiedRect.minX; x <= occupiedRect.maxX; x++)
            {
                for (int z = occupiedRect.minZ; z <= occupiedRect.maxZ; z++)
                {
                    if (x >= 0 && z >= 0 && x <= mapSizeX && z <= mapSizeZ)
                    {
                        viewBlockerCells[(z * mapSizeZ) + x] = blockView;
                    }
                }
            }

            IntVec3 thisPos = parent.Position;
            if (Current.ProgramState == ProgramState.Playing)
            {
                if (map != null)
                {
                    List <CompFieldOfViewWatcher> cmpFovs = mapCompSeenFog.fowWatchers;
                    for (int i = 0; i < cmpFovs.Count; i++)
                    {
                        CompFieldOfViewWatcher cmpFov = cmpFovs[i];
                        int thingSightRange           = cmpFov.lastSightRange;

                        if (thingSightRange > 0)
                        {
                            IntVec3 thingPos = cmpFov.parent.Position;

                            int x = thisPos.x - thingPos.x;
                            int z = thisPos.z - thingPos.z;

                            if (x * x + z * z < thingSightRange * thingSightRange)
                            {
                                cmpFov.refreshFovTarget(ref thisPos);
                            }
                        }
                    }
                }
            }

#if InternalProfile
            ProfilingUtils.stopProfiling("CompViewBlockerWatcher.updateViewBlockerCells");
#endif
        }
        public override void MapComponentTick()
        {
#if InternalProfile
            ProfilingUtils.startProfiling("0-calibration");
            ProfilingUtils.stopProfiling("0-calibration");
#endif

            currentGameTick = Find.TickManager.TicksGame;

            if (!initialized)
            {
                initialized = true;

                init();
            }
        }
Beispiel #3
0
        public override void CompTick()
        {
#if InternalProfile
            ProfilingUtils.startProfiling("CompFieldOfViewWatcher.tick");
#endif
            if (disabled)
            {
                return;
            }

            int currentTick = Find.TickManager.TicksGame;

            if (pawn != null)
            {
                // Update at every position change and then after every 1/2 second from last position change.
                if (pawnPather == null)
                {
                    pawnPather = pawn.pather;
                }
                if (pawnPather != null && pawnPather.Moving)
                {
                    lastMovementTick = currentTick;
                }

                if (lastPosition != iv3Invalid && lastPosition != parent.Position)
                {
                    lastPositionUpdateTick = currentTick;
                    updateFoV();
                }
                else if ((currentTick - lastPositionUpdateTick) % 30 == 0)
                {
                    updateFoV();
                }

                // Non pawns update at most every 30 ticks or when position change.
            }
            else if ((lastPosition != iv3Invalid && lastPosition != parent.Position) || currentTick % 30 == 0)
            {
                updateFoV();
            }

#if InternalProfile
            ProfilingUtils.stopProfiling("CompFieldOfViewWatcher.tick");
#endif
        }
Beispiel #4
0
        public override void Perform(Creature creature, float deltaTime)
        {
            //Debugger.Log("attack prio : " + prio);

            ProfilingUtils.BeginSample("CreatureAction::Perform (AttackEcoTarget)");

            if (Time.time > this.timeNextSwim)
            {
                this.timeNextSwim = Time.time + this.swimInterval;

                Vector3 position = Player.main.transform.position;

                Vector3 targetDirection = -MainCamera.camera.transform.forward;

                base.swimBehaviour.Attack(position, targetDirection, this.swimVelocity);
            }

            if (this.resetAggressionOnTime && Time.time > this.timeStartAttack + this.maxAttackDuration)
            {
                this.StopAttack();
            }

            ProfilingUtils.EndSample(null);
        }
        public static bool Prefix(Creature __instance, float deltaTime, Animator ___traitsAnimator, ref CreatureAction ___lastAction,
                                  CreatureAction ___prevBestAction, float ___flinch, float ___flinchFadeRate, List <CreatureAction> ___actions, ref int ___indexLastActionChecked,
                                  ref int ___animAggressive, ref int ___animScared, ref int ___animTired, ref int ___animHappy, ref int ___animFlinch)
        {
            TechType techType   = CraftData.GetTechType(__instance.gameObject);
            string   myTechType = techType.AsString(true);

            if (!(myTechType == "ghostleviathan" || myTechType == "ghostleviathanjuvenile") || !PassiveGhostLeviathansPatcher.Config.isGhostPassive)
            {
                return(true);
            }

            int myIndexLast = ___indexLastActionChecked;

            CreatureAction ChooseBestAction()
            {
                if (___actions.Count == 0)
                {
                    return(null);
                }
                if (__instance.liveMixin && !__instance.liveMixin.IsAlive())
                {
                    SwimBehaviour component = __instance.GetComponentInParent <SwimBehaviour>();
                    if (component)
                    {
                        component.Idle();
                    }
                    return(null);
                }
                ProfilingUtils.BeginSample("Creature.ChooseBestAction");
                float          mynum            = 0f;
                CreatureAction mycreatureAction = null;

                if (___prevBestAction != null)
                {
                    mycreatureAction = ___prevBestAction;
                    ProfilingUtils.BeginSample("bestAction.Evaluate");
                    mynum = mycreatureAction.Evaluate(__instance);
                    ProfilingUtils.EndSample(null);
                }
                myIndexLast++;
                if (myIndexLast >= ___actions.Count)
                {
                    myIndexLast = 0;
                }
                CreatureAction creatureAction2 = ___actions[myIndexLast];

                ProfilingUtils.BeginSample("current.Evaluate");
                float num2 = creatureAction2.Evaluate(__instance);

                ProfilingUtils.EndSample(null);
                if (num2 > mynum && !Utils.NearlyEqual(num2, 0f, 1E-45f))
                {
                    mycreatureAction = creatureAction2;
                }
                ProfilingUtils.EndSample(null);
                return(mycreatureAction);
            }

            ___indexLastActionChecked = myIndexLast;

            ProfilingUtils.BeginSample("CreatureBehavior::Update");
            ProfilingUtils.BeginSample("choose action");
            CreatureAction creatureAction = ChooseBestAction();

            if (___prevBestAction != creatureAction)
            {
                if (___prevBestAction)
                {
                    ___prevBestAction.StopPerform(__instance);
                }
                if (creatureAction)
                {
                    //Logger.Log(creatureAction.ToString());
                    creatureAction.StartPerform(__instance);
                }
                ___prevBestAction = creatureAction;
            }
            ProfilingUtils.EndSample(null);
            if (creatureAction)
            {
                ProfilingUtils.BeginSample("perform action");
                creatureAction.Perform(__instance, deltaTime);
                ProfilingUtils.EndSample(null);
            }
            float num = DayNightUtils.Evaluate(1f, __instance.activity);

            __instance.Tired.Value = Mathf.Lerp(__instance.Tired.Value, 1f - num, 0.1f * deltaTime);
            ProfilingUtils.BeginSample("update traits");
            __instance.Curiosity.UpdateTrait(deltaTime);
            __instance.Friendliness.UpdateTrait(deltaTime);
            __instance.Hunger.UpdateTrait(deltaTime);
            __instance.Aggression.UpdateTrait(deltaTime);
            __instance.Scared.UpdateTrait(deltaTime);
            __instance.Tired.UpdateTrait(deltaTime);
            __instance.Happy.UpdateTrait(deltaTime);
            ___flinch = Mathf.Lerp(___flinch, 0f, ___flinchFadeRate * deltaTime);
            ProfilingUtils.EndSample(null);
            if (___traitsAnimator && ___traitsAnimator.isActiveAndEnabled)
            {
                ___traitsAnimator.SetFloat(___animAggressive, __instance.Aggression.Value);
                ___traitsAnimator.SetFloat(___animScared, __instance.Scared.Value);
                ___traitsAnimator.SetFloat(___animTired, __instance.Tired.Value);
                ___traitsAnimator.SetFloat(___animHappy, __instance.Happy.Value);
                ___traitsAnimator.SetFloat(___animFlinch, ___flinch);
            }
            ProfilingUtils.EndSample(null);
            return(false);
        }
        public static bool Prefix(MoveTowardsTarget __instance)
        {
            float aggressionMultiplier;
            int   aggressionRadius;

            if (CraftData.GetTechType(__instance.gameObject) == TechType.Crash)
            {
                return(true); // Explody ambush fish just runs normal method
            }

            if (Player.main.precursorOutOfWater || !Player.main.IsUnderwater() || PrecursorMoonPoolTrigger.inMoonpool || (Ocean.main.GetDepthOf(Player.main.gameObject) < 5))
            {
                return(true);
            }

            Vehicle veh = Player.main.currentMountedVehicle;

            if (veh != null)
            {
                if (veh.precursorOutOfWater)
                {
                    return(true);
                }
            }

            //BR// Adjust aggression levels
            if (Config.DEATHRUN.Equals(DeathRun.config.creatureAggression) || Config.EXORBITANT.Equals(DeathRun.config.creatureAggression))
            {
                if (DayNightCycle.main.timePassedAsFloat > DeathRun.FULL_AGGRESSION)
                {
                    aggressionMultiplier = 4;
                    aggressionRadius     = 6;
                }
                else if (DayNightCycle.main.timePassedAsFloat > DeathRun.MORE_AGGRESSION)
                {
                    aggressionMultiplier = 2;
                    aggressionRadius     = 3;
                }
                else
                {
                    return(true);
                }
            }
            else if (Config.HARD.Equals(DeathRun.config.creatureAggression) && (DayNightCycle.main.timePassedAsFloat > DeathRun.MORE_AGGRESSION))
            {
                aggressionMultiplier = 2;
                aggressionRadius     = 3;
            }
            else
            {
                return(true); // Just run normal method
            }

            ProfilingUtils.BeginSample("UpdateCurrentTarget");
            if (EcoRegionManager.main != null && (Mathf.Approximately(__instance.requiredAggression, 0f) || __instance.creature.Aggression.Value * aggressionMultiplier >= __instance.requiredAggression))
            {
                IEcoTarget ecoTarget = EcoRegionManager.main.FindNearestTarget(__instance.targetType, __instance.transform.position, __instance.isTargetValidFilter, aggressionRadius);

                if (ecoTarget != null)
                {
                    __instance.currentTarget = ecoTarget;
                }
                else
                {
                    __instance.currentTarget = null;
                }
            }
            ProfilingUtils.EndSample(null);
            return(false);
        }
        public static void PostFix(EcoRegion __instance, EcoTargetType type, Vector3 wsPos, EcoRegion.TargetFilter isTargetValid, ref float bestDist, ref IEcoTarget best)
        {
            if (DeathRun.crashFishSemaphore)
            {
                return;
            }

            ProfilingUtils.BeginSample("EcoRegion.FindNearestTarget");
            __instance.timeStamp = Time.time;
            System.Collections.Generic.HashSet <IEcoTarget> hashSet;
            if (!__instance.ecoTargets.TryGetValue((int)type, out hashSet))
            {
                ProfilingUtils.EndSample(null);
                return;
            }
            float num = float.MaxValue;

            foreach (IEcoTarget ecoTarget in hashSet)
            {
                if (ecoTarget != null && !ecoTarget.Equals(null))
                {
                    float sqrMagnitude = (wsPos - ecoTarget.GetPosition()).sqrMagnitude;

                    if (((ecoTarget.GetGameObject() == Player.main.gameObject) && !Player.main.IsInside() && Player.main.IsUnderwater() && !Player.main.precursorOutOfWater) ||
                        (ecoTarget.GetGameObject().GetComponent <Vehicle>() && (ecoTarget.GetGameObject().GetComponent <Vehicle>() == Player.main.currentMountedVehicle)) && !Player.main.currentMountedVehicle.precursorOutOfWater)
                    {
                        bool feeding = false;
                        if (ecoTarget.GetGameObject() == Player.main.gameObject)
                        {
                            Pickupable held = Inventory.main.GetHeld();
                            if (held != null && (held.GetTechType() == TechType.Peeper))
                            {
                                feeding = true;
                            }
                        }

                        float depth = Ocean.main.GetDepthOf(ecoTarget.GetGameObject());
                        if ((depth > 5) && !feeding)
                        {
                            if (Config.DEATHRUN.Equals(DeathRun.config.creatureAggression) || Config.EXORBITANT.Equals(DeathRun.config.creatureAggression))
                            {
                                if (DayNightCycle.main.timePassedAsFloat >= DeathRun.FULL_AGGRESSION)
                                {
                                    sqrMagnitude = 1; //BR// Player appears very close! (i.e. attractive target)
                                }
                                else if (DayNightCycle.main.timePassedAsFloat >= DeathRun.MORE_AGGRESSION)
                                {
                                    sqrMagnitude /= 4;
                                }
                                else
                                {
                                    sqrMagnitude /= 2;
                                }
                            }
                            else if (Config.HARD.Equals(DeathRun.config.creatureAggression))
                            {
                                if (DayNightCycle.main.timePassedAsFloat >= DeathRun.FULL_AGGRESSION)
                                {
                                    sqrMagnitude /= 3; //BR// Player appears closer! (i.e. attractive target)
                                }
                                else if (DayNightCycle.main.timePassedAsFloat >= DeathRun.MORE_AGGRESSION)
                                {
                                    sqrMagnitude /= 2;
                                }
                            }
                        }
                    }

                    if (sqrMagnitude < num && (isTargetValid == null || isTargetValid(ecoTarget)))
                    {
                        best = ecoTarget;
                        num  = sqrMagnitude;
                    }
                }
            }
            if (best != null)
            {
                bestDist = Mathf.Sqrt(num);
            }
            ProfilingUtils.EndSample(null);
        }
 public static void DoSingleTick_Prefix()
 {
     ProfilingUtils.startProfiling("1-DoSingleTick");
 }
 public static void DoSingleTick_Postfix()
 {
     ProfilingUtils.stopProfiling("1-DoSingleTick");
 }
Beispiel #10
0
        public void calculateFoV(Thing thing, int intRadius, bool peek)
        {
            if (!setupDone)
            {
                return;
            }

#if InternalProfile
            ProfilingUtils.startProfiling("CompFieldOfViewWatcher.calculateFoV");
#endif

            int mapSizeX = this.mapSizeX;
            int mapSizeZ = this.mapSizeZ;

            bool[] oldViewMap = viewMapSwitch ? this.viewMap1 : this.viewMap2;
            bool[] newViewMap = viewMapSwitch ? this.viewMap2 : this.viewMap1;

            IntVec3 position          = thing.Position;
            Faction faction           = lastFaction;
            short[] factionShownCells = lastFactionShownCells;

            int peekRadius = (peek ? intRadius + 1 : intRadius);

            // Calculate new view rect.
            CellRect occupedRect     = thing.OccupiedRect();
            int      newViewRectMinX = Math.Min(position.x - peekRadius, occupedRect.minX);
            int      newViewRectMaxX = Math.Max(position.x + peekRadius, occupedRect.maxX);
            int      newViewRectMinZ = Math.Min(position.z - peekRadius, occupedRect.minZ);
            int      newViewRectMaxZ = Math.Max(position.z + peekRadius, occupedRect.maxZ);

            int newViewWidth = newViewRectMaxX - newViewRectMinX + 1;
            int newViewArea  = newViewWidth * (newViewRectMaxZ - newViewRectMinZ + 1);


            int oldViewRectMinZ = viewRect.minZ;
            int oldViewRectMaxZ = viewRect.maxZ;
            int oldViewRectMinX = viewRect.minX;
            int oldViewRectMaxX = viewRect.maxX;

            int oldViewWidth = viewRect.Width;
            int oldViewArea  = viewRect.Area;


            // Create the new view map if needed.
            if (newViewMap == null || newViewMap.Length < newViewArea)
            {
                newViewMap = new bool[(int)(newViewArea * 1.20f)];
                if (viewMapSwitch)
                {
                    this.viewMap2 = newViewMap;
                }
                else
                {
                    this.viewMap1 = newViewMap;
                }
            }


#if InternalProfile
            ProfilingUtils.startProfiling("CompFieldOfViewWatcher.calculateFoV-seen");
#endif
            // Occupied cells are always visible.
            int occupiedX;
            int occupiedZ;
            int oldViewRectIdx;
            for (occupiedX = occupedRect.minX; occupiedX <= occupedRect.maxX; occupiedX++)
            {
                for (occupiedZ = occupedRect.minZ; occupiedZ <= occupedRect.maxZ; occupiedZ++)
                {
                    newViewMap[((occupiedZ - newViewRectMinZ) * newViewWidth) + (occupiedX - newViewRectMinX)] = true;
                    if (oldViewMap == null || occupiedX < oldViewRectMinX || occupiedZ < oldViewRectMinZ || occupiedX > oldViewRectMaxX || occupiedZ > oldViewRectMaxZ)
                    {
                        mapCompSeenFog.incrementSeen(faction, factionShownCells, (occupiedZ * mapSizeX) + occupiedX);
                    }
                    else
                    {
                        oldViewRectIdx = ((occupiedZ - oldViewRectMinZ) * oldViewWidth) + (occupiedX - oldViewRectMinX);
                        ref bool oldViewMapValue = ref oldViewMap[oldViewRectIdx];
                        if (!oldViewMapValue)
                        {
                            // Old cell was not visible. Increment seen counter in global grid.
                            mapCompSeenFog.incrementSeen(faction, factionShownCells, (occupiedZ * mapSizeX) + occupiedX);
                        }
                        else
                        {
                            // Old cell was already visible. Mark it to not be unseen.
                            oldViewMapValue = false;
                        }
                    }
                }
            }
Beispiel #11
0
        public float calcPawnSightRange(IntVec3 position, bool forTargeting, bool shouldMove)
        {
            if (pawn == null)
            {
                Log.Error("calcPawnSightRange performed on non pawn thing");
                return(0);
            }

#if InternalProfile
            ProfilingUtils.startProfiling("CompFieldOfViewWatcher.calcPawnSightRange");
#endif
            float sightRange = 0f;

            initMap();

            bool sleeping = !isMechanoid && pawn.CurJob != null && pawn.jobs.curDriver.asleep;

            if (!shouldMove && !sleeping && (pawnPather == null || !pawnPather.Moving))
            {
                Verb attackVerb = null;
                if (pawn.CurJob != null)
                {
                    JobDef jobDef = pawn.CurJob.def;
                    if (jobDef == JobDefOf.ManTurret)
                    {
                        Building_Turret mannedTurret = pawn.CurJob.targetA.Thing as Building_Turret;
                        if (mannedTurret != null)
                        {
                            attackVerb = mannedTurret.AttackVerb;
                        }
                    }
                    else if (jobDef == JobDefOf.AttackStatic || jobDef == JobDefOf.AttackMelee || jobDef == JobDefOf.Wait_Combat || jobDef == JobDefOf.Hunt)
                    {
                        if (pawn.equipment != null)
                        {
                            ThingWithComps primary = pawn.equipment.Primary;
                            if (primary != null && primary.def.IsRangedWeapon)
                            {
                                attackVerb = primary.GetComp <CompEquippable>().PrimaryVerb;
                            }
                        }
                    }
                }

                if (attackVerb != null && attackVerb.verbProps.range > baseViewRange && attackVerb.verbProps.requireLineOfSight && attackVerb.EquipmentSource.def.IsRangedWeapon)
                {
                    float attackVerbRange = attackVerb.verbProps.range;
                    if (baseViewRange < attackVerbRange)
                    {
                        int ticksStanding = Find.TickManager.TicksGame - lastMovementTick;

                        float statValue     = pawn.GetStatValue(StatDefOf.AimingDelayFactor, true);
                        int   ticksToSearch = (attackVerb.verbProps.warmupTime * statValue).SecondsToTicks() * Mathf.RoundToInt((attackVerbRange - baseViewRange) / 2);

                        if (ticksStanding >= ticksToSearch)
                        {
                            sightRange = attackVerbRange * capacities.GetLevel(PawnCapacityDefOf.Sight);
                        }
                        else
                        {
                            int incValue = Mathf.RoundToInt((attackVerbRange - baseViewRange) * ((float)ticksStanding / ticksToSearch));

                            sightRange = (baseViewRange + incValue) * capacities.GetLevel(PawnCapacityDefOf.Sight);
                        }
                    }
                }
            }

            if (sightRange == 0f)
            {
                sightRange = baseViewRange * capacities.GetLevel(PawnCapacityDefOf.Sight);
            }

            if (!forTargeting && sleeping)
            {
                // Sleeping: sight reduced to 20% (if not for targeting).
                sightRange *= 0.2f;
            }
            // TODO: Apply moving penality?

            /*else if (!calcOnlyBase && pawnPather.Moving) {
             *      // When moving, sight reduced to 90%s.
             *      sightRange *= 0.9f;
             * }
             */

            // Check if standing on an affect view object.
            List <CompAffectVision> compsAffectVision = mapCompSeenFog.compAffectVisionGrid[(position.z * mapSizeX) + position.x];
            int compsCount = compsAffectVision.Count;
            for (int i = 0; i < compsCount; i++)
            {
                sightRange *= compsAffectVision[i].Props.fovMultiplier;
            }

            // Additional dark and weather debuff.
            if (!isMechanoid)
            {
                float currGlow = glowGrid.GameGlowAt(position);
                if (currGlow != 1f)
                {
                    float darkModifier = 0.6f;
                    // Each bionic eye reduce the dark debuff by 20.
                    int hediffsCount = hediffs.Count;
                    for (int i = 0; i < hediffsCount; i++)
                    {
                        if (hediffs[i].def == HediffDefOf.BionicEye)
                        {
                            darkModifier += 0.2f;
                        }
                    }

                    // Apply only if to debuff.
                    if (darkModifier < 1f)
                    {
                        // Adjusted to glow (100% full light - 60% dark).
                        sightRange *= Mathf.Lerp(darkModifier, 1f, currGlow);
                    }
                }

                if (!roofGrid.Roofed(position.x, position.z))
                {
                    float weatherFactor = weatherManager.CurWeatherAccuracyMultiplier;
                    if (weatherFactor != 1f)
                    {
                        // Weather factor is applied by half.
                        sightRange *= Mathf.Lerp(0.5f, 1f, weatherFactor);
                    }
                }
            }

            // Mininum sight.
            if (sightRange < 1f)
            {
                return(1);
            }

#if InternalProfile
            ProfilingUtils.stopProfiling("CompFieldOfViewWatcher.calcPawnSightRange");
#endif
            return(sightRange);
        }
Beispiel #12
0
        public void updateFoV(bool forceUpdate = false)
        {
            if (disabled || !setupDone || Current.ProgramState == ProgramState.MapInitializing)
            {
                return;
            }

#if InternalProfile
            ProfilingUtils.startProfiling("CompFieldOfViewWatcher.updateFoV");
#endif
            ThingWithComps thing       = base.parent;
            IntVec3        newPosition = thing.Position;

            if (thing != null && thing.Spawned && thing.Map != null && newPosition != iv3Invalid)
            {
                initMap();

                Faction newFaction = thing.Faction;

                if (newFaction != null && (pawn == null || !pawn.Dead))
                {
                    // Faction things or alive pawn!

                    if (pawn != null)
                    {
                        // Alive Pawns!

                        int  sightRange;
                        bool isPeeking = false;
                        if (raceProps != null && raceProps.Animal && (pawn.playerSettings == null || pawn.playerSettings.Master == null || pawn.training == null || !pawn.training.HasLearned(TrainableDefOf.Release)))
                        {
                            // If animal, only those with a master set and release training can contribute to the faction FoW.
                            sightRange = -1;
                        }
                        else
                        {
                            sightRange = Mathf.RoundToInt(calcPawnSightRange(newPosition, false, false));

                            if ((pawnPather == null || !pawnPather.Moving) && pawn.CurJob != null)
                            {
                                JobDef jobDef = pawn.CurJob.def;
                                if (jobDef == JobDefOf.AttackStatic || jobDef == JobDefOf.AttackMelee || jobDef == JobDefOf.Wait_Combat || jobDef == JobDefOf.Hunt)
                                {
                                    isPeeking = true;
                                }
                            }
                        }

                        if (!calculated || forceUpdate || newFaction != lastFaction || newPosition != lastPosition || sightRange != lastSightRange || isPeeking != lastIsPeeking)
                        {
                            calculated     = true;
                            lastPosition   = newPosition;
                            lastSightRange = sightRange;
                            lastIsPeeking  = isPeeking;

                            // Faction change. Unseen and clear old seen cells
                            if (lastFaction != newFaction)
                            {
                                if (lastFaction != null)
                                {
                                    unseeSeenCells(lastFaction, lastFactionShownCells);
                                }
                                lastFaction           = newFaction;
                                lastFactionShownCells = mapCompSeenFog.getFactionShownCells(newFaction);
                            }


                            if (sightRange != -1)
                            {
                                calculateFoV(thing, sightRange, isPeeking);
                            }
                            else
                            {
                                unseeSeenCells(lastFaction, lastFactionShownCells);
                            }
                        }
                    }
                    else if (turret != null && compMannable == null)
                    {
                        // Automatic turrets!

                        int sightRange = Mathf.RoundToInt(turret.GunCompEq.PrimaryVerb.verbProps.range);

                        if (Find.Storyteller.difficulty.difficulty >= 4 ||                         // Intense and Extreme difficulties disable FoV from turrets.
                            (compPowerTrader != null && !compPowerTrader.PowerOn) ||
                            (compRefuelable != null && !compRefuelable.HasFuel) ||
                            (compFlickable != null && !compFlickable.SwitchIsOn))
                        {
                            sightRange = 0;
                        }

                        if (!calculated || forceUpdate || newFaction != lastFaction || newPosition != lastPosition || sightRange != lastSightRange)
                        {
                            calculated     = true;
                            lastPosition   = newPosition;
                            lastSightRange = sightRange;

                            // Faction change. Unseen and clear old seen cells
                            if (lastFaction != newFaction)
                            {
                                if (lastFaction != null)
                                {
                                    unseeSeenCells(lastFaction, lastFactionShownCells);
                                }
                                lastFaction           = newFaction;
                                lastFactionShownCells = mapCompSeenFog.getFactionShownCells(newFaction);
                            }

                            if (sightRange != 0)
                            {
                                calculateFoV(thing, sightRange, false);
                            }
                            else
                            {
                                unseeSeenCells(lastFaction, lastFactionShownCells);
                                revealOccupiedCells();
                            }
                        }
                    }
                    else if (compProvideVision != null)
                    {
                        // Vision providers!

                        // TODO: Calculate range applying dark and weather debufs.
                        int sightRange = Mathf.RoundToInt(compProvideVision.Props.viewRadius);

                        if ((compPowerTrader != null && !compPowerTrader.PowerOn) ||
                            (compRefuelable != null && !compRefuelable.HasFuel) ||
                            (compFlickable != null && !compFlickable.SwitchIsOn))
                        {
                            sightRange = 0;
                        }

                        if (!calculated || forceUpdate || newFaction != lastFaction || newPosition != lastPosition || sightRange != lastSightRange)
                        {
                            calculated     = true;
                            lastPosition   = newPosition;
                            lastSightRange = sightRange;

                            // Faction change. Unseen and clear old seen cells
                            if (lastFaction != newFaction)
                            {
                                if (lastFaction != null)
                                {
                                    unseeSeenCells(lastFaction, lastFactionShownCells);
                                }
                                lastFaction           = newFaction;
                                lastFactionShownCells = mapCompSeenFog.getFactionShownCells(newFaction);
                            }

                            if (sightRange != 0)
                            {
                                calculateFoV(thing, sightRange, false);
                            }
                            else
                            {
                                unseeSeenCells(lastFaction, lastFactionShownCells);
                                revealOccupiedCells();
                            }
                        }
                    }
                    else if (building != null)
                    {
                        // Generic building.

                        int sightRange = 0;

                        if (!calculated || forceUpdate || newFaction != lastFaction || newPosition != lastPosition || sightRange != lastSightRange)
                        {
                            calculated     = true;
                            lastPosition   = newPosition;
                            lastSightRange = sightRange;

                            // Faction change. Unseen and clear old seen cells
                            if (lastFaction != newFaction)
                            {
                                if (lastFaction != null)
                                {
                                    unseeSeenCells(lastFaction, lastFactionShownCells);
                                }
                                lastFaction           = newFaction;
                                lastFactionShownCells = mapCompSeenFog.getFactionShownCells(newFaction);
                            }

                            unseeSeenCells(lastFaction, lastFactionShownCells);
                            revealOccupiedCells();
                        }
                    }
                    else
                    {
                        Log.Warning("Non disabled thing... " + parent.ThingID);
                    }
                }
                else if (newFaction != lastFaction)
                {
                    // Faction change (from a faction to nothing). Unseen and clear old seen cells
                    if (lastFaction != null)
                    {
                        unseeSeenCells(lastFaction, lastFactionShownCells);
                    }
                    lastFaction           = newFaction;
                    lastFactionShownCells = mapCompSeenFog.getFactionShownCells(newFaction);
                }
            }

#if InternalProfile
            ProfilingUtils.stopProfiling("CompFieldOfViewWatcher.updateFoV");
#endif
        }
        public static void computeFieldOfViewWithShadowCasting(
            int startX, int startY, int radius,
            bool[] viewBlockerCells, int maxX, int maxY,
            bool handleSeenAndCache, MapComponentSeenFog mapCompSeenFog, Faction faction, short[] factionShownCells,
            bool[] fovGrid, int fovGridMinX, int fovGridMinY, int fovGridWidth,
            bool[] oldFovGrid, int oldFovGridMinX, int oldFovGridMaxX, int oldFovGridMinY, int oldFovGridMaxY, int oldFovGridWidth,
            byte specificOctant = 255,
            int targetX         = -1,
            int targetY         = -1)
        {
#if InternalProfile
            ProfilingUtils.startProfiling("computeFieldOfViewWithShadowCasting");
#endif
            int r_r = radius * radius;

            if (specificOctant == 255)
            {
                for (byte octant = 0; octant < 8; ++octant)
                {
                    computeFieldOfViewInOctantZero(
                        octant,
                        fovGrid,
                        fovGridMinX,
                        fovGridMinY,
                        fovGridWidth,
                        oldFovGrid,
                        oldFovGridMinX,
                        oldFovGridMaxX,
                        oldFovGridMinY,
                        oldFovGridMaxY,
                        oldFovGridWidth,
                        radius,
                        r_r,
                        startX,
                        startY,
                        maxX,
                        maxY,
                        viewBlockerCells,
                        handleSeenAndCache, mapCompSeenFog, faction, factionShownCells,
                        targetX,
                        targetY,
                        0, 1, 1, 1, 0);
                }
            }
            else
            {
                computeFieldOfViewInOctantZero(
                    specificOctant,
                    fovGrid,
                    fovGridMinX,
                    fovGridMinY,
                    fovGridWidth,
                    oldFovGrid,
                    oldFovGridMinX,
                    oldFovGridMaxX,
                    oldFovGridMinY,
                    oldFovGridMaxY,
                    oldFovGridWidth,
                    radius,
                    r_r,
                    startX,
                    startY,
                    maxX,
                    maxY,
                    viewBlockerCells,
                    handleSeenAndCache, mapCompSeenFog, faction, factionShownCells,
                    targetX,
                    targetY,
                    0, 1, 1, 1, 0);
            }

#if InternalProfile
            ProfilingUtils.stopProfiling("computeFieldOfViewWithShadowCasting");
#endif
        }