コード例 #1
0
        static void evaluateWeaponAttackOnVehicle(float expectedDamage, Weapon w, ref DamageExpectationRecord damageExpectationRecord, Vector3 attackerPosition, Vehicle targetVehicle, Vector3 targetPosition, Quaternion targetRotation)
        {
            // use hit table to figure out where this will go
            Dictionary <VehicleChassisLocations, float> locations = GetLocationDictionary(attackerPosition, targetVehicle, targetPosition, targetRotation);

            foreach (KeyValuePair <VehicleChassisLocations, float> locKVP in locations)
            {
                VehicleChassisLocations loc = locKVP.Key;
                float probability           = locKVP.Value;

                DamageExpectationRecord locRecord = new DamageExpectationRecord();
                damageExpectationRecord.AddChildRecord(probability, locRecord);

                float existingArmor          = targetVehicle.ArmorForLocation((int)loc);
                float armorThatWillBeRemoved = Mathf.Min(existingArmor, expectedDamage);
                float damageRemaining        = expectedDamage - existingArmor;
                locRecord.AddVehicleArmorDamage(armorThatWillBeRemoved, loc);

                if (damageRemaining > 0)
                {
                    // some goes in to the structure
                    float currentStructure = targetVehicle.GetCurrentStructure(loc);

                    float structureDamage = Mathf.Min(damageRemaining, currentStructure);
                    //float damageAfterStructure = damageRemaining - structureDamage;

                    locRecord.AddVehicleStructureDamage(structureDamage, loc);
                }
            }
        }
コード例 #2
0
        // 0-19  == 1-20 = left side  -> 20
        // 20-39 == 21-40 = right side -> 20
        // 40-83 == 41-85 = front / rear -> 45
        // 84-99 == 85-100 = turret -> 15
        public static VehicleChassisLocations GetRandomVehicleLocation()
        {
            VehicleChassisLocations location = VehicleChassisLocations.Front;

            bool isFront     = Mod.Random.Next(0, 100) < 80;
            int  locationIdx = Mod.Random.Next(0, 100);

            if (locationIdx <= 19)
            {
                location = VehicleChassisLocations.Left;
            }
            else if (locationIdx <= 39)
            {
                location = VehicleChassisLocations.Right;
            }
            else if (locationIdx <= 83)
            {
                location = isFront ? VehicleChassisLocations.Front : VehicleChassisLocations.Rear;
            }
            else if (locationIdx <= 99)
            {
                location = VehicleChassisLocations.Turret;
            }

            Mod.Log.Trace?.Write($" - Returning random location: {location}");
            return(location);
        }
コード例 #3
0
 public static void RecordVehicleDamage(Vehicle __instance, VehicleChassisLocations vLoc, float totalDamage)
 {
     if (vLoc == VehicleChassisLocations.None || vLoc == VehicleChassisLocations.Invalid)
     {
         return;
     }
     RecordUnitDamage(vLoc.ToString(), totalDamage, __instance.GetCurrentArmor(vLoc), __instance.GetCurrentStructure(vLoc));
 }
コード例 #4
0
 public static void LogVehicleHit(VehicleChassisLocations __result, Dictionary <VehicleChassisLocations, int> hitTable, float randomRoll, VehicleChassisLocations bonusLocation, float bonusLocationMultiplier)
 {
     LogHitSequence(__result, randomRoll, bonusLocation, bonusLocationMultiplier,
                    TryGet(hitTable, VehicleChassisLocations.Turret) + Separator +
                    TryGet(hitTable, VehicleChassisLocations.Front) + Separator +
                    TryGet(hitTable, VehicleChassisLocations.Left) + Separator +
                    TryGet(hitTable, VehicleChassisLocations.Right) + Separator +
                    TryGet(hitTable, VehicleChassisLocations.Rear) + FillBlanks(3));
 }
コード例 #5
0
        public void AddVehicleArmorDamage(float damage, VehicleChassisLocations loc)
        {
            float existingDamage = 0.0f;

            if (vehicleArmorLocationDictionary.ContainsKey(loc))
            {
                existingDamage = vehicleArmorLocationDictionary[loc];
            }
            vehicleArmorLocationDictionary[loc] = existingDamage + damage;
        }
