Example #1
0
 void OnDamage(ManDamage.DamageInfo info)
 {
     foreach (Spinner target in targetSpinners)
     {
         Vector3 axis = target.m_RotationAxis, perp = new Vector3(0f, 1f - axis.y, axis.y);
         float   angle = Vector3.SignedAngle(perp, target.trans.localRotation * perp, axis);
         target.SetAutoSpin(SetFullSpeedInstead);
         target.Reset();
         target.SetAngle(angle);
     }
 }
            private static int HandleCollision(Projectile __instance, ArmorPiercing armorPiercing, Damageable damageable, Vector3 hitPoint, Vector3 impactVector, Collider otherCollider, bool ForceDestroy)
            {
                int retVal = 0;

                if (!((Component)__instance).gameObject.activeInHierarchy)
                {
                    DebugPrint("projectile is inactive in hierarchy");
                    return(0);
                }
                if ((bool)PatchProjectile.m_Stuck.GetValue(__instance))
                {
                    DebugPrint("projectile is stuck");
                    return(0);
                }
                bool singleImpact  = (bool)PatchProjectile.m_SingleImpact.GetValue(__instance);
                bool hasHitTerrain = false;

                bool  stickOnContact = (bool)PatchProjectile.m_StickOnContact.GetValue(__instance);
                float deathDelay     = (float)PatchProjectile.GetDeathDelay.Invoke(__instance, null);

                // handle damage calculations and explosions
                if (damageable)
                {
                    DebugPrint("Projectile hit a damageable");
                    float damage = armorPiercing.remainingDamage;

                    // Armor pierce works as follows:
                    // Deal full damage to the first block we hit. After that, (1 - pierce) * dealt damage is subtracted from remaining damage (if any)
                    DebugPrint($"Stage 1 - create new DamageInfo");
                    ManDamage.DamageInfo damageInfo = new ManDamage.DamageInfo(damage, (ManDamage.DamageType)PatchProjectile.m_DamageType.GetValue(__instance), (ModuleWeapon)PatchProjectile.m_Weapon.GetValue(__instance), __instance.Shooter, hitPoint, __instance.rbody.velocity, 0f, 0f);
                    DebugPrint($"Stage 2 - deal the damage");
                    float fracDamageRemaining = Singleton.Manager <ManDamage> .inst.DealDamage(damageInfo, damageable);

                    DebugPrint("break 3");
                    float damageDealt = fracDamageRemaining > 0.0f ? damage * (1 - fracDamageRemaining) : damage;
                    DebugPrint($"Stage 4a - Just dealt {damageDealt} damage to damageable {damageable.name} ({damageable.Health}), original shell has damage {damage}");

                    // block was destroyed, damage potentially leftover
                    if (fracDamageRemaining > 0.0f)
                    {
                        retVal = (int)Mathf.Max(0.0f, (damage * fracDamageRemaining) - (damageDealt * (1.0f - armorPiercing.armorPierce)));
                        DebugPrint($"Killed damageable {damageable.name}, SHELL DMG {damage} ==[REMAINING DMG]=> {retVal}");
                    }
                    else
                    {
                        DebugPrint($"Failed to kill damageable {damageable.name}, SHELL DMG {damage} ==[REMAINING DMG]=> 0");
                    }
                    // no damage leftover cases:
                    if (retVal == 0)
                    {
                        if (deathDelay != 0.0f && !stickOnContact)
                        {
                            // penetration fuse, but failed to kill = flattened, spawn the explosion now
                            deathDelay = 0.0f;
                            PatchProjectile.SpawnExplosion.Invoke(__instance, new object[] { hitPoint, damageable });
                        }
                        else if ((bool)PatchProjectile.IsProjectileArmed.Invoke(__instance, null) && !stickOnContact)
                        {
                            // no penetration fuse, check if armed and not stick on contact - stick on contact explosions are done later
                            PatchProjectile.SpawnExplosion.Invoke(__instance, new object[] { hitPoint, damageable });
                        }
                    }
                }
                else if (otherCollider is TerrainCollider || otherCollider.gameObject.layer == Globals.inst.layerLandmark || otherCollider.GetComponentInParents <TerrainObject>(true))
                {
                    DebugPrint("Stage 4b");
                    hasHitTerrain = true;
                    PatchProjectile.SpawnTerrainHitEffect.Invoke(__instance, new object[] { hitPoint });
                    DebugPrint("Stage 4bb");

                    // if explode on terrain, explode and end, no matter death delay
                    if ((bool)PatchProjectile.m_ExplodeOnTerrain.GetValue(__instance) && (bool)PatchProjectile.IsProjectileArmed.Invoke(__instance, null))
                    {
                        PatchProjectile.SpawnExplosion.Invoke(__instance, new object[] { hitPoint, null });

                        // if default single impact behavior, explode on terrain, then die.
                        // else, keep the bouncing explosions
                        if (singleImpact)
                        {
                            __instance.Recycle(false);
                            return(0);
                        }
                    }
                }

                DebugPrint("Stage 5 - play sfx");
                Singleton.Manager <ManSFX> .inst.PlayImpactSFX(__instance.Shooter, (ManSFX.WeaponImpactSfxType) PatchProjectile.m_ImpactSFXType.GetValue(__instance), damageable, hitPoint, otherCollider);

                DebugPrint("Stage 6 - handle recycle");
                // if here, then no stick on contact, and no damage is leftover, so start destruction sequence
                if (ForceDestroy)   // if projectile hits a shield, always destroy
                {
                    __instance.Recycle(false);
                }
                else if (deathDelay == 0f)
                {
                    // If hasn't hit terrain, and still damage left, return here - don't recycle
                    if (!hasHitTerrain && retVal > 0)
                    {
                        return(retVal);
                    }
                    __instance.Recycle(false);
                }
                else if (!(bool)PatchProjectile.m_HasSetCollisionDeathDelay.GetValue(__instance))
                {
                    PatchProjectile.m_HasSetCollisionDeathDelay.SetValue(__instance, true);
                    PatchProjectile.SetProjectileForDelayedDestruction.Invoke(__instance, new object[] { deathDelay });
                    if (__instance.SeekingProjectile)
                    {
                        __instance.SeekingProjectile.enabled = false;
                    }
                    PatchProjectile.OnDelayedDeathSet.Invoke(__instance, null);
                }

                DebugPrint("Stage 7 - handle stick on terrain");
                bool stickOnTerrain = (bool)PatchProjectile.m_StickOnTerrain.GetValue(__instance);

                DebugPrint("HUH");
                if (stickOnContact && (stickOnTerrain || !hasHitTerrain))
                {
                    DebugPrint("WHAT");
                    GameObject test3 = otherCollider.gameObject;
                    DebugPrint("WHAT 1");
                    Transform trans = test3.transform;
                    DebugPrint("WHAT 2");
                    Vector3 scale = trans.lossyScale;
                    DebugPrint("WHAT 3");
                    if (otherCollider.gameObject.transform.lossyScale.Approximately(Vector3.one, 0.001f))
                    {
                        DebugPrint("Stage 7a");
                        ((Component)__instance).transform.SetParent(otherCollider.gameObject.transform);
                        PatchProjectile.SetStuck.Invoke(__instance, new object[] { true });
                        SmokeTrail smoke = (SmokeTrail)PatchProjectile.m_Smoke.GetValue(__instance);
                        if (smoke)
                        {
                            smoke.enabled = false;
                            smoke.Reset();
                        }

                        DebugPrint("Stage 7b");
                        Visible stuckTo = Singleton.Manager <ManVisible> .inst.FindVisible(otherCollider);

                        PatchProjectile.m_VisibleStuckTo.SetValue(__instance, stuckTo);
                        if (stuckTo.IsNotNull())
                        {
                            stuckTo.RecycledEvent.Subscribe(new Action <Visible>((Action <Visible>)PatchProjectile.OnParentDestroyed.GetValue(__instance)));
                        }
                        DebugPrint("Stage 7c");
                        if ((bool)PatchProjectile.m_ExplodeOnStick.GetValue(__instance))
                        {
                            Visible    visible         = (Visible)PatchProjectile.m_VisibleStuckTo.GetValue(__instance);
                            Damageable directHitTarget = visible.IsNotNull() ? visible.damageable : null;
                            PatchProjectile.SpawnExplosion.Invoke(__instance, new object[] { hitPoint, directHitTarget });
                        }
                        DebugPrint("Stage 7d");
                        if (((Transform)PatchProjectile.m_StickImpactEffect.GetValue(__instance)).IsNotNull())
                        {
                            PatchProjectile.SpawnStickImpactEffect.Invoke(__instance, new object[] { hitPoint });
                        }
                    }
                    else
                    {
                        d.LogWarning(string.Concat(new string[]
                        {
                            "Won't attach projectile ",
                            __instance.name,
                            " to ",
                            otherCollider.name,
                            ", as scale is not one"
                        }));
                    }
                }
                DebugPrint("FINAL");
                return(retVal);
            }
