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(); } }
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 }
public static void DoSingleTick_Prefix() { ProfilingUtils.startProfiling("1-DoSingleTick"); }
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; } } } }
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); }
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 }