public static void Postfix(CombatHUDStatusPanel __instance, List <CombatHUDStatusIndicator> ___Buffs, List <CombatHUDStatusIndicator> ___Debuffs)
        {
            Mod.Log.Trace?.Write("CHUDSP:RDC - entered.");
            if (__instance != null && __instance.DisplayedCombatant != null)
            {
                AbstractActor target = __instance.DisplayedCombatant as AbstractActor;
                // We can receive a building here, so
                if (target != null)
                {
                    if (target.Combat.HostilityMatrix.IsLocalPlayerEnemy(target.team))
                    {
                        SensorScanType scanType = SensorLockHelper.CalculateSharedLock(target, ModState.LastPlayerActorActivated);

                        // Hide the buffs and debuffs if the current scanType is less than allInfo
                        if (scanType < SensorScanType.AllInformation)
                        {
                            //// Hide the buffs and debuffs
                            ___Buffs.ForEach(si => si.gameObject.SetActive(false));
                            ___Debuffs.ForEach(si => si.gameObject.SetActive(false));
                        }
                    }

                    // Calculate stealth pips
                    Traverse stealthDisplayT = Traverse.Create(__instance).Field("stealthDisplay");
                    CombatHUDStealthBarPips stealthDisplay = stealthDisplayT.GetValue <CombatHUDStealthBarPips>();
                    VfxHelper.CalculateMimeticPips(stealthDisplay, target);
                }
            }
        }
