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 @@ -38,9 +38,9 @@ if (!attackerPos) continue; - // The returned entities are sorted by RangeManager already + // The returned entities are sorted by RangeManager already. // Only consider units implementing Health since wolves deal damage. - let targets = Attacking.EntitiesNearPoint(attackerPos, 200, players, IID_Health).filter(ent => { + let targets = Attacking.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 @@ -139,7 +139,10 @@ "" + "" + "" + - "" + + "" + + "" + + "" + + "" + "" + Attacking.BuildAttackEffectsSchema() + "" + @@ -429,7 +432,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 @@ "" + "" + "" + - "" + + "" + + "" + + "" + + "" + "" + Attacking.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 @@ -52,7 +52,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 @@ -76,7 +77,7 @@ return; // If we didn't hit the main target look for nearby units. - let ents = Attacking.EntitiesNearPoint(Vector2D.from3D(data.position), this.MISSILE_HIT_RADIUS, + let ents = Attacking.EntitiesNearPoint(Vector2D.from3D(data.position), 0, this.MISSILE_HIT_RADIUS, Attacking.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 @@ -89,7 +89,7 @@ }, "Splash": { "Shape": "Circular", - "Range": 10, + "MaxRange": 10, "FriendlyFire": "false", "Damage": { "Hack": 0.0, @@ -253,7 +253,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 @@ -176,7 +176,8 @@ "attacker": attacker, "attackerOwner": attackerOwner, "origin": origin, - "radius": 10, + "minRange": 0, + "maxRange": 10, "shape": "Linear", "direction": new Vector3D(1, 747, 0), "friendlyFire": false, @@ -184,7 +185,7 @@ let fallOff = function(x, y) { - return (1 - x * x / (data.radius * data.radius)) * (1 - 25 * y * y / (data.radius * data.radius)); + return (1 - x * x / (data.maxRange * data.maxRange)) * (1 - 25 * y * y / (data.maxRange * data.maxRange)); }; let hitEnts = new Set(); @@ -269,13 +270,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] }); @@ -351,7 +352,8 @@ "attacker": 50, "attackerOwner": attackerOwner, "origin": new Vector2D(3, 4), - "radius": radius, + "minRange": minRange, + "maxRange": radius, "shape": "Circular", "friendlyFire": false, }); @@ -484,7 +486,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 } }; @@ -579,7 +582,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 @@ -17,7 +17,7 @@ let template = { "Shape": "Circular", - "Range": 10.7, + "MaxRange": 10.7, "FriendlyFire": "false", "Damage": { "Hack": 0.0, @@ -45,7 +45,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/Attacking.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Attacking.js +++ binaries/data/mods/public/simulation/helpers/Attacking.js @@ -259,14 +259,15 @@ * @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. */ Attacking.prototype.CauseDamageOverArea = function(data) { - let nearEnts = this.EntitiesNearPoint(data.origin, data.radius, + let nearEnts = this.EntitiesNearPoint(data.origin, data.minRange, data.maxRange, this.GetPlayersToDamage(data.attackerOwner, data.friendlyFire)); let damageMultiplier = 1; @@ -275,7 +276,7 @@ { let entityPosition = Engine.QueryInterface(ent, IID_Position).GetPosition2D(); if (data.shape == 'Circular') // circular effect with quadratic falloff in every direction - damageMultiplier = 1 - data.origin.distanceToSquared(entityPosition) / (data.radius * data.radius); + damageMultiplier = 1 - Math.max(0, Math.square(data.origin.distanceTo(entityPosition) - data.minRange) / Math.square(data.maxRange - data.minRange)); else if (data.shape == 'Linear') // linear effect with quadratic falloff in two directions (only used for certain missiles) { // Get position of entity relative to splash origin. @@ -287,12 +288,12 @@ let perpPos = relativePos.cross(direction); // The width of linear splash is one fifth of the normal splash radius. - let width = data.radius / 5; + let width = data.maxRange / 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)) * + damageMultiplier = (1 - parallelPos * parallelPos / (data.maxRange * data.maxRange)) * (1 - perpPos * perpPos / (width * width)); else damageMultiplier = 0; @@ -352,19 +353,20 @@ /** * Gets entities near a give point for given players. * @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 may 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} itf - Interface IID that returned entities must implement. Defaults to none. * @return {number[]} The id's of the entities in range of the given point. */ -Attacking.prototype.EntitiesNearPoint = function(origin, radius, players, itf = 0) +Attacking.prototype.EntitiesNearPoint = function(origin, minRange, maxRange, players, itf = 0) { // If there is insufficient data return an empty array. - 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, itf); + return cmpRangeManager.ExecuteQueryAroundPos(origin, minRange, maxRange, players, itf); }; /** Index: binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_artillery.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_artillery.xml +++ binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_artillery.xml @@ -22,7 +22,7 @@ Circular - 7 + 7 false 0.0 Index: binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_bolt.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_bolt.xml +++ binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_bolt.xml @@ -21,7 +21,7 @@ Linear - 4 + 4 false 0.0 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 300.0 Index: binaries/data/mods/public/simulation/templates/template_unit_ship_quinquereme.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_ship_quinquereme.xml +++ binaries/data/mods/public/simulation/templates/template_unit_ship_quinquereme.xml @@ -14,7 +14,7 @@ 0 Circular - 10 + 10 false 0.0 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 @@ -14,7 +14,7 @@ 0 Linear - 8.0 + 8.0 false 0.0 Index: binaries/data/mods/public/simulation/templates/template_unit_siege_stonethrower.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_siege_stonethrower.xml +++ binaries/data/mods/public/simulation/templates/template_unit_siege_stonethrower.xml @@ -23,7 +23,7 @@ Circular - 10 + 10 false 0.0 Index: binaries/data/mods/public/simulation/templates/units/rome_siege_onager.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/rome_siege_onager.xml +++ binaries/data/mods/public/simulation/templates/units/rome_siege_onager.xml @@ -8,7 +8,7 @@ 5000 Circular - 10 + 10 false 40.0 Index: binaries/data/mods/public/simulation/templates/units/theb_siege_fireraiser.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/theb_siege_fireraiser.xml +++ binaries/data/mods/public/simulation/templates/units/theb_siege_fireraiser.xml @@ -23,7 +23,7 @@ Circular - 20 + 20 true 200.0