void buildMech(Mech m) { string[] parts = new string[9]{ m.Core, m.Arms, m.Legs, m.Head, m.Booster, m.Weapon1L, m.Weapon1R, m.Weapon2L, m.Weapon2R }; // Create new array to store skinned mesh renderers SkinnedMeshRenderer[] newSMR = new SkinnedMeshRenderer[5]; Material[] materials = new Material[5]; for (int i = 0; i < 5; i++) { // Load mech part GameObject part = Resources.Load (parts [i], typeof(GameObject)) as GameObject; // Extract Skinned Mesh newSMR [i] = part.GetComponentInChildren<SkinnedMeshRenderer> () as SkinnedMeshRenderer; // Load texture materials [i] = Resources.Load (parts [i] + "mat", typeof(Material)) as Material; } // Replace all SkinnedMeshRenderer[] curSMR = GetComponentsInChildren<SkinnedMeshRenderer> (); for (int i = 0; i < curSMR.Length; i++){ curSMR[i].sharedMesh = newSMR[i].sharedMesh; curSMR[i].material = materials[i]; curSMR[i].enabled = true; } // Make weapons buildWeapons (new string[4]{parts[5],parts[6],parts[7],parts[8]}); }
public BaseMech(Mech mech) { MechName = mech.Name; MechAttack = mech.Attack; MechDefense = mech.Defense; MechWeight = mech.Weight; WeightClass = AssignMechWeightClass(mech.Weight); Faction = mech.Faction; }
public void enact(Mech mech) { switch (type) { case ActionTypes.Idle: { } break; case ActionTypes.Attack: { } break; case ActionTypes.Hide: { } break; case ActionTypes.Evade: { } break; case ActionTypes.Flee: { } break; case ActionTypes.Shield: { // do actions } break; case ActionTypes.EMP: { // do actions } break; case ActionTypes.Charge: { // do actions } break; case ActionTypes.Dodge: { } break; case ActionTypes.Collect: { // do actions } break; case ActionTypes.Defend: { // do actions } break; case ActionTypes.Destroy: { // do actions } break; case ActionTypes.Move: { // do actions } break; default: { // do nothing } break; } }
public void addMechtoMechTable(string name, int attack, int defense, int weight, string faction, string range, string speed, string pilot, int mechgroupid) { Mech newMech = new Mech(); newMech.Name = name; newMech.Faction = faction; newMech.Attack = attack; newMech.Defense = defense; newMech.Weight = weight; newMech.Range = range; newMech.Speed = speed; newMech.Pilot = pilot; newMech.MechGroupId = mechgroupid; entities.Mechs.Add(newMech); entities.SaveChanges(); }
/// <summary> /// Even though a projectile is instantiated, it won't begin doining anything /// until the owning mech launches it. This establishes ownership, etc. /// </summary> /// <param name="ownerMech"></param> /// <param name="weaponIdx"></param> public void Launch(Mech ownerMech, int weaponIdx, Vector3 position, Quaternion rotation) { #if DEBUG_PROJECTILE Debug.Log(string.Format("Projectile from Weapon: {0} has launched!", WeaponIndex)); #endif Owner = ownerMech; WeaponIndex = weaponIdx; OwnerWeapon = Owner.GetWeapon(WeaponIndex); transform.position = position; transform.rotation = rotation; IsHit = false; PayloadDelivered = false; DistTraveled = 0.0f; DespawnTimer = 0.0f; Launched = true; }
private static float CalculateCheckMod(Mech mech, float multi, bool gutsSkill) { int rawSkill = gutsSkill ? mech.SkillGuts : mech.SkillPiloting; int actorSkill = SkillUtils.NormalizeSkill(rawSkill); Mod.Log.Debug?.Write($"Actor: {CombatantUtils.Label(mech)} has rawSkill: {actorSkill} normalized to {actorSkill}"); int malus = 0; if (!gutsSkill) { // Piloting checks must use damage malus malus += mech.ActuatorDamageMalus(); } float adjustedSkill = actorSkill - malus > 0f ? actorSkill - malus : 0f; Mod.Log.Info?.Write($" AdjustedSkill: {adjustedSkill} = actorSkill: {actorSkill} - malus: {malus}."); float checkMod = adjustedSkill * multi; Mod.Log.Info?.Write($" CheckMod: {checkMod} = adjustedSkill: {adjustedSkill} * multi: {multi}"); return(checkMod); }
public void TestPunchDamage_TargetDamageStat_UndamagedAttacker() { // Test override stat Mech attacker50 = TestHelper.BuildTestMech(tonnage: 50); ActorMeleeCondition attackerCondition50 = TestHelper.AllEnabledCondition(attacker50); ModState.meleeConditionCache[attacker50.DistinctId()] = attackerCondition50; attacker50.StatCollection.AddStatistic <float>(ModStats.PunchTargetDamage, 2f); Assert.AreEqual(100, attacker50.PunchDamage()); // Test override stat @ 0; should default to ModValue Mod.Config.Melee.Punch.TargetDamagePerAttackerTon = 3.0f; attacker50.StatCollection.Set <float>(ModStats.PunchTargetDamage, 0); Assert.AreEqual(150, attacker50.PunchDamage()); // Test override stat @ negatives; should default to modValue Mod.Config.Melee.Punch.TargetDamagePerAttackerTon = 4.0f; attacker50.StatCollection.Set <float>(ModStats.PunchTargetDamage, -20); Assert.AreEqual(200, attacker50.PunchDamage()); // Reset for other tests Mod.Config.Melee.Punch.TargetDamagePerAttackerTon = 0.5f; }
public static void Prefix(Mech __instance) { try { if (!Control.settings.HeatDamageInjuryEnabled) { return; } var mech = __instance; if (!mech.IsOverheated) { return; } if (mech.StatCollection.ReceiveHeatDamageInjury()) { mech.pilot?.SetNeedsInjury(InjuryReason.NotSet); } } catch (Exception e) { Control.mod.Logger.LogError(e); } }
static Weapon FindWeaponToHitTarget(AbstractActor attacker, List <Weapon> weaponList, ICombatant target) { Mech targetMech = target as Mech; bool targetIsEvasive = ((targetMech != null) && (targetMech.IsEvasive)); for (int wi = 0; wi < weaponList.Count; ++wi) { Weapon w = weaponList[wi]; if (!attacker.Combat.LOFCache.UnitHasLOFToTargetAtTargetPosition( attacker, target, w.MaxRange, attacker.CurrentPosition, attacker.CurrentRotation, target.CurrentPosition, target.CurrentRotation, w.IndirectFireCapable)) { continue; } float dmg = GetExpectedDamageForMultiTargetWeapon(attacker, attacker.CurrentPosition, target, target.CurrentPosition, targetIsEvasive, w, attacker.MaxTargets); if (dmg > 0) { return(w); } } return(null); }
public void TestMimetic_AttackMod_NoDecay_Pinged_ProbeCarrier() { Mech attacker = TestHelper.BuildTestMech(); Mech target = TestHelper.BuildTestMech(); target.CurrentPosition = new Vector3(0f, 0, 0); Traverse previousPositionT = Traverse.Create(target).Field("previousPosition"); previousPositionT.SetValue(new Vector3(0f, 0f, 0f)); attacker.StatCollection.AddStatistic <float>("SpotterDistanceMultiplier", 1f); attacker.StatCollection.AddStatistic <float>("SpotterDistanceAbsolute", 0f); attacker.StatCollection.Set(ModStats.ProbeCarrier, 3); target.StatCollection.AddStatistic <float>("SpottingVisibilityMultiplier", 1f); target.StatCollection.AddStatistic <float>("SpottingVisibilityAbsolute", 0f); target.StatCollection.Set(ModStats.MimeticEffect, "4_0.10_1_2"); target.StatCollection.Set(ModStats.PingedByProbe, 2); EWState attackerState = new EWState(attacker); EWState targetState = new EWState(target); Assert.AreEqual(0, targetState.MimeticAttackMod(attackerState)); }
public static void Postfix(Mech __instance, ChassisLocations location, float damage, WeaponHitInfo hitInfo) { Mod.Log.Trace?.Write("M:ASSD - entered."); if (ModState.BreachCheck == 0f || ModState.BreachAttackId == ModState.NO_ATTACK_SEQUENCE_ID) { return; } // nothing to do if (hitInfo.attackSequenceId != ModState.BreachAttackId) { Mod.Log.Warn?.Write($"AttackSequenceId: {hitInfo.attackSequenceId} does not match hull breach attack sequence id: {ModState.BreachAttackId}... wasn't expecting this, skipping!"); return; } Mod.Log.Debug?.Write($" --- Location: {location} needs breach check."); if (ModState.BreachHitsMech.ContainsKey(location)) { ModState.BreachHitsMech[location]++; } else { ModState.BreachHitsMech.Add(location, 1); } }
public static void Prefix(Mech __instance) { try { if (!ShutdownInjuryProtectionFeature.settings.HeatDamageInjuryEnabled) { return; } var mech = __instance; if (!mech.IsOverheated) { return; } if (mech.StatCollection.ReceiveHeatDamageInjury().Get()) { mech.pilot?.SetNeedsInjury(Pilot_InjuryReasonDescription_Patch.InjuryReasonOverheated); } } catch (Exception e) { Control.Logger.Error.Log(e); } }
private static void Postfix(Mech __instance) { var mech = __instance; if (!modSettings.LosingLimbAlwaysPanics || mech == null || mech.IsDead || mech.IsFlaggedForDeath && mech.HasHandledDeath) { return; } var index = GetPilotIndex(mech); if (trackedPilots[index].mech != mech.GUID) { return; } if (trackedPilots[index].panicWorsenedRecently && modSettings.OneChangePerTurn) { return; } ApplyPanicDebuff(mech); }
private void CalculateModifiers(Mech attacker, AbstractActor target) { // If target is prone, -2 modifier if (target.IsProne) { this.AttackModifiers.Add(ModText.LT_Label_Target_Prone, Mod.Config.Melee.ProneTargetAttackModifier); } // +2 to hit for each upper/lower actuator hit ActorMeleeCondition attackerCondition = ModState.GetMeleeCondition(attacker); int leftArmMalus = (2 - attackerCondition.LeftArmActuatorsCount) * Mod.Config.Melee.Punch.ArmActuatorDamageMalus; int rightArmMalus = (2 - attackerCondition.RightArmActuatorsCount) * Mod.Config.Melee.Punch.ArmActuatorDamageMalus; int bestMalus = leftArmMalus <= rightArmMalus ? leftArmMalus : rightArmMalus; // If the ignore actuators stat is set, set the malus to 0 regardless of damage Statistic ignoreActuatorsStat = attacker.StatCollection.GetStatistic(ModStats.PhysicalWeaponIgnoreActuators); if (ignoreActuatorsStat != null && ignoreActuatorsStat.Value <bool>()) { bestMalus = 0; } // Add actuator damage if it exists if (bestMalus != 0) { this.AttackModifiers.Add(ModText.LT_Label_Actuator_Damage, bestMalus); } // Check for attack modifier statistic Statistic phyWeapAttackMod = attacker.StatCollection.GetStatistic(ModStats.PhysicalWeaponAttackMod); if (phyWeapAttackMod != null && phyWeapAttackMod.Value <int>() != 0) { this.AttackModifiers.Add(ModText.LT_Label_Physical_Weapon_Attack_Mod, attacker.StatCollection.GetValue <int>(ModStats.PhysicalWeaponAttackMod)); } }
void buildMech(Mech m) { string[] parts = new string[9] { m.Core, m.Arms, m.Legs, m.Head, m.Booster, m.Weapon1L, m.Weapon1R, m.Weapon2L, m.Weapon2R }; // Create new array to store skinned mesh renderers SkinnedMeshRenderer[] newSMR = new SkinnedMeshRenderer[5]; Material[] materials = new Material[5]; for (int i = 0; i < 5; i++) { // Load mech part GameObject part = Resources.Load(parts [i], typeof(GameObject)) as GameObject; // Extract Skinned Mesh newSMR [i] = part.GetComponentInChildren <SkinnedMeshRenderer> () as SkinnedMeshRenderer; // Load texture materials [i] = Resources.Load(parts [i] + "mat", typeof(Material)) as Material; } // Replace all SkinnedMeshRenderer[] curSMR = GetComponentsInChildren <SkinnedMeshRenderer> (); for (int i = 0; i < curSMR.Length; i++) { curSMR[i].sharedMesh = newSMR[i].sharedMesh; curSMR[i].material = materials[i]; curSMR[i].enabled = true; } // Make weapons buildWeapons(new string[4] { parts[5], parts[6], parts[7], parts[8] }); }
private static void Postfix(Mech __instance) { var mech = __instance; if (!modSettings.LosingLimbAlwaysPanics || mech == null || mech.IsDead || mech.IsFlaggedForDeath && mech.HasHandledDeath) { return; } var index = GetActorIndex(mech); if (TrackedActors[index].Guid != mech.GUID) { return; } if (TrackedActors[index].PanicWorsenedRecently && modSettings.OneChangePerTurn) { return; } TrackedActors[index].PanicStatus++; }
internal static float PercentForStructureLocation(Mech mech, int Location) { // Invalid locations are always 100% // This helps makes the functions generic for the missing leg back armor, for example if (Location == 0) { return(1); } if (mech != null) { Statistic stat = mech.StatCollection.GetStatistic(mech.GetStringForStructureLocation((ChassisLocations)Location)); if (stat == null) { LogDebug($"Can't get structure stat { mech.DisplayName } location:{ Location}"); return(0); } LogDebug($"Structure stat { mech.DisplayName } location:{ Location} cur:{stat.Value<float>()} max:{stat.DefaultValue<float>()}"); return(stat.Value <float>() / stat.DefaultValue <float>()); } LogDebug($"Mech null"); return(0); }
public float utility(Mech mech) { switch (type) { case ActionTypes.Idle: { return maxIdleValue; } case ActionTypes.Attack: { float best_utility = 0; // foreach (Mech enemy in ec.mechs) { // if ((enemy.transform.position - mech.transform.position).sqrMagnitude < mech.sensorRange * mech .sensorRange) { // var utility = compensatedScore(considerations.Select(cons => { // var con_utility = cons.utility(mech, enemy.transform); // // Debug.Log(enemy.name + " | " + cons.type + ": " + con_utility); // return con_utility; // })); // mech.target = (utility > best_utility) ? enemy.transform : mech.target; // best_utility = (utility > best_utility) ? utility : best_utility; // } // } // Debug.Log(mech.name + " | " + type + ": " + best_utility); return best_utility; } case ActionTypes.Hide: { var best_utility = 0; return best_utility; } case ActionTypes.Flee: { var best_utility = 0; return best_utility; } case ActionTypes.Shield: { var best_utility = 0; return best_utility; } case ActionTypes.EMP: { var best_utility = 0; return best_utility; } case ActionTypes.Charge: { var best_utility = 0; return best_utility; } case ActionTypes.Dodge: { var best_utility = 0; return best_utility; } case ActionTypes.Collect: { var best_utility = 0; return best_utility; } case ActionTypes.Defend: { var best_utility = 0; return best_utility; } case ActionTypes.Destroy: { var best_utility = 0; return best_utility; } case ActionTypes.Move: { var best_utility = 0; return best_utility; } default: { var best_utility = 0; return best_utility; } } }
public static void Postfix(Mech __instance) { Mod.Log.Trace("M:I entered."); __instance.StatCollection.AddStatistic <int>(ModStats.TurnsOverheated, 0); }
public static void Prefix(UnitSpawnPointGameLogic __instance, ref MechDef mDef, PilotDef pilot, Team team, Mech __result) { if (__instance.team == TeamDefinition.TargetsTeamDefinitionGuid) { if (ModState.AIGetsPlayerMechs) { var oldmDef = mDef; ModInit.modLog.LogMessage( $"AI UNIT: First mech in playerMechs was {ModState.playerMechs.First().mechDef.Name} with count {ModState.playerMechs.First().count}"); var playerMechVariants = ModState.playerMechs .Where(x => x.mechDef.Description.Id == oldmDef.Description.Id).OrderBy(x => x.count) .ToList(); ModInit.modLog.LogMessage( $"AI UNIT: Filtered to match mechdef IDs and reordered! First mech in playerMechVariants is now {playerMechVariants.First().mechDef.Name} with count {playerMechVariants.First().count}"); ModState.playerMechs.First().count += 1; var newMechDef = playerMechVariants.FirstOrDefault()?.mechDef; if (newMechDef != null) { newMechDef.DependenciesLoaded(1000U); mDef = newMechDef; } } } }
public static void ChooseBestWeaponForTarget(AbstractActor unit, ICombatant target, bool isStationary) { List <Weapon> ammoWeapons = new List <Weapon>(); foreach (Weapon weapon in unit.Weapons) { if (CustomAmmoCategories.isWeaponHasDiffirentAmmo(weapon) == true) { CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " has ammo to choose\n"); ammoWeapons.Add(weapon); } } if (ammoWeapons.Count == 0) { CustomAmmoCategoriesLog.Log.LogWrite(" None choosable ammo\n"); return; } ; if (target is Mech) { CustomAmmoCategoriesLog.Log.LogWrite(" Target is mech\n"); Mech targetMech = (target as Mech); List <Weapon> ammoHeatWeapons = new List <Weapon>(); foreach (Weapon weapon in ammoWeapons) { if (CustomAmmoCategories.isWeaponHasHeatAmmo(weapon) == true) { CustomAmmoCategories.switchToMostHeatAmmo(weapon); CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " has hit ammo\n"); ammoHeatWeapons.Add(weapon); } } float expectedHeat = CustomAmmoCategories.calcHeatCoeff(unit, target); CustomAmmoCategoriesLog.Log.LogWrite(" Expected heat " + expectedHeat + "\n"); if ((targetMech.CurrentHeat + expectedHeat) > targetMech.OverheatLevel) { foreach (Weapon weapon in ammoHeatWeapons) { CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " - ammo choosed\n"); ammoWeapons.Remove(weapon); } } List <int> hitLocations = targetMech.GetPossibleHitLocations(unit); List <Weapon> ammoClusterWeapon = new List <Weapon>(); foreach (Weapon weapon in ammoWeapons) { if (CustomAmmoCategories.isWeaponHasClusterAmmo(weapon)) { CustomAmmoCategories.switchToMostClusterAmmo(weapon); CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " has cluster ammo\n"); ammoClusterWeapon.Add(weapon); } } foreach (Weapon weapon in ammoClusterWeapon) { float toHit = 0f; if (weapon.parent.HasLOFToTargetUnit(target, weapon.MaxRange, CustomAmmoCategories.getIndirectFireCapable(weapon))) { toHit = weapon.GetToHitFromPosition(target, 1, unit.CurrentPosition, target.CurrentPosition, true, targetMech.IsEvasive, false); } if (toHit < 0.4f) { CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " cluster toHit is too low " + toHit + "\n"); continue; } if (CustomAmmoCategories.hasHittableLocations(weapon, hitLocations, targetMech) == true) { CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " can crit one of locations\n"); ammoWeapons.Remove(weapon); } } } AbstractActor targetActor = (target as AbstractActor); foreach (Weapon weapon in ammoWeapons) { List <string> avaibleAmmo = CustomAmmoCategories.getAvaibleEffectiveAmmo(weapon); if (avaibleAmmo.Count == 0) { continue; } ; CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " choose ammo default algorithm\n"); string bestAmmo = ""; float expectedDamage = 0; foreach (string ammoId in avaibleAmmo) { CustomAmmoCategories.SetWeaponAmmo(weapon, ammoId); float toHit = 0f; if (unit.HasLOFToTargetUnit(target, weapon.MaxRange, CustomAmmoCategories.getIndirectFireCapable(weapon))) { toHit = weapon.GetToHitFromPosition(target, 1, unit.CurrentPosition, target.CurrentPosition, true, (targetActor != null) ? targetActor.IsEvasive : false, false); } float nonClusterCoeff = 1f; int numberOfShots = weapon.ShotsWhenFired * weapon.ProjectilesPerShot; if ((toHit > 0.6f) && (numberOfShots == 1)) { nonClusterCoeff = 1.2f; } float tempExpectedDamage = numberOfShots * weapon.DamagePerShot * toHit * nonClusterCoeff; CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " toHit " + toHit + " expectedDamage:" + tempExpectedDamage + "\n"); if (tempExpectedDamage > expectedDamage) { expectedDamage = tempExpectedDamage; bestAmmo = ammoId; } } if (string.IsNullOrEmpty(bestAmmo) == false) { CustomAmmoCategories.SetWeaponAmmo(weapon, bestAmmo); CustomAmmoCategoriesLog.Log.LogWrite(" " + weapon.UIName + " best ammo choosed\n"); } } }
// Resolve mech hits - mark components invalid, but kill the pilot on a head-hit private static void ResolveMechHullBreaches(Mech targetMech) { bool needsQuip = false; foreach (ChassisLocations hitLocation in ModState.BreachHitsMech.Keys) { List <MechComponent> componentsInLocation = targetMech.allComponents.Where(mc => mc.mechComponentRef.DamageLevel == ComponentDamageLevel.Functional && mc.mechComponentRef.MountedLocation == hitLocation).ToList(); // Check for immunity in this location bool hasImmunity = false; foreach (MechComponent mc in componentsInLocation) { if (mc.StatCollection.ContainsStatistic(ModStats.HullBreachImmunity)) { Mod.Log.Debug($" Component: {mc.UIName} grants hull breach immunity, skipping!"); hasImmunity = true; break; } } if (hasImmunity) { continue; } // If no immunity, sum the breach check across all trials float passChance = 1f - ModState.BreachCheck; float sequencePassChance = Mathf.Pow(passChance, ModState.BreachHitsMech[hitLocation]); float sequenceThreshold = 1f - sequencePassChance; Mod.Log.Debug($" For pass chance: {passChance} with n trials: {ModState.BreachHitsMech[hitLocation]} has sequencePassChance: {sequencePassChance} => sequenceThreshold: {sequenceThreshold}"); // Check for failure bool passedCheck = CheckHelper.DidCheckPassThreshold(sequenceThreshold, targetMech, 0f, Mod.Config.LocalizedFloaties[ModConfig.FT_Hull_Breach]); Mod.Log.Debug($"Actor: {CombatantUtils.Label(targetMech)} HULL BREACH check: {passedCheck} for location: {hitLocation}"); if (!passedCheck) { string floatieText = new Text(Mod.Config.LocalizedFloaties[ModConfig.FT_Hull_Breach]).ToString(); MultiSequence showInfoSequence = new ShowActorInfoSequence(targetMech, floatieText, FloatieMessage.MessageNature.Debuff, false); targetMech.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(showInfoSequence)); needsQuip = true; if (hitLocation <= ChassisLocations.RightTorso) { switch (hitLocation) { case ChassisLocations.Head: Mod.Log.Debug($" Head structure damage taken, killing pilot!"); targetMech.GetPilot().KillPilot(targetMech.Combat.Constants, "", 0, DamageType.Enemy, null, null); break; case ChassisLocations.CenterTorso: default: if (hitLocation == ChassisLocations.CenterTorso) { Mod.Log.Debug($" Center Torso hull breach!"); } // Walk the location and disable every component in it foreach (MechComponent mc in componentsInLocation) { Mod.Log.Debug($" Marking component: {mc.defId} of type: {mc.componentDef.Description.Name} nonfunctional"); mc.DamageComponent(default(WeaponHitInfo), ComponentDamageLevel.NonFunctional, true); } break; } } } } if (needsQuip) { QuipHelper.PublishQuip(targetMech, Mod.Config.Qips.Breach); } }
public static void ShowStructureDamageThroughArmour(HUDMechArmorReadout __instance) { try { HUDMechArmorReadout me = __instance; Mech mech = me.DisplayedMech; MechDef mechDef = mech?.MechDef ?? me.DisplayedMechDef; if (mech == null && mechDef == null) { return; } ChassisLocations[] location = me.flipFrontDisplay ? Flipped : Normal; int[] back = me.flipFrontDisplay != me.flipRearDisplay ? new int[] { 0, 0, 4, 3, 2 } : new int[] { 0, 0, 2, 3, 4 }; Color clear = Color.clear; Color[] armor = (Color[])armorProp.GetValue(me, null); Color[] armorRear = (Color[])armorRearProp.GetValue(me, null); Color[] outline = null, outlineRear = null, structure = null, structureRear = null; for (int i = 0; i < 8; i++) { float percent = float.NaN; // Front if (armor[i] != clear) // Skip check on armour-less locations { if (IsStructureDamaged(ref percent, mech, mechDef, location[i])) { if (structure == null) // Lazy reflection access { structure = (Color[])structureProp.GetValue(me, null); outline = (Color[])outlineProp.GetValue(me, null); } outline[i] = structure[i] = armor[i]; if (me.UseForCalledShots) { armor[i] = clear; } else { armor[i].a *= 0.5f; // Front has structure over armor, but structure has more blank to fill. } } } // Back if (i < 2 || i > 4) { continue; } int j = back[i]; if (armorRear[j] != clear) { if (IsStructureDamaged(ref percent, mech, mechDef, location[i])) // i is not typo. We want to check same chassis location as front. { if (structureRear == null) { structureRear = (Color[])structureRearProp.GetValue(me, null); outlineRear = (Color[])outlineRearProp.GetValue(me, null); } outlineRear[j] = structureRear[j] = armorRear[j]; armorRear[j] = clear; } } } } catch (Exception ex) { Error(ex); } }
public MechMovingState(Mech character, MechStateMachine stateMachine) : base(character, stateMachine) { }
public void Init() { pathFinderMech = CreatePathFinderMech(); // pathFinderVehicle = CreatePathFindingVehicle(); }
public static void HUDMechArmorReadout_SetHoveredArmor_Postfix(HUDMechArmorReadout __instance, ArmorLocation location, Mech ___displayedMech) { if (__instance == null || __instance.HUD == null || __instance.HUD.SelectedActor == null || __instance.HUD.SelectedTarget == null) { return; // nothing to do } if (__instance.UseForCalledShots && location == ArmorLocation.Head) { Mod.Log.Trace("HUDMAR:SHA entered"); bool canAlwaysCalledShot = false; List <Statistic> customStats = ActorHelper.FindCustomStatistic(ModStats.CalledShowAlwaysAllow, __instance.HUD.SelectedActor); foreach (Statistic stat in customStats) { if (stat.ValueType() == typeof(bool) && stat.Value <bool>()) { canAlwaysCalledShot = true; } } bool canBeTargeted = __instance.HUD.SelectedTarget.IsShutDown || __instance.HUD.SelectedTarget.IsProne || canAlwaysCalledShot; Mod.Log.Debug($" Hover - target:({___displayedMech.DistinctId()}) canBeTargeted:{canBeTargeted} by attacker:({__instance.HUD.SelectedActor.DistinctId()})"); Mod.Log.Debug($" isShutdown:{___displayedMech.IsShutDown} isProne:{___displayedMech.IsProne} canAlwaysCalledShot:{canAlwaysCalledShot}"); if (!canBeTargeted) { Mod.Log.Debug(" preventing targeting of head."); __instance.ClearHoveredArmor(ArmorLocation.Head); } else { Mod.Log.Debug(" target head can be targeted."); } } }
// Use this for initialization void Start() { // Every weapon must have a protoweapon component Proto = GetComponent<ProtoWeapon>(); // Note - not every weapon has to have an animator. Up to use code to check for null Animator = GetComponent<Animator>(); Owner = transform.root.gameObject.GetComponent<Mech>(); if (Owner == null) Debug.LogWarning("Weapon attached to a nonmech item. No owner, so it won't attribute damage correctly."); // Reset the Weapon ResetWeapon(); }
private void FireFlyJets(Mech mech) { if (fuel < Type.FuelUsage || !keepFlying) { keepFlying = false; return; } fuel -= Type.FuelUsage; Vec3 vel = mech.MainGun.Rotation.GetForward(); vel = vel.GetNormalize() * Type.Velocity; //mech.PhysicsModel.Bodies[0].LinearVelocity = vel; mech.PhysicsModel.Bodies[0].AddForce(ForceType.GlobalAtLocalPos, 0, 1000f * vel, Position); }
public PilotTracker(Mech mech) { this.mech = mech.GUID; panicStatus = PanicStatus.Confident; panicWorsenedRecently = false; }
public float invUtility(Mech m, Transform t) { return 1 - utility(m,t); }
public void FullReset() { pathFinderMech = null; // pathFinderVehicle = null; }
public float utility(Mech m, Transform t) { Mech mech = m; Transform target = t; float result = 0f; switch (type) { case ConsiderationTypes.Distance: { var dir = (target.position - mech.transform.position); result = Mathf.Max(Mathf.Min(utilCurve.Evaluate(dir.magnitude / mech.sensorRange), 1), 0); } break; case ConsiderationTypes.EnemyHealth: { var enemy = target.GetComponent<Mech>(); var hp_ratio = enemy.currentHealth / enemy.totalHealth; result = utilCurve.Evaluate(hp_ratio); } break; case ConsiderationTypes.EnemyTeamSize: { var enemy = target.GetComponent<Mech>(); var cur_team_size = enemy.currentTeamSize / (float)enemy.maxTeamSize; result = utilCurve.Evaluate(cur_team_size); } break; case ConsiderationTypes.Health: { var hp_ratio = mech.currentHealth / mech.totalHealth; result = utilCurve.Evaluate(hp_ratio); } break; case ConsiderationTypes.LineOfSight: { var los = Physics.Linecast(mech.transform.position, target.position); // inverse && los -> 0 // inverse && !los -> 1 // !inverse && los -> 1 // !inverse && !los -> 0 result = inverse ? (los ? 0 : 1) : (los ? 1 : 0); } break; case ConsiderationTypes.TeamSize: { var cur_team_size = mech.currentTeamSize / (float)mech.maxTeamSize; result = utilCurve.Evaluate(cur_team_size); } break; case ConsiderationTypes.Time: { var cur_time = Time.time - startTime; var time_ratio = cur_time / timeLimit; result = Mathf.Min(utilCurve.Evaluate(time_ratio), 1); } break; case ConsiderationTypes.WeaponCooldown: { // var wep = mech.CurrentWeapon; // var cooldown_over = wep.fireTime < 0; // // inverse && cooldown_over -> 0 // // inverse && !cooldown_over -> 1 // // !inverse && cooldown_over -> 1 // // !inverse && !cooldown_over -> 0 // result = inverse // ? (cooldown_over ? 0 : 1) // : (cooldown_over ? 1 : 0); } break; default: { // Do nothing } break; } return result; }
public static IStackSequence DoneNoAnimation(this Mech mech) { mech.OnActivationBegin(mech.GUID, -1); return(mech.GetDoneWithActorOrders()); }
private void FireDashJets(Mech mech) { if (fuel < Type.FuelUsage) return; fuel -= Type.FuelUsage; Vec3 vel = mech.PhysicsModel.GetBody("mainBody").Rotation.GetForward(); vel = vel.GetNormalize() * Type.Velocity; mech.PhysicsModel.GetBody("mainBody").LinearVelocity = vel; }
public static bool OverridePaperDollTooltip(CombatHUDMechTrayArmorHover __instance, Mech mech, ArmorLocation location) { try { if (!FriendOrFoe(mech, Settings.ShowAmmoInTooltip, Settings.ShowEnemyAmmoInTooltip)) { return(true); } CombatHUDMechTrayArmorHover me = __instance; CombatHUDTooltipHoverElement ToolTip = (CombatHUDTooltipHoverElement)MechTrayArmorHoverToolTipProp.GetValue(me, null); ToolTip.BuffStrings.Clear(); ToolTip.DebuffStrings.Clear(); ToolTip.BasicString = Mech.GetLongArmorLocation(location); foreach (MechComponent mechComponent in mech.GetComponentsForLocation(MechStructureRules.GetChassisLocationFromArmorLocation(location), ComponentType.NotSet)) { string componentName = mechComponent.UIName.ToString(); int allAmmo = 1; if (mechComponent is Weapon weaponComp && !weaponComp.AmmoCategoryValue.Is_NotSet) { componentName += "<size=80%> (x" + (allAmmo = weaponComp.CurrentAmmo) + ")"; } else if (mechComponent is AmmunitionBox ammo) { int curr = ammo.CurrentAmmo, max = ammo.AmmoCapacity; componentName += "<size=80%> (" + curr + "/" + max + ")"; if (curr < max / 2) { componentName = "<#808080>" + componentName; } } if (mechComponent.DamageLevel >= ComponentDamageLevel.NonFunctional || allAmmo <= 0) { ToolTip.DebuffStrings.Add(new Text(componentName)); } else { ToolTip.BuffStrings.Add(new Text(componentName)); } }
private void FireJumpJets(Mech mech) { //mech.PhysicsModel.Bodies[0].AddForce(ForceType.GlobalAtGlobalPos, TickDelta, Vec3.ZAxis*Type.Force, mech.Position); //mech.PhysicsModel.Bodies[0].AddForce(ForceType.GlobalAtGlobalPos, TickDelta, Vec3.ZAxis * 2500f, mech.Position); if (fuel < Type.Fuel) return; fuel = 0f; Vec3 vel = mech.PhysicsModel.Bodies[0].LinearVelocity; vel.Z = Type.Velocity; mech.PhysicsModel.Bodies[0].LinearVelocity = vel; }
public static bool hasHittableLocations(Weapon weapon, List <int> hitLocations, Mech target) { foreach (int location in hitLocations) { if (weapon.DamagePerShot * 2 >= target.ArmorForLocation(location)) { return(true); } } return(false); }
/// <summary> /// Start /// Pretty much everything that we do in MechUserControl we /// only do for the local player.. /// </summary> private void Start() { if (!isLocalPlayer) return; // get the transform of the main camera if (Camera.main != null) { m_Cam = Camera.main.transform; } else { Debug.LogWarning( "Warning: no main camera found. Third person character needs a Camera tagged \"MainCamera\", for camera-relative controls."); // we use self-relative controls in this case, which probably isn't what the user wants, but hey, we warned them! } // get the third person character ( this should never be null due to require component ) m_MechController = GetComponent<MechController>(); m_Mech = GetComponent<Mech>(); }
internal static void UpdateStructureDamage( this Mech mech, ChassisLocations location, WeaponHitInfo hitInfo, ref float damage ) { if (damage <= 0) { return; // ignore 0 damage calls } var properties = ComponentExplosionsFeature.Shared.GetCASEProperties(mech, (int)location); if (properties == null) { return; } ComponentExplosionsFeature.IsInternalExplosionContained = true; Control.Logger.Debug?.Log($"prevent explosion pass through from {Mech.GetAbbreviatedChassisLocation(location)}"); var maxStructureDamage = mech.GetCurrentStructure(location); Control.Logger.Debug?.Log($"damage={damage} maxStructureDamage={maxStructureDamage}"); if (properties.MaximumDamage == null) { damage = Mathf.Min(maxStructureDamage, damage); mech.PublishFloatieMessage("EXPLOSION CONTAINED"); return; } var newInternalDamage = Mathf.Min(damage, properties.MaximumDamage.Value); var backDamage = damage - newInternalDamage; Control.Logger.Debug?.Log($"reducing structure damage from {damage} to {newInternalDamage}"); damage = Mathf.Min(maxStructureDamage, newInternalDamage); mech.PublishFloatieMessage("EXPLOSION REDIRECTED"); if (backDamage <= 0) { return; } if ((location & ChassisLocations.Torso) == 0) { return; } ArmorLocation armorLocation; switch (location) { case ChassisLocations.LeftTorso: armorLocation = ArmorLocation.LeftTorsoRear; break; case ChassisLocations.RightTorso: armorLocation = ArmorLocation.RightTorsoRear; break; default: armorLocation = ArmorLocation.CenterTorsoRear; break; } var armor = mech.GetCurrentArmor(armorLocation); if (armor <= 0) { return; } var armorDamage = Mathf.Min(backDamage, armor); Control.Logger.Debug?.Log($"added blowout armor damage {armorDamage} to {Mech.GetLongArmorLocation(armorLocation)}"); mech.ApplyArmorStatDamage(armorLocation, armorDamage, hitInfo); }
private void OnActionSetToAttack(Mech obj) => Action = UnitAction.PrimaryAttack;
protected override BehaviorTreeResults Tick() { if (unit.HasMovedThisRound) { return(new BehaviorTreeResults(BehaviorNodeState.Failure)); } BehaviorVariableValue targetLanceGuidValue = this.tree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_TARGET_GUID_KEY); if (targetLanceGuidValue == null) { return(new BehaviorTreeResults(BehaviorNodeState.Failure)); } string targetLanceGuid = targetLanceGuidValue.StringVal; Lance targetLance = DestinationUtil.FindLanceByGUID(this.tree, targetLanceGuid); if (targetLance == null) { return(new BehaviorTreeResults(BehaviorNodeState.Failure)); } List <AbstractActor> lanceMembers = AIUtil.GetLanceUnits(this.unit.Combat, this.unit.LanceId); float travelDistance = Mathf.Max(this.unit.MaxSprintDistance, this.unit.MaxWalkDistance); if (this.waitForLance) { for (int i = 0; i < lanceMembers.Count; i++) { AbstractActor abstractActor = lanceMembers[i] as AbstractActor; if (abstractActor != null) { float lanceMemberTravelDistance = Mathf.Max(abstractActor.MaxWalkDistance, abstractActor.MaxSprintDistance); travelDistance = Mathf.Min(travelDistance, lanceMemberTravelDistance); } } } AbstractActor targetActor = null; float targetTonnage = 0; for (int i = 0; i < targetLance.unitGuids.Count; i++) { ITaggedItem itemByGUID = this.unit.Combat.ItemRegistry.GetItemByGUID(targetLance.unitGuids[i]); if (itemByGUID != null) { AbstractActor abstractActor = itemByGUID as AbstractActor; if (abstractActor != null && !abstractActor.IsDead) { if (abstractActor is Mech) { Mech mech = (Mech)abstractActor; if (mech.tonnage > targetTonnage) { targetActor = mech; targetTonnage = mech.tonnage; } } else if (abstractActor is Vehicle) { Vehicle vehicle = (Vehicle)abstractActor; if (vehicle.tonnage > targetTonnage) { targetActor = vehicle; targetTonnage = vehicle.tonnage; } } } } } if (targetActor == null) { Main.Logger.LogError("[MoveToFollowLanceNode] Target Actor is null"); return(new BehaviorTreeResults(BehaviorNodeState.Failure)); } Main.LogDebug($"[MoveToFollowLanceNode] Target to follow is '{targetActor.DisplayName} {targetActor.VariantName}'"); bool shouldSprint = this.tree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_SHOULD_SPRINT_KEY).BoolVal; shouldSprint = (!this.unit.HasAnyContactWithEnemy); shouldSprint = (this.unit.CurrentPosition - targetActor.CurrentPosition).magnitude > 200f; // sprint if the unit is over 200 metres away AbstractActor closestDetectedEnemy = AiUtils.GetClosestDetectedEnemy(this.unit, targetLance); Vector3 lookDirection = (closestDetectedEnemy == null) ? targetActor.CurrentPosition : closestDetectedEnemy.CurrentPosition; MoveType moveType = (shouldSprint) ? MoveType.Sprinting : MoveType.Walking; this.unit.Pathing.UpdateAIPath(targetActor.CurrentPosition, lookDirection, moveType); Vector3 vectorToTarget = this.unit.Pathing.ResultDestination - this.unit.CurrentPosition; float distanceToTarget = vectorToTarget.magnitude; if (distanceToTarget > travelDistance) { // If the target is out of range, head in the direction of that unit to the maximum possible travel distance for this turn vectorToTarget = vectorToTarget.normalized * travelDistance; } // Ensure the units aren't crowded Vector3 targetDestination = RoutingUtil.Decrowd(this.unit.CurrentPosition + vectorToTarget, this.unit); targetDestination = RegionUtil.MaybeClipMovementDestinationToStayInsideRegion(this.unit, targetDestination); float followLanceZoneRadius = this.unit.BehaviorTree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_ZONE_RADIUS_KEY).FloatVal; if (RoutingUtils.IsUnitInsideRadiusOfPoint(this.unit, targetActor.CurrentPosition, followLanceZoneRadius)) { return(new BehaviorTreeResults(BehaviorNodeState.Failure)); } this.unit.Pathing.UpdateAIPath(targetDestination, lookDirection, (shouldSprint) ? MoveType.Sprinting : MoveType.Walking); targetDestination = this.unit.Pathing.ResultDestination; float maxCost = this.unit.Pathing.MaxCost; PathNodeGrid currentGrid = this.unit.Pathing.CurrentGrid; Vector3 targetActorPosition = targetActor.CurrentPosition; if ((currentGrid.GetValidPathNodeAt(targetDestination, maxCost) == null || (targetDestination - targetActor.CurrentPosition).magnitude > 1f) && this.unit.Combat.EncounterLayerData.inclineMeshData != null) { float maxSlope = Mathf.Tan(0.0174532924f * AIUtil.GetMaxSteepnessForAllLance(this.unit)); List <AbstractActor> lanceUnits = AIUtil.GetLanceUnits(this.unit.Combat, this.unit.LanceId); targetDestination = this.unit.Combat.EncounterLayerData.inclineMeshData.GetDestination(this.unit.CurrentPosition, targetDestination, maxCost, maxSlope, this.unit, shouldSprint, lanceUnits, this.unit.Pathing.CurrentGrid, out targetActorPosition); } Vector3 currentPosition = this.unit.CurrentPosition; AIUtil.LogAI(string.Format("issuing order from [{0} {1} {2}] to [{3} {4} {5}] looking at [{6} {7} {8}]", new object[] { currentPosition.x, currentPosition.y, currentPosition.z, targetDestination.x, targetDestination.y, targetDestination.z, targetActorPosition.x, targetActorPosition.y, targetActorPosition.z }), "AI.DecisionMaking"); return(new BehaviorTreeResults(BehaviorNodeState.Success) { orderInfo = new MovementOrderInfo(targetDestination, targetActorPosition) { IsSprinting = shouldSprint }, debugOrderString = string.Format("{0} moving toward destination: {1} dest: {2}", this.name, targetDestination, targetActor.CurrentPosition) }); }
public MechResearchState(Mech character, MechStateMachine stateMachine) : base(character, stateMachine) { }
private static void Prefix(Mech __instance, string sourceID, int stackItemID) { if (__instance.IsOverheated) { CBTPilotingRules rules = new CBTPilotingRules(__instance.Combat); float gutsTestChance = rules.GetGutsModifier(__instance); float skillRoll = __instance.Combat.NetworkRandom.Float(); float ammoRoll = __instance.Combat.NetworkRandom.Float(); int turnsOverheated = __instance.StatCollection.ContainsStatistic(ModStats.TurnsOverheated) ? __instance.StatCollection.GetValue <int>("TurnsOverheated") : 0; float shutdownPercentage = HeatHelper.GetShutdownPercentageForTurn(turnsOverheated); float ammoExplosionPercentage = HeatHelper.GetAmmoExplosionPercentageForTurn(turnsOverheated); Mod.Log.Debug($"Mech:{CombatantHelper.LogLabel(__instance)} is overheated for {turnsOverheated} turns. Checking shutdown override."); Mod.Log.Debug($" Guts -> skill: {__instance.SkillGuts} divisor: {Mod.Config.GutsDivisor} bonus: {gutsTestChance}"); Mod.Log.Debug($" Skill roll: {skillRoll} plus guts roll: {skillRoll + gutsTestChance} target: {shutdownPercentage}"); Mod.Log.Debug($" Ammo roll: {ammoRoll} plus guts roll: {ammoRoll + gutsTestChance} target: {ammoExplosionPercentage}"); if (Mod.Config.UseGuts) { ammoRoll = ammoRoll + gutsTestChance; skillRoll = skillRoll + gutsTestChance; } MultiSequence sequence = new MultiSequence(__instance.Combat); sequence.SetCamera(CameraControl.Instance.ShowDeathCam(__instance, false, -1f), 0); if (HeatHelper.CanAmmoExplode(__instance)) { if (ammoRoll < ammoExplosionPercentage) { __instance.Combat.MessageCenter.PublishMessage(new FloatieMessage(__instance.GUID, __instance.GUID, "Ammo Overheated!", FloatieMessage.MessageNature.CriticalHit)); var ammoBox = __instance.ammoBoxes.Where(box => box.CurrentAmmo > 0).OrderByDescending(box => box.CurrentAmmo / box.AmmoCapacity).FirstOrDefault(); if (ammoBox != null) { WeaponHitInfo fakeHit = new WeaponHitInfo(stackItemID, -1, -1, -1, string.Empty, string.Empty, -1, null, null, null, null, null, null, null, new AttackDirection[] { AttackDirection.None }, null, null, null); ammoBox.DamageComponent(fakeHit, ComponentDamageLevel.Destroyed, true); } return; } sequence.AddChildSequence(new ShowActorInfoSequence(__instance, "Ammo Explosion Avoided!", FloatieMessage.MessageNature.Debuff, true), sequence.ChildSequenceCount - 1); } if (!__instance.IsPastMaxHeat) { if (skillRoll < shutdownPercentage) { Mod.Log.Debug(string.Format("Skill Check Failed! Initiating Shutdown")); MechEmergencyShutdownSequence mechShutdownSequence = new MechEmergencyShutdownSequence(__instance); sequence.AddChildSequence(mechShutdownSequence, sequence.ChildSequenceCount - 1); __instance.StatCollection.Set <int>("TurnsOverheated", 0); } else { Mod.Log.Debug(string.Format("Skill Check Succeeded!")); sequence.AddChildSequence(new ShowActorInfoSequence(__instance, "Shutdown Override Successful!", FloatieMessage.MessageNature.Buff, true), sequence.ChildSequenceCount - 1); turnsOverheated += 1; __instance.StatCollection.Set <int>("TurnsOverheated", turnsOverheated); } } sequence.AddChildSequence(new DelaySequence(__instance.Combat, 2f), sequence.ChildSequenceCount - 1); __instance.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(sequence)); } else { int turnsOverheated = __instance.StatCollection.GetValue <int>("TurnsOverheated"); if (turnsOverheated > 0) { __instance.StatCollection.Set <int>("TurnsOverheated", 0); } } }
void Start() { mech = GetComponent<Mech>(); actions = actionTypes.Select (at => Actions.createType(at)).ToList(); moves = movementTypes.Select(mt => Actions.createType(mt)).ToList(); }