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 @@ -461,6 +461,12 @@ return attackBonus; }; +// Calculate the elevation damage multiplier +Attack.prototype.GetElevationBonus = function(type, elevationDifference) +{ + return Math.max(0.1, 1 + 0.01 * (elevationDifference + (this.template[type].ElevationBonus || 0))); +}; + /** * Attack the target entity. This should only be called after a successful range check, * and should only be called after GetTimers().repeat msec has passed since the last @@ -501,7 +507,7 @@ // Add inaccuracy based on spread. let distanceModifiedSpread = ApplyValueModificationsToEntity("Attack/Ranged/Spread", +this.template.Ranged.Spread, this.entity) * - targetPosition.horizDistanceTo(selfPosition) / 100; + predictedPosition.horizDistanceTo(selfPosition) / 100; let randNorm = randomNormal2D(); let offsetX = randNorm[0] * distanceModifiedSpread; @@ -509,6 +515,8 @@ let realTargetPosition = new Vector3D(predictedPosition.x + offsetX, targetPosition.y, predictedPosition.z + offsetZ); + let elevationDifference = selfPosition.y - realTargetPosition.y; + // Recalculate when the missile will hit the target position. let realHorizDistance = realTargetPosition.horizDistanceTo(selfPosition); timeToTarget = realHorizDistance / horizSpeed; @@ -528,7 +536,7 @@ "position": realTargetPosition, "direction": missileDirection, "projectileId": id, - "multiplier": this.GetAttackBonus(type, target), + "multiplier": this.GetAttackBonus(type, target) * this.GetElevationBonus(type, elevationDifference), "isSplash": false, "attackerOwner": attackerOwner }; Index: binaries/data/mods/public/simulation/components/Damage.js =================================================================== --- binaries/data/mods/public/simulation/components/Damage.js +++ binaries/data/mods/public/simulation/components/Damage.js @@ -117,6 +117,7 @@ "radius": data.radius, "shape": data.shape, "strengths": data.splashStrengths, + "multiplier": data.multiplier, "direction": data.direction, "playersToDamage": this.GetPlayersToDamage(data.attackerOwner, data.friendlyFire), "type": data.type, @@ -215,7 +216,7 @@ "strengths": data.strengths, "target": ent, "attacker": data.attacker, - "multiplier": damageMultiplier, + "multiplier": data.multiplier * damageMultiplier, "type": data.type + ".Splash", "attackerOwner": data.attackerOwner }); 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 @@ -155,6 +155,7 @@ "radius": 10, "shape": "Linear", "strengths": { "hack" : 100, "pierce" : 0, "crush": 0 }, + "multiplier": 1, "direction": new Vector3D(1, 747, 0), "playersToDamage": [2], "type": "Ranged",