Exemple #2
0
        public static void ObfuscateArmorAndStructText(AbstractActor target, TextMeshProUGUI armorHover, TextMeshProUGUI structHover)
        {
            if (target == null)
            {
                Mod.Log.Warn?.Write("Helper::HideArmorAndStructure - target is null!");
            }
            if (armorHover == null)
            {
                Mod.Log.Warn?.Write("Helper::HideArmorAndStructure - armorHover is null!");
            }
            if (structHover == null)
            {
                Mod.Log.Warn?.Write("Helper::HideArmorAndStructure - structHover is null!");
            }

            try
            {
                SensorScanType scanType      = SensorLockHelper.CalculateSharedLock(target, ModState.LastPlayerActorActivated);
                bool           hasVisualScan = VisualLockHelper.CanSpotTarget(
                    ModState.LastPlayerActorActivated, ModState.LastPlayerActorActivated.CurrentPosition,
                    target, target.CurrentPosition, target.CurrentRotation, target.Combat.LOS);

                string armorText;
                string structText;
                if (scanType >= SensorScanType.StructAndWeaponID)
                {
                    // See all values
                    armorText  = armorHover.text;
                    structText = structHover.text;
                }
                else if (scanType >= SensorScanType.ArmorAndWeaponType || hasVisualScan)
                {
                    // See max armor, max struct
                    string rawArmor = armorHover.text;
                    string maxArmor = rawArmor.Split('/')[1];

                    string rawStruct = structHover.text;
                    string maxStruct = rawStruct.Split('/')[1];

                    armorText  = $"? / {maxArmor}";
                    structText = $"? / {maxStruct}";
                }
                else
                {
                    // See ? / ?
                    armorText  = "? / ?";
                    structText = "? / ?";
                }

                // TODO: Sensor lock should give you an exact amount at the point you're locked
                armorHover.SetText(armorText);
                structHover.SetText(structText);
            }
            catch (Exception e)
            {
                Mod.Log.Error?.Write(e, $"Failed to obfuscate armor and structure text for unit: {CombatantUtils.Label(target)}" +
                                     $" from position of last-activated actor: {CombatantUtils.Label(ModState.LastPlayerActorActivated)}.");
            }
        }
        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 static void Postfix(CombatHUDVehicleArmorHover __instance)
        {
            HUDVehicleArmorReadout       ___Readout = (HUDVehicleArmorReadout)Traverse.Create(__instance).Property("Readout").GetValue();
            CombatHUDTooltipHoverElement ___ToolTip = (CombatHUDTooltipHoverElement)Traverse.Create(__instance).Property("ToolTip").GetValue();

            if (___Readout != null && ___Readout.DisplayedVehicle != null && ___Readout.DisplayedVehicle.Combat != null && ___ToolTip != null)
            {
                Vehicle target = ___Readout.DisplayedVehicle;
                if (!target.Combat.HostilityMatrix.IsLocalPlayerFriendly(target.TeamId))
                {
                    SensorScanType scanType = SensorLockHelper.CalculateSharedLock(target, ModState.LastPlayerActorActivated);
                    if (scanType < SensorScanType.AllInformation)
                    {
                        ___ToolTip.BuffStrings.Clear();
                        ___ToolTip.DebuffStrings.Clear();
                    }
                }
            }
        }
            public static void Postfix(CombatHUDActorInfo __instance, AbstractActor ___displayedActor,
                                       BattleTech.Building ___displayedBuilding, ICombatant ___displayedCombatant)
            {
                if (__instance == null || ___displayedActor == null)
                {
                    return;
                }

                try {
                    bool            isEnemyOrNeutral = false;
                    VisibilityLevel visibilityLevel  = VisibilityLevel.None;
                    if (___displayedCombatant != null)
                    {
                        if (___displayedCombatant.IsForcedVisible)
                        {
                            visibilityLevel = VisibilityLevel.LOSFull;
                        }
                        else if (___displayedBuilding != null)
                        {
                            visibilityLevel = __instance.Combat.LocalPlayerTeam.VisibilityToTarget(___displayedBuilding);
                        }
                        else if (___displayedActor != null)
                        {
                            if (__instance.Combat.HostilityMatrix.IsLocalPlayerFriendly(___displayedActor.team))
                            {
                                visibilityLevel = VisibilityLevel.LOSFull;
                            }
                            else
                            {
                                visibilityLevel  = __instance.Combat.LocalPlayerTeam.VisibilityToTarget(___displayedActor);
                                isEnemyOrNeutral = true;
                            }
                        }
                    }

                    Traverse setGOActiveMethod = Traverse.Create(__instance).Method("SetGOActive", new Type[] { typeof(MonoBehaviour), typeof(bool) });
                    // The actual method should handle allied and friendly units fine, so we can just change it for enemies
                    if (isEnemyOrNeutral && visibilityLevel >= VisibilityLevel.Blip0Minimum && ___displayedActor != null)
                    {
                        SensorScanType scanType      = SensorLockHelper.CalculateSharedLock(___displayedActor, ModState.LastPlayerActorActivated);
                        bool           hasVisualScan = VisualLockHelper.CanSpotTarget(ModState.LastPlayerActorActivated, ModState.LastPlayerActorActivated.CurrentPosition,
                                                                                      ___displayedActor, ___displayedActor.CurrentPosition, ___displayedActor.CurrentRotation, ___displayedActor.Combat.LOS);

                        Mod.Log.Debug?.Write($"Updating item visibility for enemy: {CombatantUtils.Label(___displayedActor)} to scanType: {scanType} and " +
                                             $"hasVisualScan: {hasVisualScan} from lastActivated: {CombatantUtils.Label(ModState.LastPlayerActorActivated)}");

                        // Values that are always displayed
                        setGOActiveMethod.GetValue(__instance.NameDisplay, true);
                        setGOActiveMethod.GetValue(__instance.PhaseDisplay, true);

                        if (scanType >= SensorScanType.StructAndWeaponID)
                        {
                            // Show unit summary
                            setGOActiveMethod.GetValue(__instance.DetailsDisplay, true);

                            // Show active state
                            setGOActiveMethod.GetValue(__instance.InspiredDisplay, false);

                            // Show armor and struct
                            setGOActiveMethod.GetValue(__instance.ArmorBar, true);
                            setGOActiveMethod.GetValue(__instance.StructureBar, true);

                            if (___displayedActor as Mech != null)
                            {
                                setGOActiveMethod.GetValue(__instance.StabilityDisplay, true);
                                setGOActiveMethod.GetValue(__instance.HeatDisplay, true);
                            }
                            else
                            {
                                setGOActiveMethod.GetValue(__instance.StabilityDisplay, false);
                                setGOActiveMethod.GetValue(__instance.HeatDisplay, false);
                            }
                        }
                        else if (scanType >= SensorScanType.ArmorAndWeaponType || hasVisualScan)
                        {
                            // Show unit summary
                            setGOActiveMethod.GetValue(__instance.DetailsDisplay, false);

                            // Show active state
                            setGOActiveMethod.GetValue(__instance.InspiredDisplay, false);

                            // Show armor and struct
                            setGOActiveMethod.GetValue(__instance.ArmorBar, true);
                            setGOActiveMethod.GetValue(__instance.StructureBar, true);

                            setGOActiveMethod.GetValue(__instance.StabilityDisplay, false);
                            setGOActiveMethod.GetValue(__instance.HeatDisplay, false);
                        }
                        else
                        {
                            // Hide unit summary
                            setGOActiveMethod.GetValue(__instance.DetailsDisplay, false);

                            // Hide active state
                            setGOActiveMethod.GetValue(__instance.InspiredDisplay, false);

                            // Hide armor and struct
                            setGOActiveMethod.GetValue(__instance.ArmorBar, false);
                            setGOActiveMethod.GetValue(__instance.StructureBar, false);

                            setGOActiveMethod.GetValue(__instance.StabilityDisplay, false);
                            setGOActiveMethod.GetValue(__instance.HeatDisplay, false);
                        }

                        // TODO: DEBUG TESTING
                        if (__instance.MarkDisplay != null)
                        {
                            setGOActiveMethod.GetValue(__instance.MarkDisplay, true);
                        }

                        CombatHUDStateStack stateStack = (CombatHUDStateStack)Traverse.Create(__instance).Property("StateStack").GetValue();
                        setGOActiveMethod.GetValue(stateStack, false);
                    }
                    else
                    {
                        if (__instance.MarkDisplay != null && ___displayedActor != null)
                        {
                            setGOActiveMethod.GetValue(__instance.MarkDisplay, ___displayedActor.IsMarked);
                        }
                    }
                } catch (Exception e) {
                    Mod.Log.Info?.Write($"Error updating item visibility! Error was: {e.Message}");
                }
            }
