public static void SetDirectionMarker(AttackDirectionIndicator __instance, AttackDirection direction) { try { AttackDirectionIndicator me = __instance; if (me.Owner == null || me.Owner.IsDead || Combat == null) { return; } Color orig = me.ColorInactive; Color?[] activeColors = __instance.Owner?.team?.IsFriendly(Combat?.LocalPlayerTeam) ?? false ? FacingMarkerPlayerColors : FacingMarkerEnemyColors; object[] colors; if (direction != AttackDirection.ToProne && direction != AttackDirection.FromTop) { colors = new object[] { activeColors?[0] ?? orig, activeColors?[1] ?? orig, activeColors?[2] ?? orig, activeColors?[3] ?? orig }; if (direction != AttackDirection.None) { int dirIndex = Math.Max(0, Math.Min((int)direction - 1, LOSDirectionCount - 1)); colors[dirIndex] = FacingMarkerTargetColors?[dirIndex] ?? me.ColorActive; //Log( $"Direction {direction}, Index {dirIndex}, Color {colors[ dirIndex ]}" ); } } else { if (ActiveState == null) { return; } FiringPreviewManager.PreviewInfo info = ActiveState.FiringPreview.GetPreviewInfo(me.Owner); orig = info.HasLOF ? (FacingMarkerTargetColors?[4] ?? me.ColorActive) : (activeColors?[4] ?? me.ColorInactive); colors = new object[] { orig, orig, orig, orig }; } SetColors.Invoke(__instance, colors); } catch (Exception ex) { Error(ex); } }
public static void Postfix(FiringPreviewManager __instance, ref FiringPreviewManager.PreviewInfo __result, ICombatant target) { try { if (__result.availability != FiringPreviewManager.TargetAvailability.PossibleDirect) { return; } AbstractActor selectedActor = HUD?.SelectedActor; SelectionState activeState = HUD?.SelectionHandler?.ActiveState; float dist = Vector3.Distance(activeState.PreviewPos, target.CurrentPosition); if (selectedActor.Weapons.Any(w => !w.IndirectFireCapable && w.IsEnabled && w.CanFire && w.MaxRange > dist)) { Logger.Info($"[FiringPreviewManager_GetPreviewInfo_POSTFIX] Smart indirect lof preview blocked by some direct fire only weapon"); return; } if (!CanSmartIndirect(selectedActor, activeState.PreviewPos, activeState.PreviewRot, target)) { return; } __result.availability = FiringPreviewManager.TargetAvailability.PossibleIndirect; } catch (Exception e) { Logger.Error(e); } }
public static void SetupLOS(WeaponRangeIndicators __instance, Vector3 position, AbstractActor selectedActor, ICombatant target, bool usingMultifire, bool isMelee) { try { if (Mats == null) { return; } WeaponRangeIndicators me = __instance; lineA = lineB = null; if (LinesAnimated) { BrightnessLerp = AdvanceBrightness(0.7f); } typeIndex = dirIndex = 0; if (target is Mech || target is Vehicle) { bool canSee = selectedActor.HasLOSToTargetUnit(target); dirIndex = canSee ? Math.Max(0, Math.Min((int)Combat.HitLocation.GetAttackDirection(position, target) - 1, LOSDirectionCount - 1)) : 0; } Mats[NoAttack][dirIndex].ApplyOutOfRange(me); if (isMelee) { typeIndex = Melee; } else { FiringPreviewManager.PreviewInfo info = ActiveState.FiringPreview.GetPreviewInfo(target); if (info.HasLOF) { typeIndex = info.LOFLevel == LineOfFireLevel.LOFClear ? Clear : BlockedPre; } else { typeIndex = Indirect; } } Mats[typeIndex][dirIndex].Apply(me, usingMultifire); } catch (Exception ex) { Error(ex); } }
// ============ Smart Indirect Fire ============ public static void SmartIndirectFireLoF(FiringPreviewManager __instance, ref FiringPreviewManager.PreviewInfo __result, ICombatant target) { try { if (__result.availability != PossibleDirect) { return; } AbstractActor actor = HUD?.SelectedActor; float dist = Vector3.Distance(ActiveState.PreviewPos, target.CurrentPosition); foreach (Weapon w in actor.Weapons) // Don't change LoF if any direct weapon is enabled and can shot { if (!w.IndirectFireCapable && w.IsEnabled && w.MaxRange > dist && w.CanFire) { return; } } //Verbo( "Smart indirect blocked by {0}: {1}, {2}, {3}, {4}, {5}", w, dist, w.MaxRange, w.IsDisabled, w.IsEnabled, w.IndirectFireCapable ); if (!CanSmartIndirect(actor, ActiveState.PreviewPos, ActiveState.PreviewRot, target)) { return; } __result.availability = PossibleIndirect; } catch (Exception ex) { Error(ex); } }
static bool Prefix( ref Vector3 position, ref Quaternion rotation, ref bool isPositionLocked, ref AbstractActor selectedActor, ref ICombatant target, ref bool usingMultifire, ref bool isLocked, ref bool isMelee, WeaponRangeIndicators __instance) { CombatHUD HUD = (CombatHUD)ReflectionHelper.GetPrivateProperty(__instance, "HUD"); if (__instance.DEBUG_showLOSLines) { __instance.GetDebugDrawer().DrawLines(selectedActor, HUD.SelectionHandler.ActiveState, target); } LineRenderer line = (LineRenderer)ReflectionHelper.InvokePrivateMethode(__instance, "getLine", new object[] { }); Vector3 vector = Vector3.Lerp(position, position + selectedActor.HighestLOSPosition, __instance.sourceLaserDestRatio); Vector3 vector2 = Vector3.Lerp(target.CurrentPosition, target.TargetPosition, __instance.targetLaserDestRatio); AbstractActor abstractActor = target as AbstractActor; if (isMelee) { line.startWidth = __instance.LOSWidthBegin; line.endWidth = __instance.LOSWidthEnd; line.material = __instance.MaterialInRange; line.startColor = __instance.FinalLOSLockedTarget.color; line.endColor = __instance.FinalLOSLockedTarget.color; line.positionCount = 2; line.SetPosition(0, vector); Vector3 vector3 = vector - vector2; vector3.Normalize(); vector3 *= __instance.LineEndOffset; vector2 += vector3; line.SetPosition(1, vector2); ReflectionHelper.InvokePrivateMethode(__instance, "SetEnemyTargetable", new object[] { target, true }); List <AbstractActor> allActors = selectedActor.Combat.AllActors; allActors.Remove(selectedActor); allActors.Remove(abstractActor); PathNode pathNode; Vector3 attackPosition; float num; selectedActor.Pathing.GetMeleeDestination(abstractActor, allActors, out pathNode, out attackPosition, out num); HUD.InWorldMgr.ShowAttackDirection(HUD.SelectedActor, abstractActor, HUD.Combat.HitLocation.GetAttackDirection(attackPosition, target), vector2.y, MeleeAttackType.Punch, 0); } if (abstractActor != null) { HUD.InWorldMgr.SetGuardedActive(abstractActor); } FiringPreviewManager.PreviewInfo previewInfo = HUD.SelectionHandler.ActiveState.FiringPreview.GetPreviewInfo(target); AttackDirection direction = HUD.Combat.HitLocation.GetAttackDirection(position, target); bool status = false; Color chosenColor = __instance.FinalLOSInRange.color; if (direction == AttackDirection.FromFront && ModSettings.Direct.Active) { chosenColor = ModSettings.Direct.Color; status = true; } if ((direction == AttackDirection.FromLeft || direction == AttackDirection.FromRight) && ModSettings.Side.Active) { chosenColor = ModSettings.Side.Color; status = true; } if (direction == AttackDirection.FromBack && ModSettings.Back.Active) { chosenColor = ModSettings.Back.Color; status = true; } if ((target.UnitType == UnitType.Turret || target.UnitType == UnitType.Building) && status) { chosenColor = ModSettings.Direct.Color; } if (previewInfo.availability == FiringPreviewManager.TargetAvailability.NotSet) { Debug.LogError("Error - trying to draw line with no FiringPreviewManager availability!"); } bool flag = HUD.SelectionHandler.ActiveState.SelectionType != SelectionType.Sprint || HUD.SelectedActor.CanShootAfterSprinting; bool flag2 = !isPositionLocked && previewInfo.availability != FiringPreviewManager.TargetAvailability.BeyondMaxRange && previewInfo.availability != FiringPreviewManager.TargetAvailability.BeyondRotation; if (flag && (previewInfo.IsCurrentlyAvailable || flag2)) { if (usingMultifire) { if (target == HUD.SelectedTarget) { line.startColor = (line.endColor = __instance.FinalLOSMultiTargetKBSelection.color); } else if (isLocked) { line.startColor = (line.endColor = __instance.FinalLOSLockedTarget.color); } else { line.startColor = (line.endColor = __instance.FinalLOSUnlockedTarget.color); } } else { float shotQuality = (float)ReflectionHelper.InvokePrivateMethode(__instance, "GetShotQuality", new object[] { selectedActor, position, rotation, target }); Color endColor = Color.Lerp(Color.clear, __instance.FinalLOSInRange.color, shotQuality); line.startColor = (line.endColor = endColor); } line.material = __instance.MaterialInRange; if (previewInfo.HasLOF) { line.positionCount = 2; line.SetPosition(0, vector); Vector3 vector4 = vector - vector2; vector4.Normalize(); vector4 *= __instance.LineEndOffset; vector2 += vector4; if (previewInfo.LOFLevel == LineOfFireLevel.LOFClear) { if (target == HUD.SelectionHandler.ActiveState.FacingEnemy) { if (status) { float shotQuality = (float)ReflectionHelper.InvokePrivateMethode(__instance, "GetShotQuality", new object[] { selectedActor, position, rotation, target }); line.material.color = Color.white; line.endColor = line.startColor = Color.Lerp(Color.clear, chosenColor, shotQuality); } line.startWidth = __instance.LOSWidthBegin * __instance.LOSWidthFacingTargetMultiplier; line.endWidth = __instance.LOSWidthEnd * __instance.LOSWidthFacingTargetMultiplier; } else { if (status) { float shotQuality = (float)ReflectionHelper.InvokePrivateMethode(__instance, "GetShotQuality", new object[] { selectedActor, position, rotation, target }); line.material.color = Color.white; line.endColor = line.startColor = Color.Lerp(Color.clear, chosenColor, shotQuality); if (direction == AttackDirection.FromLeft || direction == AttackDirection.FromRight) { if (ModSettings.Side.Dashed) { line.material = __instance.MaterialOutOfRange; line.material.color = line.endColor; } line.startWidth = line.endWidth = ModSettings.Side.Thickness; } else if (direction == AttackDirection.FromBack) { if (ModSettings.Back.Dashed) { line.material = __instance.MaterialOutOfRange; line.material.color = line.endColor; } line.startWidth = line.endWidth = ModSettings.Back.Thickness; } else { if (ModSettings.Side.Dashed) { line.material = __instance.MaterialOutOfRange; line.material.color = line.endColor; } line.startWidth = line.endWidth = ModSettings.Direct.Thickness; } } } line.SetPosition(1, vector2); } else { if (target == HUD.SelectionHandler.ActiveState.FacingEnemy) { line.startWidth = __instance.LOSWidthBegin * __instance.LOSWidthFacingTargetMultiplier; line.endWidth = __instance.LOSWidthBegin * __instance.LOSWidthFacingTargetMultiplier; } else { line.startWidth = __instance.LOSWidthBegin; line.endWidth = __instance.LOSWidthBegin; } Vector3 vector5 = previewInfo.collisionPoint; vector5 = Vector3.Project(vector5 - vector, vector2 - vector) + vector; line.SetPosition(1, vector5); if (ModSettings.ObstructedAttackerSide.Active) { line.material.color = Color.white; line.startColor = line.endColor = ModSettings.ObstructedAttackerSide.Color; if (ModSettings.ObstructedAttackerSide.Colorside && direction != AttackDirection.ToProne) { line.startColor = line.endColor = chosenColor; } line.startWidth = line.endWidth = ModSettings.ObstructedAttackerSide.Thickness; if (ModSettings.ObstructedAttackerSide.Dashed) { line.material = __instance.MaterialOutOfRange; line.material.color = line.endColor; } } LineRenderer line2 = (LineRenderer)ReflectionHelper.InvokePrivateMethode(__instance, "getLine", new object[] { }); line2.positionCount = 2; line2.startWidth = __instance.LOSWidthBlocked; line2.endWidth = __instance.LOSWidthBlocked; line2.material = __instance.MaterialInRange; if (ModSettings.ObstructedTargetSide.Active) { line2.material.color = Color.white; line2.startColor = line2.endColor = ModSettings.ObstructedTargetSide.Color; line2.startWidth = line2.endWidth = ModSettings.ObstructedTargetSide.Thickness; if (ModSettings.ObstructedTargetSide.Dashed) { line2.material = __instance.MaterialOutOfRange; line2.material.color = line2.endColor; } } else { line2.startColor = line2.endColor = __instance.FinalLOSBlocked.color; line2.startWidth = line2.endWidth = __instance.LOSWidthBlocked; } line2.SetPosition(0, vector5); line2.SetPosition(1, vector2); GameObject coverIcon = (GameObject)ReflectionHelper.InvokePrivateMethode(__instance, "getCoverIcon", new object[] { }); if (!coverIcon.activeSelf) { coverIcon.SetActive(true); } coverIcon.transform.position = vector5; } } else { if (ModSettings.Indirect.Active) { float shotQuality = (float)ReflectionHelper.InvokePrivateMethode(__instance, "GetShotQuality", new object[] { selectedActor, position, rotation, target }); Color couleur = ModSettings.Indirect.Color; if (ModSettings.Indirect.Colorside) { couleur = chosenColor; } Color color6 = Color.Lerp(Color.clear, couleur, shotQuality); if (ModSettings.Indirect.Dashed) { line.material = __instance.MaterialOutOfRange; line.material.color = color6; line.startWidth = line.endWidth = ModSettings.Indirect.Thickness; } else { line.material.color = Color.white; line.endColor = line.startColor = color6; } } int num2 = Mathf.Min(Mathf.Max((int)(NvMath.SqrMagnitudeXZ(vector, vector2) / (__instance.IndirectFireSegFreq * __instance.IndirectFireSegFreq)), __instance.IndirectFireMinPoints), __instance.IndirectFireMaxPoints); Vector3[] pointsForArcDodgeBuildings = WeaponRangeIndicators.GetPointsForArcDodgeBuildings(num2, __instance.IndirectFireMinArcHeight, vector, vector2, HUD.Combat.MapMetaData, __instance.IndirectFireBuffer, __instance.IndirectFireMaxArcHeight, __instance.IndirectFireCheckFreq, false); line.positionCount = num2; line.SetPositions(pointsForArcDodgeBuildings); } ReflectionHelper.InvokePrivateMethode(__instance, "SetEnemyTargetable", new object[] { target, true }); if (abstractActor != null) { HUD.InWorldMgr.ShowAttackDirection(HUD.SelectedActor, abstractActor, HUD.Combat.HitLocation.GetAttackDirection(position, target), vector2.y, MeleeAttackType.NotSet, HUD.InWorldMgr.NumWeaponsTargeting(target)); } } else { line.positionCount = 2; line.SetPosition(0, vector); line.SetPosition(1, vector2); line.startColor = (line.endColor = __instance.FinalLOSOutOfRange.color); line.material = __instance.MaterialOutOfRange; ReflectionHelper.InvokePrivateMethode(__instance, "SetEnemyTargetable", new object[] { target, false }); } return(false); }
static bool Prefix( ref Vector3 position, ref Quaternion rotation, ref bool isPositionLocked, ref AbstractActor selectedActor, ref ICombatant target, ref bool usingMultifire, ref bool isLocked, ref bool isMelee, WeaponRangeIndicators __instance) { // var colorSettings = SettingsHelper.LoadSettings(); CombatHUD HUD = (CombatHUD)ReflectionHelper.GetPrivateProperty(__instance, "HUD"); // set up this line drawer because it has some materials we want later if (__instance.DEBUG_showLOSLines) { DEBUG_LOSLineDrawer debugDrawer = (DEBUG_LOSLineDrawer)ReflectionHelper.InvokePrivateMethode(__instance, "GetDebugDrawer", new object[] { }); debugDrawer.DrawLines(selectedActor, HUD.SelectionHandler.ActiveState, target); } LineRenderer line = (LineRenderer)ReflectionHelper.InvokePrivateMethode(__instance, "getLine", new object[] { }); Vector3 vector = Vector3.Lerp(position, position + selectedActor.HighestLOSPosition, __instance.sourceLaserDestRatio); Vector3 vector2 = Vector3.Lerp(target.CurrentPosition, target.TargetPosition, __instance.targetLaserDestRatio); AbstractActor targetActor = target as AbstractActor; // melee if (isMelee) { line.startWidth = __instance.LOSWidthBegin; line.endWidth = __instance.LOSWidthEnd; line.material = __instance.MaterialInRange; line.startColor = __instance.LOSLockedTarget; line.endColor = __instance.LOSLockedTarget; line.positionCount = 2; line.SetPosition(0, vector); Vector3 vector3 = vector - vector2; vector3.Normalize(); vector3 *= __instance.LineEndOffset; vector2 += vector3; line.SetPosition(1, vector2); ReflectionHelper.InvokePrivateMethode(__instance, "SetEnemyTargetable", new object[] { target, true }); List <AbstractActor> allActors = selectedActor.Combat.AllActors; allActors.Remove(selectedActor); allActors.Remove(targetActor); PathNode pathNode = default(PathNode); Vector3 attackPosition = default(Vector3); float num = default(float); selectedActor.Pathing.GetMeleeDestination(targetActor, allActors, out pathNode, out attackPosition, out num); HUD.InWorldMgr.ShowAttackDirection(HUD.SelectedActor, targetActor, HUD.Combat.HitLocation.GetAttackDirection(attackPosition, target), vector2.y, MeleeAttackType.Punch, 0); } // not melee else { FiringPreviewManager.PreviewInfo previewInfo = HUD.SelectionHandler.ActiveState.FiringPreview.GetPreviewInfo(target); if (previewInfo.availability == FiringPreviewManager.TargetAvailability.NotSet) { Debug.LogError("Error - trying to draw line with no FiringPreviewManager availability!"); } // why is the bad case first. just dump out of the f*****g method, doug else { bool flag = HUD.SelectionHandler.ActiveState.SelectionType != SelectionType.Sprint || HUD.SelectedActor.CanShootAfterSprinting; bool flag2 = !isPositionLocked && previewInfo.availability != FiringPreviewManager.TargetAvailability.BeyondMaxRange && previewInfo.availability != FiringPreviewManager.TargetAvailability.BeyondRotation; if (flag && (previewInfo.IsCurrentlyAvailable || flag2)) { // multiple targets, even if only one selected if (usingMultifire) { if (target == HUD.SelectedTarget) { LineRenderer lineRenderer = line; Color color2 = lineRenderer.startColor = (line.endColor = __instance.LOSMultiTargetKBSelection); } else if (isLocked) { LineRenderer lineRenderer2 = line; Color color2 = lineRenderer2.startColor = (line.endColor = __instance.LOSLockedTarget); } else { LineRenderer lineRenderer3 = line; Color color2 = lineRenderer3.startColor = (line.endColor = __instance.LOSUnlockedTarget); } } // normal shot else { float shotQuality = (float)ReflectionHelper.InvokePrivateMethode(__instance, "GetShotQuality", new object[] { selectedActor, position, rotation, target }); Color color5 = Color.Lerp(Color.clear, __instance.LOSInRange, shotQuality); LineRenderer lineRenderer4 = line; Color color2 = lineRenderer4.startColor = (line.endColor = color5); } line.material = __instance.MaterialInRange; // straight line shot if (previewInfo.HasLOF) { line.positionCount = 2; line.SetPosition(0, vector); Vector3 vector4 = vector - vector2; vector4.Normalize(); vector4 *= __instance.LineEndOffset; vector2 += vector4; if (previewInfo.LOFLevel == LineOfFireLevel.LOFClear) { if (target == HUD.SelectionHandler.ActiveState.FacingEnemy) { line.startWidth = __instance.LOSWidthBegin * __instance.LOSWidthFacingTargetMultiplier; line.endWidth = __instance.LOSWidthEnd * __instance.LOSWidthFacingTargetMultiplier; } else { line.startWidth = __instance.LOSWidthBegin; line.endWidth = __instance.LOSWidthEnd; } line.SetPosition(1, vector2); } else { if (target == HUD.SelectionHandler.ActiveState.FacingEnemy) { line.startWidth = __instance.LOSWidthBegin * __instance.LOSWidthFacingTargetMultiplier; line.endWidth = __instance.LOSWidthBegin * __instance.LOSWidthFacingTargetMultiplier; } else { line.startWidth = __instance.LOSWidthBegin; line.endWidth = __instance.LOSWidthBegin; } Vector3 collisionPoint = previewInfo.collisionPoint; collisionPoint = Vector3.Project(collisionPoint - vector, vector2 - vector) + vector; line.SetPosition(1, collisionPoint); LineRenderer line2 = (LineRenderer)ReflectionHelper.InvokePrivateMethode(__instance, "getLine", new object[] { }); line2.positionCount = 2; line2.startWidth = __instance.LOSWidthBlocked; line2.endWidth = __instance.LOSWidthBlocked; line2.material = __instance.MaterialInRange; LineRenderer lineRenderer5 = line2; Color color2 = lineRenderer5.startColor = (line2.endColor = __instance.LOSBlocked); line2.SetPosition(0, collisionPoint); line2.SetPosition(1, vector2); GameObject coverIcon = (GameObject)ReflectionHelper.InvokePrivateMethode(__instance, "getCoverIcon", new object[] { }); if (!coverIcon.activeSelf) { coverIcon.SetActive(true); } coverIcon.transform.position = collisionPoint; } } // arc shot else { // other than formatting this block is the only thing that changed from the decompiled code Vector3[] pointsForArc = WeaponRangeIndicators.GetPointsForArc(18, 30f, vector, vector2); float shotQuality = (float)ReflectionHelper.InvokePrivateMethode(__instance, "GetShotQuality", new object[] { selectedActor, position, rotation, target }); // alright future me, this is probably destructive in some way, but // this lets us set the color of the line via that color6 bit. line.material.color = Color.white; Color color6 = Color.Lerp( Color.clear, BTMLColorLOSMod.ModSettings.IndirectLineOfFireArcColor, shotQuality); line.endColor = (line.startColor = color6); line.positionCount = 18; line.SetPositions(pointsForArc); } ReflectionHelper.InvokePrivateMethode(__instance, "SetEnemyTargetable", new object[] { target, true }); if (targetActor != null) { HUD.InWorldMgr.ShowAttackDirection(HUD.SelectedActor, targetActor, HUD.Combat.HitLocation.GetAttackDirection(position, target), vector2.y, MeleeAttackType.NotSet, HUD.InWorldMgr.NumWeaponsTargeting(target)); } } // sprinted and can't shoot or out of rotation/weapon range else { line.positionCount = 2; line.SetPosition(0, vector); line.SetPosition(1, vector2); LineRenderer lineRenderer6 = line; Color color2 = lineRenderer6.startColor = (line.endColor = __instance.LOSOutOfRange); line.material = __instance.MaterialOutOfRange; ReflectionHelper.InvokePrivateMethode(__instance, "SetEnemyTargetable", new object[] { target, false }); } } } return(false); }