/* CAC introduces burning effects, which applies heat for each hex you move through, and if you end your turn in a burning hex.
         *   Calculate this heat so we can show it to the player
         *   TODO: Handle unaffected by fire
         */
        public static int CACTerrainHeat(this Mech mech)
        {
            float terrainHeat = 0f;

            // If the unit has been marked as not being affected by fire, skip it entirely
            if (mech.UnaffectedFire())
            {
                return(0);
            }

            if (mech.Pathing.CurrentPath != null && mech.Pathing.CurrentPath.Count > 0)
            {
                List <WayPoint> waypointsFromPath = ActorMovementSequence.ExtractWaypointsFromPath(
                    mech, mech.Pathing.CurrentPath, mech.Pathing.ResultDestination, (ICombatant)mech.Pathing.CurrentMeleeTarget, mech.Pathing.MoveType
                    );
                List <MapTerrainCellWaypoint> terrainWaypoints = DynamicMapHelper.getVisitedWaypoints(mech.Combat, waypointsFromPath);
                Mod.HeatLog.Trace?.Write($"  Count of waypointsFromPath: {waypointsFromPath.Count}  terrainWaypoints: {terrainWaypoints.Count}");

                float sumOfCellHeat = 0f;
                int   totalCells    = 0;
                foreach (MapTerrainCellWaypoint cell in terrainWaypoints)
                {
                    if (cell != null && cell.cell.BurningStrength > 0)
                    {
                        Mod.HeatLog.Trace?.Write($" --Adding {cell.cell.BurningStrength} heat from cell at worldPos: {cell.cell.WorldPos()}");
                        sumOfCellHeat += cell.cell.BurningStrength;
                        totalCells    += 1;
                    }
                }
                terrainHeat = totalCells != 0 ? (float)Math.Ceiling(sumOfCellHeat / totalCells) : 0;
                Mod.HeatLog.Trace?.Write($"TerrainHeat: {terrainHeat} = sumOfHeat: {sumOfCellHeat} / totalCells: {totalCells}");
            }
            else
            {
                MapTerrainDataCellEx cell = mech.Combat.MapMetaData.GetCellAt(mech.CurrentPosition) as MapTerrainDataCellEx;
                if (cell != null && cell.BurningStrength > 0)
                {
                    Mod.HeatLog.Trace?.Write($"Adding {cell.BurningStrength} heat from current position: {mech.CurrentPosition}");
                    terrainHeat = cell.BurningStrength;
                }
            }

            return((int)Math.Ceiling(terrainHeat));
        }
        // Replicates logic from Mech::AdjustedHeatSinkCapacity to allow displaying multiplier
        public static float DesignMaskHeatMulti(this Mech mech, bool isProjectedHeat)
        {
            float capacityMulti = 1f;

            try {
                // Check for currently occupied, or future
                if (isProjectedHeat)
                {
                    Mod.HeatLog.Trace?.Write("Calculating projected position heat.");
                    if (mech.Pathing != null && mech.Pathing.CurrentPath != null && mech.Pathing.CurrentPath.Count > 0)
                    {
                        // Determine the destination designMask
                        Mod.HeatLog.Trace?.Write($"CurrentPath has: {mech.Pathing.CurrentPath.Count} nodes, using destination path: {mech.Pathing.ResultDestination}");
                        DesignMaskDef destinationDesignMaskDef = mech?.Combat?.MapMetaData?.GetPriorityDesignMaskAtPos(mech.Pathing.ResultDestination);
                        if (destinationDesignMaskDef != null && !Mathf.Approximately(destinationDesignMaskDef.heatSinkMultiplier, 1f))
                        {
                            Mod.HeatLog.Trace?.Write($"Destination design mask: {destinationDesignMaskDef?.Description?.Name} has heatSinkMulti: x{destinationDesignMaskDef?.heatSinkMultiplier} ");
                            capacityMulti *= destinationDesignMaskDef.heatSinkMultiplier;
                        }

                        // Check for any cells along the way that will apply the burning sticky effect.
                        //   See CustomAmmoCategories\designmask\DesignMaskBurningForest
                        List <WayPoint> waypointsFromPath = ActorMovementSequence.ExtractWaypointsFromPath(
                            mech, mech.Pathing.CurrentPath, mech.Pathing.ResultDestination, (ICombatant)mech.Pathing.CurrentMeleeTarget, mech.Pathing.MoveType
                            );
                        List <MapTerrainCellWaypoint> terrainWaypoints = DynamicMapHelper.getVisitedWaypoints(mech.Combat, waypointsFromPath);
                        Mod.HeatLog.Trace?.Write($"  Count of waypointsFromPath: {waypointsFromPath?.Count}  terrainWaypoints: {terrainWaypoints?.Count}");

                        // This assumes 1) only KMission is using stickyEffects that modify HeatSinkCapacity and 2) it has a stackLimit of 1. Anything else will break this.
                        float stickyModifier = 1f;
                        foreach (MapTerrainCellWaypoint cell in terrainWaypoints)
                        {
                            if (cell != null && cell?.cell?.BurningStrength > 0 && cell?.cell?.mapMetaData?.designMaskDefs != null)
                            {
                                Mod.HeatLog.Trace?.Write($"  checking burningCell for designMask.");
                                foreach (DesignMaskDef cellDesignMaskDef in cell?.cell?.mapMetaData?.designMaskDefs?.Values)
                                {
                                    Mod.HeatLog.Trace?.Write($"    checking designMask for stickyEffects.");
                                    if (cellDesignMaskDef.stickyEffect != null && cellDesignMaskDef.stickyEffect?.statisticData != null &&
                                        cellDesignMaskDef.stickyEffect.statisticData.statName == ModStats.HBS_HeatSinkCapacity)
                                    {
                                        Mod.HeatLog.Trace?.Write($"      found stickyEffects.");
                                        stickyModifier = Single.Parse(cellDesignMaskDef.stickyEffect.statisticData.modValue);
                                    }
                                }
                            }
                        }
                        if (!Mathf.Approximately(stickyModifier, 1f))
                        {
                            capacityMulti *= stickyModifier;
                            Mod.HeatLog.Trace?.Write($"  capacityMulti: {capacityMulti} after stickyModifier: {stickyModifier}");
                        }
                    }
                    else
                    {
                        Mod.HeatLog.Trace?.Write($"Current path is null or has 0 count, skipping.");
                    }
                }
                else
                {
                    Mod.HeatLog.Trace?.Write("Calculating current position heat.");
                    if (mech.occupiedDesignMask != null && !Mathf.Approximately(mech.occupiedDesignMask.heatSinkMultiplier, 1f))
                    {
                        Mod.HeatLog.Trace?.Write($"Multi for currentPos is: {mech?.occupiedDesignMask?.heatSinkMultiplier}");
                        capacityMulti *= mech.occupiedDesignMask.heatSinkMultiplier;
                    }
                }

                if (mech?.Combat?.MapMetaData?.biomeDesignMask != null && !Mathf.Approximately(mech.Combat.MapMetaData.biomeDesignMask.heatSinkMultiplier, 1f))
                {
                    Mod.HeatLog.Trace?.Write($"Biome: {mech.Combat.MapMetaData.biomeDesignMask.Id} has heatSinkMulti: x{mech.Combat.MapMetaData.biomeDesignMask.heatSinkMultiplier} ");
                    capacityMulti *= mech.Combat.MapMetaData.biomeDesignMask.heatSinkMultiplier;
                }
            } catch (Exception e) {
                Mod.HeatLog.Error?.Write(e, $"Failed to calculate designMaskHeatMulti due to error: {e}");
            }

            Mod.HeatLog.Trace?.Write($"Calculated capacityMulti: {capacityMulti} x globalHeatSinkMulti: {mech.Combat.Constants.Heat.GlobalHeatSinkMultiplier} ");
            capacityMulti *= mech.Combat.Constants.Heat.GlobalHeatSinkMultiplier;
            return(capacityMulti);
        }