/// <summary> /// Calculates body scale factors based on body type /// </summary> /// <param name="pawn">Which pawn to measure for</param> /// <returns>Width factor as First, height factor as second</returns> public static Vector2 GetCollisionBodyFactors(Pawn pawn) { if (pawn == null) { Log.Error("CE calling GetCollisionBodyHeightFactor with nullPawn"); return(new Vector2(1, 1)); } var factors = BoundsInjector.ForPawn(pawn); if (pawn.GetPosture() != PawnPosture.Standing) { RacePropertiesExtensionCE props = pawn.def.GetModExtension <RacePropertiesExtensionCE>() ?? new RacePropertiesExtensionCE(); var shape = props.bodyShape; if (shape == CE_BodyShapeDefOf.Invalid) { Log.ErrorOnce("CE returning BodyType Undefined for pawn " + pawn.ToString(), 35000198 + pawn.GetHashCode()); } factors.x *= shape.widthLaying / shape.width; factors.y *= shape.heightLaying / shape.height; } return(factors); }
private static void CalculateHeightRange(Thing thing, out FloatRange heightRange, out float shotHeight) { shotHeight = 0; heightRange = new FloatRange(0, 0); if (thing == null) { return; } var plant = thing as Plant; if (plant != null) { //Height matches up exactly with visual size heightRange = new FloatRange(0f, BoundsInjector.ForPlant(plant).y); return; } if (thing is Building) { if (thing is Building_Door door && door.Open) { return; //returns heightRange = (0,0) & shotHeight = 0. If not open, doors have FillCategory.Full so returns (0, WallCollisionHeight) } if (thing.def.Fillage == FillCategory.Full) { heightRange = new FloatRange(0, WallCollisionHeight); shotHeight = WallCollisionHeight; return; } float fillPercent = thing.def.fillPercent; heightRange = new FloatRange(Mathf.Min(0f, fillPercent), Mathf.Max(0f, fillPercent)); shotHeight = fillPercent; return; } float collisionHeight = 0f; float shotHeightOffset = 0; var pawn = thing as Pawn; if (pawn != null) { collisionHeight = CE_Utility.GetCollisionBodyFactors(pawn).y; shotHeightOffset = collisionHeight * (1 - BodyRegionMiddleHeight); // Humanlikes in combat crouch to reduce their profile if (pawn.IsCrouching()) { float crouchHeight = BodyRegionBottomHeight * collisionHeight; // Minimum height we can crouch down to // Find the highest adjacent cover Map map = pawn.Map; foreach (IntVec3 curCell in GenAdjFast.AdjacentCells8Way(pawn.Position)) { if (curCell.InBounds(map)) { Thing cover = curCell.GetCover(map); if (cover != null && cover.def.Fillage == FillCategory.Partial && !cover.IsPlant()) { var coverHeight = new CollisionVertical(cover).Max; if (coverHeight > crouchHeight) { crouchHeight = coverHeight; } } } } collisionHeight = Mathf.Min(collisionHeight, crouchHeight + 0.01f + shotHeightOffset); // We crouch down only so far that we can still shoot over our own cover and never beyond our own body size } } else { collisionHeight = thing.def.fillPercent; } var edificeHeight = 0f; if (thing.Map != null) { var edifice = thing.Position.GetCover(thing.Map); if (edifice != null && edifice.GetHashCode() != thing.GetHashCode() && !edifice.IsPlant()) { edificeHeight = new CollisionVertical(edifice).heightRange.max; } } float fillPercent2 = collisionHeight; heightRange = new FloatRange(Mathf.Min(edificeHeight, edificeHeight + fillPercent2), Mathf.Max(edificeHeight, edificeHeight + fillPercent2)); shotHeight = heightRange.max - shotHeightOffset; }