コード例 #6
0
 public static void LogVehicleDamage(Vehicle __instance, VehicleChassisLocations vLoc)
 {
     try {
         if (vLoc == VehicleChassisLocations.None || vLoc == VehicleChassisLocations.Invalid)
         {
             return;
         }
         LogActorDamage(__instance.GetCurrentArmor(vLoc), __instance.GetCurrentStructure(vLoc));
     }                 catch (Exception ex) { Error(ex); }
 }
コード例 #7
0
 public RepairRecord()
 {
     InnerStructure          = 0f;
     Armor                   = 0f;
     Components              = 0;
     TurnsSinceDamage        = 1;
     MechStructureLocations  = new ChassisLocations[0];
     MechArmorLocations      = new ArmorLocation[0];
     VehicleLocations        = new VehicleChassisLocations[0];
     AffectInstalledLocation = false;
     repairTrigger           = new RepairTrigger();
 }
コード例 #8
0
        internal static void applyStructureStatDamage(
            Vehicle vehicle,
            VehicleChassisLocations location,
            float damage,
            WeaponHitInfo hitInfo
            )
        {
            try
            {
                if (!ComponentExplosionsFeature.IsInternalExplosion)
                {
                    return;
                }

                var properties = ComponentExplosionsFeature.Shared.GetCASEProperties(vehicle, (int)location);
                if (properties?.MaximumDamage == null)
                {
                    return;
                }

                var directDamage = Mathf.Min(damage, properties.MaximumDamage.Value);
                var backDamage   = damage - directDamage;
                Control.Logger.Debug?.Log($"reducing structure damage from {damage} to {directDamage} in {location}");
                damage = directDamage;

                if (backDamage <= 0)
                {
                    return;
                }

                vehicle.PublishFloatieMessage("EXPLOSION REDIRECTED");

                var armorLocation = VehicleChassisLocations.Rear;
                var armor         = vehicle.GetCurrentArmor(armorLocation);
                if (armor <= 0)
                {
                    return;
                }

                var armorDamage = Mathf.Min(backDamage, armor);
                Control.Logger.Debug?.Log($"added blowout armor damage {armorDamage} to {armorLocation}");

                vehicle.applyArmorStatDamage(armorLocation, armorDamage, hitInfo);
            }
            catch (Exception e)
            {
                Control.Logger.Error.Log(e);
            }
            finally
            {
                vehicle.applyStructureStatDamage(location, damage, hitInfo);
            }
        }
コード例 #9
0
 internal static float FixMultiplier(VehicleChassisLocations location, float multiplier)
 {
     if (location == VehicleChassisLocations.None)
     {
         return(0);
     }
     if (VehicleCalledShotMultiplier != 1)
     {
         multiplier *= VehicleCalledShotMultiplier;
     }
     // ClusterChanceNeverMultiplyHead does not apply to Vehicle
     return(multiplier);
 }
コード例 #10
0
        private static void ShowDamageFloatie(Vehicle vehicle, VehicleChassisLocations location, float damage, string sourceGUID)
        {
            if (vehicle != null && vehicle.GameRep != null)
            {
                Vector3 vector = vehicle.GameRep.GetHitPosition((int)location) + UnityEngine.Random.insideUnitSphere * 5f;
                FloatieMessage.MessageNature nature = vehicle.GetCurrentArmor(location) > 0f ?
                                                      FloatieMessage.MessageNature.ArmorDamage : FloatieMessage.MessageNature.StructureDamage;

                FloatieMessage message = new FloatieMessage(sourceGUID, vehicle.GUID, $"{damage}",
                                                            SharedState.Combat.Constants.CombatUIConstants.floatieSizeMedium, nature,
                                                            vector.x, vector.y, vector.z);

                SharedState.Combat.MessageCenter.PublishMessage(message);
            }
        }
コード例 #11
0
        public float GetVehicleStructureDamageForLocation(VehicleChassisLocations loc)
        {
            float dmg = 0.0f;

            if (vehicleChassisLocationDictionary.ContainsKey(loc))
            {
                dmg = vehicleChassisLocationDictionary[loc];
            }

            for (int childIndex = 0; childIndex < children.Count; ++childIndex)
            {
                ChildWithProbability c = children[childIndex];
                dmg += c.DamageExpectationRecord.GetVehicleStructureDamageForLocation(loc) * c.Probability;
            }
            return(dmg);
        }
