Exemplo n.º 1
0
        private void DamageGrid(HitEntity hitEnt, ProInfo t)
        {
            var grid = hitEnt.Entity as MyCubeGrid;

            if (grid == null || grid.MarkedForClose || !hitEnt.HitPos.HasValue || hitEnt.Blocks == null)
            {
                hitEnt.Blocks?.Clear();
                return;
            }
            if (t.AmmoDef.DamageScales.Shields.Type == ShieldDef.ShieldType.Heal || (!t.AmmoDef.Const.SelfDamage || !MyAPIGateway.Session.SessionSettings.EnableTurretsFriendlyFire) && t.Ai.MyGrid.IsSameConstructAs(grid))
            {
                t.BaseDamagePool = 0;
                return;
            }

            _destroyedSlims.Clear();
            _destroyedSlimsClient.Clear();
            var largeGrid      = grid.GridSizeEnum == MyCubeSize.Large;
            var areaRadius     = largeGrid ? t.AmmoDef.Const.AreaRadiusLarge : t.AmmoDef.Const.AreaRadiusSmall;
            var detonateRadius = largeGrid ? t.AmmoDef.Const.DetonateRadiusLarge : t.AmmoDef.Const.DetonateRadiusSmall;
            var maxObjects     = t.AmmoDef.Const.MaxObjectsHit;
            var areaEffect     = t.AmmoDef.AreaEffect.AreaEffect;
            var explosive      = areaEffect == AreaEffectType.Explosive;
            var radiant        = areaEffect == AreaEffectType.Radiant;
            var detonateOnEnd  = t.AmmoDef.AreaEffect.Detonation.DetonateOnEnd;
            var detonateDmg    = t.DetonationDamage;
            var shieldBypass   = t.AmmoDef.DamageScales.Shields.Type == ShieldDef.ShieldType.Bypass;
            var attackerId     = shieldBypass ? grid.EntityId : t.Target.FiringCube.EntityId;
            var attacker       = shieldBypass ? (MyEntity)grid : t.Target.FiringCube;
            var areaEffectDmg  = areaEffect != AreaEffectType.Disabled ? t.AreaEffectDamage : 0;
            var hitMass        = t.AmmoDef.Mass;
            var sync           = MpActive && (DedicatedServer || IsServer);
            var hasAreaDmg     = areaEffectDmg > 0;
            var radiantCascade = radiant && !detonateOnEnd;
            var primeDamage    = !radiantCascade || !hasAreaDmg;
            var radiantBomb    = radiant && detonateOnEnd;
            var damageType     = explosive || radiant ? MyDamageType.Explosion : MyDamageType.Bullet;

            var fallOff          = t.AmmoDef.Const.FallOffScaling && t.DistanceTraveled > t.AmmoDef.DamageScales.FallOff.Distance;
            var fallOffMultipler = 1f;

            if (fallOff)
            {
                fallOffMultipler = (float)MathHelperD.Clamp(1.0 - ((t.DistanceTraveled - t.AmmoDef.DamageScales.FallOff.Distance) / (t.AmmoDef.Const.MaxTrajectory - t.AmmoDef.DamageScales.FallOff.Distance)), t.AmmoDef.DamageScales.FallOff.MinMultipler, 1);
            }

            var damagePool = t.BaseDamagePool;

            if (t.AmmoDef.Const.VirtualBeams)
            {
                var hits = t.WeaponCache.Hits;
                damagePool    *= hits;
                areaEffectDmg *= hits;
            }
            var objectsHit           = t.ObjectsHit;
            var countBlocksAsObjects = t.AmmoDef.ObjectsHit.CountBlocks;

            List <Vector3I> radiatedBlocks = null;

            if (radiant)
            {
                GetBlockSphereDb(grid, areaRadius, out radiatedBlocks);
            }

            var done     = false;
            var nova     = false;
            var outOfPew = false;

            for (int i = 0; i < hitEnt.Blocks.Count; i++)
            {
                if (done || outOfPew && !nova)
                {
                    break;
                }

                var rootBlock = hitEnt.Blocks[i];

                if (!nova)
                {
                    if (_destroyedSlims.Contains(rootBlock) || _destroyedSlimsClient.Contains(rootBlock))
                    {
                        continue;
                    }
                    if (rootBlock.IsDestroyed)
                    {
                        _destroyedSlims.Add(rootBlock);
                        if (IsClient)
                        {
                            _destroyedSlimsClient.Add(rootBlock);
                            if (_slimHealthClient.ContainsKey(rootBlock))
                            {
                                _slimHealthClient.Remove(rootBlock);
                            }
                        }
                        continue;
                    }
                }
                var door = rootBlock.FatBlock as MyDoorBase;
                if (door != null && door.Open && !HitDoor(hitEnt, door))
                {
                    continue;
                }

                var radiate  = radiantCascade || nova;
                var dmgCount = 1;
                if (radiate)
                {
                    if (nova)
                    {
                        GetBlockSphereDb(grid, detonateRadius, out radiatedBlocks);
                    }
                    if (radiatedBlocks != null)
                    {
                        ShiftAndPruneBlockSphere(grid, rootBlock.Position, radiatedBlocks, _slimsSortedList);
                    }

                    done     = nova;
                    dmgCount = _slimsSortedList.Count;
                }

                for (int j = 0; j < dmgCount; j++)
                {
                    var   block       = radiate ? _slimsSortedList[j].Slim : rootBlock;
                    var   blockHp     = !IsClient ? block.Integrity : _slimHealthClient.ContainsKey(block) ? _slimHealthClient[block] : block.Integrity;
                    float damageScale = 1;

                    if (t.AmmoDef.Const.DamageScaling)
                    {
                        var d = t.AmmoDef.DamageScales;
                        if (d.MaxIntegrity > 0 && blockHp > d.MaxIntegrity)
                        {
                            outOfPew   = true;
                            damagePool = 0;
                            continue;
                        }

                        if (d.Grids.Large >= 0 && largeGrid)
                        {
                            damageScale *= d.Grids.Large;
                        }
                        else if (d.Grids.Small >= 0 && !largeGrid)
                        {
                            damageScale *= d.Grids.Small;
                        }

                        MyDefinitionBase blockDef = null;
                        if (t.AmmoDef.Const.ArmorScaling)
                        {
                            blockDef = block.BlockDefinition;
                            var isArmor = AllArmorBaseDefinitions.Contains(blockDef);
                            if (isArmor && d.Armor.Armor >= 0)
                            {
                                damageScale *= d.Armor.Armor;
                            }
                            else if (!isArmor && d.Armor.NonArmor >= 0)
                            {
                                damageScale *= d.Armor.NonArmor;
                            }

                            if (isArmor && (d.Armor.Light >= 0 || d.Armor.Heavy >= 0))
                            {
                                var isHeavy = HeavyArmorBaseDefinitions.Contains(blockDef);
                                if (isHeavy && d.Armor.Heavy >= 0)
                                {
                                    damageScale *= d.Armor.Heavy;
                                }
                                else if (!isHeavy && d.Armor.Light >= 0)
                                {
                                    damageScale *= d.Armor.Light;
                                }
                            }
                        }
                        if (t.AmmoDef.Const.CustomDamageScales)
                        {
                            if (blockDef == null)
                            {
                                blockDef = block.BlockDefinition;
                            }
                            float modifier;
                            var   found = t.AmmoDef.Const.CustomBlockDefinitionBasesToScales.TryGetValue(blockDef, out modifier);

                            if (found)
                            {
                                damageScale *= modifier;
                            }
                            else if (t.AmmoDef.DamageScales.Custom.IgnoreAllOthers)
                            {
                                continue;
                            }
                        }
                        if (fallOff)
                        {
                            damageScale *= fallOffMultipler;
                        }
                    }

                    var blockIsRoot   = block == rootBlock;
                    var primaryDamage = primeDamage || blockIsRoot;

                    if (damagePool <= 0 && primaryDamage || objectsHit >= maxObjects)
                    {
                        break;
                    }

                    var scaledDamage = damagePool * damageScale;
                    if (primaryDamage)
                    {
                        if (countBlocksAsObjects)
                        {
                            objectsHit++;
                        }

                        if (scaledDamage <= blockHp)
                        {
                            outOfPew   = true;
                            damagePool = 0;
                        }
                        else
                        {
                            _destroyedSlims.Add(block);
                            if (IsClient)
                            {
                                _destroyedSlimsClient.Add(block);
                                if (_slimHealthClient.ContainsKey(block))
                                {
                                    _slimHealthClient.Remove(block);
                                }
                            }
                            damagePool -= blockHp;
                        }
                    }
                    else
                    {
                        scaledDamage = areaEffectDmg * damageScale;
                        if (scaledDamage >= blockHp)
                        {
                            _destroyedSlims.Add(block);
                            if (IsClient)
                            {
                                _destroyedSlimsClient.Add(block);
                                if (_slimHealthClient.ContainsKey(block))
                                {
                                    _slimHealthClient.Remove(block);
                                }
                            }
                        }
                    }

                    if (!IsClient)
                    {
                        block.DoDamage(scaledDamage, damageType, sync, null, attackerId);
                    }
                    else
                    {
                        var hasBlock = _slimHealthClient.ContainsKey(block);
                        if (hasBlock && _slimHealthClient[block] - scaledDamage > 0)
                        {
                            _slimHealthClient[block] -= scaledDamage;
                        }
                        else if (hasBlock)
                        {
                            _slimHealthClient.Remove(block);
                        }
                        else if (block.Integrity - scaledDamage > 0)
                        {
                            _slimHealthClient[block] = blockHp - scaledDamage;
                        }
                    }

                    var theEnd = damagePool <= 0 || objectsHit >= maxObjects;

                    if (explosive && (!detonateOnEnd && blockIsRoot || detonateOnEnd && theEnd))
                    {
                        var rootPos = grid.GridIntegerToWorld(rootBlock.Position);
                        if (areaEffectDmg > 0)
                        {
                            SUtils.CreateMissileExplosion(this, areaEffectDmg * damageScale, areaRadius, rootPos, hitEnt.Intersection.Direction, attacker, grid, t.AmmoDef, true);
                        }
                        if (detonateOnEnd && theEnd)
                        {
                            SUtils.CreateMissileExplosion(this, detonateDmg * damageScale, detonateRadius, rootPos, hitEnt.Intersection.Direction, attacker, grid, t.AmmoDef, true);
                        }
                    }
                    else if (!nova)
                    {
                        if (hitMass > 0 && blockIsRoot)
                        {
                            var speed = t.AmmoDef.Trajectory.DesiredSpeed > 0 ? t.AmmoDef.Trajectory.DesiredSpeed : 1;
                            ApplyProjectileForce(grid, grid.GridIntegerToWorld(rootBlock.Position), hitEnt.Intersection.Direction, (hitMass * speed));
                        }

                        if (radiantBomb && theEnd)
                        {
                            nova = true;
                            i--;
                            t.BaseDamagePool = 0;
                            t.ObjectsHit     = maxObjects;
                            objectsHit       = int.MinValue;
                            var aInfo = t.AmmoDef.AreaEffect;
                            var dInfo = aInfo.Detonation;

                            if (dInfo.DetonationDamage > 0)
                            {
                                damagePool = detonateDmg;
                            }
                            else if (aInfo.AreaEffectDamage > 0)
                            {
                                damagePool = areaEffectDmg;
                            }
                            else
                            {
                                damagePool = scaledDamage;
                            }
                            break;
                        }
                    }
                }
            }
            if (!countBlocksAsObjects)
            {
                t.ObjectsHit += 1;
            }
            if (!nova)
            {
                t.BaseDamagePool = damagePool;
                t.ObjectsHit     = objectsHit;
            }
            if (radiantCascade || nova)
            {
                _slimsSortedList.Clear();
            }
            hitEnt.Blocks.Clear();
        }
        private void DamageVoxel(HitEntity hitEnt, ProInfo info, bool canDamage)
        {
            var entity  = hitEnt.Entity;
            var destObj = hitEnt.Entity as MyVoxelBase;

            if (destObj == null || entity == null || !hitEnt.HitPos.HasValue)
            {
                return;
            }
            var shieldHeal = info.AmmoDef.DamageScales.Shields.Type == ShieldDef.ShieldType.Heal;

            if (!info.AmmoDef.Const.VoxelDamage || shieldHeal)
            {
                info.BaseDamagePool = 0;
                return;
            }

            using (destObj.Pin())
            {
                var detonateOnEnd = info.AmmoDef.Const.AmmoAreaEffect && info.AmmoDef.AreaEffect.Detonation.DetonateOnEnd && info.AmmoDef.AreaEffect.AreaEffect != AreaEffectType.Radiant;

                info.ObjectsHit++;
                float damageScale = 1;
                if (info.AmmoDef.Const.VirtualBeams)
                {
                    damageScale *= info.WeaponCache.Hits;
                }

                var scaledDamage = info.BaseDamagePool * damageScale;
                var fallOff      = info.AmmoDef.Const.FallOffScaling && info.DistanceTraveled > info.AmmoDef.DamageScales.FallOff.Distance;
                if (fallOff)
                {
                    var fallOffMultipler = (float)MathHelperD.Clamp(1.0 - ((info.DistanceTraveled - info.AmmoDef.DamageScales.FallOff.Distance) / (info.AmmoDef.Const.MaxTrajectory - info.AmmoDef.DamageScales.FallOff.Distance)), info.AmmoDef.DamageScales.FallOff.MinMultipler, 1);
                    scaledDamage *= fallOffMultipler;
                }

                var oRadius       = info.AmmoDef.AreaEffect.AreaEffectRadius;
                var minTestRadius = info.DistanceTraveled - info.PrevDistanceTraveled;
                var tRadius       = oRadius < minTestRadius ? minTestRadius : oRadius;
                var objHp         = (int)MathHelper.Clamp(MathFuncs.VolumeCube(MathFuncs.LargestCubeInSphere(tRadius)), 5000, double.MaxValue);


                if (tRadius > 5)
                {
                    objHp *= 5;
                }
                if (scaledDamage < objHp)
                {
                    var reduceBy = objHp / scaledDamage;
                    oRadius /= reduceBy;
                    if (oRadius < 1)
                    {
                        oRadius = 1;
                    }

                    info.BaseDamagePool = 0;
                }
                else
                {
                    info.BaseDamagePool -= objHp;
                    if (oRadius < minTestRadius)
                    {
                        oRadius = minTestRadius;
                    }
                }

                destObj.PerformCutOutSphereFast(hitEnt.HitPos.Value, (float)oRadius, true);
                //Log.Line($"TestHealth: {objHp} - tRadius:{tRadius} - oRadius:{oRadius} - travel:{minTestRadius} - base:{info.BaseDamagePool} - det:{detonateOnEnd}");

                if (detonateOnEnd && info.BaseDamagePool <= 0)
                {
                    var det     = info.AmmoDef.AreaEffect.Detonation;
                    var dRadius = det.DetonationRadius;
                    var dDamage = det.DetonationDamage;

                    //var dObjHp = (int)MathHelper.Clamp(MathFuncs.VolumeCube(MathFuncs.LargestCubeInSphere(dRadius)), 5000, double.MaxValue);
                    //if (dRadius > 5) dObjHp *= 5;
                    //dObjHp *= 5;
                    //var reduceBy = dObjHp / dDamage;
                    //dRadius /= reduceBy;

                    if (dRadius < 1.5)
                    {
                        dRadius = 1.5f;
                    }

                    //Log.Line($"radius: {det.DetonationRadius} - dRadius:{dRadius} - reduceBy:{reduceBy} - dObjHp:{dObjHp}");
                    if (canDamage)
                    {
                        //destObj.PerformCutOutSphereFast(hitEnt.HitPos.Value, dRadius, true);
                        SUtils.CreateMissileExplosion(this, dDamage, dRadius, hitEnt.HitPos.Value, hitEnt.Intersection.Direction, info.Target.FiringCube, destObj, info.AmmoDef, true);
                    }
                }
            }
        }