public static void PlayVFX(AIMCritInfo info) { try { ICombatant target = info.target; if (target.GameRep == null) { return; } MechComponent component = info.component; bool isAmmo = component is AmmunitionBox, isJumpJet = component is Jumpjet, isHeatSink = component.componentDef is HeatSinkDef; if (target.team.LocalPlayerControlsTeam) { AudioEventManager.PlayAudioEvent("audioeventdef_musictriggers_combat", "critical_hit_friendly ", null, null); } else if (!target.team.IsFriendly(Combat.LocalPlayerTeam)) { AudioEventManager.PlayAudioEvent("audioeventdef_musictriggers_combat", "critical_hit_enemy", null, null); } if (target.GameRep is MechRepresentation MechRep && !isJumpJet && !isHeatSink && !isAmmo && component.DamageLevel > ComponentDamageLevel.Functional) { MechRep.PlayComponentCritVFX(info.GetCritLocation()); } if (isAmmo && component.DamageLevel > ComponentDamageLevel.Functional) { target.GameRep.PlayVFX(info.GetCritLocation(), Combat.Constants.VFXNames.componentDestruction_AmmoExplosion, true, Vector3.zero, true, -1f); } } catch (Exception ex) { Error(ex); } }
public static void Prefix(Turret __instance) { try { if (__instance.Combat.IsLoadingFromSave) { return; } var turret = __instance; var num = __instance.allComponents.Select(x => int.Parse(x.uid)).DefaultIfEmpty().Max(); foreach (var componentRef in turret.TurretDef.Inventory) { if (componentRef.ComponentDefType == ComponentType.Weapon) { } else if (componentRef.ComponentDefType == ComponentType.AmmunitionBox) { } else { num++; var component = new MechComponent(turret, turret.Combat, componentRef, num.ToString()); turret.allComponents.Add(component); } } } catch (Exception e) { Control.mod.Logger.LogError(e); } }
public static int GetEngineModifier(AbstractActor actor) { int engineMod = 0; if (actor.GetTags().Contains("unit_powerarmor")) { Mod.Log.Debug($" Actor:{actor.DisplayName}_{actor.GetPilot().Name} is PowerArmor, skipping engine bonus."); } else { MechComponent mainEngineComponent = actor?.allComponents?.FirstOrDefault(c => c?.componentDef?.GetComponent <EngineCoreDef>() != null); if (mainEngineComponent != null) { EngineCoreDef engine = mainEngineComponent?.componentDef?.GetComponent <EngineCoreDef>(); float tonnage = GetUnitTonnage(actor); engineMod = CalculateEngineModifier(tonnage, engine.Rating); Mod.Log.Debug($" Actor:{actor.DisplayName}_{actor.GetPilot().Name} with engine rating: {engine?.Rating} has engineMod:{engineMod}"); } else { Mod.Log.Info($" Actor:{actor.DisplayName}_{actor.GetPilot().Name} has no engine - is this expected?"); } } return(engineMod); }
public static void CancelCreatedEffects(MechComponent mechComponent, bool performAuraRefresh = true) { if (mechComponent.DamageLevel >= ComponentDamageLevel.NonFunctional) { mechComponent.CancelCreatedEffects(performAuraRefresh); } }
internal static bool ProcessLocationalEffectData(ref EffectData effect, MechComponent mechComponent) { if (effect.effectType == EffectType.StatisticEffect && LocationNaming.IsLocational(effect.Description.Id) && LocationNaming.Create(mechComponent, out var naming)) { var data = effect.ToJSON(); effect = new EffectData(); effect.FromJSON(data); Control.mod.Logger.LogDebug($"Replacing location in {effect.Description.Id} with {naming.LocationId}"); effect.statisticData.statName = naming.InterpolateStatisticName(effect.statisticData.statName); effect.Description = new BaseDescriptionDef( naming.InterpolateEffectId(effect.Description.Id), naming.InterpolateText(effect.Description.Name), naming.InterpolateText(effect.Description.Details), naming.InterpolateText(effect.Description.Icon) ); return(true); } return(false); }
internal static int CriticalSlotsHitLinked(this MechComponent mechComponent, int?setHits = null) { var ce = mechComponent.GetCriticalEffects(); if (ce == null) { throw new Exception("should not happen"); } if (!ce.HasLinked) { throw new Exception("shouldn't really happen too"); } var statisticName = mechComponent.ScopedId(ce.LinkedStatisticName, true); var collection = mechComponent.parent.StatCollection; var critStat = collection.GetStatistic(statisticName) ?? collection.AddStatistic(statisticName, 0); if (setHits.HasValue) { critStat.SetValue(setHits.Value); } return(critStat?.Value <int>() ?? 0); }
static public List <ComponentLocator> GetWeaponComponentLocatorList(Mech m) { List <ComponentLocator> compLocList = new List <ComponentLocator>(); foreach (ChassisLocations loc in System.Enum.GetValues(typeof(ChassisLocations))) { if ((loc == ChassisLocations.All) || (loc == ChassisLocations.Arms) || (loc == ChassisLocations.Legs) || (loc == ChassisLocations.Torso) || (loc == ChassisLocations.None)) { continue; } int inventorySlotsCount = m.MechDef.GetChassisLocationDef(loc).InventorySlots; if (inventorySlotsCount == 0) { continue; } for (int slotIndex = 0; slotIndex < inventorySlotsCount; ++slotIndex) { MechComponent component = m.GetComponentInSlot(loc, slotIndex); if (component is Weapon) { ComponentLocator compLoc = new ComponentLocator(m, loc, slotIndex); compLocList.Add(compLoc); } } } return(compLocList); }
public static bool ResolveSystemFailureCheck(Mech mech, int heatToCheck, int rootSequenceGUID, float heatCheck) { bool failedSystemFailureCheck = !CheckHelper.DidCheckPassThreshold(Mod.Config.Heat.SystemFailures, heatToCheck, mech, heatCheck, ModText.FT_Check_System_Failure); Mod.Log.Debug?.Write($" failedSystemFailureCheck: {failedSystemFailureCheck}"); if (failedSystemFailureCheck) { Mod.Log.Info?.Write($"-- System Failure check failed, forcing system damage on unit: {CombatantUtils.Label(mech)}"); List <MechComponent> functionalComponents = new List <MechComponent>(); foreach (MechComponent mc in mech.allComponents) { bool canTarget = mc.IsFunctional; if (mc.mechComponentRef.Is <Flags>(out Flags flagsCC)) { if (flagsCC.IsSet(ModStats.ME_IgnoreDamage)) { canTarget = false; Mod.Log.Trace?.Write($" Component: {mc.Name} / {mc.UIName} is marked ignores_damage."); } } if (canTarget) { functionalComponents.Add(mc); } } MechComponent componentToDamage = functionalComponents.GetRandomElement(); Mod.Log.Info?.Write($" Destroying component: {componentToDamage.UIName} from heat damage."); WeaponHitInfo fakeHit = new WeaponHitInfo(rootSequenceGUID, -1, -1, -1, string.Empty, string.Empty, -1, null, null, null, null, null, null, null, new AttackDirection[] { AttackDirection.None }, null, null, null); componentToDamage.DamageComponent(fakeHit, ComponentDamageLevel.Destroyed, true); } return(failedSystemFailureCheck); }
static Dictionary <ComponentLocator, float> getComponentDictionary(Mech targetMech, ChassisLocations chassisLoc) { Dictionary <ComponentLocator, float> componentDict = new Dictionary <ComponentLocator, float>(); int inventorySlotsCount = targetMech.MechDef.GetChassisLocationDef(chassisLoc).InventorySlots; if (inventorySlotsCount == 0) { return(componentDict); } float slotProbability = 1.0f / inventorySlotsCount; for (int slotIndex = 0; slotIndex < inventorySlotsCount; ++slotIndex) { MechComponent component = targetMech.GetComponentInSlot(chassisLoc, slotIndex); if (component != null) { ComponentLocator compLoc = new ComponentLocator(targetMech, chassisLoc, slotIndex); componentDict[compLoc] = slotProbability; } } return(componentDict); }
public static void Postfix(MechComponent __instance, ref Text __result) { try { if (!__instance.IsFunctional || __instance.GetType() != typeof(Weapon)) { return; } Weapon weapon = (Weapon)__instance; if (IsJammed(weapon)) { string originalUIName = __result.ToString(); Color color = LazySingletonBehavior <UIManager> .Instance.UIColorRefs.orangeHalf; __result = new Localize.Text($"<color=#{ColorUtility.ToHtmlStringRGBA(color)}>{originalUIName}</color>", new object[] { }); //string weaponCaliber = new String(originalUIName.Where(Char.IsDigit).ToArray()); //__result = new Localize.Text($"JAMMED <size=75%>(UAC/{weaponCaliber})</size>", new object[] { }); //__result.Append(" <size=75%>( JAMMED )</size>", new object[0]); //__result = new Localize.Text("UAC JAMMED", new object[] { }); } } catch (Exception e) { Logger.Error(e); } }
// crit engine reduces speed // destroyed engine destroys CT public static bool Prefix(MechComponent __instance, CombatGameState ___combat, WeaponHitInfo hitInfo, ComponentDamageLevel damageLevel, bool applyEffects) { try { if (__instance.mechComponentRef.Is <Flags>(out var f) && f.IsSet("ignore_damage")) { MechCheckForCritPatch.Message = null; return(false); } if (!CirticalHitStatesHandler.Shared.ProcessWeaponHit(__instance, ___combat, hitInfo, damageLevel, applyEffects, MechCheckForCritPatch.MessageAdditions)) { MechCheckForCritPatch.Message = null; return(false); } if (!EngineCrits.ProcessWeaponHit(__instance, hitInfo, damageLevel, applyEffects, MechCheckForCritPatch.MessageAdditions)) { MechCheckForCritPatch.Message = null; return(false); } } catch (Exception e) { Control.mod.Logger.LogError(e); } return(true); }
/*public static bool ShouldAffectThisActor(this AuraCache instance, AbstractActor fromActor, EffectData effect, EffectTriggerType triggerSource) { * return (bool)mShouldAffectThisActor.Invoke(instance, new object[] { fromActor, effect, triggerSource }); * } * public static bool AuraConditionsPassed(this AuraCache instance, AbstractActor fromActor, MechComponent auraComponent, EffectData effectData, float distSquared, EffectTriggerType triggerSource) { * return (bool)mAuraConditionsPassed.Invoke(instance, new object[] { fromActor, auraComponent, effectData, distSquared, triggerSource }); * }*/ public static bool Prefix(AuraCache __instance, AbstractActor fromActor, MechComponent auraComponent, float distSquared, ref List <EffectData> __result) { /*AbstractActor Owner = (AbstractActor)FOwner.Invoke(__instance, new object[0] { }); * List<EffectData> effectDataList = new List<EffectData>(); * for (int index = 0; index < auraComponent.componentDef.statusEffects.Length; ++index) { * if (__instance.ShouldAffectThisActor(fromActor, auraComponent.componentDef.statusEffects[index], EffectTriggerType.Preview) && __instance.AuraConditionsPassed(fromActor, auraComponent, auraComponent.componentDef.statusEffects[index], distSquared, EffectTriggerType.Preview)) * effectDataList.Add(auraComponent.componentDef.statusEffects[index]); * } * ActivatableComponent activatable = auraComponent.componentDef.GetComponent<ActivatableComponent>(); * if (activatable != null) { * if (auraComponent.isActive()) { * for (int index = 0; index < activatable.statusEffects.Length; ++index) { * if (__instance.ShouldAffectThisActor(fromActor, activatable.statusEffects[index], EffectTriggerType.Preview) && __instance.AuraConditionsPassed(fromActor, auraComponent, activatable.statusEffects[index], distSquared, EffectTriggerType.Preview)) * effectDataList.Add(activatable.statusEffects[index]); * } * } else { * for (int index = 0; index < activatable.offlineStatusEffects.Length; ++index) { * if (__instance.ShouldAffectThisActor(fromActor, activatable.offlineStatusEffects[index], EffectTriggerType.Preview) && __instance.AuraConditionsPassed(fromActor, auraComponent, activatable.offlineStatusEffects[index], distSquared, EffectTriggerType.Preview)) * effectDataList.Add(activatable.offlineStatusEffects[index]); * } * } * } * __result = effectDataList;*/ return(false); //Log.LogWrite("AuraCache.PreviewAura prefix owner:" + Owner.DisplayName + ":" + Owner.GUID + " from: " + fromActor.DisplayName + ":" + fromActor.GUID + " component:" + auraComponent.defId + "\n"); }
private static MechComponent FindAndCritComponent(AIMCritInfo critInfo, float random) { MechComponent component = critInfo.FindComponentFromRoll(random); if (component != null) { if (DebugLog) { Verbo("Play crit SFX and VFX on {0} ({1}) at {2}", component, component.DamageLevel, component.Location); } PlaySFX(critInfo); PlayVFX(critInfo); AttackDirector.AttackSequence attackSequence = GetAttackSequence(critInfo.hitInfo); attackSequence?.FlagAttackScoredCrit(component as Weapon, component as AmmunitionBox); ComponentDamageLevel newDamageLevel = GetDegradedComponentLevel(critInfo); if (DebugLog) { Verbo("Component damaged to {0}", newDamageLevel); } try { component.DamageComponent(critInfo.hitInfo, newDamageLevel, true); } catch (Exception ex) { Error(ex); } } return(component); }
// crit engine reduces speed // destroyed engine destroys CT public static bool Prefix(MechComponent __instance, WeaponHitInfo hitInfo, ComponentDamageLevel damageLevel, bool applyEffects) { try { if (!EngineCrits.ProcessWeaponHit(__instance, hitInfo, damageLevel, applyEffects, MechCheckForCritPatch.MessageAdditions)) { MechCheckForCritPatch.Message = null; return(false); } if (!Structure.ProcessWeaponHit(__instance, hitInfo, damageLevel, applyEffects)) { MechCheckForCritPatch.Message = null; return(false); } if (!Armor.ProcessWeaponHit(__instance, hitInfo, damageLevel, applyEffects)) { MechCheckForCritPatch.Message = null; return(false); } } catch (Exception e) { Control.mod.Logger.LogError(e); } return(true); }
public static bool CanBeActivated(this MechComponent component) { ActivatableComponent activatable = component.componentDef.GetComponent <ActivatableComponent>(); if (component.DamageLevel >= ComponentDamageLevel.Destroyed) { return(false); } if (activatable == null) { return(false); } ; if (activatable.CanBeactivatedManualy == false) { return(false); } if (activatable.ChargesCount == -1) { return(true); } ; if (activatable.ChargesCount > 0) { if (activatable.ChargesCount <= component.ChargesCount()) { return(false); } ; } ; return(true); }
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 bool isFailDanger(this MechComponent component) { ActivatableComponent activatable = component.componentDef.GetComponent <ActivatableComponent>(); Mech mech = component.parent as Mech; if (activatable.FailCrit && component.isExplode()) { return(true); } ; if (mech == null) { return(false); } foreach (var Location in activatable.FailDamageLocations) { if (mech != null) { foreach (var lcomp in mech.GetComponentsForLocation(Location, ComponentType.AmmunitionBox)) { return(true); } } if (component.parent.StructureForLocation((int)Location) < activatable.FailISDamage) { return(true); } } return(false); }
internal static float LogAIMCritChance(float chance, object hitLocation) { thisCritChance = chance; thisCritLocation = hitLocation.ToString(); thisCritComp = null; return(chance); }
private static TagSet prepareTags(MechComponent target) { //Control.Log($"Prepating tags for "+target.defId); string GUID = target.getCCGUID(); TagSet tags = null; if (CustomCombatTagsHelper.tagsCache.ContainsKey(GUID) == false) { //Control.Log($" not in cache"); if (CustomCombatTagsHelper.checkExistance(target.StatCollection, CustomCombatTagsHelper.CCComponentTagsStatName) == false) { //Control.Log($" have no statistic value:"+ CustomCombatTagsHelper.CCComponentTagsStatName); tags = new TagSet(); tags.AddRange(target.componentDef.ComponentTags); } else { string tags_string = target.StatCollection.GetStatistic(CustomCombatTagsHelper.CCComponentTagsStatName).Value <string>(); tags = TagSet.Parse(tags_string); //Control.Log($" have statistic value:" + CustomCombatTagsHelper.CCComponentTagsStatName+":"+tags_string); } CustomCombatTagsHelper.tagsCache[GUID] = tags; } else { //Control.Log($" in cache"); tags = CustomCombatTagsHelper.tagsCache[GUID]; } return(tags); }
public static void RestartPassiveEffects(this MechComponent @this, bool performAuraRefresh) { if (HeatSinkCapacityStatFeature.Shared.IgnoreShutdown(@this)) { return; } @this.RestartPassiveEffects(performAuraRefresh); }
public static bool setAIRollPassed(this MechComponent component, bool val) { if (Core.checkExistance(component.StatCollection, AIRollPassStatName) == false) { component.StatCollection.AddStatistic <bool>(AIRollPassStatName, false); } return(component.StatCollection.Set <bool>(AIRollPassStatName, val)); }
public static bool isAIRollPassed(this MechComponent component) { if (Core.checkExistance(component.StatCollection, AIRollPassStatName) == false) { component.StatCollection.AddStatistic <bool>(AIRollPassStatName, false); } return(component.StatCollection.GetStatistic(AIRollPassStatName).Value <bool>()); }
public static void playDestroySound(this MechComponent component) { ActivatableComponent activatable = component.componentDef.GetComponent <ActivatableComponent>(); if (activatable != null) { activatable.playDestroySound(component.parent.GameRep.audioObject); } }
private float getHeatMult(MechComponent mechComponent) { if (mechComponent.componentDef.Is <HeatSinkingCost>(out var costFactor)) { return(costFactor.HeatUpkeepMult); } return(1f); }
public VFXObjects(MechComponent p) { this.parent = p; ActivatableComponent activatable = this.parent.componentDef.GetComponent <ActivatableComponent>(); if (activatable != null) { GameObject parentObject = p.parent.GameRep.gameObject; Weapon weapon = p as Weapon; if (weapon != null) { if (weapon.weaponRep != null) { parentObject = weapon.weaponRep.gameObject; } } Log.LogWrite(p.defId + " is activatable \n"); if (activatable.presistantVFX.isInited) { try { Log.LogWrite(p.defId + " spawning " + activatable.presistantVFX.VFXPrefab + " \n"); presitantObject = new ObjectSpawnDataSelf(activatable.presistantVFX.VFXPrefab, parentObject, new Vector3(activatable.presistantVFX.VFXOffsetX, activatable.presistantVFX.VFXOffsetY, activatable.presistantVFX.VFXOffsetZ), new Vector3(activatable.presistantVFX.VFXScaleX, activatable.presistantVFX.VFXScaleY, activatable.presistantVFX.VFXScaleZ), true, false); presitantObject.SpawnSelf(parent.parent.Combat); } catch (Exception e) { Log.LogWrite(" Fail to spawn vfx " + e.ToString() + "\n"); } } else { presitantObject = null; } if (activatable.activateVFX.isInited) { Log.LogWrite(p.defId + " spawning " + activatable.activateVFX.VFXPrefab + " \n"); activateObject = new ObjectSpawnDataSelf(activatable.activateVFX.VFXPrefab, parentObject, new Vector3(activatable.activateVFX.VFXOffsetX, activatable.activateVFX.VFXOffsetY, activatable.activateVFX.VFXOffsetZ), new Vector3(activatable.activateVFX.VFXScaleX, activatable.activateVFX.VFXScaleY, activatable.activateVFX.VFXScaleZ), true, false); } else { activateObject = null; } if (activatable.destroyedVFX.isInited) { Log.LogWrite(p.defId + " spawning " + activatable.destroyedVFX.VFXPrefab + " \n"); destroyedObject = new ObjectSpawnDataSelf(activatable.destroyedVFX.VFXPrefab, parentObject, new Vector3(activatable.destroyedVFX.VFXOffsetX, activatable.destroyedVFX.VFXOffsetY, activatable.destroyedVFX.VFXOffsetZ), new Vector3(activatable.destroyedVFX.VFXScaleX, activatable.destroyedVFX.VFXScaleY, activatable.destroyedVFX.VFXScaleZ), true, false); } else { destroyedObject = null; } } }
public static int OverrideLocation(this MechComponent component) { if (component.componentDef.IsIgnoreDamage()) { return(0); } return(component.Location); }
private static void SetDamageLevel(MechComponent mechComponent, WeaponHitInfo hitInfo, ComponentDamageLevel damageLevel) { mechComponent.StatCollection.ModifyStat( hitInfo.attackerId, hitInfo.stackItemUID, "DamageLevel", StatCollection.StatOperation.Set, damageLevel); }
internal static bool ProcessWeaponHit(MechComponent mechComponent, WeaponHitInfo hitInfo, ComponentDamageLevel damageLevel, bool applyEffects) { if (mechComponent.componentDef.IsStructure()) { return(false); } return(true); }
public static void PublishComponentState(MechComponent mechComponent) { if (mechComponent.DamageLevel == ComponentDamageLevel.Penalized) { var critMessage = new Text("{0} CRIT", mechComponent.UIName); var ce = mechComponent.GetCriticalEffects(); if (ce?.CritFloatieMessage != null) { if (ce.CritFloatieMessage == "") { return; } critMessage = new Text(ce.CritFloatieMessage); } mechComponent.PublishMessage( critMessage, FloatieMessage.MessageNature.CriticalHit ); } else if (mechComponent.DamageLevel == ComponentDamageLevel.Destroyed) { // dont show destroyed if a mech is known to be incapacitated var actor = mechComponent.parent; if (actor.IsDead || actor.IsFlaggedForDeath) { return; } // dont show destroyed if a whole section was destroyed, counters spam //if (actor is Mech mech) //{ // var location = mechComponent.mechComponentRef.MountedLocation; // var mechLocationDestroyed = mech.IsLocationDestroyed(location); // if (mechLocationDestroyed) // { // return; // } //} var destroyedMessage = new Text("{0} DESTROYED", mechComponent.UIName); var ce = mechComponent.GetCriticalEffects(); if (ce?.DestroyedFloatieMessage != null) { if (ce.DestroyedFloatieMessage == "") { return; } destroyedMessage = new Text(ce.DestroyedFloatieMessage); } mechComponent.PublishMessage( destroyedMessage, FloatieMessage.MessageNature.ComponentDestroyed ); } }
public static bool CheckForCrit(AIMCritInfo info, int hitLocation, bool logCrit) { try { if (info?.weapon == null) { return(true); } info.SetHitLocation(hitLocation); AbstractActor target = info.target; if (SkipCritingDeadMech && IsBeatingDeadMech(target)) { return(false); } float chance = info.GetCritChance(); for (int i = 1; chance > 0; i++) { float critRoll = Combat.NetworkRandom.Float(); // If use original code AttackDirector.GetRandomFromCache( info.hitInfo, 2 ), may run out of rolls if (DebugLog) { Verbo("Crit {3} roll {0} <= chance {1}? {2}", critRoll, chance, critRoll <= chance, i); } if (i == 1) { AttackLog.LogAIMCritRoll(critRoll); } if (critRoll > chance) { break; } float slotRoll = Combat.NetworkRandom.Float(); if (AttackLog.thisCritComp == null) { AttackLog.LogAIMSlotRoll(slotRoll); } MechComponent component = FindAndCritComponent(info, slotRoll); if (i > 1) { Verbo("Crit x{0} on location {1} of {2} by {3}. Roll {4} <= Chance {5}. Crit'ed {6}", i, component?.Location ?? hitLocation, info.target, info.weapon, critRoll, chance, component?.UIName.ToString() ?? "(None)"); } if (logCrit) { AttackLog.LogCritResult(target, info.weapon); logCrit = false; } if (!Settings.MultipleCrits) { break; } chance -= critRoll; } PostCheckForCrit(info, logCrit); } catch (Exception ex) { Error(ex); } return(false); }