public ActorInitiative(AbstractActor actor) { //SkillBasedInit.Logger.Log($"Initializing ActorInitiative for {actor.DisplayName} with GUID {actor.GUID}."); if (actor.GetType() == typeof(Mech)) { this.type = ActorType.Mech; } else if (actor.GetType() == typeof(Vehicle)) { this.type = ActorType.Vehicle; } else { this.type = ActorType.Turret; } // --- UNIT IMPACTS --- // Static initiative from tonnage float tonnage = UnitHelper.GetUnitTonnage(actor); int tonnageMod = UnitHelper.GetTonnageModifier(tonnage); // Any special modifiers by type int typeMod = UnitHelper.GetTypeModifier(actor); // Any modifiers that come from the chassis/mech/vehicle defs int componentsMod = UnitHelper.GetNormalizedComponentModifier(actor); // Modifier from the engine int engineMod = UnitHelper.GetEngineModifier(actor); // --- PILOT IMPACTS --- Pilot pilot = actor.GetPilot(); PilotHelper.LogPilotStats(pilot); // Normalize skills so that values above 10 don't screw the system this.gunneryEffectMod = PilotHelper.GetGunneryModifier(pilot); this.gutsEffectMod = PilotHelper.GetGutsModifier(pilot); this.injuryBounds = PilotHelper.GetInjuryBounds(pilot); this.pilotingEffectMod = PilotHelper.GetPilotingModifier(pilot); this.randomnessBounds = PilotHelper.GetRandomnessBounds(pilot); this.tacticsEffectMod = PilotHelper.GetTacticsModifier(pilot); int pilotTagsMod = PilotHelper.GetTagsModifier(pilot); this.calledShotMod = PilotHelper.GetCalledShotModifier(pilot); this.vigilianceMod = PilotHelper.GetVigilanceModifier(pilot); // --- COMBO IMPACTS -- // Determine the melee modifier int[] meleeMods = PilotHelper.GetMeleeModifiers(pilot, tonnage); this.meleeAttackMod = meleeMods[0]; this.meleeDefenseMod = meleeMods[1]; Mod.Log.Debug($"Actor:{actor.DisplayName}_{pilot.Name} has meleeAttackMod:{meleeAttackMod} meleeDefenseMod:{meleeDefenseMod}"); // Log the full view for testing roundInitBase = tonnageMod; roundInitBase += typeMod; roundInitBase += componentsMod; roundInitBase += engineMod; roundInitBase += tacticsEffectMod; roundInitBase += pilotTagsMod; Mod.Log.Info($"Actor:{actor.DisplayName}_{pilot.Name} has " + $"roundInitBase:{roundInitBase} = (tonnage:{tonnageMod} + typeMod:{typeMod} + components:{componentsMod} + engine:{engineMod} " + $"tactics:{tacticsEffectMod} + pilotTags:{pilotTagsMod}) " + $"randomness:({randomnessBounds[0]}-{randomnessBounds[1]}) " + $"injuryBounds:({injuryBounds[0]}-{injuryBounds[1]}) " + $"gutsMod:{gutsEffectMod} pilotingMod:{pilotingEffectMod} tacticsMod:{tacticsEffectMod}"); }
private static string BuildTooltipText(AbstractActor actor) { ActorInitiative actorInit = ActorInitiativeHolder.GetOrCreate(actor); // -- Mech List <string> mechDetails = new List <string> { }; Mech actorMech = actor as Mech; float tonnage = actorMech.MechDef.Chassis.Tonnage; int tonnageMod = UnitHelper.GetTonnageModifier(tonnage); mechDetails.Add($"MECH => tonnage:{tonnageMod}"); int expectedInitMax = tonnageMod; // Any modifiers that come from the chassis/mech/vehicle defs int componentsMod = UnitHelper.GetNormalizedComponentModifier(actor); if (componentsMod > 0) { mechDetails.Add($"<color=#00FF00>{componentsMod:+0} components</color>"); } else if (componentsMod < 0) { mechDetails.Add($"<color=#FF0000>{componentsMod:0} components</color>"); } expectedInitMax += componentsMod; // Modifier from the engine int engineMod = UnitHelper.GetEngineModifier(actor); if (engineMod > 0) { mechDetails.Add($"<color=#00FF00>{engineMod:+0} engine</color>"); } else if (engineMod < 0) { mechDetails.Add($"<color=#FF0000>{engineMod:0} engine</color>"); } expectedInitMax += engineMod; // Check for leg / side loss Mech mech = (Mech)actor; if (mech.IsLocationDestroyed(ChassisLocations.LeftLeg) || mech.IsLocationDestroyed(ChassisLocations.RightLeg)) { int rawMod = Mod.Config.CrippledMovementModifier + actorInit.pilotingEffectMod; int penalty = Math.Min(-1, rawMod); mechDetails.Add($"<color=#FF0000>{penalty} Leg Destroyed</color>"); expectedInitMax += penalty; } // Check for prone if (actor.IsProne) { int rawMod = Mod.Config.ProneModifier + actorInit.pilotingEffectMod; int penalty = Math.Min(-1, rawMod); mechDetails.Add($"<color=#FF0000>{penalty} Prone</color>"); expectedInitMax += penalty; } // Check for shutdown if (actor.IsShutDown) { int rawMod = Mod.Config.ShutdownModifier + actorInit.pilotingEffectMod; int penalty = Math.Min(-1, rawMod); mechDetails.Add($"<color=#FF0000>{penalty} Shutdown</color>"); expectedInitMax += penalty; } // Check for melee impacts if (actorInit.lastRoundMeleeMod > 0) { expectedInitMax -= actorInit.lastRoundMeleeMod; mechDetails.Add($"<color=#FF0000>-{actorInit.lastRoundMeleeMod} Melee Impact</color>"); } // --- PILOT --- List <string> pilotDetails = new List <string> { }; Pilot selectedPilot = actor.GetPilot(); int tacticsMod = PilotHelper.GetTacticsModifier(selectedPilot); pilotDetails.Add($"PILOT => Tactics: <color=#00FF00>{tacticsMod:+0}</color>"); expectedInitMax += tacticsMod; int pilotTagsMod = PilotHelper.GetTagsModifier(selectedPilot); pilotDetails.AddRange(PilotHelper.GetTagsModifierDetails(selectedPilot)); expectedInitMax += pilotTagsMod; int[] randomnessBounds = PilotHelper.GetRandomnessBounds(selectedPilot); int expectedInitRandMin = randomnessBounds[0]; int expectedInitRandMax = randomnessBounds[1]; // Check for inspired status if (actor.IsMoraleInspired || actor.IsFuryInspired) { pilotDetails.Add($"<color=#00FF00>+1 to +3 Inspired</color>"); expectedInitRandMin += 1; expectedInitRandMin += 3; } // Check for injuries. If there injuries on the previous round, apply them in full force. Otherwise, reduce them. if (actorInit.lastRoundInjuryMod != 0) { pilotDetails.Add($"<color=#FF0000>-{actorInit.lastRoundInjuryMod} Fresh Injury</color>"); expectedInitMax -= actorInit.lastRoundInjuryMod; } else if (actor.GetPilot().Injuries != 0) { // TODO: fold this in int rawPenalty = actorInit.CalculateInjuryPenalty(0, actor.GetPilot().Injuries); int penalty = (int)Math.Ceiling(rawPenalty / 2.0); pilotDetails.Add($"<color=#FF0000>-{penalty} Painful Injury</color>"); expectedInitMax -= penalty; } // Check for an overly cautious player if (actorInit.lastRoundHesitationPenalty > 0) { expectedInitMax -= actorInit.lastRoundHesitationPenalty; pilotDetails.Add($"<color=#FF0000>-{actorInit.lastRoundHesitationPenalty} Hesitation</color>"); } // Check for called shot if (actorInit.lastRoundCalledShotMod > 0) { expectedInitMax -= actorInit.lastRoundCalledShotMod; pilotDetails.Add($"<color=#FF0000>-{actorInit.lastRoundCalledShotMod} Called Shot Target</color>"); } // Check for vigilance if (actorInit.lastRoundVigilanceMod > 0) { expectedInitMax -= actorInit.lastRoundVigilanceMod; pilotDetails.Add($"<color=#00FF00>-{actorInit.lastRoundVigilanceMod} Vigilance</color>"); } // Finally, randomness bounds pilotDetails.Add($"\nRandom (tactics): <color=#FF0000>-{actorInit.randomnessBounds[0]} to -{actorInit.randomnessBounds[1]}</color>"); int maxInit = Math.Max(expectedInitMax - expectedInitRandMin, Mod.MinPhase); int minInit = Math.Max(expectedInitMax - expectedInitRandMax, Mod.MinPhase); List <string> toolTipDetails = new List <string> { }; toolTipDetails.Add(String.Join(", ", mechDetails.ToArray())); toolTipDetails.Add(String.Join(", ", pilotDetails.ToArray())); toolTipDetails.Add($"Expected Phase: <b>{maxInit} to {minInit}</b>"); toolTipDetails.Add($"Hover over init in Mechlab/Deploy for details."); string tooltipText = String.Join("\n", toolTipDetails.ToArray()); return(tooltipText); }
public static void Postfix(LanceLoadoutSlot __instance, GameObject ___initiativeObj, TextMeshProUGUI ___initiativeText, UIColorRefTracker ___initiativeColor, HBSTooltip ___initiativeTooltip, LanceConfiguratorPanel ___LC) { if (___initiativeObj == null || ___initiativeText == null || ___initiativeColor == null || ___initiativeTooltip == null) { return; } //SkillBasedInit.Logger.Log($"LanceLoadoutSlot::RefreshInitiativeData::post - disabling text"); bool bothSelected = __instance.SelectedMech != null && __instance.SelectedPilot != null; if (!bothSelected) { ___initiativeText.SetText("-"); ___initiativeColor.SetUIColor(UIColor.MedGray); } else { int initValue = 0; // --- MECH --- MechDef selectedMechDef = __instance.SelectedMech.MechDef; List <string> details = new List <string>(); // Static initiative from tonnage float tonnage = __instance.SelectedMech.MechDef.Chassis.Tonnage; int tonnageMod = UnitHelper.GetTonnageModifier(tonnage); initValue += tonnageMod; details.Add($"Tonnage Base: {tonnageMod}"); // Any special modifiers by type - NA, Mech is the only type // Any modifiers that come from the chassis/mech/vehicle defs int componentsMod = UnitHelper.GetNormalizedComponentModifier(selectedMechDef); initValue += componentsMod; if (componentsMod > 0) { details.Add($"<space=2em><color=#00FF00>{componentsMod:+0} components</color>"); } else if (componentsMod < 0) { details.Add($"<space=2em><color=#FF0000>{componentsMod:0} components</color>"); } // Modifier from the engine int engineMod = UnitHelper.GetEngineModifier(selectedMechDef); initValue += engineMod; if (engineMod > 0) { details.Add($"<space=2em><color=#00FF00>{engineMod:+0} engine</color>"); } else if (engineMod < 0) { details.Add($"<space=2em><color=#FF0000>{engineMod:0} engine</color>"); } // --- PILOT --- Pilot selectedPilot = __instance.SelectedPilot.Pilot; int tacticsMod = PilotHelper.GetTacticsModifier(selectedPilot); details.Add($"<space=2em>{tacticsMod:+0} tactics"); initValue += tacticsMod; int pilotTagsMod = PilotHelper.GetTagsModifier(selectedPilot); details.AddRange(PilotHelper.GetTagsModifierDetails(selectedPilot)); initValue += pilotTagsMod; int[] randomnessBounds = PilotHelper.GetRandomnessBounds(selectedPilot); // --- LANCE --- if (___LC != null) { initValue += ___LC.lanceInitiativeModifier; if (___LC.lanceInitiativeModifier > 0) { details.Add($"<space=2em><color=#00FF00>{___LC.lanceInitiativeModifier:+0} lance</color>"); } else if (___LC.lanceInitiativeModifier < 0) { details.Add($"<space=2em><color=#FF0000>{___LC.lanceInitiativeModifier:0} lance</color>"); } } // --- Badge --- ___initiativeText.SetText($"{initValue}"); ___initiativeText.color = Color.black; ___initiativeColor.SetUIColor(UIColor.White); // --- Tooltip --- int maxInit = Math.Max(initValue - randomnessBounds[0], Mod.MinPhase); int minInit = Math.Max(initValue - randomnessBounds[1], Mod.MinPhase); details.Add($"Total:{initValue}"); details.Add($"<space=2em><color=#FF0000>-{randomnessBounds[0]} to -{randomnessBounds[1]} randomness</color> (piloting)"); details.Add($"<b>Expected Phase<b>: {maxInit} to {minInit}"); string tooltipTitle = $"{selectedMechDef.Name}: {selectedPilot.Name}"; string tooltipText = String.Join("\n", details.ToArray()); BaseDescriptionDef initiativeData = new BaseDescriptionDef("LLS_MECH_TT", tooltipTitle, tooltipText, null); ___initiativeTooltip.enabled = true; ___initiativeTooltip.SetDefaultStateData(TooltipUtilities.GetStateDataFromObject(initiativeData)); } }