示例#1
0
        static void Postfix(ToHit __instance, ref string __result, AbstractActor attacker, Weapon weapon, ICombatant target,
                            Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
        {
            Mod.Log.Trace?.Write("TH:GAMD entered");

            if (attacker.HasMovedThisRound && attacker.JumpedLastRound ||
                (SharedState.CombatHUD?.SelectionHandler?.ActiveState != null &&
                 SharedState.CombatHUD?.SelectionHandler?.ActiveState is SelectionStateJump))
            {
                string localText = new Text(Mod.LocalizedText.Labels[ModText.LT_Label_Attacker_Jumped]).ToString();
                __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, Mod.Config.ToHitSelfJumped);
            }

            // Check melee patches
            MeleeAttack selectedAttack = ModState.GetSelectedAttack(attacker);

            if (selectedAttack != null && weapon.Type == WeaponType.Melee)
            {
                foreach (KeyValuePair <string, int> kvp in selectedAttack.AttackModifiers)
                {
                    string localText = new Text(Mod.LocalizedText.Labels[kvp.Key]).ToString();
                    Mod.Log.Info?.Write($" - Found attack modifier for desc: {localText} = {kvp.Value}");

                    __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, kvp.Value);
                }
            }
        }
 public static void SaveRangedModifierState(ref float __result, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
 {
     try {
         LineOfFire     = lofLevel;
         IsMoraleAttack = isCalledShot;
         SaveStates(attacker, target, weapon);
     }                 catch (Exception ex) { Error(ex); }
 }
示例#3
0
        private static float GetWeaponDamage(AbstractActor target, WeaponHitInfo hitInfo, Weapon weapon)
        {
            float           damage          = weapon.parent == null ? weapon.DamagePerShot : weapon.DamagePerShotAdjusted(weapon.parent.occupiedDesignMask);
            AbstractActor   attacker        = Combat.FindActorByGUID(hitInfo.attackerId);
            LineOfFireLevel lineOfFireLevel = attacker.VisibilityCache.VisibilityToTarget(target).LineOfFireLevel;

            return(target.GetAdjustedDamage(damage, weapon.Category, target.occupiedDesignMask, lineOfFireLevel, false));
        }
 public static void SaveRangedToolTipState(CombatHUDWeaponSlot __instance, ICombatant target)
 {
     try {
         CombatHUDWeaponSlot slot = __instance;
         LineOfFire     = ActiveState.FiringPreview.GetPreviewInfo(target as AbstractActor).LOFLevel;
         IsMoraleAttack = ActiveState.SelectionType == SelectionType.FireMorale;
         SaveStates(HUD.SelectedActor, target, slot.DisplayedWeapon);
     }                 catch (Exception ex) { Error(ex); }
 }
        static void Postfix(AbstractActor source, ICombatant target, LineOfFireLevel __result)
        {
            if (ModState.CurrentTurretForLOF != null)
            {
                ModState.CurrentTurretForLOF = null;
            }

            if (!source.team.IsLocalPlayer && !(target is BattleTech.Building building))
            {
                Mod.Log.Trace?.Write($"== LOF RESULT: {__result}");
            }
        }
        static void Prefix(AbstractActor source, ICombatant target, LineOfFireLevel __result)
        {
            if (!source.team.IsLocalPlayer && !(target is BattleTech.Building building))
            {
                Mod.Log.Trace?.Write($"== CALCULATING LOF FROM {CombatantUtils.Label(source)} TO TARGET: {CombatantUtils.Label(source)}");
            }

            if (source is Turret turret && ModState.IsUrbanBiome && ModState.AmbushTurretGUIDtoBuilding.Keys.Contains(turret.GUID))
            {
                Mod.Log.Trace?.Write($"Turret {CombatantUtils.Label(turret)} is calculating it's LOF");
                ModState.CurrentTurretForLOF = turret;
            }
        }
        private static void Postfix(ToHit __instance, ref float __result, AbstractActor attacker, Weapon weapon, ICombatant target,
                                    Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel)
        {
            string cacheKey  = StraightTonnageCalculator.CacheKey(attacker, target);
            bool   keyExists = ModState.CachedComparisonMods.TryGetValue(cacheKey, out int modifier);

            if (!keyExists)
            {
                modifier = StraightTonnageCalculator.Modifier(attacker, target);
                ModState.CachedComparisonMods.Add(cacheKey, modifier);
            }

            __result += modifier;
        }
示例#8
0
        private static bool CanSmartIndirect(AbstractActor attacker, Vector3 attackPosition, Quaternion attackRotation, ICombatant target, bool checkWeapon = true)
        {
            bool pointless   = CGS.ToHit.GetIndirectModifier(attacker) >= CGC.ToHit.ToHitCoverObstructed;
            bool unreachable = !attacker.IsTargetPositionInFiringArc(target, attackPosition, attackRotation, target.CurrentPosition);
            bool impossible  = checkWeapon && !CanFireIndirectWeapon(attacker, Vector3.Distance(attackPosition, target.CurrentPosition));

            if (pointless || unreachable || impossible)
            {
                return(false);
            }

            LineOfFireLevel lof = CGS.LOFCache.GetLineOfFire(attacker, attackPosition, target, target.CurrentPosition, target.CurrentRotation, out _);

            return(lof == LineOfFireLevel.LOFObstructed);
        }
示例#9
0
        public bool HasZoomVisionToTarget(Weapon weapon, float distance, LineOfFireLevel lofLevel)
        {
            // If we're firing indirectly, zoom doesn't count
            if (weapon.IndirectFireCapable && lofLevel < LineOfFireLevel.LOFObstructed)
            {
                Mod.Log.Debug?.Write("Line of fire is indirect - cannot use zoom!");
                return(false);
            }

            if (zoomVision == null || weapon.Type == WeaponType.Melee || weapon.Type == WeaponType.NotSet)
            {
                Mod.Log.Debug?.Write("Zoom vision is null, weaponType is melee or unset - cannot use zoom!");
                return(false);
            }

            return(distance < zoomVision.MaximumRange);
        }
示例#10
0
        // 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);
        }
示例#11
0
        static void Postfix(ToHit __instance, ref float __result, AbstractActor attacker, Weapon weapon, ICombatant target,
                            Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
        {
            Mod.Log.Trace?.Write("TH:GAM entered");

            if (__instance == null || weapon == null)
            {
                return;
            }

            if (
                (attacker.HasMovedThisRound && attacker.JumpedLastRound) ||
                (SharedState.CombatHUD?.SelectionHandler?.ActiveState != null &&
                 SharedState.CombatHUD?.SelectionHandler?.ActiveState is SelectionStateJump)
                )
            {
                __result += (float)Mod.Config.ToHitSelfJumped;
            }
        }
        private static bool CanSmartIndirect(AbstractActor attacker, Vector3 attackPosition, Quaternion attackRotation, ICombatant target, bool checkWeapon = true)
        {
            if (Combat.ToHit.GetIndirectModifier(attacker) >= CombatConstants.ToHit.ToHitCoverObstructed)
            {
                return(false);                                                                                           // Abort if it is pointless
            }
            Vector3 targetPos = target.CurrentPosition;

            if (!attacker.IsTargetPositionInFiringArc(target, attackPosition, attackRotation, targetPos))
            {
                return(false);                                                                                            // Abort if can't shot
            }
            if (checkWeapon && !CanFireIndirectWeapon(attacker, Vector3.Distance(attackPosition, targetPos)))
            {
                return(false);                                                                                                  // Can't indirect
            }
            LineOfFireLevel lof = Combat.LOFCache.GetLineOfFire(attacker, attackPosition, target, targetPos, target.CurrentRotation, out _);

            return(lof == LineOfFireLevel.LOFObstructed);
        }
        public static void Postfix(ToHit __instance, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot, ref string __result)
        {
            string str  = string.Empty;
            bool   flag = lofLevel < LineOfFireLevel.LOFObstructed && (CustomAmmoCategories.getIndirectFireCapable(weapon));
            float  weaponDirectFireModifier = CustomAmmoCategories.getDirectFireModifier(weapon);

            if (flag == false)
            {
                //CustomAmmoCategoriesLog.Log.LogWrite(attacker.DisplayName + " has LOS on " + target.DisplayName + ". Apply DirectFireModifier " + weaponDirectFireModifier + "\n");
                if (!NvMath.FloatIsNearZero(weaponDirectFireModifier))
                {
                    __result = string.Format("{0}WEAPON-DIRECT-FIRE {1:+#;-#}; ", (object)__result, (object)(int)weaponDirectFireModifier);
                }
            }
            CombatGameState combat = (CombatGameState)typeof(ToHit).GetField("combat", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance);

            return;
        }
 public static bool OverrideRangedModifiers(ref float __result, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
 {
     try {
         __result = SumModifiers(RangedModifiers);
         return(false);
     } catch (Exception ex) {
         return(Error(new ApplicationException("Error in ranged modifier '" + thisModifier + "'", ex)));
     }
 }
 public static void Postfix(LineOfSight __instance, AbstractActor source, Vector3 sourcePosition, ICombatant target, ref LineOfFireLevel __result)
 {
     if (target is AbstractActor a && a.HasIndirectFireImmunity && __instance.GetVisibilityToTargetWithPositionsAndRotations(source, sourcePosition, a) != VisibilityLevel.LOSFull)
     {
         __result = LineOfFireLevel.LOFBlocked;
     }
 }
示例#16
0
        /*static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
         * {
         *  var targetPropertyGetter = AccessTools.Property(typeof(Weapon), "IndirectFireCapable").GetGetMethod();
         *  var replacementMethod = AccessTools.Method(typeof(ToHit_GetAllModifiersDescription), nameof(IndirectFireCapable));
         *  return Transpilers.MethodReplacer(instructions, targetPropertyGetter, replacementMethod);
         * }
         *
         * private static bool IndirectFireCapable(Weapon weapon)
         * {
         *  //CustomAmmoCategoriesLog.Log.LogWrite("get ToHit_GetAllModifiersDescription IndirectFireCapable\n");
         *  return CustomAmmoCategories.getIndirectFireCapable(weapon);
         * }*/

        public static bool Prefix(ToHit __instance, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot, ref string __result)
        {
            string str                      = string.Empty;
            bool   flag                     = lofLevel < LineOfFireLevel.LOFObstructed && (CustomAmmoCategories.getIndirectFireCapable(weapon));
            float  rangeModifier            = __instance.GetRangeModifier(weapon, attackPosition, targetPosition);
            float  coverModifier            = __instance.GetCoverModifier(attacker, target, lofLevel);
            float  selfSpeedModifier        = __instance.GetSelfSpeedModifier(attacker);
            float  sprintedModifier         = __instance.GetSelfSprintedModifier(attacker);
            float  armMountedModifier       = __instance.GetSelfArmMountedModifier(weapon);
            float  stoodUpModifier          = __instance.GetStoodUpModifier(attacker);
            float  heightModifier           = __instance.GetHeightModifier(attackPosition.y, targetPosition.y);
            float  heatModifier             = __instance.GetHeatModifier(attacker);
            float  targetTerrainModifier    = __instance.GetTargetTerrainModifier(target, targetPosition, false);
            float  selfTerrainModifier      = __instance.GetSelfTerrainModifier(attackPosition, false);
            float  targetSpeedModifier      = __instance.GetTargetSpeedModifier(target, weapon);
            float  selfDamageModifier       = __instance.GetSelfDamageModifier(attacker, weapon);
            float  targetSizeModifier       = __instance.GetTargetSizeModifier(target);
            float  shutdownModifier         = __instance.GetTargetShutdownModifier(target, false);
            float  targetProneModifier      = __instance.GetTargetProneModifier(target, false);
            float  accuracyModifier1        = __instance.GetWeaponAccuracyModifier(attacker, weapon);
            float  accuracyModifier2        = __instance.GetAttackerAccuracyModifier(attacker);
            float  enemyEffectModifier      = __instance.GetEnemyEffectModifier(target);
            float  refireModifier           = __instance.GetRefireModifier(weapon);
            float  directFireModifier       = __instance.GetTargetDirectFireModifier(target, flag);
            float  indirectModifier         = __instance.GetIndirectModifier(attacker, flag);
            float  moraleAttackModifier     = __instance.GetMoraleAttackModifier(target, isCalledShot);
            float  weaponDirectFireModifier = CustomAmmoCategories.getDirectFireModifier(weapon);

            if (!NvMath.FloatIsNearZero(rangeModifier))
            {
                str = string.Format("{0}RANGE {1:+#;-#}; ", (object)str, (object)(int)rangeModifier);
            }
            if (!NvMath.FloatIsNearZero(coverModifier))
            {
                str = string.Format("{0}COVER {1:+#;-#}; ", (object)str, (object)(int)rangeModifier);
            }
            if (!NvMath.FloatIsNearZero(selfSpeedModifier))
            {
                str = string.Format("{0}SELF-MOVED {1:+#;-#}; ", (object)str, (object)(int)selfSpeedModifier);
            }
            if (!NvMath.FloatIsNearZero(sprintedModifier))
            {
                str = string.Format("{0}SELF-SPRINTED {1:+#;-#}; ", (object)str, (object)(int)sprintedModifier);
            }
            if (!NvMath.FloatIsNearZero(armMountedModifier))
            {
                str = string.Format("{0}SELF-ARM MOUNTED {1:+#;-#}; ", (object)str, (object)(int)armMountedModifier);
            }
            if (!NvMath.FloatIsNearZero(stoodUpModifier))
            {
                str = string.Format("{0}STOOD UP {1:+#;-#}; ", (object)str, (object)(int)stoodUpModifier);
            }
            if (!NvMath.FloatIsNearZero(heightModifier))
            {
                str = string.Format("{0}HEIGHT {1:+#;-#}; ", (object)str, (object)(int)heightModifier);
            }
            if (!NvMath.FloatIsNearZero(heatModifier))
            {
                str = string.Format("{0}HEAT {1:+#;-#}; ", (object)str, (object)(int)heatModifier);
            }
            if (!NvMath.FloatIsNearZero(targetTerrainModifier))
            {
                str = string.Format("{0}TERRAIN {1:+#;-#}; ", (object)str, (object)(int)targetTerrainModifier);
            }
            if (!NvMath.FloatIsNearZero(selfTerrainModifier))
            {
                str = string.Format("{0}TERRAIN SELF {1:+#;-#}; ", (object)str, (object)(int)selfTerrainModifier);
            }
            if (!NvMath.FloatIsNearZero(targetSpeedModifier))
            {
                str = string.Format("{0}TARGET-SPEED {1:+#;-#}; ", (object)str, (object)(int)targetSpeedModifier);
            }
            if (!NvMath.FloatIsNearZero(selfDamageModifier))
            {
                str = string.Format("{0}SELF-DAMAGE {1:+#;-#}; ", (object)str, (object)(int)selfDamageModifier);
            }
            if (!NvMath.FloatIsNearZero(targetSizeModifier))
            {
                str = string.Format("{0}TARGET-SIZE {1:+#;-#}; ", (object)str, (object)(int)targetSizeModifier);
            }
            if (!NvMath.FloatIsNearZero(shutdownModifier))
            {
                str = string.Format("{0}TARGET-SHUTDOWN {1:+#;-#}; ", (object)str, (object)(int)shutdownModifier);
            }
            if (!NvMath.FloatIsNearZero(targetProneModifier))
            {
                str = string.Format("{0}TARGET-PRONE {1:+#;-#}; ", (object)str, (object)(int)targetProneModifier);
            }
            if (!NvMath.FloatIsNearZero(accuracyModifier1))
            {
                str = string.Format("{0}ATTACKER-EFFECTS {1:+#;-#}; ", (object)str, (object)(int)accuracyModifier1);
            }
            if (!NvMath.FloatIsNearZero(accuracyModifier2))
            {
                str = string.Format("{0}ATTACKER-SELF-EFFECTS {1:+#;-#}; ", (object)str, (object)(int)accuracyModifier2);
            }
            if (!NvMath.FloatIsNearZero(enemyEffectModifier))
            {
                str = string.Format("{0}ENEMY-EFFECTS {1:+#;-#}; ", (object)str, (object)(int)enemyEffectModifier);
            }
            if (!NvMath.FloatIsNearZero(refireModifier))
            {
                str = string.Format("{0}REFIRE {1:+#;-#}; ", (object)str, (object)(int)refireModifier);
            }
            if (!NvMath.FloatIsNearZero(directFireModifier))
            {
                str = string.Format("{0}DIRECT-FIRE {1:+#;-#}; ", (object)str, (object)(int)directFireModifier);
            }
            if (!NvMath.FloatIsNearZero(indirectModifier))
            {
                str = string.Format("{0}INDIRECT-FIRE {1:+#;-#}; ", (object)str, (object)(int)indirectModifier);
            }
            if (!NvMath.FloatIsNearZero(moraleAttackModifier))
            {
                str = string.Format("{0}CALLED-SHOT {1:+#;-#}; ", (object)str, (object)(int)moraleAttackModifier);
            }
            float b = rangeModifier + coverModifier + selfSpeedModifier + sprintedModifier + armMountedModifier
                      + stoodUpModifier + heightModifier + heatModifier + targetTerrainModifier + selfTerrainModifier
                      + targetSpeedModifier + selfDamageModifier + targetSizeModifier + shutdownModifier + targetProneModifier
                      + accuracyModifier1 + accuracyModifier2 + enemyEffectModifier + refireModifier + directFireModifier
                      + indirectModifier + moraleAttackModifier;

            if (flag == false)
            {
                CustomAmmoCategoriesLog.Log.LogWrite(attacker.DisplayName + " has LOS on " + target.DisplayName + ". Apply DirectFireModifier " + weaponDirectFireModifier + "\n");
                if (!NvMath.FloatIsNearZero(weaponDirectFireModifier))
                {
                    str = string.Format("{0}WEAPON-DIRECT-FIRE {1:+#;-#}; ", (object)str, (object)(int)weaponDirectFireModifier);
                }
                b += weaponDirectFireModifier;
            }
            CombatGameState combat = (CombatGameState)typeof(ToHit).GetField("combat", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance);

            if ((double)b < 0.0 && !combat.Constants.ResolutionConstants.AllowTotalNegativeModifier)
            {
                b = 0.0f;
            }
            float allModifiers = __instance.GetAllModifiers(attacker, weapon, target, attackPosition, targetPosition, lofLevel, isCalledShot);

            if (!NvMath.FloatsAreEqual(allModifiers, b))
            {
                CustomAmmoCategoriesLog.Log.LogWrite("Strange behavior calced modifier " + b + " not equal geted " + allModifiers + "\n");
                AttackDirector.attackLogger.LogError((object)("ERROR!!! breakdown of Universal Modifier didn't match actual Universal Modifier. Check TargetingRules! current modifier: " + (object)b + ", doubleCheck modifier: " + (object)allModifiers));
            }
            __result = str;
            return(false);
        }
示例#17
0
        public static bool Prefix(AttackDirector.AttackSequence __instance, Weapon weapon, int groupIdx, int weaponIdx, int numberOfShots, bool indirectFire, float dodgedDamage, ref WeaponHitInfo __result)
        {
            WeaponHitInfo hitInfo = new WeaponHitInfo();

            hitInfo.attackerId        = __instance.attacker.GUID;
            hitInfo.targetId          = __instance.target.GUID;
            hitInfo.numberOfShots     = numberOfShots;
            hitInfo.stackItemUID      = __instance.stackItemUID;
            hitInfo.attackSequenceId  = __instance.id;
            hitInfo.attackGroupIndex  = groupIdx;
            hitInfo.attackWeaponIndex = weaponIdx;
            hitInfo.toHitRolls        = new float[numberOfShots];
            hitInfo.locationRolls     = new float[numberOfShots];
            hitInfo.dodgeRolls        = new float[numberOfShots];
            hitInfo.dodgeSuccesses    = new bool[numberOfShots];
            hitInfo.hitLocations      = new int[numberOfShots];
            hitInfo.hitPositions      = new Vector3[numberOfShots];
            hitInfo.hitVariance       = new int[numberOfShots];
            hitInfo.hitQualities      = new AttackImpactQuality[numberOfShots];
            if (AttackDirector.hitLogger.IsLogEnabled)
            {
                Vector3         collisionWorldPos;
                LineOfFireLevel lineOfFire           = __instance.Director.Combat.LOS.GetLineOfFire(__instance.attacker, __instance.attackPosition, __instance.target, __instance.target.CurrentPosition, __instance.target.CurrentRotation, out collisionWorldPos);
                float           allModifiers         = __instance.Director.Combat.ToHit.GetAllModifiers(__instance.attacker, weapon, __instance.target, __instance.attackPosition + __instance.attacker.HighestLOSPosition, __instance.target.TargetPosition, lineOfFire, __instance.isMoraleAttack);
                string          modifiersDescription = __instance.Director.Combat.ToHit.GetAllModifiersDescription(__instance.attacker, weapon, __instance.target, __instance.attackPosition + __instance.attacker.HighestLOSPosition, __instance.target.TargetPosition, lineOfFire, __instance.isMoraleAttack);
                Pilot           pilot = __instance.attacker.GetPilot();
                AttackDirector.hitLogger.Log((object)string.Format("======================================== Unit Firing: {0} | Weapon: {1} | Shots: {2}", (object)__instance.attacker.DisplayName, (object)weapon.Name, (object)numberOfShots));
                AttackDirector.hitLogger.Log((object)string.Format("======================================== Hit Info: GROUP {0} | ID {1}", (object)groupIdx, (object)weaponIdx));
                AttackDirector.hitLogger.Log((object)string.Format("======================================== MODIFIERS: {0}... FINAL: [[ {1} ]] ", (object)modifiersDescription, (object)allModifiers));
                if (pilot != null)
                {
                    AttackDirector.hitLogger.Log((object)__instance.Director.Combat.ToHit.GetBaseToHitChanceDesc(__instance.attacker));
                }
                else
                {
                    AttackDirector.hitLogger.Log((object)string.Format("======================================== Gunnery Check: NO PILOT"));
                }
            }
            float toHitChance = __instance.Director.Combat.ToHit.GetToHitChance(__instance.attacker, weapon, __instance.target, __instance.attackPosition, __instance.target.CurrentPosition, __instance.numTargets, __instance.meleeAttackType, __instance.isMoraleAttack);

            if (Mech.TEST_KNOCKDOWN)
            {
                toHitChance = 1f;
            }
            if (AttackDirector.hitLogger.IsLogEnabled)
            {
                AttackDirector.hitLogger.Log((object)string.Format("======================================== HIT CHANCE: [[ {0:P2} ]]", (object)toHitChance));
            }
            hitInfo.attackDirection       = __instance.Director.Combat.HitLocation.GetAttackDirection(__instance.attackPosition, __instance.target);
            hitInfo.attackDirectionVector = __instance.Director.Combat.HitLocation.GetAttackDirectionVector(__instance.attackPosition, __instance.target);
            object[]         args       = new object[6];
            HitGeneratorType hitGenType = HitGeneratorType.NotSet;

            if (weapon.weaponDef.ComponentTags.Contains("wr-clustered_shots"))
            {
                hitGenType = HitGeneratorType.Individual;
            }
            if (hitGenType == HitGeneratorType.NotSet)
            {
                if (CustomAmmoCategories.checkExistance(weapon.StatCollection, CustomAmmoCategories.AmmoIdStatName) == true)
                {
                    string           ammoId  = weapon.StatCollection.GetStatistic(CustomAmmoCategories.AmmoIdStatName).Value <string>();
                    ExtAmmunitionDef extAmmo = CustomAmmoCategories.findExtAmmo(ammoId);
                    hitGenType = extAmmo.HitGenerator;
                }
                if (hitGenType == HitGeneratorType.NotSet)
                {
                    ExtWeaponDef extWeapon = CustomAmmoCategories.getExtWeaponDef(weapon.weaponDef.Description.Id);
                    hitGenType = extWeapon.HitGenerator;
                }
            }
            if (hitGenType != HitGeneratorType.NotSet)
            {
                switch (hitGenType)
                {
                case HitGeneratorType.Individual:
                    args[0] = hitInfo; args[1] = groupIdx; args[2] = weaponIdx; args[3] = weapon; args[4] = toHitChance; args[5] = dodgedDamage;
                    typeof(AttackDirector.AttackSequence).GetMethod("GetIndividualHits", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, args);
                    hitInfo = (WeaponHitInfo)args[0];
                    break;

                case HitGeneratorType.Cluster:
                    args[0] = hitInfo; args[1] = groupIdx; args[2] = weaponIdx; args[3] = weapon; args[4] = toHitChance; args[5] = dodgedDamage;
                    typeof(AttackDirector.AttackSequence).GetMethod("GetClusteredHits", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, args);
                    hitInfo = (WeaponHitInfo)args[0];
                    //__instance.GetClusteredHits(ref hitInfo, groupIdx, weaponIdx, weapon, toHitChance, dodgedDamage);
                    break;

                case HitGeneratorType.Streak:
                    //args[0] = hitInfo; args[1] = groupIdx; args[2] = weaponIdx; args[3] = weapon; args[4] = toHitChance; args[5] = dodgedDamage;
                    //typeof(AttackDirector.AttackSequence).GetMethod("GetClusteredHits", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, args);
                    //hitInfo = (WeaponHitInfo)args[0];
                    AttackSequence_GenerateHitInfo.GetStreakHits(__instance, ref hitInfo, groupIdx, weaponIdx, weapon, toHitChance, dodgedDamage);
                    //__instance.GetClusteredHits(ref hitInfo, groupIdx, weaponIdx, weapon, toHitChance, dodgedDamage);
                    break;

                default:
                    AttackDirector.attackLogger.LogError((object)string.Format("GenerateHitInfo found invalid weapon type: {0}, using basic hit info", (object)hitGenType));
                    args[0] = hitInfo; args[1] = groupIdx; args[2] = weaponIdx; args[3] = weapon; args[4] = toHitChance; args[5] = dodgedDamage;
                    typeof(AttackDirector.AttackSequence).GetMethod("GetIndividualHits", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, args);
                    hitInfo = (WeaponHitInfo)args[0];
                    //__instance.GetIndividualHits(ref hitInfo, groupIdx, weaponIdx, weapon, toHitChance, dodgedDamage);
                    break;
                }
            }
            else
            {
                switch (weapon.Type)
                {
                case WeaponType.Autocannon:
                case WeaponType.Gauss:
                case WeaponType.Laser:
                case WeaponType.PPC:
                case WeaponType.Flamer:
                case WeaponType.Melee:
                    args[0] = hitInfo; args[1] = groupIdx; args[2] = weaponIdx; args[3] = weapon; args[4] = toHitChance; args[5] = dodgedDamage;
                    typeof(AttackDirector.AttackSequence).GetMethod("GetIndividualHits", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, args);
                    hitInfo = (WeaponHitInfo)args[0];
                    //__instance.GetIndividualHits(ref hitInfo, groupIdx, weaponIdx, weapon, toHitChance, dodgedDamage);
                    break;

                case WeaponType.LRM:
                    args[0] = hitInfo; args[1] = groupIdx; args[2] = weaponIdx; args[3] = weapon; args[4] = toHitChance; args[5] = dodgedDamage;
                    typeof(AttackDirector.AttackSequence).GetMethod("GetClusteredHits", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, args);
                    hitInfo = (WeaponHitInfo)args[0];
                    //__instance.GetClusteredHits(ref hitInfo, groupIdx, weaponIdx, weapon, toHitChance, dodgedDamage);
                    break;

                case WeaponType.SRM:
                    args[0] = hitInfo; args[1] = groupIdx; args[2] = weaponIdx; args[3] = weapon; args[4] = toHitChance; args[5] = dodgedDamage;
                    typeof(AttackDirector.AttackSequence).GetMethod("GetIndividualHits", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, args);
                    hitInfo = (WeaponHitInfo)args[0];
                    //__instance.GetIndividualHits(ref hitInfo, groupIdx, weaponIdx, weapon, toHitChance, dodgedDamage);
                    break;

                case WeaponType.MachineGun:
                    args[0] = hitInfo; args[1] = groupIdx; args[2] = weaponIdx; args[3] = weapon; args[4] = toHitChance; args[5] = dodgedDamage;
                    typeof(AttackDirector.AttackSequence).GetMethod("GetIndividualHits", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, args);
                    hitInfo = (WeaponHitInfo)args[0];
                    //__instance.GetIndividualHits(ref hitInfo, groupIdx, weaponIdx, weapon, toHitChance, dodgedDamage);
                    break;

                default:
                    AttackDirector.attackLogger.LogError((object)string.Format("GenerateHitInfo found invalid weapon type: {0}, using basic hit info", (object)weapon.Type));
                    args[0] = hitInfo; args[1] = groupIdx; args[2] = weaponIdx; args[3] = weapon; args[4] = toHitChance; args[5] = dodgedDamage;
                    typeof(AttackDirector.AttackSequence).GetMethod("GetIndividualHits", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, args);
                    hitInfo = (WeaponHitInfo)args[0];
                    //__instance.GetIndividualHits(ref hitInfo, groupIdx, weaponIdx, weapon, toHitChance, dodgedDamage);
                    break;
                }
            }
            __result = hitInfo;
            return(false);
            //return hitInfo;
        }
示例#18
0
        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);
        }