コード例 #12
0
        public static ChassisLocations FakeVehicleLocation(this VehicleChassisLocations loc)
        {
            switch (loc)
            {
            case VehicleChassisLocations.Front: return(ChassisLocations.LeftArm);

            case VehicleChassisLocations.Rear: return(ChassisLocations.RightArm);

            case VehicleChassisLocations.Turret: return(ChassisLocations.Head);

            case VehicleChassisLocations.Left: return(ChassisLocations.LeftLeg);

            case VehicleChassisLocations.Right: return(ChassisLocations.RightLeg);

            default: return(ChassisLocations.None);
            }
        }
コード例 #13
0
 internal static float GetCurrentArmor(
     Vehicle vehicle,
     VehicleChassisLocations location
     )
 {
     try
     {
         if (ComponentExplosionsFeature.IsInternalExplosion)
         {
             return(0);
         }
     }
     catch (Exception e)
     {
         Control.mod.Logger.LogError(e);
     }
     return(vehicle.GetCurrentArmor(location));
 }
コード例 #14
0
        public static bool OverrideHUDVehicleCalledShotPercent(ref string __result, VehicleChassisLocations location, VehicleChassisLocations targetedLocation)
        {
            try {
                Dictionary <VehicleChassisLocations, int> hitTable = Combat.HitLocation.GetVehicleHitTable(AttackDirection);
                if (CacheNeedRefresh(hitTable, (int)targetedLocation))
                {
                    HitTableTotalWeight = SumWeight(hitTable, targetedLocation, FixMultiplier(targetedLocation, ActorCalledShotBonus), scale);
                }

                int local = TryGet(hitTable, location) * scale;
                if (location == targetedLocation)
                {
                    local = (int)(local * FixMultiplier(targetedLocation, ActorCalledShotBonus));
                }

                __result = FineTuneAndFormat(hitTable, location, local, Settings.ShowRealVehicleCalledShotChance);
                return(false);
            }                 catch (Exception ex) { return(Error(ex)); }
        }
コード例 #15
0
        public static VehicleChassisLocations GetSwarmLocationForVehicle()
        {
            int randomIdx  = Mod.Random.Next(0, Mod.Config.Melee.Swarm.VehicleLocationsTotalWeight);
            int currentIdx = 0;
            VehicleChassisLocations selectedLocation = VehicleChassisLocations.Rear;

            foreach (KeyValuePair <VehicleChassisLocations, int> kvp in Mod.Config.Melee.Swarm.VehicleLocations)
            {
                if (randomIdx <= currentIdx + kvp.Value)
                {
                    Mod.Log.Debug?.Write($"randomIdx: {randomIdx} is <= currentIdx: {currentIdx} + weight: {kvp.Value}, using location: {kvp.Key}");
                    selectedLocation = kvp.Key;
                    break;
                }
                else
                {
                    currentIdx += kvp.Value;
                }
            }

            Mod.Log.Debug?.Write($"Returning randomly selected swarm location: {selectedLocation}");
            return(selectedLocation);
        }
コード例 #16
0
        public static void Postfix(Vehicle __instance, VehicleChassisLocations location, float damage, WeaponHitInfo hitInfo)
        {
            Mod.Log.Trace("V:ASSD - entered.");

            if (ModState.BreachCheck == 0f)
            {
                return;
            }                                           // nothing to do
            if (hitInfo.attackSequenceId != ModState.BreachAttackId)
            {
                Mod.Log.Error("INCOHERENT ATTACK SEQUENCE- SKIPPING!");
                return;
            }

            Mod.Log.Debug($" --- Location: {location} needs breach check.");
            if (ModState.BreachHitsVehicle.ContainsKey(location))
            {
                ModState.BreachHitsVehicle[location]++;
            }
            else
            {
                ModState.BreachHitsVehicle.Add(location, 1);
            }
        }
