public MeleeAttackEffector(int weaponStrength, MeleeAttackType attackType = MeleeAttackType.Regular, DamageType damageType = DamageType.Regular) { this.weaponStrength = weaponStrength; this.attackType = attackType; this.damageType = damageType; }
static void Postfix(Mech attacker, ICombatant target, ref MeleeAttackType __result) { MeleeAttack selectedAttack = ModState.GetSelectedAttack(attacker); if (selectedAttack != null) { Mod.Log.Info?.Write($"Forcing melee animation to {selectedAttack.AttackAnimation} for " + $"attacker: {attacker.DistinctId()} vs. target: {target.DistinctId()}"); __result = selectedAttack.AttackAnimation; } }
public static bool OverrideMeleeModifiers(ref float __result, Mech attacker, ICombatant target, Vector3 targetPosition, MeleeAttackType meleeAttackType) { try { AttackType = meleeAttackType; Weapon weapon = (meleeAttackType == MeleeAttackType.DFA) ? attacker.DFAWeapon : attacker.MeleeWeapon; SaveStates(attacker, target, weapon); __result = SumModifiers(MeleeModifiers); return(false); } catch (Exception ex) { return(Error(new ApplicationException("Error in melee modifier '" + thisModifier + "'", ex))); } }
public static bool OverrideMeleeToolTips(CombatHUDWeaponSlot __instance, ICombatant target) { try { CombatHUDWeaponSlot slot = __instance; bool isDFA = (bool)contemplatingDFA?.Invoke(slot, new object[] { target }); AttackType = isDFA ? MeleeAttackType.DFA : MeleeAttackType.Punch; SaveStates(HUD.SelectedActor, target, slot.DisplayedWeapon); SetToolTips(__instance, MeleeModifiers); return(false); } catch (Exception ex) { return(Error(new ApplicationException("Error in melee modifier '" + thisModifier + "'", ex))); } }
static void Prefix(MechMeleeSequence __instance) { try { Pilot pilot = __instance.owningActor.GetPilot(); if (pilot.IsJuggernaut() && Fields.JuggernautCharges) { Logger.Debug("[MechMeleeSequence_BuildMeleeDirectorSequence_PREFIX] Fields.JuggernautCharges: " + Fields.JuggernautCharges); MeleeAttackType selectedMeleeType = (MeleeAttackType)AccessTools.Property(typeof(MechMeleeSequence), "selectedMeleeType").GetValue(__instance, null); Logger.Info("[MechMeleeSequence_BuildMeleeDirectorSequence_PREFIX] BEFORE selectedMeleeType: " + selectedMeleeType); selectedMeleeType = MeleeAttackType.Charge; Logger.Info("[MechMeleeSequence_BuildMeleeDirectorSequence_PREFIX] AFTER selectedMeleeType: " + selectedMeleeType); } } catch (Exception e) { Logger.Error(e); } }
// The default method assumes an absractActor exists, and tries to draw a line of fire. We don't have that, so skip it. public static void ResolveSourcelessWeaponDamage(this Mech mech, WeaponHitInfo hitInfo, Weapon weapon, MeleeAttackType meleeAttackType) { AttackDirector.AttackSequence attackSequence = ModState.Combat.AttackDirector.GetAttackSequence(hitInfo.attackSequenceId); float damagePerShot = weapon.DamagePerShot; float structureDamagePerShot = weapon.StructureDamagePerShot; LineOfFireLevel lineOfFireLevel = LineOfFireLevel.LOFClear; damagePerShot = mech.GetAdjustedDamage(damagePerShot, weapon.WeaponCategoryValue, mech.occupiedDesignMask, lineOfFireLevel, false); structureDamagePerShot = mech.GetAdjustedDamage(structureDamagePerShot, weapon.WeaponCategoryValue, mech.occupiedDesignMask, lineOfFireLevel, false); foreach (KeyValuePair <int, float> keyValuePair in hitInfo.ConsolidateCriticalHitInfo(mech.GUID, damagePerShot)) { if (keyValuePair.Key != 0 && keyValuePair.Key != 65536 && (mech.ArmorForLocation(keyValuePair.Key) <= 0f || structureDamagePerShot > 0f)) { ChassisLocations chassisLocationFromArmorLocation = MechStructureRules.GetChassisLocationFromArmorLocation((ArmorLocation)keyValuePair.Key); if (!mech.IsLocationDestroyed(chassisLocationFromArmorLocation)) { Traverse checkForCritT = Traverse.Create(mech).Method("CheckForCrit", new Type[] { typeof(WeaponHitInfo), typeof(ChassisLocations), typeof(Weapon) }); checkForCritT.GetValue(new object[] { hitInfo, chassisLocationFromArmorLocation, weapon }); } } } if (weapon.HeatDamagePerShot > 0f) { bool flag = false; for (int i = 0; i < hitInfo.numberOfShots; i++) { if (hitInfo.DidShotHitTarget(mech.GUID, i) && hitInfo.ShotHitLocation(i) != 0 && hitInfo.ShotHitLocation(i) != 65536) { flag = true; mech.AddExternalHeat(string.Format("Heat Damage from {0}", weapon.Description.Name), (int)weapon.HeatDamagePerShotAdjusted(hitInfo.hitQualities[i])); } } if (flag && attackSequence != null) { attackSequence.FlagAttackDidHeatDamage(mech.GUID); } } float num3 = hitInfo.ConsolidateInstability(mech.GUID, weapon.Instability(), mech.Combat.Constants.ResolutionConstants.GlancingBlowDamageMultiplier, mech.Combat.Constants.ResolutionConstants.NormalBlowDamageMultiplier, mech.Combat.Constants.ResolutionConstants.SolidBlowDamageMultiplier); num3 *= mech.StatCollection.GetValue <float>("ReceivedInstabilityMultiplier"); num3 *= mech.EntrenchedMultiplier; mech.AddAbsoluteInstability(num3, StabilityChangeSource.Attack, hitInfo.attackerId); }
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; }
public static void CreateImaginaryAttack(Mech attacker, Weapon attackWeapon, ICombatant target, int weaponHitInfoStackItemUID, float[] damageClusters, DamageType damageType, MeleeAttackType attackType) { Mod.Log.Info?.Write($" Creating imaginary attack for attacker: {attacker.DistinctId()} at position: {attacker?.CurrentPosition} and rot: {attacker?.CurrentRotation} " + $"vs. target: {target.DistinctId()} at position: {target?.CurrentPosition} and rot: {target?.CurrentRotation} " + $"using weapon => isNull: {attackWeapon == null} name: {attackWeapon?.Name} damageType: {damageType} attackType: {attackType}"); if (attackWeapon.ammo() == null) { Mod.Log.Error?.Write($"AMMO is null!"); } if (attackWeapon.mode() == null) { Mod.Log.Error?.Write($"Mode is null!"); } if (attackWeapon.exDef() == null) { Mod.Log.Error?.Write($"exDef is null!"); } AttackDirector.AttackSequence attackSequence = target.Combat.AttackDirector.CreateAttackSequence(0, attacker, target, attacker.CurrentPosition, attacker.CurrentRotation, 0, new List <Weapon>() { attackWeapon }, attackType, 0, false ); AttackDirection[] attackDirections = new AttackDirection[damageClusters.Length]; WeaponHitInfo hitInfo = new WeaponHitInfo(0, attackSequence.id, 0, 0, attacker.GUID, target.GUID, 1, null, null, null, null, null, null, null, attackDirections, null, null, null) { attackerId = attacker.GUID, targetId = target.GUID, numberOfShots = damageClusters.Length, stackItemUID = weaponHitInfoStackItemUID, locationRolls = new float[damageClusters.Length], hitLocations = new int[damageClusters.Length], hitPositions = new Vector3[damageClusters.Length], hitQualities = new AttackImpactQuality[damageClusters.Length] }; AttackDirection attackDirection = attacker.Combat.HitLocation.GetAttackDirection(attacker, target); Mod.Log.Info?.Write($" Attack direction is: {attackDirection}"); int i = 0; foreach (int damage in damageClusters) { // Set hit qualities hitInfo.attackDirections[i] = attackDirection; hitInfo.hitQualities[i] = AttackImpactQuality.Solid; hitInfo.hitPositions[i] = attacker.CurrentPosition; float adjustedDamage = damage; float randomRoll = (float)Mod.Random.NextDouble(); if (target is Mech mech) { ArmorLocation location = SharedState.Combat.HitLocation.GetHitLocation(attacker.CurrentPosition, mech, randomRoll, ArmorLocation.None, 0f); hitInfo.hitLocations[i] = (int)location; adjustedDamage = mech.GetAdjustedDamageForMelee(damage, attackWeapon.WeaponCategoryValue); Mod.Log.Info?.Write($" {adjustedDamage} damage to location: {location}"); ShowDamageFloatie(mech, location, adjustedDamage, hitInfo.attackerId); } else if (target is Vehicle vehicle) { VehicleChassisLocations location = SharedState.Combat.HitLocation.GetHitLocation(attacker.CurrentPosition, vehicle, randomRoll, VehicleChassisLocations.None, 0f); hitInfo.hitLocations[i] = (int)location; adjustedDamage = vehicle.GetAdjustedDamageForMelee(damage, attackWeapon.WeaponCategoryValue); Mod.Log.Info?.Write($" {adjustedDamage} damage to location: {location}"); ShowDamageFloatie(vehicle, location, adjustedDamage, hitInfo.attackerId); } else if (target is Turret turret) { BuildingLocation location = BuildingLocation.Structure; hitInfo.hitLocations[i] = (int)BuildingLocation.Structure; adjustedDamage = turret.GetAdjustedDamageForMelee(damage, attackWeapon.WeaponCategoryValue); Mod.Log.Info?.Write($" {adjustedDamage} damage to location: {location}"); ShowDamageFloatie(turret, adjustedDamage, hitInfo.attackerId); } // Make the target take weapon damage target.TakeWeaponDamage(hitInfo, hitInfo.hitLocations[i], attackWeapon, adjustedDamage, 0, 0, damageType); i++; } // Cleanup after myself target.Combat.AttackDirector.RemoveAttackSequence(attackSequence); }
static public float EvaluateFirepowerReductionFromAttack(AbstractActor attacker, Vector3 attackerPosition, ICombatant target, Vector3 targetPosition, Quaternion targetRotation, List <Weapon> weapons, MeleeAttackType attackType) { AbstractActor actor = target as AbstractActor; if (actor == null) { return(0.0f); } DamageExpectationRecord damageExpectationRecord = EvaluateAttack(attacker, attackerPosition, target, targetPosition, targetRotation, weapons, attackType); float dmg = 0.0f; List <ComponentLocator> weaponList = GetWeaponComponentLocatorList(actor); for (int weaponIndex = 0; weaponIndex < weaponList.Count; ++weaponIndex) { ComponentLocator compLoc = weaponList[weaponIndex]; MechComponent mechComp = compLoc.GetComponent(); Weapon w = mechComp as Weapon; if (w.CanFire) { float weaponBaseDamage = w.ShotsWhenFired * w.DamagePerShot; if (w.DamageLevel == ComponentDamageLevel.Functional) { int expDmg = Mathf.RoundToInt(damageExpectationRecord.GetComponentDamageForLocation(compLoc)); if (expDmg == 1) { // that's like half damage dmg += weaponBaseDamage * 0.5f; } else if (expDmg > 1) { dmg += weaponBaseDamage; } } else if (w.DamageLevel == ComponentDamageLevel.Penalized) { int expDmg = Mathf.RoundToInt(damageExpectationRecord.GetComponentDamageForLocation(compLoc)); if (expDmg >= 1) { dmg += weaponBaseDamage; } } } } return(dmg); }
static public DamageExpectationRecord EvaluateAttack(AbstractActor attacker, Vector3 attackerPosition, ICombatant target, Vector3 targetPosition, Quaternion targetRotation, List <Weapon> weapons, MeleeAttackType attackType) { // for all weapons in an attack // figure out the locations that are likely to be hit // use HitTable to figure this out // for each location, figure out the chance to // - do criticals (without breaching armor?) // - breach armor // - do structural damage // - do component damage (weapons get damaged, then destroyed) // - trigger ammo explosion // - lose the location // - lose sub-locations // - kill the mech // types.cs ConsolidateCriticalHitInfo // Mech.cs CheckForCrit // CombatCritChance GetCritChance DamageExpectationRecord root = new DamageExpectationRecord(); for (int weaponIndex = 0; weaponIndex < weapons.Count; ++weaponIndex) { Weapon w = weapons[weaponIndex]; // figure out chance to hit the target AbstractActor targetActor = target as AbstractActor; bool targetIsEvasive = (targetActor != null) && (targetActor.IsEvasive); float toHitProbability = w.GetToHitFromPosition(target, 1, attackerPosition, targetPosition, true, targetIsEvasive); DamageExpectationRecord weaponDamageExpectationRecord = new DamageExpectationRecord(); root.AddChildRecord(toHitProbability, weaponDamageExpectationRecord); float expectedDamage = w.ShotsWhenFired * w.DamagePerShotFromPosition(attackType, attackerPosition, target); Mech targetMech = target as Mech; Vehicle targetVehicle = target as Vehicle; Turret targetTurret = target as Turret; Building targetBuilding = target as Building; if (targetMech != null) { evaluateWeaponAttackOnMech(expectedDamage, w, ref weaponDamageExpectationRecord, attackerPosition, targetMech, targetPosition, targetRotation); } else if (targetVehicle != null) { evaluateWeaponAttackOnVehicle(expectedDamage, w, ref weaponDamageExpectationRecord, attackerPosition, targetVehicle, targetPosition, targetRotation); } else if (targetTurret != null) { evaluateWeaponAttackOnTurret(expectedDamage, w, ref weaponDamageExpectationRecord, attackerPosition, targetTurret, targetPosition, targetRotation); } else if (targetBuilding != null) { evaluateWeaponAttackOnBuilding(expectedDamage, w, ref weaponDamageExpectationRecord, attackerPosition, targetBuilding, targetPosition, targetRotation); } } consolidateDamageExpectationRecord(ref root, target); return(root); }
private static float CounterNarc(ToHit tohit, AbstractActor attacker, Weapon wep, ICombatant target, Vector3 apos, Vector3 tpos, LineOfFireLevel lof, MeleeAttackType mat, bool calledshot) { AbstractActor at = target as AbstractActor; if (at != null && at.HasIndirectFireImmunity && at.Combat.EffectManager.GetAllEffectsTargetingWithBaseID(at, "StatusEffect-NARC-IncomingAttBonus").Count > 0) { return(3); } return(0); }
public static void Postfix(Mech __instance, WeaponHitInfo hitInfo, Weapon weapon, MeleeAttackType meleeAttackType) { Mod.Log.Trace("M:RWD entered."); AttackDirector.AttackSequence attackSequence = __instance.Combat.AttackDirector.GetAttackSequence(hitInfo.attackSequenceId); AbstractActor actor = __instance.Combat.FindActorByGUID(hitInfo.targetId); if (actor is Mech target) { CombatResolutionConstantsDef crcd = __instance.Combat.Constants.ResolutionConstants; float stabilityDamage = hitInfo.ConsolidateInstability(hitInfo.targetId, weapon.Instability(), crcd.GlancingBlowDamageMultiplier, crcd.NormalBlowDamageMultiplier, crcd.SolidBlowDamageMultiplier); stabilityDamage *= __instance.StatCollection.GetValue <float>("ReceivedInstabilityMultiplier"); stabilityDamage *= __instance.EntrenchedMultiplier; Mod.Log.Debug($" == Checking Piloting Stability"); Mod.Log.Debug($" target:{CombatantHelper.LogLabel(target)} isMech:{(actor is Mech)} IsDead:{target.IsDead} IsUnsteady:{target.IsUnsteady} IsOrWillBeProne:{target.IsOrWillBeProne}"); Mod.Log.Debug($" weapon stability damage:{stabilityDamage}"); if (stabilityDamage > 0 && !target.IsDead && target.IsUnsteady && !target.IsOrWillBeProne) { float skillBonus = (float)target.SkillPiloting / __instance.Combat.Constants.PilotingConstants.PilotingDivisor; float skillRoll = __instance.Combat.NetworkRandom.Float(); float skillTotal = skillRoll + skillBonus; Mod.Log.Debug($" Skill check -> bonus: {skillBonus} roll: {skillRoll} rollTotal: {skillTotal} target:{Mod.Config.PilotStabilityCheck}"); if (skillTotal < Mod.Config.PilotStabilityCheck) { Mod.Log.Debug(string.Format(" Skill Check Failed! Flagging for Knockdown")); bool showMessage = !target.IsFlaggedForKnockdown; target.FlagForKnockdown(); if (Mod.Config.ShowAllStabilityRolls || showMessage) { target.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(new ShowActorInfoSequence(target, $"Stability Check: Failed!", FloatieMessage.MessageNature.Debuff, true))); } } else { Mod.Log.Debug(string.Format(" Skill Check Succeeded!")); if (Mod.Config.ShowAllStabilityRolls) { target.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(new ShowActorInfoSequence(target, $"Stability Check: Passed!", FloatieMessage.MessageNature.Buff, true))); } } } else { Mod.Log.Debug($" target has no stability damage, is not unsteady, or is dead or prone - skipping"); } } }
public override void OnInspectorGUI() { // base.OnInspectorGUI(); _actionSetting = (EnemyActionSetting)target; EditorGUILayout.BeginVertical(); EditorGUILayout.LabelField("General settings:", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Action type:"); EnemyActionType newType = (EnemyActionType)_enemyActionType.enumValueIndex; newType = (EnemyActionType)EditorGUILayout.EnumPopup(newType); _enemyActionType.enumValueIndex = (int)newType; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); _damage.intValue = Mathf.Max(EditorGUILayout.IntField(new GUIContent("Damage:"), _damage.intValue), 5); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); _rate.floatValue = Mathf.Max(EditorGUILayout.FloatField(new GUIContent("Attack rate:"), _rate.floatValue), 3); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Max attack angle:"); _maxAngle.intValue = EditorGUILayout.IntSlider(_maxAngle.intValue, 0, 40); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Max distance for attack:"); _maxDistance.intValue = EditorGUILayout.IntSlider(_maxDistance.intValue, 0, 30); EditorGUILayout.EndHorizontal(); if (_actionSetting.actionType == EnemyActionType.DISTANCE) { EditorGUILayout.Space(); EditorGUILayout.LabelField("Distance attack settings:", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Distance attack type:"); DistanceAttackType distance = (DistanceAttackType)_distanceAttackType.enumValueIndex; distance = (DistanceAttackType)EditorGUILayout.EnumPopup(distance); _distanceAttackType.enumValueIndex = (int)distance; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Attack calculation type:"); AttackCalculationType calculationType = (AttackCalculationType)_attackCalculationType.enumValueIndex; calculationType = (AttackCalculationType)EditorGUILayout.EnumPopup(calculationType); _attackCalculationType.enumValueIndex = (int)calculationType; EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(_projectilePrefab, new GUIContent("Projectile prefab:")); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.Slider(_projectileSpeed, 0, 50, new GUIContent("Projectile speed: ")); EditorGUILayout.EndHorizontal(); if (_actionSetting.distanceAttackType == DistanceAttackType.TRIPLE) { EditorGUILayout.Space(); EditorGUILayout.LabelField("Triple attack settings:", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); EditorGUILayout.Slider(_angleTriple, 0, 30, new GUIContent("Projectile triple angle: ")); EditorGUILayout.EndHorizontal(); } else if (_actionSetting.distanceAttackType == DistanceAttackType.MACHINE_GUN) { EditorGUILayout.Space(); EditorGUILayout.LabelField("Machine gun attack settings:", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Max offset for attack:"); _offset.floatValue = EditorGUILayout.FloatField(_offset.floatValue); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Rate in milliseconds:"); _machineGunRate.intValue = EditorGUILayout.IntField(_machineGunRate.intValue); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Magazine amount:"); _magazineAmount.intValue = EditorGUILayout.IntField(_magazineAmount.intValue); EditorGUILayout.EndHorizontal(); } } else { EditorGUILayout.Space(); EditorGUILayout.LabelField("Melee attack settings:", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Melee type:"); MeleeAttackType melee = (MeleeAttackType)_meleeAttackType.enumValueIndex; melee = (MeleeAttackType)EditorGUILayout.EnumPopup(melee); _meleeAttackType.enumValueIndex = (int)melee; EditorGUILayout.EndHorizontal(); if (_actionSetting.meleeAttackType == MeleeAttackType.EXPLOSION) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Time to explosion:"); _timeToExplode.intValue = EditorGUILayout.IntSlider(_timeToExplode.intValue, 0, 5); EditorGUILayout.EndHorizontal(); } } EditorGUILayout.EndVertical(); serializedObject.ApplyModifiedProperties(); }
public override void Deserialize( GenericReader reader ) { base.Deserialize( reader ); int version = reader.ReadInt(); int test = 0; if (version > 57) { m_Orders = new List<OrderInfo>(); int orderCount = reader.ReadInt(); for (int i = 0; i < orderCount; i++) { OrderInfo newOrder = new OrderInfo("", 1, 1, this); OrderInfo.Deserialize(reader, newOrder); m_Orders.Add(newOrder); } } if (version > 55) { m_Deadly = reader.ReadInt(); } if (version > 54) { m_Nation = (Nation)reader.ReadInt(); m_Government = (GovernmentEntity)reader.ReadItem(); m_Organization = (CustomGuildStone)reader.ReadItem(); } if( version > 53 ) m_AuraType = (AuraType)reader.ReadInt(); if( version > 52 ) m_CustomBreathType = (CustomBreathType)reader.ReadInt(); if( version > 51 ) m_ManeuverResistance = reader.ReadInt(); if( version > 50 ) { m_CantInterrupt = reader.ReadBool(); m_CantParry = reader.ReadBool(); m_HasNoCorpse = reader.ReadBool(); } if( version > 49 ) { int count = reader.ReadInt(); for( int i = 0; i < count; i++ ) m_SecondaryWikiConfigs.Add( reader.ReadString() ); count = reader.ReadInt(); for( int i = 0; i < count; i++ ) { XMLEventType eventType = (XMLEventType)reader.ReadInt(); List<string> list = new List<string>(); int codeCount = reader.ReadInt(); for( int a = 0; a < codeCount; a++ ) list.Add( reader.ReadString() ); m_XMLEventsDatabase.Add( eventType, list ); } } if( version > 48 ) m_RangedAttackType = (RangedAttackType)reader.ReadInt(); if( version > 47 ) m_CustomSkinnableParts = reader.ReadStrongItemList(); if( version > 46 ) { m_NoWoundedMovePenalty = reader.ReadBool(); m_MeleeAttackType = (MeleeAttackType)reader.ReadInt(); } if( version > 45 ) m_WikiConfig = reader.ReadString(); if( version > 44 ) { m_Technique = reader.ReadString(); m_TechniqueLevel = reader.ReadInt(); } if( version > 43 ) m_StableTicket = reader.ReadItem(); if( version > 41 ) m_StabledOwner = reader.ReadMobile(); if( version > 40 ) m_ReceivedNewLoot = reader.ReadBool(); if( version > 39 ) { m_TimeOfDeath = reader.ReadDeltaTime(); if( reader.ReadBool() ) BeginRess( reader.ReadDeltaTime() - DateTime.Now, this.Corpse ); m_Lives = reader.ReadInt(); } if( version > 38 ) m_ReleaseTime = reader.ReadDateTime(); if( version > 37 ) m_MarkedForTermination = reader.ReadBool(); if( version > 36 ) { m_FavouriteStance = reader.ReadString(); m_FavouriteManeuver = reader.ReadString(); } if( version > 34 ) m_CombatStyles = new CombatStyles( reader ); if( version > 32 ) m_Feats = new Feats( reader, true ); if( version > 33 ) m_FixedScales = reader.ReadBool(); if( version > 31 ) { m_NoDeathCondition = reader.ReadBool(); m_NoDeath = reader.ReadBool(); m_NoDeathMsg = reader.ReadString(); m_NoDeathSound = reader.ReadInt(); } if( version > 30 ) this.Frozen = reader.ReadBool(); if( version > 27 ) { m_VanishTime = reader.ReadDateTime(); m_VanishEmote = reader.ReadString(); } m_CreatureGroup = (CreatureGroup)reader.ReadInt(); if( version < 29 ) { test = reader.ReadInt(); m_IsSneaky = test > 0; } else m_IsSneaky = reader.ReadBool(); if( version < 29 ) { test = reader.ReadInt(); m_TakesLifeOnKill = test > 0; } else m_TakesLifeOnKill = reader.ReadBool(); m_Description = reader.ReadString(); m_Intimidated = reader.ReadInt(); if( version < 29 ) { test = reader.ReadInt(); m_IsHuntingHound = test > 0; } else m_IsHuntingHound = reader.ReadBool(); m_XPScale = reader.ReadInt(); m_StatScale = reader.ReadInt(); m_SkillScale = reader.ReadInt(); m_Level = reader.ReadInt(); m_XP = reader.ReadInt(); m_NextLevel = reader.ReadInt(); if( version < 29 ) { test = reader.ReadInt(); m_Warned = test > 0; } else m_Warned = reader.ReadBool(); m_WarningTime = reader.ReadDateTime(); m_BribingTime = reader.ReadDateTime(); m_EmployerFeatLevel = reader.ReadInt(); m_TargetsName = reader.ReadString(); m_Employer = reader.ReadMobile(); m_HiringTime = reader.ReadDateTime(); if( version < 29 ) { test = reader.ReadInt(); m_Bribed = test > 0; } else m_Bribed = reader.ReadBool(); m_LastSeen = reader.ReadDateTime(); if( version < 29 ) { test = reader.ReadInt(); m_CanBeInformant = test > 0; } else m_CanBeInformant = reader.ReadBool(); m_CurrentAI = (AIType)reader.ReadInt(); m_DefaultAI = (AIType)reader.ReadInt(); m_iRangePerception = reader.ReadInt(); m_iRangeFight = reader.ReadInt(); m_iTeam = reader.ReadInt(); m_dActiveSpeed = reader.ReadDouble(); m_dPassiveSpeed = reader.ReadDouble(); m_dCurrentSpeed = reader.ReadDouble(); if ( m_iRangePerception == OldRangePerception ) m_iRangePerception = DefaultRangePerception; m_pHome.X = reader.ReadInt(); m_pHome.Y = reader.ReadInt(); m_pHome.Z = reader.ReadInt(); if ( version >= 1 ) { m_iRangeHome = reader.ReadInt(); int i, iCount; iCount = reader.ReadInt(); for ( i=0; i< iCount; i++ ) { string str = reader.ReadString(); Type type = Type.GetType( str ); if ( type != null ) { m_arSpellAttack.Add( type ); } } iCount = reader.ReadInt(); for ( i=0; i< iCount; i++ ) { string str = reader.ReadString(); Type type = Type.GetType( str ); if ( type != null ) { m_arSpellDefense.Add( type ); } } } else { m_iRangeHome = 0; } if ( version >= 2 ) { m_FightMode = ( FightMode )reader.ReadInt(); m_bControlled = reader.ReadBool(); m_ControlMaster = reader.ReadMobile(); m_ControlTarget = reader.ReadMobile(); m_ControlDest = reader.ReadPoint3D(); m_ControlOrder = (OrderType) reader.ReadInt(); m_dMinTameSkill = reader.ReadDouble(); if ( version < 9 ) reader.ReadDouble(); m_bTamable = reader.ReadBool(); m_bSummoned = reader.ReadBool(); if ( m_bSummoned ) { m_SummonEnd = reader.ReadDeltaTime(); new UnsummonTimer( m_ControlMaster, this, m_SummonEnd - DateTime.Now ).Start(); } m_iControlSlots = reader.ReadInt(); } else { m_FightMode = FightMode.Closest; m_bControlled = false; m_ControlMaster = null; m_ControlTarget = null; m_ControlOrder = OrderType.None; } if ( version >= 3 ) m_Loyalty = reader.ReadInt(); else m_Loyalty = MaxLoyalty; // Wonderfully Happy if ( version >= 4 ) m_CurrentWayPoint = reader.ReadItem() as WayPoint; if ( version >= 5 ) m_SummonMaster = reader.ReadMobile(); if ( version >= 6 ) { //m_HitsMax = reader.ReadInt(); //m_StamMax = reader.ReadInt(); //m_ManaMax = reader.ReadInt(); m_DamageMin = reader.ReadInt(); m_DamageMax = reader.ReadInt(); } if ( version >= 7 ) { m_PhysicalResistance = reader.ReadInt(); m_PhysicalDamage = reader.ReadInt(); m_FireResistance = reader.ReadInt(); m_FireDamage = reader.ReadInt(); m_ColdResistance = reader.ReadInt(); m_ColdDamage = reader.ReadInt(); m_PoisonResistance = reader.ReadInt(); m_PoisonDamage = reader.ReadInt(); m_EnergyResistance = reader.ReadInt(); m_EnergyDamage = reader.ReadInt(); } if ( version >= 8 ) m_Owners = reader.ReadStrongMobileList(); else m_Owners = new List<Mobile>(); if ( version >= 10 ) { m_IsDeadPet = reader.ReadBool(); m_IsBonded = reader.ReadBool(); m_BondingBegin = reader.ReadDateTime(); m_OwnerAbandonTime = reader.ReadDateTime(); } if ( version >= 11 ) m_HasGeneratedLoot = reader.ReadBool(); else m_HasGeneratedLoot = true; if ( version >= 12 ) m_Paragon = reader.ReadBool(); else m_Paragon = false; if ( version >= 13 && reader.ReadBool() ) m_Friends = reader.ReadStrongMobileList(); else if ( version < 13 && m_ControlOrder >= OrderType.Unfriend ) ++m_ControlOrder; if ( version < 16 ) Loyalty *= 10; double activeSpeed = m_dActiveSpeed; double passiveSpeed = m_dPassiveSpeed; SpeedInfo.GetSpeeds( this, ref activeSpeed, ref passiveSpeed ); bool isStandardActive = false; for ( int i = 0; !isStandardActive && i < m_StandardActiveSpeeds.Length; ++i ) isStandardActive = ( m_dActiveSpeed == m_StandardActiveSpeeds[i] ); bool isStandardPassive = false; for ( int i = 0; !isStandardPassive && i < m_StandardPassiveSpeeds.Length; ++i ) isStandardPassive = ( m_dPassiveSpeed == m_StandardPassiveSpeeds[i] ); if ( isStandardActive && m_dCurrentSpeed == m_dActiveSpeed ) m_dCurrentSpeed = activeSpeed; else if ( isStandardPassive && m_dCurrentSpeed == m_dPassiveSpeed ) m_dCurrentSpeed = passiveSpeed; if ( isStandardActive && !m_Paragon ) m_dActiveSpeed = activeSpeed; if ( isStandardPassive && !m_Paragon ) m_dPassiveSpeed = passiveSpeed; if ( version >= 14 ) { m_RemoveIfUntamed = reader.ReadBool(); m_RemoveStep = reader.ReadInt(); } if( version <= 14 && m_Paragon && Hue == 0x31 ) { Hue = Paragon.Hue; //Paragon hue fixed, should now be 0x501. } m_BluntResistance = reader.ReadInt(); m_BluntDamage = reader.ReadInt(); m_SlashingResistance = reader.ReadInt(); m_SlashingDamage = reader.ReadInt(); m_PiercingResistance = reader.ReadInt(); m_PiercingDamage = reader.ReadInt(); CheckStatTimers(); Timer.DelayCall( TimeSpan.FromSeconds( 5 ), new TimerCallback( WaitToChangeAI ) ); AddFollowers(); if ( IsAnimatedDead ) Spells.Necromancy.AnimateDeadSpell.Register( m_SummonMaster, this ); if( this.Level < 1 ) this.Level = 1; if( this.Blessed && this.Alive ) this.CanBeInformant = true; m_Intimidated = 0; if( !( this is Mercenary ) && version < 34 && this.Level > 1 ) { int bonus = this.Level / 2; int rest = this.Level % 2; this.DamageMax += bonus + rest; this.DamageMin += bonus; } LevelSystem.FixStatsAndSkills( this ); m_Deserialized = true; }
public static float GetRangeModifier(ToHit instance, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, MeleeAttackType meleeAttackType, bool isCalledShot) { if (attacker.EncounterTags.ContainsAny(Core.Settings._C3NetworkEncounterTags) == false) { return(ToHitModifiersHelper.GetRangeModifier(instance, attacker, weapon, target, attackPosition, targetPosition, lofLevel, meleeAttackType, isCalledShot)); } float realDist = Vector3.Distance(attackPosition, targetPosition); float distance = realDist; float distMod = 0f; float minRange = weapon.MinRange; float shortRange = weapon.ShortRange; float medRange = weapon.MediumRange; float longRange = weapon.LongRange; float maxRange = weapon.MaxRange; Vector3 alternateAttackPos = GetC3CachedPos(attacker, target); if (alternateAttackPos != Vector3.zero) { float alternateDist = Vector3.Distance(alternateAttackPos, targetPosition); if (alternateDist < realDist) { if (alternateDist < minRange) { distance = minRange; } else { distance = alternateDist; } } } if (distance < minRange) { distMod = weapon.parent.MinRangeAccMod(); //Log.LogWrite(" minRange "); } else if (distance < shortRange) { distMod = weapon.parent.ShortRangeAccMod(); //Log.LogWrite(" shortRange "); } else if (distance < medRange) { distMod = weapon.parent.MediumRangeAccMod(); //Log.LogWrite(" medRange "); } else if (distance < longRange) { distMod = weapon.parent.LongRangeRangeAccMod(); //Log.LogWrite(" longRange "); } else if (distance < maxRange) { distMod = weapon.parent.ExtraLongRangeAccMod(); //Log.LogWrite(" extraRange "); } ; //return distMod; return(distMod + instance.GetRangeModifierForDist(weapon, distance)); }
public static string GetRangeModifierName(ToHit instance, AbstractActor attacker, Weapon w, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, MeleeAttackType meleeAttackType, bool isCalledShot, int modifier) { if (attacker.EncounterTags.ContainsAny(Core.Settings._C3NetworkEncounterTags) == false) { if (modifier == 0) { return(string.Empty); } return(ToHitModifiersHelper.GetRangeModifierName(instance, attacker, w, target, attackPosition, targetPosition, lofLevel, meleeAttackType, isCalledShot)); } float real_range = Vector3.Distance(attackPosition, targetPosition); float range = real_range; float MinRange = w.MinRange; float ShortRange = w.ShortRange; float MediumRange = w.MediumRange; float LongRange = w.LongRange; float MaxRange = w.MaxRange; string c3_prefix = string.Empty; Vector3 alternateAttackPos = GetC3CachedPos(attacker, target); if (alternateAttackPos != Vector3.zero) { float alternateDist = Vector3.Distance(alternateAttackPos, targetPosition); //Log.Debug?.TWL(0, "GetRangeModifierName "+attacker.PilotableActorDef.ChassisID+" weapon:"+w.defId+" target:"+target.PilotableActorDef.ChassisID+" real_dist:"+ real_range+" alt dist:"+ alternateDist+" max range:"+MaxRange+" modifier:"+modifier); if ((alternateDist < real_range) && (alternateDist < MaxRange)) { c3_prefix = "(C3)"; if (alternateDist < MinRange) { range = MinRange; } else { range = alternateDist; } } } if (string.IsNullOrEmpty(c3_prefix)) { if (modifier == 0) { return(string.Empty); } } if (range < MinRange) { return(c3_prefix + "__/AIM.MIN_RANGE/__ (<" + MinRange + "m)"); } if (range < ShortRange) { return(c3_prefix + "__/AIM.SHORT_RANGE/__" + SmartRange(MinRange, range, ShortRange)); } if (range < MediumRange) { return(c3_prefix + "__/AIM.MED_RANGE/__" + SmartRange(ShortRange, range, MediumRange)); } if (range < LongRange) { return(c3_prefix + "__/AIM.LONG_RANGE/__" + SmartRange(MediumRange, range, LongRange)); } if (range < MaxRange) { return(c3_prefix + "__/AIM.MAX_RANGE/__" + SmartRange(LongRange, range, MaxRange)); } return(c3_prefix + "__/AIM.OUT_OF_RANGE/__ (>" + MaxRange + "m)"); }
public static float GetToHitFromPosition(Weapon weapon, AttackDetails details, MeleeAttackType meleeAttackType) { return(SharedState.Combat.ToHit.GetToHitChance(attacker: details.Attacker, weapon: weapon, target: details.Target, attackPosition: details.AttackPosition, targetPosition: details.TargetPosition, numTargets: 1, meleeAttackType: meleeAttackType, isMoraleAttack: false)); }
private static void Postfix(Mech __instance, WeaponHitInfo hitInfo, Weapon weapon, MeleeAttackType meleeAttackType) { AttackDirector.AttackSequence attackSequence = __instance.Combat.AttackDirector.GetAttackSequence(hitInfo.attackSequenceId); AbstractActor actor = __instance.Combat.FindActorByGUID(hitInfo.targetId); if (actor is Mech) { Mech target = actor as Mech; float stabilityDamage = hitInfo.ConsolidateInstability(weapon.Instability(), __instance.Combat.Constants.ResolutionConstants.GlancingBlowDamageMultiplier, __instance.Combat.Constants.ResolutionConstants.NormalBlowDamageMultiplier, __instance.Combat.Constants.ResolutionConstants.SolidBlowDamageMultiplier); stabilityDamage *= __instance.StatCollection.GetValue <float>("ReceivedInstabilityMultiplier"); stabilityDamage *= __instance.EntrenchedMultiplier; if (AttackDirector.attackLogger.IsLogEnabled) { AttackDirector.attackLogger.Log("[CBTPiloting] Checking Piloting Stability"); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Is Mech: {0}", (actor is Mech))); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Weapon Stab Dmg: {0}", stabilityDamage)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Target Dead: {0}", target.IsDead)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Target Unsteady: {0}", target.IsUnsteady)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Target IsOrWillBeProne: {0}", target.IsOrWillBeProne)); } if (stabilityDamage > 0 && !target.IsDead && target.IsUnsteady && !target.IsOrWillBeProne) { float skillBonus = (float)target.SkillPiloting / __instance.Combat.Constants.PilotingConstants.PilotingDivisor; float skillRoll = __instance.Combat.NetworkRandom.Float(); float skillTotal = skillRoll + skillBonus; if (AttackDirector.attackLogger.IsLogEnabled) { AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Bonus: {0}", skillBonus)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Roll: {0}", skillRoll)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Roll Total: {0}", skillTotal)); AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Target: {0}", CBTPiloting.Settings.PilotStabilityCheck)); } if (skillTotal < CBTPiloting.Settings.PilotStabilityCheck) { if (AttackDirector.attackLogger.IsLogEnabled) { AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Check Failed! Flagging for Knockdown")); } target.FlagForKnockdown(); target.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(new ShowActorInfoSequence(target, $"Stability Check: Failed!", FloatieMessage.MessageNature.Debuff, true))); } else { if (AttackDirector.attackLogger.IsLogEnabled) { AttackDirector.attackLogger.Log(string.Format("[CBTPiloting] Skill Check Succeeded!")); } target.Combat.MessageCenter.PublishMessage(new AddSequenceToStackMessage(new ShowActorInfoSequence(target, $"Stability Check: Passed!", FloatieMessage.MessageNature.Buff, true))); } } } }
public static void Postfix(Mech __instance, WeaponHitInfo hitInfo, Weapon weapon, MeleeAttackType meleeAttackType) { Mod.Log.Trace("M:RWD entered."); AttackDirector.AttackSequence attackSequence = __instance.Combat.AttackDirector.GetAttackSequence(hitInfo.attackSequenceId); AbstractActor target = __instance.Combat.FindActorByGUID(hitInfo.targetId); if (target is Mech targetMech) { // Feature: Piloting Skill Check from instability // TODO: Let instability represent this? CombatResolutionConstantsDef crcd = target.Combat.Constants.ResolutionConstants; float stabilityDamage = hitInfo.ConsolidateInstability(hitInfo.targetId, weapon.Instability(), crcd.GlancingBlowDamageMultiplier, crcd.NormalBlowDamageMultiplier, crcd.SolidBlowDamageMultiplier); stabilityDamage *= __instance.StatCollection.GetValue <float>("ReceivedInstabilityMultiplier"); stabilityDamage *= __instance.EntrenchedMultiplier; MechHelper.PilotCheckOnInstabilityDamage(targetMech, stabilityDamage); } }