Here, we are mostly talking about melee units. For a short summary, skip right to ‘Tl;dr’ section. A formula to calculate chasing TTK, alongside with an example entry and link to a spreadsheet, is presented in ‘Deriving the Formula’. Application examples of the formula are given in ‘Implications and Limitations’. Spoilers are there to make it at least somewhat compact and hide trivia info.
Most of us are aware of a stat/variable ‘attack speed’ or ‘reload time’, often inappropriately called ‘rate of fire’ (we’ll save our time not repeating Spirit of the Law’s mantra on that topic). In short, it determines the minimum time between each attack of the (melee) unit can inflict damage. While it is essential for deriving damage per second (DPS), it has its limitations, mostly for melee units: it is only applied if the victim is not retreating fast enough (time between two attacks < reload time).
However, it is safe to assume that is not true most of the time unless our victim unit is something as slow as a Battering ram (this case is partly observed in a separate section ‘What if Chase Time < Attack Reload Time?’). So, all the units also have a stat that determines their ability to inflict damage on retreating targets, though not explicitly coded by itself. This stat is most important when raiding, as enemy villagers will usually be running to safety from your harassing cavalry.
I honestly have no idea of how the stat should be called–nor have I been able to find any investigation regarding it. It could be there, analyzed for Age of Empires or any other RTS, but use a name that is obscure to me. I have decided to refer to it as ‘Chasing Time to Kill’ (chasing TTK) and define it as time required to catch up onto and kill full HP unit fleeing in a straight line. It’s time to (re?)invent the wheel.
Some time ago I was casually trying to figure out how the Attack Delay (AD) mechanic works (I won’t refer to it as ‘frame delay’ as it is just one of the components determining it). After I had managed to record some footage and observe the AD for most units, I wandered into an already existing post on this topic here that describes how it can be derived from the coded values (available via Advanced Genie Editor, or AGE). Calculated and recorded attack delays were in a great agreement; however, it was obvious there is an additional source of discrepancy probably caused by some frame rounding or game speed shenanigans (the latter is known to influence farming rates).
To extend the work of the OP mentioned earlier, I also recorded melee attack delays (by adding one extra range for every unit issued to attack an object). It appeared that melee attack delay occupies precisely half of the attack animation duration (AGE → Graphics → Anim Duration), plus one or two extra frames in the recorded footage in 60 FPS. Great thing Icewind retesetd and confirmed that as well.
Then, after being fairly disappointed with hussar’s attack anim duration (1.89 sec vs 1.35 sec of a light cav note: this was actual before Update 37650), I decided to look into its effect on raiding capabilities of this ambiguously trash unit. This is what led me to explore the nature of chasing TTK. And Spirit of the Law's video on villager gathering rate formula can be used as an excuse for formula usage here.
I tried to assume what factors could affect chasing mechanic. Among the variables that may influence the formula I came up with the following:
The phenomena of chasing should be divided into two stages with additional third one:
So, how should the variables interact with each other? Time to prove I was a diligent student in a 5th grade. (Even though I have difficulties confirming my 2nd grade…)
Calculating chasing TTK
Case study
Now let’s analyze a random case that can be met in-game. Let’s say a knight with no upgrades is pursuing a villager with loom and wheelbarrow.
Spreadsheet
Using almighty Excel, I created a spreadsheet for calculations available here. Read the notes to see what the variables mean. Rows beneath ‘Editable section’ are unlocked for editing. Required variables can be obtained via Advanced Genie Editor, or AGE. (Available in your ‘\Tools_Builds\’ subfolder of AoE2DE folder (common path for Steam would be ‘%Disk_Volume%\Program Files (x86)\Steam\steamapps\common\AoE2DE\Tools_Builds\’. Alternatively, I’ve backed up its Update 36906 compatible version here.
Theoretical chasing TTKs were then compared with recorded footage using the following test setup.
Going through the recordings revealed a slight problem: calculated chasing TTKs tend to underestimate observed values by a certain percentage; moreover, this percentage increases with the game speed and also builds up with the number of hits-to-kill (up to 5% for light cav @ ×2.0 game speed). What potential sources could there be?
Nevertheless, assuming realistic attack animation duration are several hundredths of a second longer than coded, theoretical estimates should be close enough to practical observations.
Sometimes chase time t(chase) can be lower than the attack reload time of the unit–either because the (v) is too slow (battering ram) or simply because it stops. Therefore, some units should repeat their attack animation twice, unless they reach a certain threshold of what I believe is 3 seconds (observed for hussar) that prevents the unit from a useless complete repeat of attack animations.
This is why I refrained from looking into such scenarios in-depth: I admit my utter defeat by the game logic.
Is there any practical implication for all the wasted time? Hopefully yes. Here are several examples. (All the timings and distances presented below do not count error in so they are slightly, ~1–5%, underestimated.)
However, these calculations still remain mostly theoretical. First of all, because notorious pathing problems (like what happens if three scouts are trying to snipe the same villager?) are not taken into consideration at all. Secondly, range units are ignored here as there are more factors in charge (projectile speed, accuracy, ‘missed’ shot hit probability, retreating targets, micro), with most of this variables being hardly countable or completely uncountable at all. Thirdly, there are instances of manually canceled animations and case ‘chase time < reload time’.
To conclude, I think that, while calculations presented here have limited practical meaning, they demonstrate how overlooked a variable (stat) of attack animation duration is, as so far I’ve seen it used only for attack delay calculations. This post is also incomplete because analysis of scenario ‘what if chase time < reload time’ was abandoned. Observations made here also reveal how weird the game logic can sometimes be and how influential game speed might be on the performance of the units.
Intro
Most of us are aware of a stat/variable ‘attack speed’ or ‘reload time’, often inappropriately called ‘rate of fire’ (we’ll save our time not repeating Spirit of the Law’s mantra on that topic). In short, it determines the minimum time between each attack of the (melee) unit can inflict damage. While it is essential for deriving damage per second (DPS), it has its limitations, mostly for melee units: it is only applied if the victim is not retreating fast enough (time between two attacks < reload time).
However, it is safe to assume that is not true most of the time unless our victim unit is something as slow as a Battering ram (this case is partly observed in a separate section ‘What if Chase Time < Attack Reload Time?’). So, all the units also have a stat that determines their ability to inflict damage on retreating targets, though not explicitly coded by itself. This stat is most important when raiding, as enemy villagers will usually be running to safety from your harassing cavalry.
I honestly have no idea of how the stat should be called–nor have I been able to find any investigation regarding it. It could be there, analyzed for Age of Empires or any other RTS, but use a name that is obscure to me. I have decided to refer to it as ‘Chasing Time to Kill’ (chasing TTK) and define it as time required to catch up onto and kill full HP unit fleeing in a straight line. It’s time to (re?)invent the wheel.
Background
Some time ago I was casually trying to figure out how the Attack Delay (AD) mechanic works (I won’t refer to it as ‘frame delay’ as it is just one of the components determining it). After I had managed to record some footage and observe the AD for most units, I wandered into an already existing post on this topic here that describes how it can be derived from the coded values (available via Advanced Genie Editor, or AGE). Calculated and recorded attack delays were in a great agreement; however, it was obvious there is an additional source of discrepancy probably caused by some frame rounding or game speed shenanigans (the latter is known to influence farming rates).
To extend the work of the OP mentioned earlier, I also recorded melee attack delays (by adding one extra range for every unit issued to attack an object). It appeared that melee attack delay occupies precisely half of the attack animation duration (AGE → Graphics → Anim Duration), plus one or two extra frames in the recorded footage in 60 FPS. Great thing Icewind retesetd and confirmed that as well.
Then, after being fairly disappointed with hussar’s attack anim duration (1.89 sec vs 1.35 sec of a light cav note: this was actual before Update 37650), I decided to look into its effect on raiding capabilities of this ambiguously trash unit. This is what led me to explore the nature of chasing TTK. And Spirit of the Law's video on villager gathering rate formula can be used as an excuse for formula usage here.
Deriving the Formula
I tried to assume what factors could affect chasing mechanic. Among the variables that may influence the formula I came up with the following:
Variables affecting Chasing TTK:
- Range between an attacker (a) and a victim (v)—d, tiles—a gap that an (a) has to close to start the attack animation (this is a distance between the center of both units);
- Collision size of both units, CS(a) and CS(v) in tiles, as their sum should determine the distance between both from which an attack animation can be initialized (hopefully that’s correct);
- As there are steppe lancers on the field, range(a) in tiles should be accounted for;
- Speed of both units definitely matters — V(a) and V(v), tiles per second. During the chase, its difference, V(a–v), is what allows an (a) to get close to a (v);
- As speed can be affected by some upgrades or civ bonuses, a modified version of arguments, V(a,mod) or V(v,mod), should be introduced as well;
- It is important to track the number of hits required to kill a (v). To calculate it, Dmg(a), HP(v), and Armor(v) are introduced, with their modified versions taken into consideration. The result is x in hits to kill;
- Lastly, attack animation duration is what slightly complicates the chasing TTK–t(anim), sec; 50% of this value represents t(atkd)–attack delay in seconds.
- What I found only after testing is that attack reload time bonuses (in case of melee units, Japanese inf bonus and Bulgarians stirrups represent them) do affect attack animation duration as well, but only when modified attack reload time is lower than (but, sadly for Bulgarian knights, not equal to) the attack anim duration; so, it’s true only for samurai and Bulgarian hussar. However, for some reason, it has no effect on t(atkd). This affected –t(anim) will be called t(anim,mod).
The phenomena of chasing should be divided into two stages with additional third one:
- an (a) is closing an initial gap between it and its (v)–in terms of time, it is t(1stattack);
- an (a) enters a loop where it stops for t(anim) to inflict damage while a (v) is fleeing during the time animation is played, and then an (a) closes the gap again to start a new attack animation. The loop lasts for (x–1) times as the initial blow is addressed at the first part of this list. It is called t(ch,loop) here;
- the additional third stage is when an (a) deals a final blow; it is not that different from the previous stage but there is a ‘±’ of t(atkd): ‘–’ is a scenario where a (v) escapes somehow, no ‘±’ corresponding to death of a (v), and‘+’ is a scenario where an (a) finishes its attack animation.
So, how should the variables interact with each other? Time to prove I was a diligent student in a 5th grade. (Even though I have difficulties confirming my 2nd grade…)
Calculating chasing TTK
At the first stage, (a) starts to run for its (v) while the latter is retreating. It’s therefore the prevailing speed of an (a) that is responsible for how fast it would be able to reach the (v), and thus, it is V(a) and V(v), or V(a–v) that decide the timing of the chase. However, there are more factors to consider.
– Firstly, speed is affected both by (a)’s and (v)’s upgrades such as husbandry or wheelbarrow. Speed difference after all upgrades is represented here by V(a–v,mod).
– Secondly, there is a range between (a) and (v)–called ‘d’ here–that needs to be closed. But in the game, it’s the range between the center of the units while collision is an existing factor; therefore, d should be lowered by CS(a) and CS(v)–collision size (‘radius’ in this case) of both units. The same applies to melee units with extra range, so range should also be subtracted from d. (From the recorded footage and calculations, I’m sure range is stacks with collision size of the units.) The actual distances between (a) and (v) in our case is (d – CS(a) – CS(v) – range(a)). This distance will be covered with a speed of V(a–v,mod) which allows us to calculate time it takes for an (a) to approach its (v) and start the attack animation. Here, it will be called t(c-i)–time to close-in (1):
– But that’s not all. At the moment of time corresponding to t(c-i) attack animation is only initialized. Damage, however, is not inflicted immediately as it needs to wait for attack delay with the duration of t(atkd) = t(anim)/2. By adding it to t(c-i), we receive the time when first portion of damage is inflicted–t(1stattack) (2):
The process of chasing down is shown on a short video below.
After an initial hit, if (v) continues to retreat in the same fashion, we enter simple loop of events:
In terms of variables, (i) is (3):
and (ii) is (4):
But do not forget (a) was ‘idle’ (not chasing) for the duration of t(anim). Therefore, a single iteration of chasing time (t(chase)) is (5):
The process of attack and a single chase loop is shown on a short video below.
Before compiling two parts (initial chasing and single chase loop) together, the duration of the latter should be evaluated. It is equal to number of hits to kill (x) a (v) but, as victim is already hit once during t(1stattack), the resulting hits-to-kill is (x–1). It is calculated as (6):
with all the variables already considered modified after upgrades and bonuses which is applied to shorten the formula. The whole loop then occupies t(ch,loop) (7):
A finishing touch is to remind ourselves of t(atkd) again. As mentioned before, it is added in a resulting formula with ‘±’ in front of it, with ‘–’ being the time when the attack is initialized (but no damage is inflicted yet), no ‘+’ or ‘–’ being an actual chasing TTK, and after ‘+t(atkd)’, (a) will automatically choose another target. The ‘–’ case is important as in between it and actual chasing TTK, the victim can still survive if:
– Firstly, speed is affected both by (a)’s and (v)’s upgrades such as husbandry or wheelbarrow. Speed difference after all upgrades is represented here by V(a–v,mod).
– Secondly, there is a range between (a) and (v)–called ‘d’ here–that needs to be closed. But in the game, it’s the range between the center of the units while collision is an existing factor; therefore, d should be lowered by CS(a) and CS(v)–collision size (‘radius’ in this case) of both units. The same applies to melee units with extra range, so range should also be subtracted from d. (From the recorded footage and calculations, I’m sure range is stacks with collision size of the units.) The actual distances between (a) and (v) in our case is (d – CS(a) – CS(v) – range(a)). This distance will be covered with a speed of V(a–v,mod) which allows us to calculate time it takes for an (a) to approach its (v) and start the attack animation. Here, it will be called t(c-i)–time to close-in (1):
t(c-i) = (d – CS(a) – CS(v) – range(a)) / V(a–v,mod). (1)
– But that’s not all. At the moment of time corresponding to t(c-i) attack animation is only initialized. Damage, however, is not inflicted immediately as it needs to wait for attack delay with the duration of t(atkd) = t(anim)/2. By adding it to t(c-i), we receive the time when first portion of damage is inflicted–t(1stattack) (2):
t(1stattack) = t(c-i)+ t(anim)/2. (2)
The process of chasing down is shown on a short video below.
After an initial hit, if (v) continues to retreat in the same fashion, we enter simple loop of events:
- (i) (a) stands still for the whole length of t(anim,mod) while (v) is retreating at its full speed, V(v,mod). (t(anim,mod) is introduced here because of Bulgarian hussar and Japanese samurai case mentioned earlier. Previously it had no impact, as it does not affect the duration of t(atkd))This creates a new gap between the two;
- (ii) (a) finishes its t(anim) and chases down its (v) with a speed of V(a–v,mod) (the gap in (i) is being closed) up until it’s able to hit again;
- Goto (i).
In terms of variables, (i) is (3):
t(anim,mod) * V(v,mod), (3)
and (ii) is (4):
t(anim,mod) * V(v,mod) / V(a–v,mod). (4)
But do not forget (a) was ‘idle’ (not chasing) for the duration of t(anim). Therefore, a single iteration of chasing time (t(chase)) is (5):
t(chase) = t(anim) + t(anim,mod) * V(v,mod) / V(a–v,mod). (5)
The process of attack and a single chase loop is shown on a short video below.
Before compiling two parts (initial chasing and single chase loop) together, the duration of the latter should be evaluated. It is equal to number of hits to kill (x) a (v) but, as victim is already hit once during t(1stattack), the resulting hits-to-kill is (x–1). It is calculated as (6):
(x–1) = roundup(HP(v,mod) / (Dmg(a,mod)–Melee(v,mod)) – 1), (6)
with all the variables already considered modified after upgrades and bonuses which is applied to shorten the formula. The whole loop then occupies t(ch,loop) (7):
t(ch,loop) = (x–1) * t(chase). (7)
A finishing touch is to remind ourselves of t(atkd) again. As mentioned before, it is added in a resulting formula with ‘±’ in front of it, with ‘–’ being the time when the attack is initialized (but no damage is inflicted yet), no ‘+’ or ‘–’ being an actual chasing TTK, and after ‘+t(atkd)’, (a) will automatically choose another target. The ‘–’ case is important as in between it and actual chasing TTK, the victim can still survive if:
- (v) garrisons;
- (a) is given another order;
- (a) is killed.
Chasing_TTK = t(1stattack) + t(ch,loop) ± t(atkd). (8)
Now let’s analyze a random case that can be met in-game. Let’s say a knight with no upgrades is pursuing a villager with loom and wheelbarrow.
The stats that are important to us are:
First, we need to find a time required for an attacker to catch up with the victim (1) (with ‘(1)’ been an equation in previous subsection). The distance between the two is (initial range minus collision size of both units), so it’s equal to 2.45 tiles. Speed difference between them, V(a–v,mod), is 0.47 tiles/sec. (1) then is:
So, the knight will close the gap in 5.43 seconds and proceed to attack animation. However, as per (2), damage will only be inflicted after the attack delay of 0.675 seconds. Thus, the first portion of damage is inflicted at 6.1 seconds (2).
Chasing loop is initiated. Per (3), while the knight is stuck in its attack animation, the villager escapes 1.35 * 0.88 = 1.19 tiles away from the knight. Per (4), our knight, after it finished its attack animation, will close this forming gap in:
with ‘0.47’ being the difference between both. However, the knight was already idle for its attack animation time, so by (5), the chase loop occupies:
with 1.35 being the duration of the attack animation.
To calculate the length of chasing loop, hits-to-kill subtract one (quick reminder: one hit was already inflicted during (1)) according to (6) should be calculated:
with 40 being villager’s HP and 9 being knight’s resulting damage per hit.
In (7), we just multiply time of a single chasing loop (5) by hits-to-kill (6):
This is the time the whole chasing loop occupies. Finally, this loop should be merged with first attack time (2) and ±attack delay time (8) should be added:
It means that at ~20.95 sec knight initializes its final attack animation, at ~21.6 sec pursued villager is killed, and at ~22.3 sec knight is looking for other tasks.
- Let’s say the distance between the two initially was just 3 tiles when the (v)–victim, our villager–started its run to safety (default LOS of both is 4; let’s assume reaction time was not on top);
- Collision size (‘radius’) of our (a)–attacker, knight–is 0.25 tiles (here onward derived from AGE); villager’s CS is 0.2 tiles;
- Our knight has 0 range so we can disregard it; were it a steppe lancer, 1 would be used instead;
- Knight has the base speed of 1.35 tiles/sec. It’s unmodified in our case;
- Villager has 0.8 tiles/sec default speed. However, after wheelbarrow, it become 0.88 tiles/sec instead;
- Knight deals 10 damage per attack and has no upgrades; villager has 40 HP and 1 armor after loom;
- Knight has attack animation duration of 1.35 seconds. Therefore, attack delay occupies 0.675 seconds.
First, we need to find a time required for an attacker to catch up with the victim (1) (with ‘(1)’ been an equation in previous subsection). The distance between the two is (initial range minus collision size of both units), so it’s equal to 2.45 tiles. Speed difference between them, V(a–v,mod), is 0.47 tiles/sec. (1) then is:
t(c-i) = 2.55 tiles / 0.47 tiles/second ≈ 5.43 seconds. (1)
So, the knight will close the gap in 5.43 seconds and proceed to attack animation. However, as per (2), damage will only be inflicted after the attack delay of 0.675 seconds. Thus, the first portion of damage is inflicted at 6.1 seconds (2).
Chasing loop is initiated. Per (3), while the knight is stuck in its attack animation, the villager escapes 1.35 * 0.88 = 1.19 tiles away from the knight. Per (4), our knight, after it finished its attack animation, will close this forming gap in:
1.19 tiles / 0.47 tiles/second ≈ 2.53 seconds, (4)
with ‘0.47’ being the difference between both. However, the knight was already idle for its attack animation time, so by (5), the chase loop occupies:
t(chase) = 1.19 + 1.35 ≈ 3.88 seconds, (5)
with 1.35 being the duration of the attack animation.
To calculate the length of chasing loop, hits-to-kill subtract one (quick reminder: one hit was already inflicted during (1)) according to (6) should be calculated:
(x–1) = roundup(40 / 9 – 1) = 4, (6)
with 40 being villager’s HP and 9 being knight’s resulting damage per hit.
In (7), we just multiply time of a single chasing loop (5) by hits-to-kill (6):
t(ch,loop) = 3.88 * 4 = 15.51 seconds. (7)
This is the time the whole chasing loop occupies. Finally, this loop should be merged with first attack time (2) and ±attack delay time (8) should be added:
Chasing_TTK = 6.1 + 15.51 ± 0.675 = 21.61 ± 0.675 seconds. (8)
It means that at ~20.95 sec knight initializes its final attack animation, at ~21.6 sec pursued villager is killed, and at ~22.3 sec knight is looking for other tasks.
Using almighty Excel, I created a spreadsheet for calculations available here. Read the notes to see what the variables mean. Rows beneath ‘Editable section’ are unlocked for editing. Required variables can be obtained via Advanced Genie Editor, or AGE. (Available in your ‘\Tools_Builds\’ subfolder of AoE2DE folder (common path for Steam would be ‘%Disk_Volume%\Program Files (x86)\Steam\steamapps\common\AoE2DE\Tools_Builds\’. Alternatively, I’ve backed up its Update 36906 compatible version here.
Theoretical chasing TTKs were then compared with recorded footage using the following test setup.
Test Setup
Victims (villagers) and attackers (cavalry units) were spawned in a tunnel of palisades separated by five tiles and walled-in with some Gaia objects (gold piles). At a set timer (five seconds), gold piles were removed, (v) ordered to walk to the end of palisade tunnel with (a) patrolled into them.
The whole process was recorded (60 FPS; the game was run at ~230–240 FPS) and (i) the time frames when the (v) received damage (based on the healthbar above them) were remembered. (The exact time was determined using the in-game timer; I believe it is a little bit off, for one or two frames, as triggers connected with timings manage to come in forth slightly before the timer switches seconds. Also, game speed of ×1.7 was assumed to be ×1.66 based on a comparison of one minute of footage and in-game timer). Also, (ii) attack animation durations were observed from the recorded footage for several types of (a) and game speeds. Recorded (i) and (ii) were then compared to calculated t(1stattack) and t(ch,loop), coded anim duration of the unit, and an absolute difference of theoretical and observed values was recorded.
Scenario file is here. (You can access your scenario folder in-game in scenario editor menu ('Open Scenario Folder' at the bottom right).)
The whole process was recorded (60 FPS; the game was run at ~230–240 FPS) and (i) the time frames when the (v) received damage (based on the healthbar above them) were remembered. (The exact time was determined using the in-game timer; I believe it is a little bit off, for one or two frames, as triggers connected with timings manage to come in forth slightly before the timer switches seconds. Also, game speed of ×1.7 was assumed to be ×1.66 based on a comparison of one minute of footage and in-game timer). Also, (ii) attack animation durations were observed from the recorded footage for several types of (a) and game speeds. Recorded (i) and (ii) were then compared to calculated t(1stattack) and t(ch,loop), coded anim duration of the unit, and an absolute difference of theoretical and observed values was recorded.
Scenario file is here. (You can access your scenario folder in-game in scenario editor menu ('Open Scenario Folder' at the bottom right).)
Sources of the Error
Going through the recordings revealed a slight problem: calculated chasing TTKs tend to underestimate observed values by a certain percentage; moreover, this percentage increases with the game speed and also builds up with the number of hits-to-kill (up to 5% for light cav @ ×2.0 game speed). What potential sources could there be?
Game speed itself is indeed a factor. As mentioned in ‘Background’ section, it is known to influence other game stats such as farming. On a video below, demonstration of its influence on a chasing TTK is presented (look at keshik’s side) as these are screenshots of the exact time villager death animation starts.
What is happening can be partly explained by the duration of the attack animations, t(anim). Capturing its start (the frame where attack animation started) and end (the frame where walking animation started) reveals that observed t(anim) on average exceeds a theoretical one by one or two frames depending on the game speed. 1/60 of a second is negligible by itself, but when inserted into formula, it already corresponds to 0.15 seconds increase for a keshik. Still, it only addresses half of the issue, as the total error was 0.28 sec.
The source of the residual error is beyond my grasp.
What is happening can be partly explained by the duration of the attack animations, t(anim). Capturing its start (the frame where attack animation started) and end (the frame where walking animation started) reveals that observed t(anim) on average exceeds a theoretical one by one or two frames depending on the game speed. 1/60 of a second is negligible by itself, but when inserted into formula, it already corresponds to 0.15 seconds increase for a keshik. Still, it only addresses half of the issue, as the total error was 0.28 sec.
The source of the residual error is beyond my grasp.
What if Chase Time < Attack Reload Time?
Sometimes chase time t(chase) can be lower than the attack reload time of the unit–either because the (v) is too slow (battering ram) or simply because it stops. Therefore, some units should repeat their attack animation twice, unless they reach a certain threshold of what I believe is 3 seconds (observed for hussar) that prevents the unit from a useless complete repeat of attack animations.
However, it’s far from explaining what’s actually going on. Try to patrol a hussar with husbandry into a battering ram at game speeds of ×1.7 or ×2.0 and see for yourself. This is what happened to me:
]Note: 0.7 seconds with ×1.7 game speed.
In short, on every two or three attacks hussar will either cancel the attack animation (without dealing any damage) or repeat it twice–all at the same run. With game speed is set to ×1.5, this weird double attack animation doesn’t occur as often, and after husbandry is removed, everything goes back to normal.
This weirdness has a significant impact: with ×1.0 and ×1.5 game speed, the ram is destroyed 6 to 10 (six to ten) seconds (or roughly 10 to 16%) faster in comparison with ×1.7 game speed. Still, unfinished animations were presented but showed up only once or twice.
That’s not all. Throwing in stirrups makes matters worse as only on several occasions (7 out of 18 attacks) hussar interrupts its attack after 75% of the attack anim has been played. Thus, it deals with the ram 5 seconds faster.
In short, on every two or three attacks hussar will either cancel the attack animation (without dealing any damage) or repeat it twice–all at the same run. With game speed is set to ×1.5, this weird double attack animation doesn’t occur as often, and after husbandry is removed, everything goes back to normal.
This weirdness has a significant impact: with ×1.0 and ×1.5 game speed, the ram is destroyed 6 to 10 (six to ten) seconds (or roughly 10 to 16%) faster in comparison with ×1.7 game speed. Still, unfinished animations were presented but showed up only once or twice.
That’s not all. Throwing in stirrups makes matters worse as only on several occasions (7 out of 18 attacks) hussar interrupts its attack after 75% of the attack anim has been played. Thus, it deals with the ram 5 seconds faster.
Implications and Limitations
Is there any practical implication for all the wasted time? Hopefully yes. Here are several examples. (All the timings and distances presented below do not count error in so they are slightly, ~1–5%, underestimated.)
- P1 arrived in Feudal faster than p2 did; p2 also do not have loom. P1 sees p2’s full HP villager and issues an attack command. P2 notices scout with villagers’ LOS of 4 and reacts when the gap is 3.5 tiles. In this scenario, scout deals an initial blow at ~4.7 seconds, and the vil only has ~15.5 seconds or ~12 tiles available to it if it wishes to garrison somewhere or run into the range of a TC (here onwards by time and tiles I assume a distance between starting and ending position for the attacker(chasing ttk – t(atkd)) and the time frame when the final attack animation started; at this point, only either if an attacker is killed or receives another command or victim garrisons will the latter survive).
- Loom allows villager to survive 9 scout attacks. In the same scenario, our villager will able to run away for ~29 seconds, or ~23.5 tiles before meeting its end.
- How ‘defensive’ wheelbarrow or Berber civ bonus is against scouts? It’s hard to asses as even a small group of scouts will be colliding into each other, thereby disrupting our calculations, so let’s get back to the loom scenario. In this case, ×1.1 speed multiplier results in additional 3.5 seconds or ~5.5 tiles for the villager to survive. So the answer (in terms of tiles) is ~23%.
- P1 went for fast Feudal while p2 opted for fast Castle instead. Let’s say that p2 managed to deal some hits to p1’s scout and was chasing it down, so the distance was minimal (let’s say it’s 1 tile). With speed difference of 0.35 tiles/sec, p2 will have almost 50 seconds (or 60 tiles–half of a tiny map) for his full HP scouts to survive. Were the initial distance 4 tiles, p2’s scout would be able to survive for another ~8.5 seconds.
- (Note: this line was true before Update 37650) Light cavalry has attack anim duration of 1.35 sec while hussar’s one occupies 1.89 sec. In a generic post-imp raiding scenario, they both have +4 attack and husbandry, while villagers they hunt down have hand cart. I don’t know what distance between raiding cavalry and harassed villagers on average is, so I assumed a scenario of 5 tiles when villagers started to run to safety of a TC/castle/tower. In this case, it will take light cav only 17.5 sec to deal with a single full HP vil while hussar will require almost 21.5 sec (or almost 20% more time); it is also an approximate distance villagers would be able to run before their death as their speed is ~0.97 tiles/sec.
- Post-imp generic hussar (husbandry, +4 attack) is chasing down full HP trade cart with caravan. (Initial distance was assumed to be just 1 tile.) As the speed difference is only 0.15 tiles per sec, our unfortunate hussar would have to chase a full HP trade cart for as much as 129 seconds to kill it. In comparison, light cav with the same upgrades would complete its task in 93 seconds.
- Lures also fall into our scope. Assuming an ok-microed lure, our villager shoots from a range of 3 tiles and retreats right at the end of attack animation. Agroed boar has 1.2× speed of an unupgraded villager (as it uses ‘Run’ animation) and eventually catches upon him/her in 14.4 seconds and kills a hunter in 44.25 sec. Rhino, catching up on the vil within the same time window, kills its target in 33.25 seconds instead, and elephant will have its revenge ~1.5 sec faster. Converting to tiles, we receive ~35.5/26.5/25.5 tiles for an unlucky villager, respectively. Berber/wheelbarrow villagers can lure from almost twice the distance.
- Reality is somewhat different. A slightly simplified yet realistic scenario is described under the cut below.
Let’s count other factors in:
- attack animation is canceled shortly after the arrow was fired (i. e. attack delay + micro);
- there’s the arrow with a travel time;
- collision size lowers the distance, as the arrow hits it, not the center mass (it should, right?);
- still, boar 'de-agro' is not taken into account.
t(add c-i) =[(l – CS(b)) / V(arrow)] + [t(atkd) – t(micro)], (9)
with d being the distance between the villager and the boar equal to hunter’s range of 3 tiles, CS being collision size of our boar (I assumed that units fire their projectiles from their center mass to target’s center mass but hit the size of collision box instead), V(arrow) being the velocity of the projectile, t(atkd) being the attack delay of a ranged unit, t(micro) being the time the player issued villager to run away. It will look like this in our scenario:
t(add c-i) =[(3 – 0.5) tiles / 7 tiles/second] + [0.5 – 0.6] seconds ≈ 0.26 seconds, (9)
Multiply (9) by villager’s speed (0.8 tiles / sec) and add it to the initial d in formula (1). While negligible in this case (d is only increased by ~0.2 tiles), it becomes progressively more impactful with worse microed lures. In the case where a villager starts fleeing right after the anim duration is completed (1.5 sec), boar will already be closer by ~0.6 tiles (multiply t(add c-i) by boar’s speed) resulting in chasing TTK to be ~4 seconds shorter (or lure distance being 3 tiles smaller). Micro your lures properly!
- Reality is somewhat different. A slightly simplified yet realistic scenario is described under the cut below.
- Continuing on a wildlife topic, let’s check out the wolves. Our un-loomed villager spots a wolf with its 4 LOS (the former is already running towards its prey) and with fast enough micro we order him/her to run away immediately. Wolf will close in in ~14 seconds and will kill unfortunate villager after the latter ran for ~57.5 tiles, or 72 seconds.
However, these calculations still remain mostly theoretical. First of all, because notorious pathing problems (like what happens if three scouts are trying to snipe the same villager?) are not taken into consideration at all. Secondly, range units are ignored here as there are more factors in charge (projectile speed, accuracy, ‘missed’ shot hit probability, retreating targets, micro), with most of this variables being hardly countable or completely uncountable at all. Thirdly, there are instances of manually canceled animations and case ‘chase time < reload time’.
Tl;dr
- When one melee unit (attacker) is chasing down another unit (victim), usually the attack reload time of the former is less than the time it takes it to chase the victim down and start an attack animation (i. e. its damage output is not defined by attack reload time at all). This is what is called here ‘chasing TTK’. Its major application is raiding, though it has a certain impact on retreating microed units.
- The following variables affect the outcome of chasing TTK:
- distance between the attacker and the victim;
- collision size of both units;
- range of the attacker;
- speed of both units and modifiers affecting it;
- number of hits to kill;
- attack animation duration and
- attack delay (the latter being 50% of the former).
- The formula itself is described in a corresponding section; in this summary, only a link to a spreadsheet that allows calculating it is presented. You can get required variables using Advance Genie Editor (see ‘Spreadsheet’ subsection of the post for more info).
- Japanese Samurai and Bulgarian hussar with stirrups have their attack animation duration shortened by 25% while chasing; therefore their chasing TTK is lowered, too. However, other Japanese inf or Bulgarian cav units do not experience any influence from these bonuses in chasing scenario.
- Calculated chasing TTKs underestimate real TTKs observed on recorded footage. Depending on the situation, an error is in the range of 1–5%, progressively increasing with the game speed and number of hits-to-kill (it experiences a build-up nature). As a major source of this error, in-game attack animation duration was found to be occupying slightly more time than coded, especially with higher game speeds.
- It is possible that chasing time can be less than attack reload time. However, I’ve found out the game handles such cases weirdly (see the video in ‘What if Chase Time < Attack Reload Time?’ section) and gave up on it, though it is an important part of chasing something like well-microed archers.
- In ‘Implications and Limitations’, several examples of somewhat practical applications for chasing TTK are presented.
- These calculations do not take notorious pathing problems, ranged units (as they are far more complicated) and ‘human factor’ into account which still leaves them mostly theoretical.
Afterword
To conclude, I think that, while calculations presented here have limited practical meaning, they demonstrate how overlooked a variable (stat) of attack animation duration is, as so far I’ve seen it used only for attack delay calculations. This post is also incomplete because analysis of scenario ‘what if chase time < reload time’ was abandoned. Observations made here also reveal how weird the game logic can sometimes be and how influential game speed might be on the performance of the units.
Last edited: