public static void Postfix(ref CalledShotAttackOrderInfo __result, AbstractActor attackingUnit, int enemyUnitIndex) { Mod.Log.Trace?.Write("AE:CCSLTC entered"); ICombatant combatant = attackingUnit.BehaviorTree.enemyUnits[enemyUnitIndex]; if (combatant is AbstractActor targetActor) { // Prevents blips from being the targets of called shots VisibilityLevel targetVisibility = attackingUnit.VisibilityToTargetUnit(targetActor); if (targetVisibility < VisibilityLevel.LOSFull) { Mod.Log.Info?.Write($"Target {CombatantUtils.Label(combatant)} is a blip, cannot be targeted by AI called shot"); __result = null; return; } float distance = Vector3.Distance(attackingUnit.CurrentPosition, targetActor.CurrentPosition); bool hasVisualScan = VisualLockHelper.GetVisualScanRange(attackingUnit) >= distance; SensorScanType sensorScan = SensorLockHelper.CalculateSharedLock(targetActor, attackingUnit); if (sensorScan < SensorScanType.ArmorAndWeaponType && !hasVisualScan) { Mod.Log.Info?.Write($"Target {CombatantUtils.Label(targetActor)} sensor info {sensorScan} is less than SurfaceScan and outside visualID, cannot be targeted by AI called shot"); __result = null; return; } } }
public static bool Prefix(SelectionStateFire __instance, ref bool __result, ICombatant combatant) { Mod.Log.Trace?.Write("SSF:PCC:PRE entered"); if (__instance != null && combatant != null && combatant is AbstractActor targetActor && __instance.SelectedActor != null) { CombatGameState Combat = __instance.SelectedActor.Combat; bool targetIsFriendly = Combat.HostilityMatrix.IsFriendly(combatant.team.GUID, Combat.LocalPlayerTeamGuid); if (targetIsFriendly) { Mod.Log.Trace?.Write("Friendly target, skipping check"); return(true); } EWState targetState = new EWState(targetActor); EWState attackerState = new EWState(__instance.SelectedActor); if (__instance.SelectionType == SelectionType.FireMorale) { // Prevents blips from being the targets of called shots VisibilityLevel targetVisibility = __instance.SelectedActor.VisibilityToTargetUnit(targetActor); if (targetVisibility < VisibilityLevel.LOSFull) { Mod.Log.Info?.Write($"Target {CombatantUtils.Label(combatant)} is a blip, cannot be targeted by called shot"); __result = false; return(false); } float distance = Vector3.Distance(__instance.SelectedActor.CurrentPosition, targetActor.CurrentPosition); bool hasVisualScan = VisualLockHelper.GetVisualScanRange(__instance.SelectedActor) >= distance; SensorScanType sensorScan = SensorLockHelper.CalculateSharedLock(targetActor, __instance.SelectedActor); if (sensorScan < SensorScanType.ArmorAndWeaponType && !hasVisualScan) { Mod.Log.Info?.Write($"Target {CombatantUtils.Label(targetActor)} sensor info {sensorScan} is less than SurfaceScan and range:{distance} outside visualScan range, cannot be targeted by called shot"); __result = false; return(false); } } else if (__instance.SelectionType == SelectionType.FireMulti) { if (targetState.HasStealth() || targetState.HasMimetic()) { Mod.Log.Info?.Write($"Target {CombatantUtils.Label(targetActor)} has stealth, cannot be multi-targeted!"); __result = false; return(false); } } } __result = false; return(true); }
private static string BuildToolTip(AbstractActor actor) { //Mod.Log.Debug?.Write($"EW State for actor:{CombatantUtils.Label(actor)} = {ewState}"); List <string> details = new List <string>(); // Visuals check float visualLockRange = VisualLockHelper.GetVisualLockRange(actor); float visualScanRange = VisualLockHelper.GetVisualScanRange(actor); details.Add( new Text(Mod.LocalizedText.StatusPanel[ModText.LT_PANEL_VISUALS], new object[] { visualLockRange, visualScanRange, ModState.GetMapConfig().UILabel() }) .ToString() ); // Sensors check EWState ewState = new EWState(actor); int totalDetails = ewState.GetCurrentEWCheck() + ewState.AdvancedSensorsMod(); SensorScanType checkLevel = SensorScanTypeHelper.DetectionLevelForCheck(totalDetails); float rawRangeMulti = SensorLockHelper.GetAllSensorRangeMultipliers(actor); float rangeMulti = rawRangeMulti + ewState.GetSensorsRangeMulti(); float sensorsRange = SensorLockHelper.GetSensorsRange(actor); string sensorColor = ewState.GetCurrentEWCheck() >= 0 ? "00FF00" : "FF0000"; details.Add( new Text(Mod.LocalizedText.StatusPanel[ModText.LT_PANEL_SENSORS], new object[] { sensorColor, sensorsRange, sensorColor, rangeMulti, checkLevel.Label() }) .ToString() ); // Details //{ LT_PANEL_DETAILS, " Total: <color=#{0}>{1:+0;-#}</color><size=90%> Roll: <color=#{2}>{3:+0;-#}</color> Tactics: <color=#00FF00>{4:+0;-#}</color> AdvSen: <color=#{5}>{6:+0;-#}</color>\n" string totalColor = totalDetails >= 0 ? "00FF00" : "FF0000"; string checkColor = ewState.GetRawCheck() >= 0 ? "00FF00" : "FF0000"; string advSenColor = ewState.AdvancedSensorsMod() >= 0 ? "00FF00" : "FF0000"; details.Add( new Text(Mod.LocalizedText.StatusPanel[ModText.LT_PANEL_DETAILS], new object[] { totalColor, totalDetails, checkColor, ewState.GetRawCheck(), ewState.GetRawTactics(), advSenColor, ewState.AdvancedSensorsMod() }) .ToString() ); // Heat Vision if (ewState.GetRawHeatVision() != null) { // { LT_PANEL_HEAT, "<b>Thermals</b><size=90%> Mod:<color=#{0}>{1:+0;-#}</color> / {2} heat Range:{3}m\n" }, HeatVision heatVis = ewState.GetRawHeatVision(); // Positive is bad, negative is good string modColor = heatVis.AttackMod >= 0 ? "FF0000" : "00FF00"; details.Add( new Text(Mod.LocalizedText.StatusPanel[ModText.LT_PANEL_HEAT], new object[] { modColor, heatVis.AttackMod, heatVis.HeatDivisor, heatVis.MaximumRange }) .ToString() ); } // Zoom Vision if (ewState.GetRawZoomVision() != null) { // { LT_PANEL_ZOOM, "<b>Zoom</b><size=90%> Mod:<color=#{0}>{1:+0;-#}</color? Cap:<color=#{2}>{3:+0;-#}</color> Range:{4}m\n" }, ZoomVision zoomVis = ewState.GetRawZoomVision(); // Positive is bad, negative is good string modColor = zoomVis.AttackMod >= 0 ? "FF0000" : "00FF00"; string capColor = zoomVis.AttackCap >= 0 ? "FF0000" : "00FF00"; details.Add( new Text(Mod.LocalizedText.StatusPanel[ModText.LT_PANEL_ZOOM], new object[] { modColor, zoomVis.AttackMod, capColor, zoomVis.AttackCap, zoomVis.MaximumRange }) .ToString() ); } string tooltipText = String.Join("", details.ToArray()); return(tooltipText); }