private void ComputeEffects(MyCubeGrid grid, AmmoDef ammoDef, float damagePool, ref float healthPool, long attackerId, int sysmteId, List <IMySlimBlock> blocks) { var largeGrid = grid.GridSizeEnum == MyCubeSize.Large; var eWarInfo = ammoDef.AreaEffect.EwarFields; var duration = (uint)eWarInfo.Duration; var stack = eWarInfo.StackDuration; var maxStack = eWarInfo.MaxStacks; var nextTick = Tick + 1; var maxTick = stack ? (uint)(nextTick + (duration * maxStack)) : nextTick + duration; var fieldType = ammoDef.AreaEffect.AreaEffect; var sync = MpActive && (DedicatedServer || IsServer); foreach (var block in blocks) { var cubeBlock = block.FatBlock as MyCubeBlock; if (damagePool <= 0 || healthPool <= 0) { break; } IMyFunctionalBlock funcBlock = null; if (fieldType != DotField) { if (cubeBlock == null || cubeBlock.MarkedForClose) { continue; } funcBlock = cubeBlock as IMyFunctionalBlock; var isConveyor = cubeBlock is MyConveyor; var ewared = EffectedCubes.ContainsKey(cubeBlock.EntityId); if (funcBlock == null || isConveyor || !cubeBlock.IsWorking && !ewared || ewared && !stack) { continue; } } var blockHp = block.Integrity; float damageScale = 1; var tmpDamagePool = damagePool; if (ammoDef.Const.DamageScaling) { var d = ammoDef.DamageScales; if (d.MaxIntegrity > 0 && blockHp > d.MaxIntegrity) { 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 (ammoDef.Const.ArmorScaling) { blockDef = block.BlockDefinition; var isArmor = AllArmorBaseDefinitions.Contains(blockDef) || CustomArmorSubtypes.Contains(blockDef.Id.SubtypeId); 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) || CustomHeavyArmorSubtypes.Contains(blockDef.Id.SubtypeId); if (isHeavy && d.Armor.Heavy >= 0) { damageScale *= d.Armor.Heavy; } else if (!isHeavy && d.Armor.Light >= 0) { damageScale *= d.Armor.Light; } } } if (ammoDef.Const.CustomDamageScales) { if (blockDef == null) { blockDef = block.BlockDefinition; } float modifier; var found = ammoDef.Const.CustomBlockDefinitionBasesToScales.TryGetValue(blockDef, out modifier); if (found) { damageScale *= modifier; } else if (ammoDef.DamageScales.Custom.IgnoreAllOthers) { continue; } } } var scaledDamage = tmpDamagePool * damageScale; var blockDisabled = false; if (scaledDamage <= blockHp) { tmpDamagePool = 0; } else { blockDisabled = true; tmpDamagePool -= blockHp; } if (fieldType == DotField && IsServer) { block.DoDamage(scaledDamage, MyDamageType.Explosion, sync, null, attackerId); continue; } if (funcBlock != null) { BlockState blockState; var cubeId = cubeBlock.EntityId; if (EffectedCubes.TryGetValue(cubeId, out blockState)) { if (blockState.Health > 0) { damagePool = tmpDamagePool; } if (!blockDisabled && blockState.Health - scaledDamage > 0) { blockState.Health -= scaledDamage; blockState.Endtick = Tick + (duration + 1); } else if (blockState.Endtick + (duration + 1) < maxTick) { blockState.Health = 0; healthPool -= 1; blockState.Endtick += (duration + 1); } else { blockState.Health = 0; healthPool -= 1; blockState.Endtick = maxTick; } } else { damagePool = tmpDamagePool; blockState.FunctBlock = funcBlock; var originState = blockState.FunctBlock.Enabled; blockState.FirstTick = Tick + 1; blockState.FirstState = originState; blockState.NextTick = nextTick; blockState.Endtick = Tick + (duration + 1); blockState.Session = this; blockState.AmmoDef = ammoDef; blockState.SystemId = sysmteId; if (!blockDisabled) { blockState.Health = blockHp - scaledDamage; } else { blockState.Health = 0; } } EffectedCubes[cubeId] = blockState; } } if (!IsServer) { EffectedCubes.Clear(); } }
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(); }