Example #3
0
 public static void Postfix(ref BlockManager __instance, ref TankBlock block, ref bool isPropogating, ref bool rootTransfer)
 {
     ManDamage.DamageInfo damageInfo = new ManDamage.DamageInfo(float.PositiveInfinity, ManDamage.DamageType.Standard, (Component)null, (Tank)null, block.transform.position, default(Vector3), 0.0f, 0.0f);
     block.visible.damageable.TryToDamage(damageInfo, true);
     return;
 }
Example #4
0
            private static float  DoDamage(ref ManDamage __instance, Damageable directHit, Damageable damageTarget, ManDamage.DamageInfo damageInfo)
            {
                ExplosionNerf.IngressPoint.DebugPrint("<ENM> ", "Doing DMG");

                float cabDamageDissipationFactor = (float)PatchDamage.m_CabDamageDissipationFactor.GetValue(__instance);
                // ExplosionNerf.IngressPoint.DebugPrint("A");

                float dmgDone = 0.0f;

                ManDamage.DamageInfo damageInfo1 = damageInfo.Clone();

                if (directHit != null)
                {
                    if ((UnityEngine.Object)PatchDamage.m_DamageMultiplierTable.GetValue(__instance) != (UnityEngine.Object)null)
                    {
                        // ExplosionNerf.IngressPoint.DebugPrint("B1");
                        float damageMultiplier = ((DamageMultiplierTable)PatchDamage.m_DamageMultiplierTable.GetValue(__instance)).GetDamageMultiplier(damageInfo.DamageType, directHit.DamageableType, true);
                        // ExplosionNerf.IngressPoint.DebugPrint("B2");
                        if ((double)damageMultiplier != 1.0)
                        {
                            damageInfo1.ApplyDamageMultiplier(damageMultiplier);
                        }
                        // ExplosionNerf.IngressPoint.DebugPrint("B3");
                    }

                    TankBlock hitBlock = damageTarget.Block;
                    if (hitBlock != null)
                    {
                        damageInfo1.ApplyDamageMultiplier(Mathf.Pow(hitBlock.filledCells.Length, 2.0f / 3.0f));
                    }

                    // ExplosionNerf.IngressPoint.DebugPrint("D");
                    int adjCount = 0;
                    if ((double)cabDamageDissipationFactor > 0.0 && directHit.Block.IsNotNull() && directHit.Block.IsController)
                    {
                        // ExplosionNerf.IngressPoint.DebugPrint("E1");
                        adjCount = directHit.Block.ConnectedBlocksByAP.Count();
                    }

                    if (adjCount > 0)
                    {
                        // ExplosionNerf.IngressPoint.DebugPrint("F1");
                        float cabDamageDissipationDetachFactor = (float)PatchDamage.m_CabDamageDissipationDetachFactor.GetValue(__instance);
                        // ExplosionNerf.IngressPoint.DebugPrint("F2");
                        // ManDamage.DamageInfo damageInfo2 = damageInfo1.Clone();
                        float multiplier = cabDamageDissipationFactor / (float)(adjCount + 1);
                        damageInfo1.ApplyDamageMultiplier((float)(1.0 - (double)multiplier * (double)adjCount));
                    }
                }
                dmgDone = damageTarget.TryToDamage(damageInfo1, true);

                //  || damageTarget.Block == null || damageTarget.Block.tank == null
                if (dmgDone == 0.0)
                {
                    if (damageTarget == null || damageTarget.Health <= 0.0f || damageTarget.Block == null || damageTarget.Block.PreExplodePulse || damageTarget.Block.tank == null)
                    {
                        dmgDone = 1.0f;
                    }
                    else
                    {
                        ModuleDamage module = damageTarget.Block.GetComponent <ModuleDamage>();
                        if (module != null)
                        {
                            dmgDone = (float)PatchDamage.m_ExplodeCountdownTimer.GetValue(module);
                        }
                    }
                }
                ExplosionNerf.IngressPoint.DebugPrint("<ENM> ", "Dmg Done: " + dmgDone.ToString());

                return(dmgDone);
            }
