public static void Postfix(SimGameState __instance, ref int __result, EconomyScale expenditureLevel, bool proRate) { Mod.Log.Trace?.Write($"SGS:GE entered with {__result}"); // Evaluate old versus new cost int vanillaCosts = 0; int newCosts = 0; for (int i = 0; i < __instance.PilotRoster.Count; i++) { PilotDef def = __instance.PilotRoster[i].pilotDef; vanillaCosts += __instance.GetMechWarriorValue(def); CrewDetails details = ModState.GetCrewDetails(def); newCosts += details.AdjustedSalary; } // Multiply old costs by expenditure. New has that built in. Then subtract them from the running total float expenditureCostModifier = __instance.GetExpenditureCostModifier(expenditureLevel); int vanillaTotal = Mathf.CeilToInt((float)vanillaCosts * expenditureCostModifier); Mod.Log.Trace?.Write($"Removing {vanillaCosts} costs x {expenditureCostModifier} expenditureMulti " + $"= {vanillaTotal} total vanilla costs."); __result -= vanillaTotal; // Add the new costs __result += newCosts; }
public static void Postfix() { Mod.Log.Trace?.Write("CGS:OCGD - entered."); // Reset any combat state ModState.Reset(); }
static void Postfix(AAR_ContractObjectivesWidget __instance, Contract ___theContract) { try { List <Pilot> deployedPilots = ___theContract.PlayerUnitResults.Select(ur => ur.pilot).ToList(); int hazardPaySum = 0; foreach (Pilot p in deployedPilots) { CrewDetails details = ModState.GetCrewDetails(p.pilotDef); hazardPaySum -= details.HazardPay; } Mod.Log.Debug?.Write($"Total hazard pay for mission is: {hazardPaySum}"); string hazardPayTitleS = new Text(Mod.LocalizedText.Labels[ModText.LT_Contract_Hazard_Pay], new object[] { SimGameState.GetCBillString(hazardPaySum) }).ToString(); string guid = Guid.NewGuid().ToString(); MissionObjectiveResult hazardPayObjective = new MissionObjectiveResult(hazardPayTitleS, guid, false, true, ObjectiveStatus.Succeeded, false); Traverse addObjective = Traverse.Create(__instance).Method("AddObjective", new Type[] { typeof(MissionObjectiveResult) }); addObjective.GetValue(new object[] { hazardPayObjective }); } catch (Exception e) { Mod.Log.Warn?.Write(e, "Failed to build hazard pay for contract!"); } }
// This patch needs to run to correctly fix the melee attack to the target selected by CleverGirl/AI. // During AI eval multiple targets are evaluated, and this ensures we use the attack for the one that was picked. static void Postfix(AbstractActor unit, ref BehaviorTreeResults __result) { if (__result != null && __result.nodeState == BehaviorNodeState.Success && __result.orderInfo is AttackOrderInfo attackOrderInfo) { if (attackOrderInfo.IsMelee) { Mod.Log.Debug?.Write($"Setting melee weapon for attack from attacker: {unit?.DistinctId()} versus target: {attackOrderInfo.TargetUnit?.DistinctId()}"); // Create melee options MeleeState meleeState = ModState.AddorUpdateMeleeState(unit, attackOrderInfo.AttackFromLocation, attackOrderInfo.TargetUnit); if (meleeState != null) { MeleeAttack meleeAttack = meleeState.GetHighestDamageAttackForUI(); ModState.AddOrUpdateSelectedAttack(unit, meleeAttack); } } else if (attackOrderInfo.IsDeathFromAbove) { // Create melee options MeleeState meleeState = ModState.AddorUpdateMeleeState(unit, attackOrderInfo.AttackFromLocation, attackOrderInfo.TargetUnit); if (meleeState != null) { MeleeAttack meleeAttack = meleeState.DFA; ModState.AddOrUpdateSelectedAttack(unit, meleeAttack); } } } else { Mod.Log.Trace?.Write($"BehaviorTree result is not failed: {__result?.nodeState} or is not an attackOrderInfo, skipping."); } }
public ModInfo(ModState state, string modId, bool canSuspend, bool canUnload) { State = state; ModId = modId; CanSuspend = canSuspend; CanUnload = canUnload; }
private bool ValidateAttack(Mech attacker, AbstractActor target, HashSet <MeleeAttackType> validAnimations) { ActorMeleeCondition meleeCondition = ModState.GetMeleeCondition(attacker); if (!meleeCondition.CanKick()) { Mod.MeleeLog.Info?.Write($"Attacker cannot kick, skipping."); return(false); } // If neither kick (mech) or stomp (vehicle) - we're not a valid attack. if (!validAnimations.Contains(MeleeAttackType.Kick) && !validAnimations.Contains(MeleeAttackType.Stomp)) { Mod.MeleeLog.Info?.Write("Animations do not include a kick or stomp, cannot kick."); return(false); } if (target.UnaffectedPathing()) { Mod.MeleeLog.Info?.Write($"Target is unaffected by pathing, likely a VTOL or LAM in flight. Cannot melee it!"); return(false); } // If distance > walkSpeed, disable kick/physical weapon/punch if (!state.HasWalkAttackNodes) { Mod.MeleeLog.Info?.Write($"No walking nodes found for melee attack!"); return(false); } Mod.MeleeLog.Info?.Write("KICK ATTACK validated"); return(true); }
public void OverLayerToolDidUpdateState(ModState p_newState) { if (m_button == null) { return; } switch (p_newState) { case ModState.off: m_button.activeStateIndex = 0; m_button.Unfocus(); m_lockImage.Hide(); break; case ModState.on: m_button.activeStateIndex = 1; m_lockImage.Hide(); break; case ModState.locked: m_button.activeStateIndex = 1; m_lockImage.Show(); break; } }
static void Prefix(CombatHUDAttackModeSelector __instance, CombatHUDFireButton.FireMode mode, ref string additionalDetails, bool showHeatWarnings) { Mod.UILog.Trace?.Write($"ShowFireButton called with mode: {mode}"); // Intentionally regen the meleeStates everytime the button changes, to make sure different positions calculate properly if (mode == CombatHUDFireButton.FireMode.Engage || mode == CombatHUDFireButton.FireMode.DFA) { if (SharedState.CombatHUD?.SelectionHandler?.ActiveState?.PreviewPos != ModState.MeleePreviewPos) { ModState.MeleePreviewPos = SharedState.CombatHUD.SelectionHandler.ActiveState.PreviewPos; // Update melee states ModState.AddorUpdateMeleeState( SharedState.CombatHUD.SelectionHandler.ActiveState.SelectedActor, SharedState.CombatHUD.SelectionHandler.ActiveState.PreviewPos, SharedState.CombatHUD.SelectionHandler.ActiveState.TargetedCombatant); Mod.UILog.Debug?.Write($"Updated melee state for position: {ModState.MeleePreviewPos}"); // Re-enable any buttons if they were disabled. __instance.FireButton.SetState(ButtonState.Enabled); __instance.DescriptionContainer.SetActive(true); } } else { ModState.InvalidateState(SharedState.CombatHUD?.SelectionHandler?.ActiveState?.SelectedActor); } }
static void Postfix(SGBarracksMWDetailPanel __instance, Pilot p, SGBarracksAdvancementPanel ___advancement, GameObject ___advancementSectionGO, SGBarracksDossierPanel ___dossier, SGBarracksServicePanel ___servicePanel, GameObject ___serviceSectionGO, HBSDOTweenButton ___customizeButton) { if (p == null) { return; } CrewDetails details = ModState.GetCrewDetails(p.pilotDef); GameObject skillsButton = __instance.gameObject.FindFirstChildNamed(ModConsts.GO_HBS_Barracks_Skill_Button); if (skillsButton == null) { Mod.Log.Debug?.Write("SkillsButton is null!"); } if (details.IsMechTechCrew || details.IsMedTechCrew || details.IsAerospaceCrew) { __instance.OnServiceSectionClicked(); skillsButton.SetActive(false); } else { skillsButton.SetActive(true); } }
public static float PhysicalWeaponInstability(this Mech mech) { ActorMeleeCondition attackerCondition = ModState.GetMeleeCondition(mech); if (!attackerCondition.CanUsePhysicalAttack()) { return(0); } // 0 is a signal that there's no divisor float tonnageMulti = mech.StatCollection.ContainsStatistic(ModStats.PhysicalWeaponTargetInstability) && mech.StatCollection.GetValue <float>(ModStats.PhysicalWeaponTargetInstability) > 0 ? mech.StatCollection.GetValue <float>(ModStats.PhysicalWeaponTargetInstability) : Mod.Config.Melee.PhysicalWeapon.DefaultInstabilityPerAttackerTon; float raw = (float)Math.Ceiling(tonnageMulti * mech.tonnage); Mod.MeleeLog.Debug?.Write($"PHYSICAL WEAPON instability => tonnageMulti: {tonnageMulti} x attacker tonnage: {mech.tonnage} = raw: {raw}"); // Modifiers float mod = mech.StatCollection.ContainsStatistic(ModStats.PhysicalWeaponTargetInstabilityMod) ? mech.StatCollection.GetValue <int>(ModStats.PhysicalWeaponTargetInstabilityMod) : 0f; float multi = mech.StatCollection.ContainsStatistic(ModStats.PhysicalWeaponTargetInstabilityMulti) ? mech.StatCollection.GetValue <float>(ModStats.PhysicalWeaponTargetInstabilityMulti) : 1f; // Roll up final damage float final = (float)Math.Ceiling((raw + mod) * multi); Mod.MeleeLog.Debug?.Write($" - Target instability => final: {final} = (raw: {raw} + mod: {mod}) x multi: {multi}"); return(final); }
public static float GetVisualScanRange(AbstractActor source) { // FIXME: Dirty hack here. Assuming that night vision mode only comes on during a unit's turn / selection, then goes away float visRange = ModState.IsNightVisionMode ? ModState.GetMapConfig().nightVisionVisualIDRange : ModState.GetMapConfig().visualIDRange; return(GetVisualRange(visRange, source)); }
void Resolve(ModuleDef source, ModState parent) { using (_recursionCounter.Enter()) { var name = source.Location ?? source.Name; if (_recursionCounter.Value > 100) { throw _context.Error("recursive module reference to " + name); } if (!_states.TryGetValue(source, out var state)) { var ev = new NetfuserEvent.ResolveSourceModules(_context, source) { ResolveReferences = true, Treat = ModuleTreat.Merge }; if (!IsInMainDir(source.Location)) { ev.Treat = ModuleTreat.Ignore; ev.ResolveReferences = false; } else if (parent != null && (parent.Treat == ModuleTreat.Copy || parent.Treat == ModuleTreat.Embed)) { ev.Treat = parent.Treat; } if (ev.Treat == ModuleTreat.Merge && source.Assembly.CustomAttributes.Any(a => a.TypeFullName == "System.Reflection.AssemblyMetadataAttribute" && a.HasConstructorArguments && Convert.ToString(a.ConstructorArguments[0].Value) == "NotSupported" && Convert.ToString(a.ConstructorArguments[1].Value) == "True")) // these are ref assemblies { ev.Treat = ModuleTreat.Ignore; } _context.Fire(ev); _states.Add(source, state = new ModState(source) { Treat = ev.Treat, Resolve = ev.ResolveReferences }); _context.Info($"module {name}: {state}"); } if (parent != null) { state.ReferencesToMe.Add(parent); } if (!state.Resolve || state.Resolved) { return; } state.Resolved = true; foreach (var aref in source.GetAssemblyRefs()) { var adef = source.Context.AssemblyResolver.Resolve(aref, source); if (adef != null) { foreach (var mdef in adef.Modules) { Resolve(mdef, state); } } } } }
static void Postfix(ToHit __instance, ref string __result, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot) { Mod.Log.Trace?.Write("TH:GAMD entered"); if (attacker.HasMovedThisRound && attacker.JumpedLastRound || (SharedState.CombatHUD?.SelectionHandler?.ActiveState != null && SharedState.CombatHUD?.SelectionHandler?.ActiveState is SelectionStateJump)) { string localText = new Text(Mod.LocalizedText.Labels[ModText.LT_Label_Attacker_Jumped]).ToString(); __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, Mod.Config.ToHitSelfJumped); } // Check melee patches MeleeAttack selectedAttack = ModState.GetSelectedAttack(attacker); if (selectedAttack != null && weapon.Type == WeaponType.Melee) { foreach (KeyValuePair <string, int> kvp in selectedAttack.AttackModifiers) { string localText = new Text(Mod.LocalizedText.Labels[kvp.Key]).ToString(); Mod.Log.Info?.Write($" - Found attack modifier for desc: {localText} = {kvp.Value}"); __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, kvp.Value); } } }
static void Postfix(TurnDirector __instance) { Mod.Log.Debug?.Write("TD:OCGD entered"); ModState.Reset(); // DO NOT OVERWRITE CombatDamage! }
void RenderModState(Rect root, ModState state) { GUIStyle style = ModStateStyle; string content = string.Empty; if (state == ModState.Add) { content = "+"; } else if (state == ModState.Remove) { content = "-"; } else if (state == ModState.VersionChange) { content = "?"; } else if (state == ModState.None) { content = " "; } else { throw new Exception($"ModState {state.ToString()} is not supported yet. please contact to modder."); } GUI.Label(root, content, style); }
static void Postfix(ToHit __instance, ref float __result, Mech attacker, ICombatant target, Vector3 targetPosition, MeleeAttackType meleeAttackType) { Mod.Log.Trace?.Write("TH:GAMM entered"); if (__instance == null) { return; } MeleeAttack selectedAttack = ModState.GetSelectedAttack(attacker); if (selectedAttack == null) { return; } Mod.Log.Debug?.Write("Adding CBTBE modifiers to ToHit"); int sumMod = 0; foreach (KeyValuePair <string, int> kvp in selectedAttack.AttackModifiers) { string localText = new Text(Mod.LocalizedText.Labels[kvp.Key]).ToString(); Mod.Log.Debug?.Write($" - Found attack modifier: {localText} = {kvp.Value}, adding to sum modifier"); sumMod += kvp.Value; } __result += (float)sumMod; }
private bool ValidateAttack(Mech attacker, AbstractActor target) { ActorMeleeCondition meleeCondition = ModState.GetMeleeCondition(attacker); if (!meleeCondition.CanDFA()) { Mod.MeleeLog.Info?.Write($"Attacker cannot DFA, skipping."); return(false); } if (!attacker.CanDFATargetFromPosition(target, attacker.CurrentPosition)) { Mod.MeleeLog.Info?.Write($"Attacker unable to DFA target from their position."); return(false); } if (target.UnaffectedPathing()) { Mod.MeleeLog.Info?.Write($"Target is unaffected by pathing, likely a VTOL or LAM in flight. Cannot melee it!"); return(false); } // No damage check - by rules, you can DFA? Mod.MeleeLog.Info?.Write("DFA ATTACK validated"); return(true); }
void RenderSingleMod(Rect root, Mod mod, ModState modState) { Color bgColor; if (modState == ModState.Add) { bgColor = ColorPresets.Green; } else if (modState == ModState.Remove) { bgColor = ColorPresets.Red; } else if (useVersionChecking && modState == ModState.VersionChange) { bgColor = ColorPresets.Yellow; } else { bgColor = ColorPresets.Background; } Widgets.DrawBoxSolid(root, bgColor); float leftBoxWidth = 16f; Rect ModStateRect = new Rect(root.x, root.y, leftBoxWidth, root.height); RenderModState(ModStateRect, modState); Rect DescriptionRect = new Rect(ModStateRect.xMax, root.y, root.width - ModStateRect.width, root.height); RenderModDescriptionAndVersion(DescriptionRect, mod); }
static bool Prefix(SG_HiringHall_Screen __instance, Pilot ___selectedPilot, string button) { Mod.Log.Debug?.Write("Updating Dialog"); if (___selectedPilot != null && "Hire".Equals(button, StringComparison.InvariantCultureIgnoreCase) && __instance.HireButtonValid()) { Mod.Log.Debug?.Write(" -- pilot is selected"); CrewDetails details = ModState.GetCrewDetails(___selectedPilot.pilotDef); int modifiedBonus = (int)Mathf.RoundToInt(details.AdjustedBonus); string salaryS = new Text(Mod.LocalizedText.Labels[ModText.LT_Crew_Hire_Button], new string[] { SimGameState.GetCBillString(Mathf.RoundToInt(modifiedBonus)) }) .ToString(); Mod.Log.Debug?.Write($" -- bonus will be: {salaryS}"); GenericPopupBuilder.Create("Confirm?", salaryS) .AddButton("Cancel") .AddButton("Accept", __instance.HireCurrentPilot) .CancelOnEscape() .AddFader(LazySingletonBehavior <UIManager> .Instance.UILookAndColorConstants.PopupBackfill) .Render(); return(false); } return(true); }
private bool ValidateAttack(Mech attacker, AbstractActor target, HashSet <MeleeAttackType> validAnimations) { ActorMeleeCondition meleeCondition = ModState.GetMeleeCondition(attacker); if (!meleeCondition.CanUsePhysicalAttack()) { Mod.MeleeLog.Info?.Write($"Attacker cannot make a physical attack, skipping."); return(false); } // If no punch - we're not a valid attack. if (!validAnimations.Contains(MeleeAttackType.Punch)) { Mod.MeleeLog.Info?.Write("Animations do not include a punch, cannot use physical weapon."); return(false); } if (target.UnaffectedPathing()) { Mod.MeleeLog.Info?.Write($"Target is unaffected by pathing, likely a VTOL or LAM in flight. Cannot melee it!"); return(false); } // If distance > walkSpeed, disable kick/physical weapon/punch if (!state.HasWalkAttackNodes) { Mod.MeleeLog.Info?.Write($"No walking nodes found for melee attack!"); return(false); } Mod.MeleeLog.Info?.Write("PHYSICAL WEAPON ATTACK validated"); return(true); }
static void Postfix(CombatHUDWeaponSlot __instance, Weapon ___displayedWeapon, CombatHUD ___HUD) { if (__instance == null || ___displayedWeapon == null || ___HUD.SelectedActor == null || !Mod.Config.Melee.FilterCanUseInMeleeWeaponsByAttack) { return; } MeleeAttack selectedAttack = ModState.GetSelectedAttack(___HUD.SelectedActor); if (selectedAttack != null) { Mod.UILog.Debug?.Write($"Checking ranged weapons attacker: {___HUD.SelectedActor.DistinctId()} using selectedAttack: {selectedAttack.Label}"); // Check if the weapon can fire according to the select melee type bool isAllowed = selectedAttack.IsRangedWeaponAllowed(___displayedWeapon); Mod.UILog.Debug?.Write($"Ranged weapon '{___displayedWeapon.UIName}' can fire in melee by type? {isAllowed}"); if (!isAllowed) { Mod.UILog.Debug?.Write($"Disabling weapon from selection"); __instance.ToggleButton.isChecked = false; Traverse showDisabledHexT = Traverse.Create(__instance).Method("ShowDisabledHex"); showDisabledHexT.GetValue(); } } //else //{ // // No selected attack, so revert the weapon to the state it should have // __instance.ToggleButton.isChecked = ___displayedWeapon.IsEnabled && !___displayedWeapon.IsDisabled; //} }
static void Postfix(SG_HiringHall_Screen __instance, Pilot ___selectedPilot, LocalizableText ___MWInitialCostText, UIColorRefTracker ___MWCostColor, HBSDOTweenButton ___HireButton) { Mod.Log.Debug?.Write("Updating UpdateMoneySpot"); if (___selectedPilot != null) { Mod.Log.Debug?.Write(" -- pilot is selected"); // Account for the salary CrewDetails details = ModState.GetCrewDetails(___selectedPilot.pilotDef); int modifiedBonus = (int)Mathf.RoundToInt(details.AdjustedBonus); string bonus = new Text(Mod.LocalizedText.Labels[ModText.LT_Crew_Bonus_Label], new string[] { SimGameState.GetCBillString(Mathf.RoundToInt(modifiedBonus)) }) .ToString(); Mod.Log.Debug?.Write($" -- bonus will be: {bonus}"); ___MWInitialCostText.SetText(bonus); if (modifiedBonus > ModState.SimGameState.Funds) { Mod.Log.Debug?.Write(" -- Disabling hire."); ___MWCostColor.SetUIColor(UIColor.Red); ___HireButton.SetState(ButtonState.Disabled); } else { Mod.Log.Debug?.Write(" -- Enabling hire."); ___MWCostColor.SetUIColor(UIColor.White); ___HireButton.SetState(ButtonState.Enabled); } } }
static void Postfix(SimGameState __instance, Pilot pilot, ref bool __result) { int currentMRBLevel = __instance.GetCurrentMRBLevel(); CrewDetails details = ModState.GetCrewDetails(pilot.pilotDef); __result = details.CanBeHiredAtMRBLevel(currentMRBLevel); }
static void Postfix(SGEventPanel __instance, SimGameEventOption option, SimGameInterruptManager.EventPopupEntry ___thisEntry) { if (___thisEntry != null && ___thisEntry.parameters != null && ___thisEntry.parameters[0] is SimGameEventDef eventDef) { if (ModConsts.Event_ContractExpired.Equals(eventDef.Description.Id)) { // Handle updating the contract length in the def; funds are handled by the event. if (ModConsts.Event_Option_ContractExpired_Hire_NoBonus.Equals(option.Description.Id) || ModConsts.Event_Option_ContractExpired_Hire_Bonus.Equals(option.Description.Id)) { (Pilot Pilot, CrewDetails Details)expired = ModState.ExpiredContracts.Peek(); Mod.Log.Debug?.Write($"Pilot {expired.Pilot.Name} was re-hired w/o a bonus"); expired.Details.ExpirationDay = ModState.SimGameState.DaysPassed + expired.Details.ContractTerm; ModState.UpdateOrCreateCrewDetails(expired.Pilot.pilotDef, expired.Details); } } else if (ModConsts.Event_HeadHunting.Equals(eventDef.Description.Id)) { // TODO: Anything? } } }
static void Postfix() { Mod.Log.Trace?.Write("CGS:OCGD - entered."); ModState.Reset(); VisibilityCacheGate.Reset(); }
public static PilotDef UpgradeRonin(StarSystem starSystem, PilotDef baseRoninDef) { CrewDetails details = ReadRoninTags(baseRoninDef); ModState.UpdateOrCreateCrewDetails(baseRoninDef, details); return(baseRoninDef); }
/// <summary> /// Contains information about a loaded in mod. /// </summary> /// <param name="state">The current state of the mod.</param> /// <param name="modConfig">The current mod configuration.</param> /// <param name="canSuspend">Whether the mod can be suspended.</param> /// <param name="canUnload">Whether the mod can be reloaded.</param> public ModInfo(ModState state, IModConfig modConfig, bool canSuspend, bool canUnload) { State = state; Config = modConfig; CanSuspend = canSuspend; CanUnload = canUnload; }
static bool Prefix(SimGameState __instance, PilotDef def, ref int __result) { CrewDetails details = ModState.GetCrewDetails(def); __result = details != null ? details.Salary : 0; return(false); }
private void NeedUpdate() { ModState.SaveState(); if (Session.Instance.MpActive) { ModState.NetworkUpdate(); } }
public override void OnNewGameCreated(Game game, object obj) { if (game.GameType is Campaign) { ModState.Reset(); TournamentBuilder.CreateInitialTournaments(); } }