コード例 #17
0
        public static void Postfix(Vehicle __instance, VehicleChassisLocations location, float damage, WeaponHitInfo hitInfo)
        {
            Mod.Log.Trace?.Write("V:ASSD - entered.");

            if (ModState.BreachCheck == 0f || ModState.BreachAttackId == ModState.NO_ATTACK_SEQUENCE_ID)
            {
                return;
            }                                                                                                        // nothing to do
            if (hitInfo.attackSequenceId != ModState.BreachAttackId)
            {
                Mod.Log.Warn?.Write($"AttackSequenceId: {hitInfo.attackSequenceId} does not match hull breach attack sequence id: {ModState.BreachAttackId}... wasn't expecting this, skipping!");
                return;
            }

            Mod.Log.Debug?.Write($" --- Location: {location} needs breach check.");
            if (ModState.BreachHitsVehicle.ContainsKey(location))
            {
                ModState.BreachHitsVehicle[location]++;
            }
            else
            {
                ModState.BreachHitsVehicle.Add(location, 1);
            }
        }
コード例 #18
0
 internal VehiclePlaceholderInterpolation(MechComponent mechComponent)
 {
     MechComponent = mechComponent;
     Location      = mechComponent.vehicleComponentRef.MountedLocation;
 }
コード例 #19
0
        private static float PercentForLocation(Vehicle v, VehicleChassisLocations location)
        {
            if (v != null)
            {
                var maxs = MaxStructureForLocation(v, (int)location);
                var maxa = MaxArmorForLocation(v, (int)location);
                var cs   = maxs;
                var ca   = maxa;
                if (maxs == 0 || maxa == 0)
                {
                    LogDebug($"Invalid location in vehicle {location.ToString()}");
                    return(1);
                }

                switch (location)
                {
                case VehicleChassisLocations.Turret:
                    cs = v.TurretStructure;
                    ca = v.TurretArmor;
                    break;

                case VehicleChassisLocations.Left:
                    cs = v.LeftSideStructure;
                    ca = v.LeftSideArmor;
                    break;

                case VehicleChassisLocations.Right:
                    cs = v.RightSideStructure;
                    ca = v.RightSideArmor;
                    break;

                case VehicleChassisLocations.Front:
                    cs = v.FrontStructure;
                    ca = v.FrontArmor;
                    break;

                case VehicleChassisLocations.Rear:
                    cs = v.RearStructure;
                    ca = v.RearArmor;
                    break;

                default:
                    LogDebug($"Invalid location {location}");
                    break;
                }

                float percentArmor     = ca / maxa;
                float percentStructure = cs / maxs;

                //since its easy to kill vehicles once past armor use the armor instead of structure unless structure is damaged.
                //this is reverse of mechs.
                //Remember the vehicle pilot motto - in armor we trust , structure is for the dead and defeated.
                float percentLocation = percentArmor;
                float numAdditions    = 2;

                // Use the minimum percentage between structure and armor
                // This emphasizes internal damage from a blow through (back armor gone or tandem weapons)
                percentLocation += Math.Min(percentArmor, percentStructure);
                percentLocation /= numAdditions;
                LogReport($"{location.ToString(),-20} | A:{ca:F3}/{maxa:F3} = {percentArmor * 100,10}% , S:{cs:F3}/{maxs:F3} = {percentStructure * 100,10:F3}%");
                return(percentLocation);
            }
            LogDebug($"Vehicle null");
            return(0);
        }
コード例 #20
0
 internal static bool DamageLocation(this Vehicle vehicle, WeaponHitInfo hitInfo, int originalHitLoc, VehicleChassisLocations vLoc, Weapon weapon, float totalDamage, AttackImpactQuality impactQuality)
 {
     return(Traverse.Create(vehicle).Method(nameof(DamageLocation), hitInfo, originalHitLoc, vLoc, weapon, totalDamage, impactQuality).GetValue <bool>());
 }
コード例 #21
0
 public static void PrefixVehicleCalledShot(VehicleChassisLocations bonusLocation, ref float bonusLocationMultiplier)
 {
     try {
         bonusLocationMultiplier = FixMultiplier(bonusLocation, bonusLocationMultiplier);
     }                 catch (Exception ex) { Error(ex); }
 }