Example #5
0
            private static float recursiveHandleDamage(ref ManDamage __instance, ref float __result, Damageable damageTarget, Damageable directHit, Component source, TankBlock targetBlock, Tank targetTank, string prefix, bool RecurseOverride = false)
            {
                if (RecurseOverride || PatchDamage.YetToHit.Contains(targetBlock))
                {
                    ExplosionNerf.IngressPoint.DebugPrint("\n" + prefix, "Resolving Block: " + targetBlock.name);
                    PatchDamage.YetToHit.Remove(targetBlock);

                    if (directHit != null)
                    {
                        ExplosionNerf.IngressPoint.DebugPrint(prefix, "direct hit detected");
                        TankBlock localHitBlock = directHit.Block;
                        if (localHitBlock != PatchDamage.hitBlock)
                        {
                            ExplosionNerf.IngressPoint.DebugPrint(prefix, "ONLY should happen when direct hit RESOLVED, block NOT destroyed");
                            ExplosionNerf.IngressPoint.DebugPrint(prefix, "RESOLUTION - ALWAYS BLOCK");
                            return(0.0f);
                        }

                        if (directHit == damageTarget)
                        {
                            // do actual dmg to targetBlock
                            ExplosionNerf.IngressPoint.DebugPrint(prefix, "Direct hit NEVER invincible - calculate dmg");

                            Explosion castSource = (Explosion)source;

                            // Console.WriteLine(directHit.MaxHealth <= 1.0f);
                            // Console.WriteLine(localHitBlock.GetComponent<ModuleShieldGenerator>() != null);
                            // Console.WriteLine(PatchDamage.rejectDamageEvent.GetValue());

                            ManDamage.DamageInfo damageInfo = PatchDamage.NewDamageInfo(directHit, damageTarget, targetBlock);
                            ExplosionNerf.IngressPoint.DebugPrint(prefix, "Damage: " + damageInfo.Damage.ToString());
                            float dmgDone = PatchDamage.DoDamage(ref __instance, directHit, damageTarget, damageInfo);
                            if (dmgDone == 0.0f)
                            {
                                ExplosionNerf.IngressPoint.DebugPrint(prefix, "Block NOT destroyed - mark invincible for now");
                                if (!PatchDamage.DeterminedInvincible.ContainsKey(targetTank))
                                {
                                    PatchDamage.DeterminedInvincible[targetTank] = new HashSet <TankBlock>();
                                }
                                PatchDamage.DeterminedInvincible[targetTank].Add(localHitBlock);
                            }
                            else
                            {
                                ExplosionNerf.IngressPoint.DebugPrint(prefix, "BLOCK DESTROYED - remove from consideration");
                                PatchDamage.DirectHit.SetValue(source, null);
                            }
                            PatchDamage.hitBlock = null;

                            // modify damageInfo for recursion purposes - no longer necessary
                            // damageInfo.ApplyDamageMultiplier(newDamageMult);

                            // modify dmg energy left in explosion
                            castSource.m_MaxDamageStrength *= (float)PatchDamage.m_AoEDamageBlockPercent.GetValue(directHit);
                            // PatchDamage.DirectHit.SetValue(source, null);
                            return(dmgDone);
                        }
                        else
                        {
                            ExplosionNerf.IngressPoint.DebugPrint(prefix, "Resolve Direct hit first");
                            float destroyed = PatchDamage.recursiveHandleDamage(ref __instance, ref __result, directHit, directHit, source, localHitBlock, targetTank, prefix + "|  ", true);

                            // if block was actually destroyed
                            if (destroyed != 0.0f)
                            {
                                // do actual dmg to targetBlock
                                PatchDamage.hitBlock = null;
                                ExplosionNerf.IngressPoint.DebugPrint(prefix, "Resolve NOT NECESSARILY invincible - calculate dmg (re-recurse)");
                                PatchDamage.YetToHit.Add(targetBlock);
                                directHit = (Damageable)PatchDamage.DirectHit.GetValue(source);
                                return(PatchDamage.recursiveHandleDamage(ref __instance, ref __result, damageTarget, directHit, source, targetBlock, targetTank, prefix + "|  "));
                            }
                            else
                            {
                                ExplosionNerf.IngressPoint.DebugPrint(prefix, "ONLY should happen when direct hit RESOLVED, block NOT destroyed");
                                ExplosionNerf.IngressPoint.DebugPrint(prefix, "RESOLUTION - ALWAYS BLOCK");
                                if (!PatchDamage.DeterminedInvincible.ContainsKey(targetTank))
                                {
                                    PatchDamage.DeterminedInvincible[targetTank] = new HashSet <TankBlock>();
                                }
                                PatchDamage.DeterminedInvincible[targetTank].Add(targetBlock);
                                return(0.0f);
                            }
                        }
                    }
                    else
                    {
                        ExplosionNerf.IngressPoint.DebugPrint(prefix, "no direct hit - Raycast time");
                        Vector3      actual  = source.transform.position - targetBlock.transform.position;
                        RaycastHit[] results = new RaycastHit[((int)actual.magnitude)];
                        int          hits    = Physics.RaycastNonAlloc(new Ray(targetBlock.transform.position, actual), results, actual.magnitude, Singleton.Manager <ManVisible> .inst.VisiblePickerMaskNoTechs, QueryTriggerInteraction.Ignore);

                        List <TankBlock> foundBlocks = new List <TankBlock>();
                        if (!PatchDamage.DeterminedInvincible.ContainsKey(targetTank))
                        {
                            PatchDamage.DeterminedInvincible[targetTank] = new HashSet <TankBlock>();
                        }
                        for (int i = 0; i < hits; i++)
                        {
                            // ExplosionNerf.IngressPoint.DebugPrint("Loop " + i.ToString());
                            RaycastHit test    = results[i];
                            Visible    visible = Visible.FindVisibleUpwards((Component)test.collider);
                            if ((UnityEngine.Object)visible != (UnityEngine.Object)null)
                            {
                                TankBlock block = visible.block;
                                if (block != null && block != targetBlock && block.tank != null)
                                {
                                    if (block.tank == targetTank)
                                    {
                                        // ExplosionNerf.IngressPoint.DebugPrint("Damage blocked");
                                        if (PatchDamage.YetToHit.Contains(block))
                                        {
                                            ExplosionNerf.IngressPoint.DebugPrint(prefix, "  Unresolved block found: " + block.name);
                                            foundBlocks.Add(block);
                                        }
                                        else if (PatchDamage.DeterminedInvincible[targetTank].Contains(block))
                                        {
                                            ExplosionNerf.IngressPoint.DebugPrint(prefix, "  Resolved INVINCIBLE found");
                                            PatchDamage.DeterminedInvincible[targetTank].Add(targetBlock);
                                            foundBlocks.Clear();
                                            return(0.0f);
                                        }
                                    }
                                }
                            }
                        }
                        ExplosionNerf.IngressPoint.DebugPrint(prefix, "Raycast initial pass done - no invincible found in path");
                        if (foundBlocks.Count > 0)
                        {
                            bool breakInvincible = false;
                            foreach (TankBlock block in foundBlocks)
                            {
                                if (PatchDamage.YetToHit.Contains(block))
                                {
                                    float destroyed = PatchDamage.recursiveHandleDamage(ref __instance, ref __result, block.GetComponent <Damageable>(), directHit, source, block, targetTank, prefix + "|  ");

                                    if (destroyed == 0.0f)
                                    {
                                        PatchDamage.DeterminedInvincible[targetTank].Add(targetBlock);

                                        breakInvincible = true;
                                        break;
                                    }
                                }
                                else if (PatchDamage.DeterminedInvincible[targetTank].Contains(block))
                                {
                                    PatchDamage.DeterminedInvincible[targetTank].Add(targetBlock);

                                    breakInvincible = true;
                                    ExplosionNerf.IngressPoint.DebugPrint(prefix, "Resolved INVINCIBLE found");
                                    break;
                                }
                            }

                            if (!breakInvincible)
                            {
                                ExplosionNerf.IngressPoint.DebugPrint(prefix, "(A) [Should be rare] Resolve NOT invincible - calculate dmg");
                                ManDamage.DamageInfo damageInfo = PatchDamage.NewDamageInfo(directHit, damageTarget, targetBlock);
                                ExplosionNerf.IngressPoint.DebugPrint(prefix, "Damage: " + damageInfo.Damage.ToString());
                                float dmgDone = PatchDamage.DoDamage(ref __instance, directHit, damageTarget, damageInfo);
                                if (dmgDone == 0.0f)
                                {
                                    ExplosionNerf.IngressPoint.DebugPrint(prefix, "Block NOT destroyed - mark invincible for now");
                                    if (!PatchDamage.DeterminedInvincible.ContainsKey(targetTank))
                                    {
                                        PatchDamage.DeterminedInvincible[targetTank] = new HashSet <TankBlock>();
                                    }
                                    PatchDamage.DeterminedInvincible[targetTank].Add(targetBlock);
                                }
                                else
                                {
                                    ExplosionNerf.IngressPoint.DebugPrint(prefix, "BLOCK DESTROYED - remove from consideration");
                                }
                                return(dmgDone);
                            }
                            else
                            {
                                ExplosionNerf.IngressPoint.DebugPrint(prefix, "Resolved INVINCIBLE found");
                                return(0.0f);
                            }
                        }
                        else
                        {
                            ExplosionNerf.IngressPoint.DebugPrint(prefix, "No blocks in way - Resolve NOT invincible - calculate dmg");
                            ManDamage.DamageInfo damageInfo = PatchDamage.NewDamageInfo(directHit, damageTarget, targetBlock);
                            ExplosionNerf.IngressPoint.DebugPrint(prefix, "Damage: " + damageInfo.Damage.ToString());
                            float dmgDone = PatchDamage.DoDamage(ref __instance, directHit, damageTarget, damageInfo);
                            if (dmgDone == 0.0f)
                            {
                                ExplosionNerf.IngressPoint.DebugPrint(prefix, "Block NOT destroyed - mark invincible for now");
                                if (!PatchDamage.DeterminedInvincible.ContainsKey(targetTank))
                                {
                                    PatchDamage.DeterminedInvincible[targetTank] = new HashSet <TankBlock>();
                                }
                                PatchDamage.DeterminedInvincible[targetTank].Add(targetBlock);
                            }
                            else
                            {
                                ExplosionNerf.IngressPoint.DebugPrint(prefix, "BLOCK DESTROYED - remove from consideration");
                            }
                            return(dmgDone);
                        }
                    }
                }
                ExplosionNerf.IngressPoint.DebugPrint(prefix, "END");
                return(0.0f);
            }