public override bool Touch(GameplayObject target)
        {
            if (this.Miss)
            {
                return false;
            }
            if (target != null)
            {
                if (target == this.owner && !this.weapon.HitsFriendlies)
                {
                    return false;
                }
                Projectile projectile = target as Projectile;
                if (projectile != null)
                {
                    if (this.owner != null && projectile.loyalty == this.owner.loyalty)
                    {
                        return false;
                    }
                    if (projectile.WeaponType == "Missile")
                    {
                        float ran = ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(0f, 1f);
                        if (projectile.loyalty != null && ran >= projectile.loyalty.data.MissileDodgeChance)
                        {
                            projectile.DamageMissile(this, this.damageAmount);
                            return true;
                        }
                    }
                    else if (this.weapon.Tag_Intercept || projectile.weapon.Tag_Intercept)
                    {
                        this.DieNextFrame = true;
                        projectile.DieNextFrame = true;
                    }
                    return false;
                }
                if (target is Asteroid)
                {
                    if (!this.explodes)
                    {
                        target.Damage(this, this.damageAmount);
                    }
                    this.Die(null, false);
                    return true;
                }
                if (target is ShipModule)
                {
                    ShipModule module = target as ShipModule;
                    if (module != null && module.GetParent().loyalty == this.loyalty && !this.weapon.HitsFriendlies || module == null)
                        return false;

                    if (this.weapon.TruePD)
                    {
                        this.DieNextFrame = true;
                        return true;
                    }
                    if (module.GetParent().Role == "fighter" && module.GetParent().loyalty.data.Traits.DodgeMod > 0f)
                    {
                        if (((module.GetParent().GetSystem() != null ? module.GetParent().GetSystem().RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(0f, 100f) < module.GetParent().loyalty.data.Traits.DodgeMod * 100f)
                        {
                            this.Miss = true;
                        }
                    }
                    if (this.Miss)
                    {
                        return false;
                    }
                    // Moving this to the Damage function - doesn't seem to be working? Also seems nonsensical.
                    /*
                    if (module.ModuleType == ShipModuleType.Armor || (module.ModuleType == ShipModuleType.Dummy && module.ParentOfDummy.ModuleType == ShipModuleType.Armor))
                    {
                        this.damageRadius -= module.GetParent().loyalty.data.ExplosiveRadiusReduction * this.damageRadius;
                        this.damageAmount -= module.GetParent().loyalty.data.ExplosiveRadiusReduction * this.damageAmount;
                        this.damageAmount *= this.weapon.EffectVsArmor;
                        this.damageAmount *= this.damageAmount + this.ArmorDamageBonus;
                    }

                    if (module.ModuleType == ShipModuleType.Shield && module.shield_power > 0)
                    {
                        this.damageAmount *= this.weapon.EffectVSShields;
                        this.damageAmount *= this.damageAmount + this.ShieldDamageBonus;
                        //projectiles penetrate weak shields
                        if (this.damageAmount > module.shield_power)
                        {
                            float remainder = 0;
                            module.Damage(this, this.damageAmount, ref remainder);
                            if (remainder > 0)
                            {
                                this.damageAmount = remainder;
                                return false;
                            }
                            else
                            {
                                this.damageAmount = 0;
                                this.explodes = false;
                                this.DieNextFrame = true;
                                return base.Touch(target);
                            }
                        }
                    }
                     */
                    //Non exploding projectiles should go through multiple modules if it has enough damage
                    if (!this.explodes && module.Active)
                    {
                        float remainder;

                        //Doc: If module has resistance to Armour Piercing effects, deduct that from the projectile's AP before starting AP and damage checks
                        if (module.APResist > 0)
                        {
                            this.ArmorPiercing -= (byte)module.APResist;
                            if (this.ArmorPiercing < 0)
                                this.ArmorPiercing = 0;
                        }

                        if (this.ArmorPiercing == 0 || !(module.ModuleType == ShipModuleType.Armor || (module.ModuleType == ShipModuleType.Dummy && module.ParentOfDummy.ModuleType == ShipModuleType.Armor)))
                        {
                            remainder = 0;
                            module.Damage(this, this.damageAmount, ref remainder);
                        }
                        else
                        {
                            this.ArmorPiercing--;
                            remainder = this.damageAmount;
                        }
                        if (remainder > 0)
                        {
                            this.damageAmount = remainder;
                            bool SlotFound;
                            int depth = 10;
                            Vector2 UnitVector = this.velocity;
                            while (this.damageAmount > 0)
                            {
                                UnitVector.Normalize();
                                UnitVector *= depth;
                                SlotFound = false;
                                foreach (ModuleSlot slot in module.GetParent().ModuleSlotList)
                                {
                                    if (Vector2.Distance(this.Center + UnitVector, slot.module.Center) < 8f)
                                    {
                                        SlotFound = true;
                                        if (slot.module.Active)
                                        {
                                            if (this.ArmorPiercing > 0 && (slot.module.ModuleType == ShipModuleType.Armor || (slot.module.ModuleType == ShipModuleType.Dummy && slot.module.ParentOfDummy.ModuleType == ShipModuleType.Armor)))
                                                break;
                                            else
                                            {
                                                remainder = 0;
                                                slot.module.Damage(this, this.damageAmount, ref remainder);
                                                if (remainder > 0)
                                                    this.damageAmount = remainder;
                                                else
                                                    this.damageAmount = 0f;
                                            }
                                        }
                                        break;
                                    }
                                }
                                //Slot found means it is still in the ship
                                if (SlotFound)
                                {
                                    depth += 8;
                                    this.ArmorPiercing--;
                                }
                                else
                                    break;
                            }
                        }
                    }
                    base.Health = 0f;
                }
                if (this.WeaponEffectType == "Plasma")
                {
                    Vector3 center = new Vector3(this.Center.X, this.Center.Y, -100f);
                    Vector2 forward = new Vector2((float)Math.Sin((double)base.Rotation), -(float)Math.Cos((double)base.Rotation));
                    Vector2 right = new Vector2(-forward.Y, forward.X);
                    right = Vector2.Normalize(right);
                    for (int i = 0; i < 20; i++)
                    {
                        Vector3 random = new Vector3(right.X * ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-250f, 250f), right.Y * ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-250f, 250f), ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-250f, 250f));
                        Projectile.universeScreen.flameParticles.AddParticleThreadA(center, random);
                        random = new Vector3(-forward.X + ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-150f, 150f), -forward.Y + ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-150f, 150f), ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-150f, 150f));
                        Projectile.universeScreen.flameParticles.AddParticleThreadA(center, random);
                    }
                }
                if (this.WeaponEffectType == "MuzzleBlast") // currently unused
                {
                    Vector3 center = new Vector3(this.Center.X, this.Center.Y, -100f);
                    Vector2 forward = new Vector2((float)Math.Sin((double)base.Rotation), -(float)Math.Cos((double)base.Rotation));
                    Vector2 right = new Vector2(-forward.Y, forward.X);
                    right = Vector2.Normalize(right);
                    for (int i = 0; i < 20; i++)
                    {
                        Vector3 random = new Vector3(right.X * ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-500f, 500f), right.Y * ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-500f, 500f), ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-250f, 250f));
                        Projectile.universeScreen.fireTrailParticles.AddParticleThreadA(center, random);
                        random = new Vector3(-forward.X + ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-500f, 500f), -forward.Y + ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-500f, 500f), ((this.system != null ? this.system.RNG : Ship.universeScreen.DeepSpaceRNG)).RandomBetween(-150f, 150f));
                        Projectile.universeScreen.fireTrailParticles.AddParticleThreadA(center, random);
                    }
                }
                else if (this.WeaponType == "Ballistic Cannon")
                {
                    ShipModule SMtarget = target as ShipModule;
                    if (SMtarget != null && SMtarget.ModuleType != ShipModuleType.Shield)
                    {
                        Cue impact = AudioManager.GetCue("sd_impact_bullet_small_01");
                        impact.Apply3D(Projectile.universeScreen.listener, this.emitter);
                        impact.Play();
                    }
                }
            }
            this.DieNextFrame = true;
            return base.Touch(target);
        }
        private void FireOnTargetNonVisible(Weapon w, GameplayObject fireTarget)
        {
            if (this.Owner.Ordinance < w.OrdinanceRequiredToFire || this.Owner.PowerCurrent < w.PowerRequiredToFire)
            {
                return;
            }
            w.timeToNextFire = w.fireDelay;
            if (w.IsRepairDrone)
            {
                return;
            }
            if (TargetShip == null || !TargetShip.Active || TargetShip.dying || !w.TargetValid(TargetShip.Role)
                || TargetShip.engineState == Ship.MoveState.Warp || !this.Owner.CheckIfInsideFireArc(w, TargetShip))
                return;
            Ship owner = this.Owner;
            owner.Ordinance = owner.Ordinance - w.OrdinanceRequiredToFire;
            Ship powerCurrent = this.Owner;
            powerCurrent.PowerCurrent = powerCurrent.PowerCurrent - w.PowerRequiredToFire;
            powerCurrent.PowerCurrent -= w.BeamPowerCostPerSecond * w.BeamDuration;

            this.Owner.InCombatTimer = 15f;
            if (fireTarget is Projectile)
            {
                fireTarget.Damage(w.GetOwner(), w.DamageAmount);
                return;
            }
            if (!(fireTarget is Ship))
            {
                if (fireTarget is ShipModule)
                {
                    w.timeToNextFire = w.fireDelay;
                    IOrderedEnumerable<ModuleSlot> sortedList =
                        from slot in (fireTarget as ShipModule).GetParent().ExternalSlots
                        orderby Vector2.Distance(slot.module.Center, this.Owner.Center)
                        select slot;
                    float damage = w.DamageAmount;
                    if (w.isBeam)
                    {
                        damage = damage * 90f;
                    }
                    if (w.SalvoCount > 0)
                    {
                        damage = damage * (float)w.SalvoCount;
                    }
                    sortedList.First<ModuleSlot>().module.Damage(this.Owner, damage);
                }
                return;
            }
            w.timeToNextFire = w.fireDelay;
            if ((fireTarget as Ship).ExternalSlots.Count == 0)
            {
                (fireTarget as Ship).Die(null, true);
                return;
            }
            float nearest = 0;
            ModuleSlot ClosestES = null;
            foreach (ModuleSlot ES in (fireTarget as Ship).ExternalSlots)
            {
                if (ES.module.ModuleType == ShipModuleType.Dummy || !ES.module.Active || ES.module.Health <= 0)
                    continue;
                float temp = Vector2.Distance(ES.module.Center, w.GetOwner().Center);
                if (nearest == 0 || temp < nearest)
                {
                    nearest = temp;
                    ClosestES = ES;
                }
            }
            if (ClosestES == null)
                return;
            // List<ModuleSlot>
            IEnumerable<ModuleSlot> ExternalSlots = (fireTarget as Ship).ExternalSlots.Where(close => close.module.Active && close.module.quadrant == ClosestES.module.quadrant && close.module.Health > 0);//.ToList();   //.OrderByDescending(shields=> shields.Shield_Power >0);//.ToList();
            if ((fireTarget as Ship).shield_power > 0f)
            {
                for (int i = 0; i < (fireTarget as Ship).GetShields().Count; i++)
                {
                    if ((fireTarget as Ship).GetShields()[i].Active && (fireTarget as Ship).GetShields()[i].shield_power > 0f)
                    {
                        float damage = w.DamageAmount;
                        if (w.isBeam)
                        {
                            damage = damage * 90f;
                        }
                        if (w.SalvoCount > 0)
                        {
                            damage = damage * (float)w.SalvoCount;
                        }
                        (fireTarget as Ship).GetShields()[i].Damage(this.Owner, damage);
                        return;
                    }
                }
                return;
            }
            //this.Owner.GetSystem() != null ? this.Owner.GetSystem().RNG : ArtificialIntelligence.universeScreen.DeepSpaceRNG)).RandomBetween(0f, 100f) <= 50f ||
            if (ExternalSlots.ElementAt(0).module.shield_power > 0f)
            {
                for (int i = 0; i < ExternalSlots.Count(); i++)
                {
                    if (ExternalSlots.ElementAt(i).module.Active && ExternalSlots.ElementAt(i).module.shield_power <= 0f)
                    {
                        float damage = w.DamageAmount;
                        if (w.isBeam)
                        {
                            damage = damage * 90f;
                        }
                        if (w.SalvoCount > 0)
                        {
                            damage = damage * (float)w.SalvoCount;
                        }
                        ExternalSlots.ElementAt(i).module.Damage(this.Owner, damage);
                        return;
                    }
                }
                return;
            }

            for (int i = 0; i < ExternalSlots.Count(); i++)
            {
                if (ExternalSlots.ElementAt(i).module.Active && ExternalSlots.ElementAt(i).module.shield_power <= 0f)
                {
                    float damage = w.DamageAmount;
                    if (w.isBeam)
                    {
                        damage = damage * 90f;
                    }
                    if (w.SalvoCount > 0)
                    {
                        damage = damage * (float)w.SalvoCount;
                    }
                    ExternalSlots.ElementAt(i).module.Damage(this.Owner, damage);
                    return;
                }
            }
        }