示例#19
0
        /*static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
         * {
         *  var targetPropertyGetter = AccessTools.Property(typeof(Weapon), "IndirectFireCapable").GetGetMethod();
         *  var replacementMethod = AccessTools.Method(typeof(ToHit_GetAllModifiers), nameof(IndirectFireCapable));
         *  return Transpilers.MethodReplacer(instructions, targetPropertyGetter, replacementMethod);
         * }
         *
         * private static bool IndirectFireCapable(Weapon weapon)
         * {
         *  //CustomAmmoCategoriesLog.Log.LogWrite("get ToHit_GetAllModifiers IndirectFireCapable\n");
         *  return CustomAmmoCategories.getIndirectFireCapable(weapon);
         * }*/

        public static bool Prefix(ToHit __instance, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot, ref float __result)
        {
            bool  flag = lofLevel < LineOfFireLevel.LOFObstructed && (CustomAmmoCategories.getIndirectFireCapable(weapon));
            float num  = __instance.GetRangeModifier(weapon, attackPosition, targetPosition)
                         + __instance.GetCoverModifier(attacker, target, lofLevel)
                         + __instance.GetSelfSpeedModifier(attacker)
                         + __instance.GetSelfSprintedModifier(attacker)
                         + __instance.GetSelfArmMountedModifier(weapon)
                         + __instance.GetStoodUpModifier(attacker)
                         + __instance.GetHeightModifier(attackPosition.y, targetPosition.y)
                         + __instance.GetHeatModifier(attacker)
                         + __instance.GetTargetTerrainModifier(target, targetPosition, false)
                         + __instance.GetSelfTerrainModifier(attackPosition, false)
                         + __instance.GetTargetSpeedModifier(target, weapon)
                         + __instance.GetSelfDamageModifier(attacker, weapon)
                         + __instance.GetTargetSizeModifier(target)
                         + __instance.GetTargetShutdownModifier(target, false)
                         + __instance.GetTargetProneModifier(target, false)
                         + __instance.GetWeaponAccuracyModifier(attacker, weapon)
                         + __instance.GetAttackerAccuracyModifier(attacker)
                         + __instance.GetEnemyEffectModifier(target)
                         + __instance.GetRefireModifier(weapon)
                         + __instance.GetTargetDirectFireModifier(target, flag)
                         + __instance.GetIndirectModifier(attacker, flag)
                         + __instance.GetMoraleAttackModifier(target, isCalledShot);

            if (flag == false)
            {
                float directFireModifier = CustomAmmoCategories.getDirectFireModifier(weapon);
                CustomAmmoCategoriesLog.Log.LogWrite(attacker.DisplayName + " has LOS on " + target.DisplayName + ". Apply DirectFireModifier " + directFireModifier + "\n");
                num += CustomAmmoCategories.getDirectFireModifier(weapon);
            }
            CombatGameState combat = (CombatGameState)typeof(ToHit).GetField("combat", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance);

            if ((double)num < 0.0 && !combat.Constants.ResolutionConstants.AllowTotalNegativeModifier)
            {
                num = 0.0f;
            }
            __result = num;
            return(false);
        }