Exemple #6
0
        public static void Postfix(CombatHUDTargetingComputer __instance, List <TextMeshProUGUI> ___weaponNames)
        {
            if (__instance == null || __instance.ActivelyShownCombatant == null ||
                __instance.ActivelyShownCombatant.Combat == null || __instance.ActivelyShownCombatant.Combat.HostilityMatrix == null ||
                __instance.WeaponList == null)
            {
                Mod.Log.Debug?.Write($"CHTC:RAI ~~~ TC, target, or WeaponList is null, skipping.");
                return;
            }

            if (ModState.LastPlayerActorActivated == null)
            {
                Mod.Log.Error?.Write("Attempting to refresh ActorInfo, but LastPlayerActorActivated is null. This should never happen!");
            }

            if (__instance.ActivelyShownCombatant.Combat.HostilityMatrix.IsLocalPlayerFriendly(__instance.ActivelyShownCombatant.team.GUID))
            {
                Mod.Log.Debug?.Write($"CHTC:RAI ~~~ target:{CombatantUtils.Label(__instance.ActivelyShownCombatant)} friendly, resetting.");
                __instance.WeaponList.SetActive(true);
                return;
            }

            // Only enemies or neutrals below this point
            Mod.Log.Debug?.Write($"CHTC:RAI ~~~ target:{CombatantUtils.Label(__instance.ActivelyShownCombatant)} is enemy");

            try
            {
                if (__instance.ActivelyShownCombatant is AbstractActor target)
                {
                    float range         = Vector3.Distance(ModState.LastPlayerActorActivated.CurrentPosition, target.CurrentPosition);
                    bool  hasVisualScan = VisualLockHelper.CanSpotTarget(ModState.LastPlayerActorActivated, ModState.LastPlayerActorActivated.CurrentPosition,
                                                                         target, target.CurrentPosition, target.CurrentRotation, target.Combat.LOS);
                    SensorScanType scanType = SensorLockHelper.CalculateSharedLock(target, ModState.LastPlayerActorActivated);
                    Mod.Log.Debug?.Write($"CHTC:RAI ~~~ LastActivated:{CombatantUtils.Label(ModState.LastPlayerActorActivated)} vs. enemy:{CombatantUtils.Label(target)} " +
                                         $"at range: {range} has scanType:{scanType} visualScan:{hasVisualScan}");

                    // Build the CAC side-panel
                    try
                    {
                        BuildCACDialogForTarget(ModState.LastPlayerActorActivated, __instance.ActivelyShownCombatant, range, hasVisualScan, scanType);
                    }
                    catch (Exception e)
                    {
                        Mod.Log.Error?.Write(e, $"Failed to initialize CAC SidePanel for source: {CombatantUtils.Label(ModState.LastPlayerActorActivated)} and " +
                                             $"target: {CombatantUtils.Label(__instance.ActivelyShownCombatant)}!");
                    }

                    if (scanType >= SensorScanType.StructAndWeaponID)
                    {
                        __instance.WeaponList.SetActive(true);
                        SetArmorDisplayActive(__instance, true);
                    }
                    else if (scanType >= SensorScanType.ArmorAndWeaponType || hasVisualScan)
                    {
                        SetArmorDisplayActive(__instance, true);
                        ObfuscateWeaponLabels(___weaponNames, target);

                        // Update the summary display
                        __instance.WeaponList.SetActive(true);
                        Transform       weaponListT  = __instance.WeaponList?.transform?.parent?.Find("tgtWeaponsLabel");
                        GameObject      weaponsLabel = weaponListT.gameObject;
                        TextMeshProUGUI labelText    = weaponsLabel.GetComponent <TextMeshProUGUI>();
                        labelText.SetText(new Text(Mod.LocalizedText.TargetingComputer[ModText.LT_TARG_COMP_UNIDENTIFIED]).ToString());
                    }
                    else
                    {
                        SetArmorDisplayActive(__instance, false);

                        __instance.WeaponList.SetActive(false);
                        Transform  weaponListT  = __instance.WeaponList?.transform?.parent?.Find("tgtWeaponsLabel");
                        GameObject weaponsLabel = weaponListT.gameObject;
                        weaponsLabel.SetActive(false);
                    }
                }
                else if (__instance.ActivelyShownCombatant is BattleTech.Building building)
                {
                    Mod.Log.Debug?.Write($"CHTC:RAI ~~~ target:{CombatantUtils.Label(__instance.ActivelyShownCombatant)} is enemy building");

                    SetArmorDisplayActive(__instance, true);

                    __instance.WeaponList.SetActive(false);
                    Transform  weaponListT  = __instance.WeaponList?.transform?.parent?.Find("tgtWeaponsLabel");
                    GameObject weaponsLabel = weaponListT.gameObject;
                    weaponsLabel.SetActive(false);
                }
                else
                {
                    // WTF
                }
            }
            catch (Exception e)
            {
                Mod.Log.Error?.Write(e, "Failed to RefreshActorInfo!");
            }
        }
