Page MenuHomeWildfire Games

Elevation attack bonus for ranged units
Needs ReviewPublic

Authored by temple on Aug 11 2017, 1:19 AM.
This revision needs review, but there are no reviewers specified.

Details

Reviewers
None
Trac Tickets
#4028
Summary

Units currently get extra range if they're on a hill, but it would be nice if they got a damage bonus as well. See #4028.

The question is, what shape should the bonus take?

Here's one way to think about it. The damage should be something like the kinetic energy of the projectile when it lands. Of course the real picture is messy, but we can think of energy being conserved so it's the same as the energy when we shoot the projectile, which is the kinetic energy mv^2/2 plus the potential energy mgh, where h is the elevation difference between ourselves and the target. Compared to the case with no elevation bonus (h = 0), this is a ratio of 1 + 2gh/v^2.

So the damage multiplier formula should look like 1 + k * h, where k = 2g/v^2. Here's some values of k for g = 9.81 and various projectile speeds:

  v      k     unit
 37.5  0.0140  catapult
 62.5  0.0050  javelin, slinger
 75    0.0035  archer, tower
150    0.0009  bolt shooter

We could have the bonus depend on the speed of the projectile (so catapults would get a huge elevation bonus and bolt shooters would get a very little one), or we could simplify the situation and choose one value of k for all ranged units. I prefer the second approach.

I did some testing and I think I like k = 0.01. This has a nice english meaning too: an elevation bonus of 10m corresponds to a damage bonus of 10%. We can always change it later if it turns out to be too much (or too little).

Playing on the "Empire" map for example, small hills were 10-20m high, and a 10-20% bonus there seems reasonable. Blacksmith upgrades are 20% damage each, for comparison. Cliffs and huge hills were 30-40m, but I think that's fine too. Note that the bonus becomes a penalty for ranged units that have targets above them, e.g. a unit 20m below their target has a damage multiplier of 0.8. (I added a minimum value, 0.1, otherwise mountains over 100m tall would break the formula.) So there's a double effect for ranged vs ranged battles.

Here's the units that have an elevation bonus.

template_structure_defense_defense_tower.xml:      <ElevationBonus>15</ElevationBonus>
template_structure_defense_sentry_tower.xml:      <ElevationBonus>9.0</ElevationBonus>
template_unit_mechanical_siege_tower.xml:      <ElevationBonus>10</ElevationBonus>

To get the multiplier for them, we just add this height (maybe "ElevationBonus" is a bad name?) to the elevation difference before plugging it into the formula. Note that enemies attack the base of the towers, so the damage bonus is only in one direction.

However, for units standing on walls, the bonus goes both ways, since the units are actually ~10m higher (the exact number depends on the civ). (Units on walls also have an aura for +3 armor and +20 vision, and melee units can't attack them.)

The elevation difference should use the y-coordinate of the real target position, i.e. where the missile lands. But in the Attack.js code that's not important so it's approximated by the target's current y-coordinate. That's probably okay, but I'd like to use the correct value if anyone can tell me how to do that and if it's not a big performance cost.

To get the damage multplier, we multiply the elevation bonus by the attack bonus. The attack bonus seems to be for hard counters, which are pike/spears vs cav, hunted elephants vs cav, and mace hero alexander sword cav vs other heroes. That is, there's currently no ranged hard counters, so the attack bonus here should always be 1.

In the damage component, the multiplier's applied to missiles that hit the main target and missiles that miss but hit another unit, but not to splash damage. We want the elevation bonus to apply to splash damage as well, so I've added the multiplier there. In the future, if we add hard counters for ranged units, we should do the attack bonus differently, because it should depend on the unit that was actually hit (with splash damage or a missed missile) not the unit that was aimed at. But again, since the attack bonus is always 1, the code's not doing any harm right now.

In #4028, the idea is to then remove the range bonus for units. I'm ambivalent about this at the moment (haven't thought about it enough or gone through the calculations carefully), but anyway it should be done in a separate patch.

Test Plan

See if the damage formula makes sense.
Play on maps with hills and see if the value of k seems reasonable. (Add some print lines to spit out the actual elevation differences, etc.)
See if my understanding of the code is correct.

I accidently left in the spread fix from D780, so ignore that line.
I'll add tests once the formula is okayed.

In GetRange(), there's ApplyValueModificationsToEntity for elevationBonus. Currently there's no tech or aura that actually modifies that, and I'm not sure how it would want to be applied, to elevationBonus or elevationBonus + elevationDifference or something else. (Are we expecting towers to grow?) So I simply ignored calling that in GetElevationBonus().

Diff Detail

Lint
Lint Skipped
Unit
Unit Tests Skipped

Event Timeline

temple created this revision.Aug 11 2017, 1:19 AM
temple edited the summary of this revision. (Show Details)
fatherbushido edited edge metadata.EditedAug 11 2017, 8:49 AM

Units currently get extra range if they're on a hill, but it would be nice if they got a damage bonus as well. See #4028.

The extra range ('citadel bonus') is imo sufficient.
#4028 was about avoiding some computations if we want to place at the 'best' range (reverting unitAI taking that into account) and finding a placeholder.
But last plans are to change unitAI/unitMotion.

Here's one way to think about it. The damage should be something like the kinetic energy of the projectile when it lands. Of course the real picture is messy, but we can think of energy being conserved so it's the same as the energy when we shoot the projectile, which is the kinetic energy mv^2/2 plus the potential energy mgh, where h is the elevation difference between ourselves and the target. Compared to the case with no elevation bonus (h = 0), this is a ratio of 1 + 2gh/v^2

That's exactly the things I thought at when I looked at that ticket. (one of the issue is that the multiplier is not really capped).


Well for the moment, I am for "not needed" :/ (so I won't review).

Stan added a subscriber: Stan.Aug 11 2017, 9:55 AM
Stan added inline comments.
binaries/data/mods/public/simulation/components/Attack.js
464

You should use doxygen style comments. I'm not sure this function even needs a comment as it's self explicit but maybe for parameters.

fatherbushido resigned from this revision.Aug 30 2017, 11:27 PM
fatherbushido requested changes to this revision.Oct 23 2017, 3:49 PM

I set request change as in reviewed but not wanted in the current state.

This revision now requires changes to proceed.Oct 23 2017, 3:49 PM
elexis added a subscriber: elexis.Dec 27 2017, 3:16 PM

Agree that from a gameplay point of view, either range or damage should be extended, but both seem a bit too strong.
But that is a decision for the templates.
Adding support in the code doesn't seem too bad.

It was said that range extension should be removed for performance and decidability reasons (going X to attack Y, then noticing that the range changed),
but I don't know if it's really a performance issue.

Keeping the range extension mechanism for mods or future reconsideration might not be bad.
Perhaps it could be disabled in the templates to address the performance issue without losing the feature.
But seems out of scope.

binaries/data/mods/public/simulation/components/Attack.js
464

doxygen = C++, JSdoc = JS.

GetElevationDamageBonus would indeed remove the last bit of ambiguity making the comment unneeded.

468

-> Damage component I guess

539

wold be better to only pass atomic values rather than doing any kind of computation (logic) here

This revision now requires review to proceed.Fri, Jul 19, 3:38 PM

This revision now requires review to proceed.

Not sure why and how I triggered that.