// WARNING: DUPLICATE OF HBS CODE. THIS IS LIKELY TO BREAK IF HBS CHANGES THE SOURCE FUNCTIONS
        public static float GetSensorsRange(AbstractActor source)
        {
            if (source.StatCollection.ContainsStatistic(ModStats.DisableSensors))
            {
                Mod.Log.Debug?.Write($"Returning minimum sensors range for {CombatantUtils.Label(source)} due to disabled sensors.");
                return(Mod.Config.Sensors.MinimumSensorRange());
            }

            // Add multipliers and absolute bonuses
            EWState ewState = source.GetEWState();

            Mod.Log.Trace?.Write($"  == Sensors Range for for actor:{CombatantUtils.Label(source)}");

            float rawRangeMulti = SensorLockHelper.GetAllSensorRangeMultipliers(source);
            float rangeMulti    = rawRangeMulti + ewState.GetSensorsRangeMulti();

            Mod.Log.Trace?.Write($"    rangeMulti: {rangeMulti} = rawRangeMulti: {rawRangeMulti} + sensorCheckRangeMulti: {ewState.GetSensorsRangeMulti()}");

            float rawRangeMod = SensorLockHelper.GetAllSensorRangeAbsolutes(source);
            float rangeMod    = rawRangeMod * (1 + ewState.GetSensorsRangeMulti());

            Mod.Log.Trace?.Write($"    rangeMod: {rangeMod} = rawRangeMod: {rawRangeMod} + sensorCheckRangeMulti: {ewState.GetSensorsRangeMulti()}");

            float sensorsRange = ewState.GetSensorsBaseRange() * rangeMulti + rangeMod;

            Mod.Log.Trace?.Write($"    sensorsRange: { sensorsRange} = baseRange: {ewState.GetSensorsBaseRange()} * rangeMult: {rangeMulti} + rangeMod: {rangeMod}");

            if (sensorsRange < Mod.Config.Sensors.MinimumSensorRange())
            {
                sensorsRange = Mod.Config.Sensors.MinimumSensorRange();
            }

            return(sensorsRange);
        }
        public static float GetAdjustedSensorRange(AbstractActor source, ICombatant target)
        {
            EWState sourceState       = source.GetEWState();
            float   sourceSensorRange = SensorLockHelper.GetSensorsRange(source);
            float   targetSignature   = SensorLockHelper.GetTargetSignature(target, sourceState);
            //LowVisibility.Logger.Debug($"   source:{CombatantUtils.Label(source)} sensorRange:{sourceSensorRange}m vs targetSignature:x{targetSignature}");

            //if (target != null && source.VisibilityToTargetUnit(target) > VisibilityLevel.None) {
            //    // If is sensor lock, add the Hysterisis modifier
            //    signatureModifiedRange += ___Combat.Constants.Visibility.SensorHysteresisAdditive;
            //}

            float modifiedRange = sourceSensorRange * targetSignature;

            return(modifiedRange);
        }
