Pokémon Legends: Z-A uses a real-time battle system where each move has a cooldown period before it can be used again. Move cooldowns are based on the Pokémon's speed stat and cannot be shorter than 3 seconds.
Moves from the regular combat system that modify speed do not affect cooldown in LZA. Instead, moves such as Agility or Curse modify the speed that the Pokémon moves on the map when following your trainer or chasing a target to attack. Dondozo plus Tatsugiri giving a speed boost also increases movement speed.
The time it takes for a cooldown to expire depends on two factors: the initial value of the cooldown, and the amount that is decremented each frame. Since most cooldowns will not divide evenly by the decrement, the last frame that clears the cooldown will likely add a tiny bit of extra time that is not perceivable by the user.
This explanation uses data from Legends: Z-A 2.0.0. I am not aware of it changing from earlier versions.
The DLC added Flavor Powers via donut that do modify the speed stat! Speed Power's modifiers are as follows:
- Level 1: 1.1x
- Level 2: 1.25x
- Level 3: 1.5x
These modifiers are applied directly to the speed stat and rounded down. For example, a Pokémon with a speed stat of 337 with Speed Power: Lv. 3 would have an effective speed of floor(337 * 1.5) = 505.
The cooldown is calculated as floating point. This causes some unusual decimals compared to using doubles.
First, the Pokémon must have at least 25 speed. If it has less than 25 speed, the move will use the full cooldown visible on the information screen.
If the Pokémon has more than 25 speed, the game calculates the effective speed points as effective_speed = speed - 25.
This is then divided by 0xC2C80000 (the floating point representation of -100) and multiplied by 3. This explains initial testers who observed that each point of speed over 25 reduces the cooldown by 0.03 seconds.
The final cooldown is calculated by subtracting the above value from the initial cooldown. The game ensures that this does not go under 3 seconds.
Here is an example of an Absol with Speed Power Lv. 3 using Perish Song.
Absol is using Perish Song which has a base cooldown of 20 seconds.
It has a speed of floor(337 * 1.5) = 505. Since this is higher than 25, the effective speed points are 505 - 25 = 480.
The cooldown reduction is calculated as 480 / (-100) * 3, and this is added to the base cooldown of 20 seconds to get 0x40b33332 = 5.5999994 seconds.
The result is slightly off from 5.6 seconds because it is performed as floating point arithmetic.
.text:0000007100DF5E18 LDR S4, [X22,#0x60] // s4 = 20 (base cooldown)
.text:0000007100DF5E1C FCMP S0, S2 // s0 = 505 (speed), s2 = 25 (min speed)
.text:0000007100DF5E20 B.LE loc_7100DF5E38 // if speed < 25, skip the math.
.text:0000007100DF5E24 MOV W8, #0xC2C80000 // -100
.text:0000007100DF5E28 FSUB S0, S0, S2 // 505 - 25 = 480
.text:0000007100DF5E2C FMOV S2, W8
.text:0000007100DF5E30 FDIV S0, S0, S2 // divide 480/-100 = -4.8 (0xc099999a)
.text:0000007100DF5E34 FMADD S4, S0, S1, S4 // (-4.8 * 3) + 20 = 5.5999994 (0x40b33332)
.text:0000007100DF5E38
.text:0000007100DF5E38 loc_7100DF5E38 ; CODE XREF: sub_7100DF5C60+1C0↑j
.text:0000007100DF5E38 FCMP S4, S3 // Compare to min of 3
.text:0000007100DF5E3C FCSEL S0, S3, S4, MI Move cooldowns must expire over time. My testing was on a Switch 1 which runs at 30 FPS. I observed that each update decreases the cooldown by 1/30th of a second.
Here are some float values I observed while Absol's cooldown initially started decrementing.
Speed 3 Perish Song at level 200
0x40b33332 5.5999994
0x40b22221 5.566666
0x40b11110 5.533333
Perish Song at level 200
0x412a3d71 10.64
0x4129b4e8 10.606667
0x41292c5f 10.573333
This would suggest that at the very end of the cooldown, if any time remains, then the user must wait out an entire frame for it to drop to 0. This is not enough time for a human to notice.
The Drowsy status effect works by halving the cooldown decrement, effectively doubling the cooldown time. Each frame will only reduce the value by 1/60th of a second.