Exemple #7
0
        private static void BuildCACDialogForTarget(AbstractActor source, ICombatant target, float range, bool hasVisualScan, SensorScanType scanType)
        {
            StringBuilder sb = new StringBuilder();

            VisibilityLevel visLevel = source.VisibilityToTargetUnit(target);

            if (target is Mech mech)
            {
                string fullName    = mech.Description.UIName;
                string chassisName = mech.UnitName;
                string partialName = mech.Nickname;
                string localName   = CombatNameHelper.GetEnemyMechDetectionLabel(visLevel, scanType, fullName, partialName, chassisName).ToString();

                string tonnage = "?";
                if (scanType > SensorScanType.LocationAndType)
                {
                    tonnage = new Text(Mod.LocalizedText.CACSidePanel[ModText.LT_CAC_SIDEPANEL_WEIGHT], new object[] { (int)Math.Floor(mech.tonnage) }).ToString();
                }

                string titleText = new Text(Mod.LocalizedText.CACSidePanel[ModText.LT_CAC_SIDEPANEL_TITLE],
                                            new object[] { localName, tonnage }).ToString();
                sb.Append(titleText);

                if (scanType > SensorScanType.StructAndWeaponID)
                {
                    // Movement
                    sb.Append(new Text(Mod.LocalizedText.CACSidePanel[ModText.LT_CAC_SIDEPANEL_MOVE_MECH],
                                       new object[] { mech.WalkSpeed, mech.RunSpeed, mech.JumpDistance })
                              .ToString()
                              );

                    // Heat
                    sb.Append(new Text(Mod.LocalizedText.CACSidePanel[ModText.LT_CAC_SIDEPANEL_HEAT],
                                       new object[] { mech.CurrentHeat, mech.MaxHeat })
                              .ToString()
                              );

                    // Stability
                    sb.Append(new Text(Mod.LocalizedText.CACSidePanel[ModText.LT_CAC_SIDEPANEL_STAB],
                                       new object[] { mech.CurrentStability, mech.MaxStability })
                              .ToString()
                              );
                }
            }
            else if (target is Turret turret)
            {
                string chassisName = turret.UnitName;
                string fullName    = turret.Nickname;
                string localName   = CombatNameHelper.GetTurretOrVehicleDetectionLabel(visLevel, scanType, fullName, chassisName, false).ToString();

                string titleText = new Text(Mod.LocalizedText.CACSidePanel[ModText.LT_CAC_SIDEPANEL_TITLE],
                                            new object[] { localName, "" }).ToString();
                sb.Append(titleText);
            }
            else if (target is Vehicle vehicle)
            {
                string chassisName = vehicle.UnitName;
                string fullName    = vehicle.Nickname;
                string localName   = CombatNameHelper.GetTurretOrVehicleDetectionLabel(visLevel, scanType, fullName, chassisName, true).ToString();

                string tonnage = "?";
                if (scanType > SensorScanType.LocationAndType)
                {
                    tonnage = new Text(Mod.LocalizedText.CACSidePanel[ModText.LT_CAC_SIDEPANEL_WEIGHT], new object[] { (int)Math.Floor(vehicle.tonnage) }).ToString();
                }

                string titleText = new Text(Mod.LocalizedText.CACSidePanel[ModText.LT_CAC_SIDEPANEL_TITLE],
                                            new object[] { localName, tonnage }).ToString();
                sb.Append(titleText);

                if (scanType > SensorScanType.StructAndWeaponID)
                {
                    // Movement
                    sb.Append(new Text(Mod.LocalizedText.CACSidePanel[ModText.LT_CAC_SIDEPANEL_MOVE_VEHICLE],
                                       new object[] { vehicle.CruiseSpeed, vehicle.FlankSpeed })
                              .ToString()
                              );
                }
            }


            string distance = new Text(Mod.LocalizedText.CACSidePanel[ModText.LT_CAC_SIDEPANEL_DIST],
                                       new object[] { (int)Math.Ceiling(range) }).ToString();

            sb.Append(distance);

            Text panelText = new Text(sb.ToString(), new object[] { });

            CustAmmoCategories.CombatHUDInfoSidePanelHelper.SetTargetInfo(source, target, panelText);
        }
Exemple #8
0
 public static void UpdateActorLocks(AbstractActor source, ICombatant target, VisualScanType visualLock, SensorScanType sensorLock)
 {
     if (source != null && target != null)
     {
         Locks newLocks = new Locks(source, target, visualLock, sensorLock);
         if (PlayerActorLocks.ContainsKey(source.GUID))
         {
             PlayerActorLocks[source.GUID][target.GUID] = newLocks;
         }
         else
         {
             PlayerActorLocks[source.GUID] = new Dictionary <string, Locks> {
                 [target.GUID] = newLocks
             };
         }
     }
 }