Index: binaries/data/mods/public/maps/random/polar_sea_triggers.js =================================================================== --- binaries/data/mods/public/maps/random/polar_sea_triggers.js +++ binaries/data/mods/public/maps/random/polar_sea_triggers.js @@ -51,7 +51,7 @@ // The returned entities are sorted by RangeManager already // Only consider units implementing Health since wolves deal damage. - let targets = PositionHelper.EntitiesNearPoint(attackerPos, 200, players, IID_Health).filter(ent => { + const targets = PositionHelper.EntitiesNearPoint(attackerPos, 0, 200, players, IID_Health).filter(ent => { let cmpIdentity = Engine.QueryInterface(ent, IID_Identity); return cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), targetClasses); }); Index: binaries/data/mods/public/simulation/components/Attack.js =================================================================== --- binaries/data/mods/public/simulation/components/Attack.js +++ binaries/data/mods/public/simulation/components/Attack.js @@ -157,7 +157,10 @@ "" + "" + "" + - "" + + "" + + "" + + "" + + "" + "" + AttackHelper.BuildAttackEffectsSchema() + "" + @@ -438,7 +441,9 @@ return { "attackData": this.GetAttackEffectsData(type, true), "friendlyFire": this.template[type].Splash.FriendlyFire == "true", - "radius": ApplyValueModificationsToEntity("Attack/" + type + "/Splash/Range", +this.template[type].Splash.Range, this.entity), + "minRange": ApplyValueModificationsToEntity("Attack/" + type + "/Splash/MinRange", +(this.template[type].Splash.MinRange || 0), this.entity), + "maxRange": ApplyValueModificationsToEntity("Attack/" + type + "/Splash/MaxRange", +this.template[type].Splash.MaxRange, this.entity), + "shape": this.template[type].Splash.Shape, }; }; Index: binaries/data/mods/public/simulation/components/DeathDamage.js =================================================================== --- binaries/data/mods/public/simulation/components/DeathDamage.js +++ binaries/data/mods/public/simulation/components/DeathDamage.js @@ -13,7 +13,10 @@ "" + "" + "" + - "" + + "" + + "" + + "" + + "" + "" + AttackHelper.BuildAttackEffectsSchema(); @@ -47,7 +50,8 @@ "attacker": this.entity, "attackerOwner": owner, "origin": pos, - "radius": ApplyValueModificationsToEntity("DeathDamage/Range", +this.template.Range, this.entity), + "minRange": ApplyValueModificationsToEntity("DeathDamage/MinRange", +(this.template.MinRange || 0), this.entity), + "maxRange": ApplyValueModificationsToEntity("DeathDamage/MaxRange", +this.template.MaxRange, this.entity), "shape": this.template.Shape, "friendlyFire": this.template.FriendlyFire == "true", }); Index: binaries/data/mods/public/simulation/components/DelayedDamage.js =================================================================== --- binaries/data/mods/public/simulation/components/DelayedDamage.js +++ binaries/data/mods/public/simulation/components/DelayedDamage.js @@ -48,7 +48,8 @@ "attacker": data.attacker, "attackerOwner": data.attackerOwner, "origin": Vector2D.from3D(data.position), - "radius": data.splash.radius, + "minRange": data.splash.minRange, + "maxRange": data.splash.maxRange, "shape": data.splash.shape, "direction": data.direction, "friendlyFire": data.splash.friendlyFire @@ -78,7 +79,7 @@ } // If we didn't hit the main target look for nearby units. - let ents = PositionHelper.EntitiesNearPoint(Vector2D.from3D(data.position), this.MISSILE_HIT_RADIUS, + const ents = PositionHelper.EntitiesNearPoint(Vector2D.from3D(data.position), 0, this.MISSILE_HIT_RADIUS, AttackHelper.GetPlayersToDamage(data.attackerOwner, data.friendlyFire)); for (let ent of ents) Index: binaries/data/mods/public/simulation/components/tests/test_Attack.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Attack.js +++ binaries/data/mods/public/simulation/components/tests/test_Attack.js @@ -107,7 +107,7 @@ }, "Splash": { "Shape": "Circular", - "Range": 10, + "MaxRange": 10, "FriendlyFire": "false", "Damage": { "Hack": 0.0, @@ -272,7 +272,8 @@ } }, "friendlyFire": false, - "radius": 10, + "minRange": 0, + "maxRange": 10, "shape": "Circular" }); }); Index: binaries/data/mods/public/simulation/components/tests/test_Damage.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Damage.js +++ binaries/data/mods/public/simulation/components/tests/test_Damage.js @@ -186,7 +186,8 @@ "attacker": attacker, "attackerOwner": attackerOwner, "origin": origin, - "radius": 10, + "minRange": 0, + "maxRange": 10, "shape": "Linear", "direction": new Vector3D(1, 747, 0), "friendlyFire": false, @@ -194,7 +195,10 @@ let fallOff = function(x, y) { - return (1 - x * x / (data.radius * data.radius)) * (1 - 25 * y * y / (data.radius * data.radius)); + const width = (data.maxRange - data.minRange) / 5; + return Math.max(0, + (1 - Math.max(0, Math.square((x - data.minRange) / width))) * (1 - Math.square(y / width)) + ); }; let hitEnts = new Set(); @@ -288,13 +292,13 @@ Engine.PostMessage = (ent, iid, message) => {}; const radius = 10; + const minRange = 1; let attackerOwner = 1; let fallOff = function(r) { - return 1 - r * r / (radius * radius); + return 1 - Math.square(r - minRange) / Math.square(radius - minRange); }; - AddMock(attackerOwner, IID_Player, { "GetEnemies": () => [2] }); @@ -394,7 +398,8 @@ "attacker": 50, "attackerOwner": attackerOwner, "origin": new Vector2D(3, 4), - "radius": radius, + "minRange": minRange, + "maxRange": radius, "shape": "Circular", "friendlyFire": false, }); @@ -546,7 +551,8 @@ // Add a splash damage. data.splash = {}; data.splash.friendlyFire = false; - data.splash.radius = 10; + data.splash.minRange = 0; + data.splash.maxRange = 10; data.splash.shape = "Circular"; data.splash.attackData = { "Damage": { "Hack": 0, "Pierce": 0, "Crush": 200 } }; @@ -653,7 +659,8 @@ // Test splash damage with friendly fire. data.splash = {}; data.splash.friendlyFire = true; - data.splash.radius = 10; + data.splash.minRange = 0; + data.splash.maxRange = 10; data.splash.shape = "Circular"; data.splash.attackData = { "Damage": { "Pierce": 0, "Crush": 200 } }; Index: binaries/data/mods/public/simulation/components/tests/test_DeathDamage.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_DeathDamage.js +++ binaries/data/mods/public/simulation/components/tests/test_DeathDamage.js @@ -20,7 +20,7 @@ let template = { "Shape": "Circular", - "Range": 10.7, + "MaxRange": 10.7, "FriendlyFire": "false", "Damage": { "Hack": 0.0, @@ -48,7 +48,8 @@ "attacker": deadEnt, "attackerOwner": player, "origin": pos, - "radius": template.Range, + "minRange": 0, + "maxRange": template.MaxRange, "shape": template.Shape, "friendlyFire": false }; Index: binaries/data/mods/public/simulation/helpers/Attack.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Attack.js +++ binaries/data/mods/public/simulation/helpers/Attack.js @@ -231,18 +231,19 @@ * @param {number} data.attacker - The entity id of the attacker. * @param {number} data.attackerOwner - The player id of the attacker. * @param {Vector2D} data.origin - The origin of the projectile hit. - * @param {number} data.radius - The radius of the splash damage. + * @param {number} data.minRange - The minimal radius of the area damage. + * @param {number} data.maxRange - The maximum radius of the area damage. * @param {string} data.shape - The shape of the radius. * @param {Vector3D} [data.direction] - The unit vector defining the direction. Needed for linear splash damage. * @param {boolean} data.friendlyFire - A flag indicating if allied entities also ought to be damaged. */ AttackHelper.prototype.CauseDamageOverArea = function(data) { - let nearEnts = PositionHelper.EntitiesNearPoint(data.origin, data.radius, + const nearEnts = PositionHelper.EntitiesNearPoint(data.origin, data.minRange, data.maxRange, this.GetPlayersToDamage(data.attackerOwner, data.friendlyFire)); let damageMultiplier = 1; - let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); + const cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); // Cycle through all the nearby entities and damage it appropriately based on its distance from the origin. for (let ent of nearEnts) @@ -252,7 +253,7 @@ let distance = cmpObstructionManager.DistanceToPoint(ent, data.origin.x, data.origin.y); if (data.shape == 'Circular') // circular effect with quadratic falloff in every direction - damageMultiplier = 1 - distance * distance / (data.radius * data.radius); + damageMultiplier = Math.max(0, 1 - Math.max(0, Math.square((distance - data.minRange) / (data.maxRange - data.minRange)))); else if (data.shape == 'Linear') // linear effect with quadratic falloff in two directions (only used for certain missiles) { // The entity has a position here since it was returned by the range manager. @@ -265,13 +266,14 @@ let perpPos = relativePos.cross(direction); // The width of linear splash is one fifth of the normal splash radius. - let width = data.radius / 5; + const width = (data.maxRange - data.minRange) / 5; // Check that the unit is within the distance splash width of the line starting at the missile's // landing point which extends in the direction of the missile for length splash radius. if (parallelPos >= 0 && Math.abs(perpPos) < width) // If in radius, quadratic falloff in both directions - damageMultiplier = (1 - parallelPos * parallelPos / (data.radius * data.radius)) * - (1 - perpPos * perpPos / (width * width)); + damageMultiplier = Math.max(0, + (1 - Math.max(0, Math.square((parallelPos - data.minRange) / width))) * (1 - Math.square(perpPos / width)) + ); else damageMultiplier = 0; } Index: binaries/data/mods/public/simulation/helpers/Position.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Position.js +++ binaries/data/mods/public/simulation/helpers/Position.js @@ -22,19 +22,20 @@ /** * @param {Vector2D} origin - The point to check around. - * @param {number} radius - The radius around the point to check. + * @param {number} minRange - The minimum distance the entities must have from the point to check. + * @param {number} maxRange - The maximum distance the entities may have from the point to check. * @param {number[]} players - The players of which we need to check entities. - * @param {number} iid - Interface IID that returned entities must implement. Defaults to none. + * @param {number} iid - Interface IID that returned entities must implement. Defaults to none. * * @return {number[]} The id's of the entities in range of the given point. */ -PositionHelper.prototype.EntitiesNearPoint = function(origin, radius, players, iid = 0) +PositionHelper.prototype.EntitiesNearPoint = function(origin, minRange, maxRange, players, iid = 0) { - if (!origin || !radius || !players || !players.length) + if (!origin || !maxRange || !players || !players.length) return []; - let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); - return cmpRangeManager.ExecuteQueryAroundPos(origin, 0, radius, players, iid, true); + return Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager). + ExecuteQueryAroundPos(origin, minRange, maxRange, players, iid, true); }; /** Index: binaries/data/mods/public/simulation/templates/template_unit_ship_fire.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_ship_fire.xml +++ binaries/data/mods/public/simulation/templates/template_unit_ship_fire.xml @@ -20,7 +20,7 @@ Circular - 30 + 30 true 600 Index: binaries/data/mods/public/simulation/templates/template_unit_siege_boltshooter.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_siege_boltshooter.xml +++ binaries/data/mods/public/simulation/templates/template_unit_siege_boltshooter.xml @@ -25,7 +25,7 @@ Linear - 9 + 9 false 80 Index: binaries/data/mods/public/simulation/templates/template_unit_siege_flamethrower.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_siege_flamethrower.xml +++ binaries/data/mods/public/simulation/templates/template_unit_siege_flamethrower.xml @@ -33,7 +33,7 @@ Circular - 20 + 20 true 600