Exemple #3
0
        public static int UpdateSensorCheck(AbstractActor actor, bool updateAuras)
        {
            int checkResult = ModState.GetCheckResult();

            actor.StatCollection.Set <int>(ModStats.CurrentRoundEWCheck, checkResult);
            Mod.Log.Debug?.Write($"Actor:{CombatantUtils.Label(actor)} has raw EW Check: {checkResult}");

            if (updateAuras && actor.StatCollection.ContainsStatistic(ModStats.CAESensorsRange))
            {
                float sensorsRange = SensorLockHelper.GetSensorsRange(actor);
                actor.StatCollection.Set <float>(ModStats.CAESensorsRange, sensorsRange);

                // TODO: Re-enable once KMission has researched
                actor.UpdateAuras(false);
            }

            return(checkResult);
        }
        public static SensorScanType CalculateSensorLock(AbstractActor source, Vector3 sourcePos, ICombatant target, Vector3 targetPos)
        {
            if (source.GUID == target.GUID || source.Combat.HostilityMatrix.IsFriendly(source.TeamId, target.team.GUID))
            {
                // If they are us, or allied, automatically give sensor details
                Mod.Log.Trace?.Write($"  source:{CombatantUtils.Label(source)} is friendly to target:{CombatantUtils.Label(target)}. Forcing full visibility.");
                return(SensorScanType.AllInformation);
            }

            if (source.IsDead || source.IsFlaggedForDeath)
            {
                // If we're dead, we can't have vision or sensors. If we're off the map, we can't either. If the target is off the map, we can't see it.
                Mod.Log.Trace?.Write($"  source:{CombatantUtils.Label(source)} is dead or dying. Forcing no visibility.");
                return(SensorScanType.NoInfo);
            }

            if (target.IsDead || target.IsFlaggedForDeath)
            {
                // If the target is dead, we can't have sensor but we have vision
                Mod.Log.Trace?.Write($"  target:{CombatantUtils.Label(target)} is dead or dying. Forcing no sensor lock, vision based upon visibility.");
                return(SensorScanType.NoInfo);
            }

            if (source.IsTeleportedOffScreen)
            {
                Mod.Log.Trace?.Write($"  source as is teleported off screen. Skipping.");
                return(SensorScanType.NoInfo);
            }

            if (source.StatCollection.ContainsStatistic(ModStats.DisableSensors))
            {
                Mod.Log.Debug?.Write($"Sensors disabled for source: {CombatantUtils.Label(source)}, returning no info.");
                return(SensorScanType.NoInfo);
            }

            EWState sourceState         = source.GetEWState();
            float   distance            = Vector3.Distance(sourcePos, targetPos);
            float   sensorRangeVsTarget = SensorLockHelper.GetAdjustedSensorRange(source, target);

            Mod.Log.Trace?.Write($"SensorLockHelper - source: {CombatantUtils.Label(source)} sensorRangeVsTarget: {sensorRangeVsTarget} vs distance: {distance}");
            if (target is BattleTech.Building targetBuilding)
            {
                // If the target is a building, show them so long as they are in sensor distance
                // TODO: ADD FRIENDLY ECM CHECK HERE?

                // TODO: This should be calculated more fully! Major bug here!
                SensorScanType buildingLock = sourceState.GetCurrentEWCheck() > 0 ? SensorScanType.ArmorAndWeaponType : SensorScanType.NoInfo;
                Mod.Log.Trace?.Write($"  target:{CombatantUtils.Label(targetBuilding)} is a building with lockState:{buildingLock}");
                return(buildingLock);
            }
            else if ((target as AbstractActor) != null)
            {
                AbstractActor targetActor = target as AbstractActor;
                EWState       targetState = targetActor.GetEWState();

                if (distance > sensorRangeVsTarget)
                {
                    // Check for Narc effect that will show the target regardless of range
                    SensorScanType narcLock = HasNarcBeaconDetection(target, sourceState, targetState) ? SensorScanType.LocationAndType : SensorScanType.NoInfo;
                    Mod.Log.Trace?.Write($"  source:{CombatantUtils.Label(source)} is out of range, lock from Narc is:{narcLock}");
                    return(narcLock);
                }
                else
                {
                    SensorScanType sensorLock = SensorScanType.NoInfo;
                    if (targetActor.IsTeleportedOffScreen)
                    {
                        Mod.Log.Trace?.Write($"  target is teleported off screen. Skipping.");
                    }
                    else
                    {
                        // TODO: Re-add shadowing logic
                        // TODO: SensorLock adds a boost from friendlies if they have shares sensors?
                        // We are within range, but check to see if the sensorInfoCheck failed
                        sensorLock = CalculateSensorInfoLevel(source, target);

                        // Check for Narc effect overriding detection
                        if (sensorLock < SensorScanType.LocationAndType && HasNarcBeaconDetection(targetActor, sourceState, targetState))
                        {
                            sensorLock = SensorScanType.LocationAndType;
                        }
                    }
                    Mod.Log.Trace?.Write($"SensorLockHelper - source:{CombatantUtils.Label(source)} has sensorLock:({sensorLock}) vs " +
                                         $"target:{CombatantUtils.Label(target)}");
                    return(sensorLock);
                }
            }
            else
            {
                Mod.Log.Info?.Write($"SensorLockHelper - fallthrough case for target: {CombatantUtils.Label(target)} with type: {target.GetType()}. Returning NoLock!");
                return(SensorScanType.NoInfo);
            }
        }