// Added targetThing to parameters so we can calculate its height private bool CanHitCellFromCellIgnoringRange(Vector3 shotSource, IntVec3 targetLoc, Thing targetThing = null) { // Vanilla checks if (verbProps.mustCastOnOpenGround && (!targetLoc.Standable(caster.Map) || caster.Map.thingGrid.CellContains(targetLoc, ThingCategory.Pawn))) { return(false); } if (verbProps.requireLineOfSight) { // Calculate shot vector Vector3 targetPos; if (targetThing != null) { Vector3 targDrawPos = targetThing.DrawPos; targetPos = new Vector3(targDrawPos.x, new CollisionVertical(targetThing).Max, targDrawPos.z); var targPawn = targetThing as Pawn; if (targPawn != null) { targetPos += targPawn.Drawer.leaner.LeanOffset * 0.6f; } } else { targetPos = targetLoc.ToVector3Shifted(); } Ray shotLine = new Ray(shotSource, (targetPos - shotSource)); // Create validator to check for intersection with partial cover var aimMode = CompFireModes?.CurrentAimMode; Predicate <IntVec3> CanShootThroughCell = (IntVec3 cell) => { Thing cover = cell.GetFirstPawn(caster.Map) ?? cell.GetCover(caster.Map); if (cover != null && cover != ShooterPawn && cover != caster && cover != targetThing && !cover.IsPlant() && !(cover is Pawn && cover.HostileTo(caster))) { // Skip this check entirely if we're doing suppressive fire and cell is adjacent to target if ((VerbPropsCE.ignorePartialLoSBlocker || aimMode == AimMode.SuppressFire) && cover.def.Fillage != FillCategory.Full) { return(true); } Bounds bounds = CE_Utility.GetBoundsFor(cover); // Simplified calculations for adjacent cover for gameplay purposes if (cover.def.Fillage != FillCategory.Full && cover.AdjacentTo8WayOrInside(caster)) { // Sanity check to prevent stuff behind us blocking LoS var cellTargDist = cell.DistanceTo(targetLoc); var shotTargDist = shotSource.ToIntVec3().DistanceTo(targetLoc); if (shotTargDist > cellTargDist) { return(cover is Pawn || bounds.size.y < shotSource.y); } } // Check for intersect if (bounds.IntersectRay(shotLine)) { if (Controller.settings.DebugDrawPartialLoSChecks) { caster.Map.debugDrawer.FlashCell(cell, 0, bounds.extents.y.ToString()); } return(false); } if (Controller.settings.DebugDrawPartialLoSChecks) { caster.Map.debugDrawer.FlashCell(cell, 0.7f, bounds.extents.y.ToString()); } } return(true); }; // Add validator to parameters foreach (IntVec3 curCell in SightUtility.GetCellsOnLine(shotSource, targetLoc.ToVector3(), caster.Map)) { if (Controller.settings.DebugDrawPartialLoSChecks) { caster.Map.debugDrawer.FlashCell(curCell, 0.4f); } if (curCell != shotSource.ToIntVec3() && curCell != targetLoc && !CanShootThroughCell(curCell)) { return(false); } } } return(true); }