// 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 void Postfix(MechComponent __instance, bool __state) { Mod.Log.Trace?.Write("MC:CCE:post entered."); if (__state) { Mod.Log.Debug?.Write($" Stealth effect was cancelled, parent visibility needs refreshed."); EWState parentState = new EWState(__instance.parent); PilotableActorRepresentation par = __instance.parent.GameRep as PilotableActorRepresentation; if (parentState.HasStealth()) { VfxHelper.EnableStealthVfx(__instance.parent); } else { VfxHelper.DisableSensorStealthEffect(__instance.parent); } if (parentState.HasMimetic()) { VfxHelper.EnableMimeticEffect(__instance.parent); } else { VfxHelper.DisableMimeticEffect(__instance.parent); } // Force a refresh in case the signature increased due to stealth loss // TODO: Make this player hostile only List <ICombatant> allLivingCombatants = __instance.parent.Combat.GetAllLivingCombatants(); __instance.parent.VisibilityCache.UpdateCacheReciprocal(allLivingCombatants); } }
public static void CalculateMimeticPips(CombatHUDStealthBarPips stealthDisplay, AbstractActor actor, float distanceMoved) { EWState actorState = new EWState(actor); Mod.Log.Trace?.Write($"Calculating mimeticPips for Actor: {CombatantUtils.Label(actor)}"); int stepsMoved = (int)Math.Ceiling(distanceMoved / 30f); Mod.Log.Trace?.Write($" stepsMoved: {stepsMoved} = distanceMoved: {distanceMoved} / 30"); // Update # of pips int maxPips = actorState.MaxMimeticPips(); int currentPips = actorState.CurrentMimeticPips(distanceMoved); stealthDisplay.ShowNewActorStealth(currentPips, maxPips); // Change colors to reflect maxmimums Traverse pipsT = Traverse.Create(stealthDisplay).Property("Pips"); List <Graphic> pips = pipsT.GetValue <List <Graphic> >(); for (int i = 0; i < pips.Count; i++) { Graphic g = pips[i]; if (g.isActiveAndEnabled) { //Color pipColor = Color.white; Color pipColor = new Color(50f, 206f, 230f); UIHelpers.SetImageColor(g, pipColor); } } }
public void TestStealthAttackMod_Bonuses_Pinged_ProbeCarrier() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); // Stealth - <signature_modifier>_<details_modifier>_<mediumAttackMod>_<longAttackmod>_<extremeAttackMod> target.StatCollection.Set(ModStats.StealthEffect, "0.99_9_1_2_3"); // Reduce by 3 target.StatCollection.Set(ModStats.PingedByProbe, 3); // Reduce by 2 attacker.StatCollection.Set(ModStats.ProbeCarrier, 2); EWState attackerState = new EWState(attacker); EWState targetState = new EWState(target); Weapon weapon = TestHelper.BuildTestWeapon(0, 60, 120, 240, 480); Assert.AreEqual(0, targetState.StealthAttackMod(attackerState, weapon, 30)); Assert.AreEqual(0, targetState.StealthAttackMod(attackerState, weapon, 60)); Assert.AreEqual(0, targetState.StealthAttackMod(attackerState, weapon, 90)); Assert.AreEqual(0, targetState.StealthAttackMod(attackerState, weapon, 120)); Assert.AreEqual(0, targetState.StealthAttackMod(attackerState, weapon, 200)); Assert.AreEqual(0, targetState.StealthAttackMod(attackerState, weapon, 240)); Assert.AreEqual(0, targetState.StealthAttackMod(attackerState, weapon, 400)); Assert.AreEqual(0, targetState.StealthAttackMod(attackerState, weapon, 480)); }
// WARNING: DUPLICATE OF HBS CODE. THIS IS LIKELY TO BREAK IF HBS CHANGES THE SOURCE FUNCTIONS public static float GetTargetSignature(ICombatant target, EWState sourceState) { if (target == null || (target as AbstractActor) == null) { return(1f); } AbstractActor targetActor = target as AbstractActor; float allTargetSignatureModifiers = GetAllTargetSignatureModifiers(targetActor, sourceState); float staticSignature = 1f * allTargetSignatureModifiers; // Add in any design mask boosts DesignMaskDef occupiedDesignMask = targetActor.occupiedDesignMask; if (occupiedDesignMask != null) { staticSignature *= occupiedDesignMask.signatureMultiplier; } if (staticSignature < Mod.Config.Sensors.MinSignature) { staticSignature = Mod.Config.Sensors.MinSignature; } return(staticSignature); }
// WARNING: DUPLICATE OF HBS CODE. THIS IS LIKELY TO BREAK IF HBS CHANGES THE SOURCE FUNCTIONS public static float GetAdjustedSpotterRange(AbstractActor source, ICombatant target) { float targetVisibility = 1f; AbstractActor targetActor = target as AbstractActor; if (targetActor != null) { EWState sourceState = source.GetEWState(); targetVisibility = VisualLockHelper.GetTargetVisibility(targetActor, sourceState); } float spotterRange = VisualLockHelper.GetSpotterRange(source); float modifiedRange = spotterRange * targetVisibility; if (modifiedRange < Mod.Config.Vision.MinimumVisionRange()) { modifiedRange = Mod.Config.Vision.MinimumVisionRange(); } // Round up to the nearest full hex float normalizedRange = HexUtils.CountHexes(modifiedRange, true) * 30f; Mod.Log.Trace?.Write($" -- source:{CombatantUtils.Label(source)} adjusted spotterRange:{normalizedRange}m normalized from:{modifiedRange}m"); return(normalizedRange); }
public static void Postfix() { if (EWState.InBatchProcess) { Mod.Log.Error?.Write($"Something has gone wrong in refreshing visibility cache, resetting."); EWState.ResetCache(); } }
public void TestTargetSignature_NoModifiers() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); EWState attackerState = new EWState(attacker); EWState targetState = new EWState(target); Assert.AreEqual(1.0f, SensorLockHelper.GetTargetSignature(target, attackerState)); }
private static bool HasNarcBeaconDetection(ICombatant target, EWState sourceState, EWState targetState) { bool hasDetection = false; if (target != null && targetState != null && targetState.IsNarced(sourceState)) { hasDetection = true; } return(hasDetection); }
public void TestTargetSignature_Stealth_Minus_20pct() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); // Stealth - <signature_modifier>_<details_modifier>_<mediumAttackMod>_<longAttackmod>_<extremeAttackMod> target.StatCollection.Set(ModStats.StealthEffect, "0.20_2_1_2_3"); EWState attackerState = new EWState(attacker); Assert.AreEqual(0.8f, SensorLockHelper.GetTargetSignature(target, attackerState)); }
// WARNING: DUPLICATE OF HBS CODE. THIS IS LIKELY TO BREAK IF HBS CHANGES THE SOURCE FUNCTIONS public static float GetTargetVisibility(AbstractActor target, EWState sourceState) { if (target == null) { return(1f); } float allTargetVisibilityMultipliers = GetAllTargetVisibilityMultipliers(target, sourceState); float allTargetVisibilityAbsolutes = GetAllTargetVisibilityAbsolutes(target); return(1f * allTargetVisibilityMultipliers + allTargetVisibilityAbsolutes); }
public static void Prefix(CombatHUDWeaponPanel __instance, AbstractActor ___displayedActor) { if (__instance == null || ___displayedActor == null) { return; } Mod.Log.Trace?.Write("CHUDWP:RDW - entered."); Traverse targetT = Traverse.Create(__instance).Property("target"); Traverse hoveredTargetT = Traverse.Create(__instance).Property("hoveredTarget"); Traverse HUDT = Traverse.Create(__instance).Property("HUD"); CombatHUD HUD = HUDT.GetValue <CombatHUD>(); SelectionState activeState = HUD.SelectionHandler.ActiveState; ICombatant target; if (activeState != null && activeState is SelectionStateMove) { target = hoveredTargetT.GetValue <ICombatant>(); if (target == null) { target = targetT.GetValue <ICombatant>(); } } else { target = targetT.GetValue <ICombatant>(); if (target == null) { target = hoveredTargetT.GetValue <ICombatant>(); } } if (target == null) { return; } EWState attackerState = new EWState(___displayedActor); Mod.Log.Debug?.Write($"Attacker ({CombatantUtils.Label(___displayedActor)} => EWState: {attackerState}"); bool canSpotTarget = VisualLockHelper.CanSpotTarget(___displayedActor, ___displayedActor.CurrentPosition, target, target.CurrentPosition, target.CurrentRotation, ___displayedActor.Combat.LOS); SensorScanType sensorScan = SensorLockHelper.CalculateSharedLock(target, ___displayedActor); Mod.Log.Debug?.Write($" canSpotTarget: {canSpotTarget} sensorScan: {sensorScan}"); if (target is AbstractActor targetActor) { EWState targetState = new EWState(targetActor); Mod.Log.Debug?.Write($"Target ({CombatantUtils.Label(targetActor)} => EWState: {targetState}"); } }
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); }
public void TestStealthSignatureMod() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); // Stealth - <signature_modifier>_<details_modifier>_<mediumAttackMod>_<longAttackmod>_<extremeAttackMod> target.StatCollection.Set(ModStats.StealthEffect, "0.20_2_1_2_3"); EWState attackerState = new EWState(attacker); EWState targetState = new EWState(target); Assert.AreEqual(-0.2f, targetState.StealthSignatureMod(attackerState)); }
public static void Postfix() { if (EWState.InBatchProcess) { Mod.Log.Error?.Write($"Something has gone wrong in refreshing visibility cache, resetting."); EWState.ResetCache(); } if (AbstractActor_HandleDeath.GateActive) { Mod.Log.Error?.Write($"Something has gone wrong in handling actor death, resetting VisibilityCacheGate."); VisibilityCacheGate.ExitAll(); } }
public void TestTargetSignature_Stealth_20pct() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); Traverse isShutdownT = Traverse.Create(target).Field("_isShutDown"); isShutdownT.SetValue(true); EWState attackerState = new EWState(attacker); EWState targetState = new EWState(target); Assert.AreEqual(0.5f, SensorLockHelper.GetTargetSignature(target, attackerState)); }
public static void Postfix(ref float __result, ICombatant targetUnit) { Mod.Log.Trace?.Write("MA:GEDFMTW entered"); if (targetUnit is AbstractActor targetActor) { EWState targetState = new EWState(targetActor); if (targetState.HasStealth() || targetState.HasMimetic()) { Mod.Log.Debug?.Write($"Target {CombatantUtils.Label(targetUnit)} has stealth, AI cannot multi-attack!"); __result = 0f; } } }
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); }
public void TestVisibility_NoEffects() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); attacker.StatCollection.AddStatistic <float>("SpotterDistanceMultiplier", 1f); attacker.StatCollection.AddStatistic <float>("SpotterDistanceAbsolute", 0f); target.StatCollection.AddStatistic <float>("SpottingVisibilityMultiplier", 1f); target.StatCollection.AddStatistic <float>("SpottingVisibilityAbsolute", 0f); EWState attackerState = new EWState(attacker); EWState targetState = new EWState(target); Assert.AreEqual(1.0f, VisualLockHelper.GetTargetVisibility(target, attackerState)); }
public static void RedrawFogOfWar(AbstractActor activeActor) { if (!Mod.Config.FogOfWar.RedrawFogOfWarOnActivation) { return; } FogOfWarSystem fowSystem = LazySingletonBehavior <FogOfWarView> .Instance.FowSystem; if (fowSystem == null) { Mod.Log.Error?.Write("FogOfWarSystem could not be found - this should never happen!"); return; } Mod.Log.Debug?.Write($"Redrawing FOW for actor: {CombatantUtils.Label(activeActor)}"); Traverse viewersT = Traverse.Create(fowSystem).Field("viewers"); List <AbstractActor> viewers = viewersT.GetValue <List <AbstractActor> >(); viewers.Clear(); // Reset FoW to being unseen fowSystem.WipeToValue(Mod.Config.FogOfWar.ShowTerrainThroughFogOfWar ? FogOfWarState.Surveyed : FogOfWarState.Unknown); // Add the actor as a viewer fowSystem.AddViewer(activeActor); // Check lancemates; if they have vision sharing add them as well foreach (string lanceGuid in activeActor?.lance?.unitGuids) { if (!lanceGuid.Equals(activeActor.GUID)) { ICombatant lanceMateC = activeActor.Combat.FindCombatantByGUID(lanceGuid); if (lanceMateC is AbstractActor lanceActor) { EWState lanceState = new EWState(lanceActor); if (lanceState.SharesVision()) { fowSystem.AddViewer(lanceActor); } } } } }
public static void Reset() { Mod.Log.Info?.Write($"RESETTING STATE!"); // Reinitialize state MapConfig = null; MoodController = null; LastPlayerActorActivated = null; TurnDirectorStarted = false; IsNightVisionMode = false; CheckResults = new double[ResultsToPrecalcuate]; CheckResultIdx = 0; // Combat state Combat = null; MarkContainerRefs.Clear(); EWState.ResetCache(); }
public static void Prefix(TurnDirector __instance, int round) { Mod.Log.Trace?.Write($"TD:BNR entered"); Mod.Log.Info?.Write($"=== Turn Director is beginning round: {round}"); // Update the current vision for all allied and friendly units foreach (AbstractActor actor in __instance.Combat.AllActors) { Mod.Log.Info?.Write($" -- Updating actor: {actor.DistinctId()}"); // If our sensors are offline, re-enable them if (actor.StatCollection.ContainsStatistic(ModStats.DisableSensors)) { if (round >= actor.StatCollection.GetValue <int>(ModStats.DisableSensors)) { Mod.Log.Info?.Write($"Re-enabling sensors for {CombatantUtils.Label(actor)}"); actor.StatCollection.RemoveStatistic(ModStats.DisableSensors); } else { Mod.Log.Info?.Write($"Actor: {CombatantUtils.Label(actor)} sensors are offline until: {actor.StatCollection.GetValue<int>(ModStats.DisableSensors)}"); } } // Update our sensors check ActorHelper.UpdateSensorCheck(actor, true); // Print the current state of the actor EWState actorState = new EWState(actor); Mod.Log.Info?.Write(actorState.ToString()); } // Now that all sensor checks are updated, refresh visiblity for all actors foreach (AbstractActor actor in __instance.Combat.AllActors) { if (actor.TeamId == __instance.Combat.LocalPlayerTeamGuid) { actor.VisibilityCache.RebuildCache(actor.Combat.GetAllImporantCombatants()); CombatHUDHelper.ForceNameRefresh(actor.Combat); } } }
public void TestVisibility_Shutdown() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); attacker.StatCollection.AddStatistic <float>("SpotterDistanceMultiplier", 1f); attacker.StatCollection.AddStatistic <float>("SpotterDistanceAbsolute", 0f); target.StatCollection.AddStatistic <float>("SpottingVisibilityMultiplier", 1f); target.StatCollection.AddStatistic <float>("SpottingVisibilityAbsolute", 0f); Traverse isShutdownT = Traverse.Create(target).Field("_isShutDown"); isShutdownT.SetValue(true); EWState attackerState = new EWState(attacker); EWState targetState = new EWState(target); Assert.AreEqual(0.5f, VisualLockHelper.GetTargetVisibility(target, attackerState)); }
public static void Prefix(AbstractActor __instance, int stackItemID) { if (stackItemID == -1 || __instance == null || __instance.HasBegunActivation) { // For some bloody reason DoneWithActor() invokes OnActivationBegin, EVEN THOUGH IT DOES NOTHING. GAH! return; } // Draw stealth if applicable EWState actorState = new EWState(__instance); if (actorState.HasStealth()) { Mod.Log.Debug?.Write($"-- Sending message to update stealth"); StealthChangedMessage message = new StealthChangedMessage(__instance.GUID); __instance.Combat.MessageCenter.PublishMessage(message); } // If friendly, reset the map visibility if (__instance.TeamId != __instance.Combat.LocalPlayerTeamGuid && __instance.Combat.HostilityMatrix.IsLocalPlayerFriendly(__instance.TeamId)) { Mod.Log.Info?.Write($"{CombatantUtils.Label(__instance)} IS FRIENDLY, REBUILDING FOG OF WAR"); if (actorState.HasNightVision() && ModState.GetMapConfig().isDark) { Mod.Log.Info?.Write($"Enabling night vision mode."); VfxHelper.EnableNightVisionEffect(__instance); } else { // TODO: This is likely never triggered due to the patch below... remove? if (ModState.IsNightVisionMode) { VfxHelper.DisableNightVisionEffect(); } } VfxHelper.RedrawFogOfWar(__instance); } }
// Records actor selected events to allow id of the last player unit a player selected public static void OnActorSelectedMessage(MessageCenterMessage message) { ActorSelectedMessage actorSelectedMessage = message as ActorSelectedMessage; AbstractActor actor = Combat.FindActorByGUID(actorSelectedMessage.affectedObjectGuid); if (actor.team.IsLocalPlayer) { Mod.Log.Info?.Write($"Updating last activated actor to: ({CombatantUtils.Label(actor)})"); ModState.LastPlayerActorActivated = actor; EWState actorState = new EWState(actor); if (actorState.HasNightVision() && ModState.GetMapConfig().isDark) { Mod.Log.Info?.Write($"Enabling night vision mode."); VfxHelper.EnableNightVisionEffect(actor); } else { if (ModState.IsNightVisionMode) { VfxHelper.DisableNightVisionEffect(); } } // Refresh the unit's vision VfxHelper.RedrawFogOfWar(actor); actor.VisibilityCache.RebuildCache(actor.Combat.GetAllImporantCombatants()); CombatHUDHelper.ForceNameRefresh(actor.Combat); // Hack - turn on Vision indicator? VisRangeIndicator visRangeIndicator = VisRangeIndicator.Instance; visRangeIndicator.SetState(VisRangeIndicator.VisRangeIndicatorState.On); // Refresh any CombatHUDMarkDisplays foreach (CombatHUDMarkDisplay chudMD in ModState.MarkContainerRefs.Keys) { chudMD.RefreshInfo(); } } }
public void TestStealthAttackMod_Negatives() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); // Stealth - <signature_modifier>_<details_modifier>_<mediumAttackMod>_<longAttackmod>_<extremeAttackMod> target.StatCollection.Set(ModStats.StealthEffect, "0.99_9_-1_-2_-3"); EWState attackerState = new EWState(attacker); EWState targetState = new EWState(target); Weapon weapon = TestHelper.BuildTestWeapon(0, 60, 120, 240, 480); Assert.AreEqual(0, targetState.StealthAttackMod(attackerState, weapon, 30)); Assert.AreEqual(0, targetState.StealthAttackMod(attackerState, weapon, 60)); Assert.AreEqual(1, targetState.StealthAttackMod(attackerState, weapon, 90)); Assert.AreEqual(1, targetState.StealthAttackMod(attackerState, weapon, 120)); Assert.AreEqual(2, targetState.StealthAttackMod(attackerState, weapon, 200)); Assert.AreEqual(2, targetState.StealthAttackMod(attackerState, weapon, 240)); Assert.AreEqual(3, targetState.StealthAttackMod(attackerState, weapon, 400)); Assert.AreEqual(3, targetState.StealthAttackMod(attackerState, weapon, 480)); }
// WARNING: DUPLICATE OF HBS CODE. THIS IS LIKELY TO BREAK IF HBS CHANGES THE SOURCE FUNCTIONS private static float GetAllTargetVisibilityMultipliers(AbstractActor target, EWState sourceState) { if (target == null) { return(1f); } float baseVisMulti = 1f; float shutdownVisMulti = (!target.IsShutDown) ? 1f : target.Combat.Constants.Visibility.ShutDownVisibilityModifier; float spottingVisibilityMultiplier = target.SpottingVisibilityMultiplier; EWState ewState = target.GetEWState(); float mimeticMod = ewState.MimeticVisibilityMod(sourceState); float targetVisibility = baseVisMulti * shutdownVisMulti * spottingVisibilityMultiplier * mimeticMod; Mod.Log.Trace?.Write($" Actor: {CombatantUtils.Label(target)} has visibility: {targetVisibility} = " + $"baseVisMulti: {baseVisMulti} * shutdownVisMulti: {shutdownVisMulti} * spottingVisibilityMultiplier: {spottingVisibilityMultiplier} * visionStealthMod: {mimeticMod}"); return(targetVisibility); //return baseVisMulti + shutdownVisMulti + spottingVisibilityMultiplier; }
public void TestMimetic_Visibility_DecayThreeStep() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); target.CurrentPosition = new Vector3(180f, 0, 0); Traverse previousPositionT = Traverse.Create(target).Field("previousPosition"); previousPositionT.SetValue(new Vector3(0f, 0f, 0f)); attacker.StatCollection.AddStatistic <float>("SpotterDistanceMultiplier", 1f); attacker.StatCollection.AddStatistic <float>("SpotterDistanceAbsolute", 0f); target.StatCollection.AddStatistic <float>("SpottingVisibilityMultiplier", 1f); target.StatCollection.AddStatistic <float>("SpottingVisibilityAbsolute", 0f); target.StatCollection.Set(ModStats.MimeticEffect, "4_0.10_1_2"); EWState attackerState = new EWState(attacker); EWState targetState = new EWState(target); Assert.AreEqual(0.9f, VisualLockHelper.GetTargetVisibility(target, attackerState), 0.001); }
public void TestMimetic_AttackMod_DecayOneStep_FractionalAtkMod() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); target.CurrentPosition = new Vector3(90f, 0, 0); Traverse previousPositionT = Traverse.Create(target).Field("previousPosition"); previousPositionT.SetValue(new Vector3(0f, 0f, 0f)); attacker.StatCollection.AddStatistic <float>("SpotterDistanceMultiplier", 1f); attacker.StatCollection.AddStatistic <float>("SpotterDistanceAbsolute", 0f); target.StatCollection.AddStatistic <float>("SpottingVisibilityMultiplier", 1f); target.StatCollection.AddStatistic <float>("SpottingVisibilityAbsolute", 0f); target.StatCollection.Set(ModStats.MimeticEffect, "4_0.10_0.5_2"); EWState attackerState = new EWState(attacker); EWState targetState = new EWState(target); Assert.AreEqual(2, targetState.MimeticAttackMod(attackerState)); }
// WARNING: DUPLICATE OF HBS CODE. THIS IS LIKELY TO BREAK IF HBS CHANGES THE SOURCE FUNCTIONS private static float GetAllTargetSignatureModifiers(AbstractActor target, EWState sourceState) { if (target == null) { return(1f); } float shutdownMod = (!target.IsShutDown) ? 1f : target.Combat.Constants.Visibility.ShutDownSignatureModifier; float chassisSignature = target.StatCollection.GetValue <float>(ModStats.HBS_SensorSignatureModifier); if (chassisSignature == 0f) { chassisSignature = 1.0f; // Fix until redbat fixes this } EWState ewState = target.GetEWState(); float ecmShieldMod = ewState.ECMSignatureMod(sourceState); float stealthMod = ewState.StealthSignatureMod(sourceState); float narcMod = ewState.NarcSignatureMod(sourceState); float tagMod = ewState.TagSignatureMod(sourceState); float signatureMods = (1.0f + stealthMod) * (1.0f + ecmShieldMod) * (1.0f + narcMod) * (1.0f + tagMod); float targetSignature = chassisSignature * shutdownMod * signatureMods; Mod.Log.Trace?.Write($" Actor: {CombatantUtils.Label(target)} has signature: {targetSignature} = " + $"rawSignature: {chassisSignature} x shutdown: {shutdownMod}" + $" x (1.0 + ecmShield: {ecmShieldMod})" + $" x (1.0 + stealthMod: {stealthMod})" + $" x (1.0 + narc: {narcMod})" + $" x (1.0 + tag: {tagMod})"); if (targetSignature < Mod.Config.Sensors.MinSignature) { targetSignature = Mod.Config.Sensors.MinSignature; } return(targetSignature); }