示例#20
0
            // Token: 0x06000025 RID: 37
            private static void Postfix(ToHit __instance, ref float __result, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
            {
                if (UnityGameInstance.BattleTechGame.Simulation != null && weapon != null)
                {
                    Mod.Log.Trace("TH:GAM entered");
                    bool flag3;
                    if (!attacker.HasMovedThisRound || !attacker.JumpedLastRound || attacker.SkillTactics >= Mod.Config.TacticsSkillNegateJump)
                    {
                        CombatHUD combatHUD = ModState.CombatHUD;
                        bool      flag2;
                        if (combatHUD == null)
                        {
                            flag2 = false;
                        }
                        else
                        {
                            CombatSelectionHandler selectionHandler = combatHUD.SelectionHandler;
                            flag2 = (((selectionHandler != null) ? selectionHandler.ActiveState : null) != null);
                        }
                        if (flag2)
                        {
                            CombatHUD combatHUD2 = ModState.CombatHUD;
                            object    obj;
                            if (combatHUD2 == null)
                            {
                                obj = null;
                            }
                            else
                            {
                                CombatSelectionHandler selectionHandler2 = combatHUD2.SelectionHandler;
                                obj = ((selectionHandler2 != null) ? selectionHandler2.ActiveState : null);
                            }
                            if (obj is SelectionStateJump)
                            {
                                flag3 = (attacker.SkillTactics < Mod.Config.TacticsSkillNegateJump);
                                goto IL_D8;
                            }
                        }
                        flag3 = false;
                    }
                    else
                    {
                        flag3 = true;
                    }
IL_D8:
                    if (flag3)
                    {
                        __result += (float)Mod.Config.ToHitSelfJumped;
                    }
                }
            }
            private static void Postfix(ToHit __instance, ref string __result, AbstractActor attacker, Weapon weapon, ICombatant target,
                                        Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
            {
                Mod.Log.Trace("TH:GAMD entered");

                if (attacker.HasMovedThisRound && attacker.JumpedLastRound)
                {
                    __result = string.Format("{0}JUMPED {1:+#;-#}; ", __result, Mod.Config.ToHitSelfJumped);
                }
            }
            private static void Postfix(ToHit __instance, ref float __result, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
            {
                Pilot pilot = attacker.GetPilot();

                try {
                    Pilot TargetPilot = target.GetPilot();
                    if (TargetPilot.pilotDef.PilotTags.Contains("pilot_reckless"))
                    {
                        __result = __result + (float)settings.pilot_reckless_ToBeHitBonus;
                    }
                    if (TargetPilot.pilotDef.PilotTags.Contains("pilot_cautious"))
                    {
                        __result = __result + (float)settings.pilot_reckless_ToBeHitBonus;
                    }
                    if (TargetPilot.pilotDef.PilotTags.Contains("pilot_jinxed"))
                    {
                        __result = __result + (float)settings.pilot_jinxed_ToBeHitBonus;
                    }
                    if (TargetPilot.pilotDef.PilotTags.Contains("pilot_jinxed"))
                    {
                        __result = __result + (float)settings.pilot_reckless_ToBeHitBonus;
                    }
                }
                catch (Exception) {
                }
                if (pilot.pilotDef.PilotTags.Contains("pilot_reckless"))
                {
                    __result = __result + (float)settings.pilot_reckless_ToHitBonus;
                }
                if (pilot.pilotDef.PilotTags.Contains("pilot_cautious"))
                {
                    __result = __result + (float)settings.pilot_reckless_ToHitBonus;
                }
                if (pilot.pilotDef.PilotTags.Contains("pilot_drunk") && pilot.pilotDef.TimeoutRemaining > 0)
                {
                    __result = __result + (float)settings.pilot_drunk_ToHitBonus;
                }
                if (pilot.pilotDef.PilotTags.Contains("pilot_lostech") && weapon.componentDef.ComponentTags.Contains("component_type_lostech"))
                {
                    __result = __result + (float)settings.pilot_lostech_ToHitBonus;
                }
            }
            private static void Postfix(ToHit __instance, ref string __result, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
            {
                Pilot pilot = attacker.GetPilot();

                if (pilot.pilotDef.PilotTags.Contains("pilot_reckless"))
                {
                    __result = string.Format("{0}RECKLESS {1:+#;-#}; ", __result, settings.pilot_reckless_ToHitBonus);
                }

                if (pilot.pilotDef.PilotTags.Contains("pilot_cautious"))
                {
                    __result = string.Format("{0}CAUTIOUS {1:+#;-#}; ", __result, settings.pilot_cautious_ToHitBonus);
                }

                if (pilot.pilotDef.PilotTags.Contains("pilot_drunk") && pilot.pilotDef.TimeoutRemaining > 0)
                {
                    __result = string.Format("{0}DRUNK {1:+#;-#}; ", __result, settings.pilot_drunk_ToHitBonus);
                }

                if (pilot.pilotDef.PilotTags.Contains("pilot_lostech") && weapon.componentDef.ComponentTags.Contains("component_type_lostech"))
                {
                    __result = string.Format("{0}LOSTECH TECHNICIAN {1:+#;-#}; ", __result, settings.pilot_lostech_ToHitBonus);
                }

                if (pilot.pilotDef.PilotTags.Contains("pilot_jinxed"))
                {
                    __result = string.Format("{0}JINXED {1:+#;-#}; ", __result, settings.pilot_reckless_ToHitBonus);
                }
            }
        public static void Postfix(ToHit __instance, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot, ref float __result)
        {
            bool  flag = lofLevel < LineOfFireLevel.LOFObstructed && (CustomAmmoCategories.getIndirectFireCapable(weapon));
            float num  = __result;

            if (flag == false)
            {
                //float directFireModifier = CustomAmmoCategories.getDirectFireModifier(weapon);
                //CustomAmmoCategoriesLog.Log.LogWrite(attacker.DisplayName+" has LOS on "+target.DisplayName+ ". Apply DirectFireModifier "+directFireModifier+"\n");
                num += CustomAmmoCategories.getDirectFireModifier(weapon);
            }
            CombatGameState combat = (CombatGameState)typeof(ToHit).GetField("combat", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance);

            if ((double)num < 0.0 && !combat.Constants.ResolutionConstants.AllowTotalNegativeModifier)
            {
                num = 0.0f;
            }
            __result = num;
            return;
        }
示例#25
0
        //[HarmonyBefore(new string[] { "Sheepy.BattleTechMod.AttackImprovementMod" })]
        private static void Postfix(ToHit __instance, ref string __result, AbstractActor attacker, Weapon weapon, ICombatant target,
                                    Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
        {
            //Mod.Log.Debug?.Write($"Getting modifier descriptions for attacker:{CombatantUtils.Label(attacker)} " +
            //    $"using weapon:{weapon.Name} vs target:{CombatantUtils.Label(target)}");

            //AbstractActor targetActor = target as AbstractActor;
            //if (__instance != null && attacker != null && weapon != null && target != null && targetActor != null) {
            //    float distance = Vector3.Distance(attackPosition, targetPosition);
            //    EWState attackerState = new EWState(attacker);
            //    EWState targetState = new EWState(targetActor);

            //    // Vision modifiers
            //    int zoomVisionMod = attackerState.GetZoomVisionAttackMod(weapon, distance);
            //    int heatVisionMod = attackerState.GetHeatVisionAttackMod(targetActor, distance, weapon);
            //    int mimeticMod = targetState.MimeticAttackMod(attackerState);
            //    bool canSpotTarget = VisualLockHelper.CanSpotTarget(attacker, attacker.CurrentPosition, target, target.CurrentPosition, target.CurrentRotation, attacker.Combat.LOS);

            //    // Sensor modifiers
            //    SensorScanType sensorScan = SensorLockHelper.CalculateSharedLock(targetActor, attacker);
            //    int ecmShieldMod = targetState.ECMAttackMod(attackerState);
            //    int stealthMod = targetState.StealthAttackMod(attackerState, weapon, distance);
            //    int narcMod = targetState.NarcAttackMod(attackerState);
            //    int tagMod = targetState.TagAttackMod(attackerState);
            //    if (Mod.Config.Attack.NoSensorInfoPenalty > (ecmShieldMod + stealthMod + narcMod + tagMod)) { sensorScan = SensorScanType.NoInfo; }

            //    if (sensorScan == SensorScanType.NoInfo && !canSpotTarget) {
            //        string localText = new Localize.Text(Mod.Config.LocalizedText[ModConfig.LT_ATTACK_FIRING_BLIND]).ToString();
            //        __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, Mod.Config.Attack.BlindFirePenalty);
            //    } else {
            //        if (!canSpotTarget) {
            //            string localText = new Localize.Text(Mod.Config.LocalizedText[ModConfig.LT_ATTACK_NO_VISUALS]).ToString();
            //            __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, Mod.Config.Attack.NoVisualsPenalty);
            //        } else {
            //            if (zoomVisionMod != 0) {
            //                string localText = new Localize.Text(Mod.Config.LocalizedText[ModConfig.LT_ATTACK_ZOOM_VISION]).ToString();
            //                __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, zoomVisionMod);
            //            }
            //            if (heatVisionMod != 0) {
            //                string localText = new Localize.Text(Mod.Config.LocalizedText[ModConfig.LT_ATTACK_HEAT_VISION]).ToString();
            //                __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, heatVisionMod);
            //            }
            //            if (mimeticMod != 0) {
            //                string localText = new Localize.Text(Mod.Config.LocalizedText[ModConfig.LT_ATTACK_MIMETIC]).ToString();
            //                __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, mimeticMod);
            //            }
            //        }

            //        if (sensorScan == SensorScanType.NoInfo) {
            //            string localText = new Localize.Text(Mod.Config.LocalizedText[ModConfig.LT_ATTACK_NO_SENSORS]).ToString();
            //            __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, Mod.Config.Attack.NoSensorInfoPenalty);
            //        } else {
            //            if (ecmShieldMod != 0) {
            //                string localText = new Localize.Text(Mod.Config.LocalizedText[ModConfig.LT_ATTACK_ECM_SHEILD]).ToString();
            //                __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, ecmShieldMod);
            //            }
            //            if (stealthMod != 0) {
            //                string localText = new Localize.Text(Mod.Config.LocalizedText[ModConfig.LT_ATTACK_STEALTH]).ToString();
            //                __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, stealthMod);
            //            }
            //            if (ecmShieldMod != 0) {
            //                string localText = new Localize.Text(Mod.Config.LocalizedText[ModConfig.LT_ATTACK_NARCED]).ToString();
            //                __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, narcMod);
            //            }
            //            if (stealthMod != 0) {
            //                string localText = new Localize.Text(Mod.Config.LocalizedText[ModConfig.LT_ATTACK_TAGGED]).ToString();
            //                __result = string.Format("{0}{1} {2:+#;-#}; ", __result, localText, tagMod);
            //            }
            //        }
            //    }
            //}
        }
示例#26
0
        private static void Postfix(ToHit __instance, ref float __result, AbstractActor attacker, Weapon weapon, ICombatant target,
                                    Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel)
        {
            //Mod.Log.Debug?.Write($"Getting modifiers for attacker:{CombatantUtils.Label(attacker)} " +
            //    $"using weapon:{weapon.Name} vs target:{CombatantUtils.Label(target)} with initial result:{__result}");

            AbstractActor targetActor = target as AbstractActor;

            if (__instance != null && attacker != null && targetActor != null)
            {
                float distance = Vector3.Distance(attackPosition, targetPosition);

                // Cache these
                EWState attackerState = new EWState(attacker);
                EWState targetState   = new EWState(targetActor);

                // If we can't see the target, apply the No Visuals penalty
                bool canSpotTarget    = VisualLockHelper.CanSpotTarget(attacker, attacker.CurrentPosition, target, target.CurrentPosition, target.CurrentRotation, attacker.Combat.LOS);
                int  mimeticMod       = targetState.MimeticAttackMod(attackerState);
                int  eyeballAttackMod = canSpotTarget ? mimeticMod : Mod.Config.Attack.NoVisualsPenalty;

                // Zoom applies independently of visibility (request from Harkonnen)
                int zoomVisionMod = attackerState.GetZoomVisionAttackMod(weapon, distance);
                int zoomAttackMod = attackerState.HasZoomVisionToTarget(weapon, distance, lofLevel) ? zoomVisionMod - mimeticMod : Mod.Config.Attack.NoVisualsPenalty;

                bool hasVisualAttack = (eyeballAttackMod < Mod.Config.Attack.NoVisualsPenalty || zoomAttackMod < Mod.Config.Attack.NoVisualsPenalty);

                // Sensor attack bucket.  Sensors always fallback, so roll everything up and cap
                int narcAttackMod      = targetState.NarcAttackMod(attackerState);
                int tagAttackMod       = targetState.TagAttackMod(attackerState);
                int ecmShieldAttackMod = targetState.ECMAttackMod(attackerState);
                int stealthAttackMod   = targetState.StealthAttackMod(attackerState, weapon, distance);

                bool hasSensorAttack  = SensorLockHelper.CalculateSharedLock(targetActor, attacker) > SensorScanType.NoInfo;
                int  sensorsAttackMod = Mod.Config.Attack.NoSensorsPenalty;
                if (hasSensorAttack)
                {
                    sensorsAttackMod  = 0;
                    sensorsAttackMod -= narcAttackMod;
                    sensorsAttackMod -= tagAttackMod;
                    sensorsAttackMod += ecmShieldAttackMod;
                    sensorsAttackMod += stealthAttackMod;
                }
                if (sensorsAttackMod > Mod.Config.Attack.NoSensorsPenalty)
                {
                    sensorsAttackMod = Mod.Config.Attack.NoSensorsPenalty;
                    hasSensorAttack  = false;
                }

                // Check firing blind
                if (!hasVisualAttack && !hasSensorAttack)
                {
                    __result += Mod.Config.Attack.FiringBlindPenalty;
                }
                else
                {
                    __result += (zoomAttackMod < eyeballAttackMod) ? zoomAttackMod : eyeballAttackMod;

                    if (attackerState.HasHeatVisionToTarget(weapon, distance))
                    {
                        __result += attackerState.GetHeatVisionAttackMod(targetActor, distance, weapon);
                    }

                    __result += sensorsAttackMod;
                }
            }
        }
示例#27
0
 private static void Postfix(ToHit __instance, ref float __result, AbstractActor attacker, Weapon weapon, ICombatant target, Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
 {
     if (attacker.HasMovedThisRound && attacker.JumpedLastRound)
     {
         __result = __result + (float)CBTMovement.Settings.ToHitSelfJumped;
     }
 }
            private static void Postfix(ToHit __instance, ref float __result, AbstractActor attacker, Weapon weapon, ICombatant target,
                                        Vector3 attackPosition, Vector3 targetPosition, LineOfFireLevel lofLevel, bool isCalledShot)
            {
                Mod.Log.Trace("TH:GAM entered");

                if (attacker.HasMovedThisRound && attacker.JumpedLastRound)
                {
                    __result = __result + (float)Mod.Config.ToHitSelfJumped;
                }
            }
示例#29
0
        public static bool Prefix(LineOfSight __instance, ref LineOfFireLevel __result, CombatGameState ___Combat,
                                  AbstractActor source, Vector3 sourcePosition, ICombatant target, Vector3 targetPosition, Quaternion targetRotation, out Vector3 collisionWorldPos)
        {
            Mod.Log.Trace?.Write($"LOS:GLOFU entered. ");

            Vector3 forward = targetPosition - sourcePosition;

            forward.y = 0f;
            Quaternion rotation = Quaternion.LookRotation(forward);

            Vector3[] lossourcePositions = source.GetLOSSourcePositions(sourcePosition, rotation);
            Vector3[] lostargetPositions = target.GetLOSTargetPositions(targetPosition, targetRotation);

            List <AbstractActor> allActors = new List <AbstractActor>(___Combat.AllActors);

            allActors.Remove(source);

            AbstractActor abstractActor        = target as AbstractActor;
            string        targetedBuildingGuid = null;

            if (abstractActor != null)
            {
                allActors.Remove(abstractActor);
            }
            else
            {
                targetedBuildingGuid = target.GUID;
            }

            LineSegment lineSegment = new LineSegment(sourcePosition, targetPosition);

            // Sort the target actors by distance from the source
            allActors.Sort((AbstractActor x, AbstractActor y) =>
                           Vector3.Distance(x.CurrentPosition, sourcePosition).CompareTo(Vector3.Distance(y.CurrentPosition, sourcePosition))
                           );
            float targetPositionDistance = Vector3.Distance(sourcePosition, targetPosition);

            for (int i = allActors.Count - 1; i >= 0; i--)
            {
                if (allActors[i].IsDead ||
                    Vector3.Distance(allActors[i].CurrentPosition, sourcePosition) > targetPositionDistance ||
                    lineSegment.DistToPoint(allActors[i].CurrentPosition) > allActors[i].Radius * 5f)
                {
                    // If the actor is
                    //      1) dead
                    //      2) the distance from actor to source is greater than targetPos distance
                    //      3) the distance to the actor is greater than the radious of all actors (?!?)
                    //  remove the actor from consideration
                    allActors.RemoveAt(i);
                }
            }
            float sourcePositionsWithLineOfFireToTargetPositions = 0f; // num2
            float losTargetPositionsCount    = 0f;                     // num3
            float weaponsWithUnobstructedLOF = 0f;                     // num4

            collisionWorldPos = targetPosition;
            float  shortestDistanceFromVectorToIteratedActor = 999999.9f; // num5
            Weapon longestRangeWeapon          = source.GetLongestRangeWeapon(false, false);
            float  maximumWeaponRangeForSource = (longestRangeWeapon != null) ? longestRangeWeapon.MaxRange : 0f;

            // MY CHANGE:
            float adjustedSpotterRange = ___Combat.LOS.GetAdjustedSpotterRange(source, abstractActor);
            float adjustedSensorRange  = ___Combat.LOS.GetAdjustedSensorRange(source, abstractActor);

            //LowVisibility.Logger.Log($"LineOfSight:GetLineOfFireUncached:pre - using sensorRange:{adjustedSensorRange} instead of spotterRange:{adjustedSpotterRange}.  Max weapon range is:{maximumWeaponRangeForSource} ");
            maximumWeaponRangeForSource = Mathf.Max(maximumWeaponRangeForSource, adjustedSensorRange, adjustedSpotterRange);
            for (int j = 0; j < lossourcePositions.Length; j++)
            {
                // Iterate the source positions (presumably each weapon has different source locations)
                for (int k = 0; k < lostargetPositions.Length; k++)
                {
                    // Iterate the target positions (presumably each build/mech has differnet locations)
                    losTargetPositionsCount += 1f;
                    float distanceFromSourceToTarget = Vector3.Distance(lossourcePositions[j], lostargetPositions[k]);
                    if (distanceFromSourceToTarget <= maximumWeaponRangeForSource)
                    {
                        // Possible match, check for collisions
                        lineSegment = new LineSegment(lossourcePositions[j], lostargetPositions[k]);
                        bool    canUseDirectAttack = false;
                        Vector3 vector;
                        if (targetedBuildingGuid == null)
                        {
                            // Not a building, so check for compatible actors
                            for (int l = 0; l < allActors.Count; l++)
                            {
                                if (lineSegment.DistToPoint(allActors[l].CurrentPosition) < allActors[l].Radius)
                                {
                                    vector = NvMath.NearestPointStrict(lossourcePositions[j], lostargetPositions[k], allActors[l].CurrentPosition);
                                    float distanceFromVectorToIteratedActor = Vector3.Distance(vector, allActors[l].CurrentPosition);
                                    if (distanceFromVectorToIteratedActor < allActors[l].HighestLOSPosition.y)
                                    {
                                        // TODO: Could I have this flipped, and .y is the highest y in the path? This is checking for indirect fire?
                                        // If the height of the attack is less than the HighestLOSPosition.y value, we have found the match?
                                        canUseDirectAttack          = true;
                                        weaponsWithUnobstructedLOF += 1f;
                                        if (distanceFromVectorToIteratedActor < shortestDistanceFromVectorToIteratedActor)
                                        {
                                            shortestDistanceFromVectorToIteratedActor = distanceFromVectorToIteratedActor;
                                            collisionWorldPos = vector;
                                        }
                                        break;
                                    }
                                }
                            }
                        }

                        // If there is a source position with LOS to the target, record it
                        if (__instance.HasLineOfFire(lossourcePositions[j], lostargetPositions[k], targetedBuildingGuid, maximumWeaponRangeForSource, out vector))
                        {
                            sourcePositionsWithLineOfFireToTargetPositions += 1f;
                            if (targetedBuildingGuid != null)
                            {
                                break;
                            }
                        }
                        else
                        {
                            // There is no LineOfFire between the source and targert position
                            if (canUseDirectAttack)
                            {
                                weaponsWithUnobstructedLOF -= 1f;
                            }

                            float distanceFromVectorToSourcePosition = Vector3.Distance(vector, sourcePosition);
                            if (distanceFromVectorToSourcePosition < shortestDistanceFromVectorToIteratedActor)
                            {
                                shortestDistanceFromVectorToIteratedActor = distanceFromVectorToSourcePosition;
                                // There is a collection somewhere in the path (MAYBE?)
                                collisionWorldPos = vector;
                            }
                        }
                    }
                }
                if (targetedBuildingGuid != null && sourcePositionsWithLineOfFireToTargetPositions > 0.5f)
                {
                    break;
                }
            }

            // If a building, ignore the various positions (WHY?)
            float ratioSourcePosToTargetPos = (targetedBuildingGuid != null) ?
                                              sourcePositionsWithLineOfFireToTargetPositions : (sourcePositionsWithLineOfFireToTargetPositions / losTargetPositionsCount);

            // "MinRatioFromActors": 0.2,
            float b = ratioSourcePosToTargetPos - ___Combat.Constants.Visibility.MinRatioFromActors;
            float ratioDirectAttacksToTargetPositions = Mathf.Min(weaponsWithUnobstructedLOF / losTargetPositionsCount, b);

            if (ratioDirectAttacksToTargetPositions > 0.001f)
            {
                ratioSourcePosToTargetPos -= ratioDirectAttacksToTargetPositions;
            }

            //LowVisibility.Logger.Log($"LineOfSight:GetLineOfFireUncached:pre - ratio is:{ratioSourcePosToTargetPos} / direct:{ratioDirectAttacksToTargetPositions} / b:{b}");
            // "RatioFullVis": 0.79,
            // "RatioObstructedVis": 0.41,
            if (ratioSourcePosToTargetPos >= ___Combat.Constants.Visibility.RatioFullVis)
            {
                __result = LineOfFireLevel.LOFClear;
            }
            else if (ratioSourcePosToTargetPos >= ___Combat.Constants.Visibility.RatioObstructedVis)
            {
                __result = LineOfFireLevel.LOFObstructed;
            }
            else
            {
                __result = LineOfFireLevel.LOFBlocked;
            }

            Mod.Log.Trace?.Write($"LOS:GLOFU LOS result is:{__result}");

            return(false);
        }
        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)");
        }