コード例 #22
0
 internal static void applyArmorStatDamage(this Vehicle vehicle, VehicleChassisLocations location, float damage, WeaponHitInfo hitInfo)
 {
     Traverse.Create(vehicle).Method(nameof(applyArmorStatDamage), location, damage, hitInfo).GetValue();
 }
コード例 #23
0
        static bool Prefix(PoorlyMaintainedEffect __instance, Vehicle targetVehicle)
        {
            Mod.Log.Trace?.Write("PME:AETV - entered.");

            // Note that OnEffectBegin will invoke *every* ApplyEffects, and expects the ApplyEfect to check that the target isn't null.
            if (targetVehicle == null)
            {
                return(false);
            }

            Mod.Log.Info?.Write($" Applying PoorlyMaintainedEffect to unit: {CombatantUtils.Label(targetVehicle)}");
            ModState.SuppressShowActorSequences = true;

            WeaponHitInfo hitInfo = new WeaponHitInfo(-1, -1, -1, -1, "", "", -1,
                                                      null, null, null, null, null, null, null,
                                                      new AttackDirection[] { AttackDirection.FromFront }, null, null, null);

            // Apply any structure damage first
            StringBuilder      componentDamageSB = new StringBuilder();
            VehicleRepairState repairState       = new VehicleRepairState(__instance, targetVehicle);

            foreach (MechComponent mc in repairState.DamagedComponents)
            {
                if (mc.componentType == ComponentType.AmmunitionBox)
                {
                    AmmunitionBox ab            = (AmmunitionBox)mc;
                    float         ammoReduction = Mod.Random.Next(
                        (int)(Mod.Config.PerHitPenalties.MinAmmoRemaining * 100f),
                        (int)(Mod.Config.PerHitPenalties.MaxAmmoRemaining * 100f)
                        ) / 100f;
                    int newAmmo = (int)Math.Floor(ab.CurrentAmmo * ammoReduction);
                    Mod.Log.Info?.Write($"Reducing ammoBox: {mc.UIName} from {ab.CurrentAmmo} x {ammoReduction} = {newAmmo}");
                    ab.StatCollection.Set <int>(ModStats.AmmoBoxCurrentAmmo, newAmmo);
                }
                else
                {
                    Mod.Log.Info?.Write($"Damaging component: {mc.UIName}");
                    Text localText = new Text(" - {0}\n", new object[] { mc.UIName });
                    componentDamageSB.Append(localText.ToString());

                    mc.DamageComponent(hitInfo, ComponentDamageLevel.Destroyed, false);
                }
            }

            // Then apply any armor hits
            HashSet <VehicleChassisLocations> armorHitLocs = new HashSet <VehicleChassisLocations>();

            for (int i = 0; i < repairState.ArmorHits; i++)
            {
                VehicleChassisLocations location = LocationHelper.GetRandomVehicleLocation();
                armorHitLocs.Add(location);
                float maxArmor       = targetVehicle.GetMaxArmor(location);
                float maxDamageRatio = Mod.Random.Next(
                    (int)(Mod.Config.PerHitPenalties.MinArmorLoss * 100),
                    (int)(Mod.Config.PerHitPenalties.MaxArmorLoss * 100)
                    ) / 100f;
                float damage = (float)Math.Floor(maxArmor * maxDamageRatio);
                if (targetVehicle.GetCurrentArmor(location) - damage < 0)
                {
                    damage = targetVehicle.GetCurrentArmor(location);
                }
                Mod.Log.Info?.Write($"Reducing armor in location {location} by {maxDamageRatio}% for {damage} points");

                if (damage != 0)
                {
                    targetVehicle.StatCollection.ModifyStat <float>(hitInfo.attackerId, hitInfo.stackItemUID,
                                                                    targetVehicle.GetStringForArmorLocation(location),
                                                                    StatCollection.StatOperation.Float_Subtract, damage, -1, true);
                }
            }

            // We don't limit to armor damage locations here so we can represent that armor is easily scavenged
            HashSet <VehicleChassisLocations> structHitLocs = new HashSet <VehicleChassisLocations>();

            for (int i = 0; i < repairState.StructureHits; i++)
            {
                VehicleChassisLocations location = LocationHelper.GetRandomVehicleLocation();
                structHitLocs.Add(location);
                float maxStructure   = targetVehicle.GetMaxStructure(location);
                float maxDamageRatio = Mod.Random.Next(
                    (int)(Mod.Config.PerHitPenalties.MinStructureLoss * 100),
                    (int)(Mod.Config.PerHitPenalties.MaxStructureLoss * 100)
                    ) / 100f;
                float damage = (float)Math.Floor(maxStructure * maxDamageRatio);
                if (targetVehicle.GetCurrentStructure(location) - damage < 1)
                {
                    // Never allow a hit to completely remove a limb or location
                    damage = targetVehicle.GetCurrentStructure(location) - 1;
                }
                Mod.Log.Info?.Write($"Reducing structure in location {location} by {maxDamageRatio}% for {damage} points");

                if (damage != 0)
                {
                    targetVehicle.StatCollection.ModifyStat <float>(hitInfo.attackerId, hitInfo.stackItemUID,
                                                                    targetVehicle.GetStringForStructureLocation(location),
                                                                    StatCollection.StatOperation.Float_Subtract, damage, -1, true);
                }

                targetVehicle.UpdateLocationDamageLevel(location, hitInfo.attackerId, hitInfo.stackItemUID);
            }

            // Vehicles have no head armor, can't take health hits
            PilotHelper.ApplyPilotSkillDamage(targetVehicle, hitInfo, repairState.PilotSkillHits, out string pilotSkillDamageTooltipText);

            // Build the tooltip
            StringBuilder descSB = new StringBuilder();

            if (repairState.ArmorHits > 0)
            {
                Text localText = new Text(Mod.Config.LocalizedText[ModConfig.LT_TT_DAMAGE_ARMOR], new object[] { repairState.ArmorHits });
                descSB.Append(localText.ToString());
                foreach (ChassisLocations hitLoc in armorHitLocs)
                {
                    Text locationText = new Text(" - {0}\n", new object[] { hitLoc });
                    descSB.Append(locationText.ToString());
                }
            }
            if (repairState.StructureHits > 0)
            {
                Text localText = new Text(Mod.Config.LocalizedText[ModConfig.LT_TT_DAMAGE_STRUCTURE], new object[] { repairState.StructureHits });
                descSB.Append(localText.ToString());
                foreach (ChassisLocations hitLoc in structHitLocs)
                {
                    Text locationText = new Text(" - {0}\n", new object[] { hitLoc });
                    descSB.Append(locationText.ToString());
                }
            }
            if (componentDamageSB.Length > 0)
            {
                Text localText = new Text(Mod.Config.LocalizedText[ModConfig.LT_TT_DAMAGE_COMP]);
                descSB.Append(localText.ToString());
                descSB.Append(componentDamageSB.ToString());
            }

            if (pilotSkillDamageTooltipText != null)
            {
                Text localText = new Text(Mod.Config.LocalizedText[ModConfig.LT_TT_DAMAGE_SKILL]);
                descSB.Append(localText.ToString());
                descSB.Append(pilotSkillDamageTooltipText.ToString());
            }

            Text titleText = new Text(ModState.CurrentTheme.Label, new object[] { repairState.effectRating });

            __instance.EffectData.Description = new BaseDescriptionDef("PoorlyMaintained",
                                                                       titleText.ToString(), descSB.ToString(), __instance.EffectData.Description.Icon);

            ModState.SuppressShowActorSequences = false;
            return(false);
        }
コード例 #24
0
 public static void FixZombieVehicle(Vehicle __instance, ref float totalDamage, VehicleChassisLocations vLoc)
 {
     try {
         if (vLoc == VehicleChassisLocations.None || vLoc == VehicleChassisLocations.Invalid)
         {
             return;
         }
         KillZombie("vehicle", __instance.DisplayName, __instance.GetCurrentArmor(vLoc) + __instance.GetCurrentStructure(vLoc), ref totalDamage);
     }                 catch (Exception ex) { Error(ex); }
 }
コード例 #25
0
        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);
        }
コード例 #26
0
 internal VehicleLocationNaming(VehicleChassisLocations location)
 {
     this.location = location;
 }