Make time and weather sensitive moves only weather dependent - pret/pokecrystal GitHub Wiki
In Generation 2 the Day/Night feature was introduced and, along with it, three moves that depend on it: Morning Sun (Morning), Synthesis (Day) and Moonlight (Night). The healing amount is affected by both the current weather and the time of day, according to the following list:
- ¼ Max HP (No weather and No matching time of day)
- ½ Max HP (either Harsh Sunlight active or Matching time of day)
- 100% Max HP (both Harsh Sunlight active and Matching time of day)
- ⅛ Max HP (Rain/Sandstorm active and no Matching time of day)
In Generation 3 onwards it only depends on weather, healing ½ max HP with no weather, ⅔ max HP is there's harsh sunlight, and ¼ max HP with any other weather. The objective of this tutorial will be to make the moves mentioned above behave like in modern generations.
Contents
1. Calculate ⅔ Max HP
In engine/battle/core.asm there are functions that calculate different HP amounts, like GetHalfMaxHP
or GetQuarterMaxHP
, but we need one that calculates ⅔ Max HP, so we're going to create it. Go to the mentioned file and edit it:
GetQuarterMaxHP:
...
+GetThirdMaxHP:
+; Assumes HP<768
+ call GetMaxHP
+ xor a
+ inc b
+.loop
+ dec b
+ inc a
+ dec bc
+ dec bc
+ dec bc
+ inc b
+ jr nz, .loop
+ dec a
+ ld c, a
+ ret nz
+ inc c ; At least 1.
+ ret
GetHalfMaxHP:
...
+GetTwoThirdsMaxHP: ; 2/3 Max HP
+ ; outputs bc from GetThirdMaxHP
+ call GetThirdMaxHP
+ sla c ; Multiply by 2
+ rl b
+ ret
...
Here we're creating two functions, one that calculates ⅓ of max HP, and another one that takes the result and doubles it. GetThirdMaxHP
gets the Max HP of a Pokémon (which is stored in bc
), and performs an iterative substraction where a
is increased once while bc
is decreased three times, until it goes below 0 (underflow). When this happens, a
is decreased once to discount the underflow, loads the value into c
, checks if it's 0 (in which case is increased once, since c
has to be at least 1) and finally returns. GetTwoThirdsMaxHP
calls this function and doubles the result, since 2 * ⅓ = ⅔.
Now that we can calculate ⅔ of Max HP, let's go to the next step.
2. Update the healing routine
Edit engine/battle/effect_commands.asm:
BattleCommand_TimeBasedHealContinue:
-; Time- and weather-sensitive heal.
+; Weather-sensitive heal.
ld hl, wBattleMonMaxHP
ld de, wBattleMonHP
ldh a, [hBattleTurn]
and a
jr z, .start
ld hl, wEnemyMonMaxHP
ld de, wEnemyMonHP
.start
; Index for .Multipliers
; Default restores half max HP.
- ld c, 2
+ ld c, 1
; Don't bother healing if HP is already full.
+ inc c ; Temporarily increase c to compare bytes correctly.
push bc
call CompareBytes
pop bc
jr z, .Full
+ dec c ; Return c to its original value.
-; Don't factor in time of day in link battles.
- ld a, [wLinkMode]
- and a
- jr nz, .Weather
-
- ld a, [wTimeOfDay]
- cp b
- jr z, .Weather
- dec c ; double
...
.Multipliers:
- dw GetEighthMaxHP
dw GetQuarterMaxHP
dw GetHalfMaxHP
- dw GetMaxHP
+ dw GetTwoThirdsMaxHP
So let's explain what's happening. ld c, 1
serves as our index for .Multipliers
, which will initially point to GetHalfMaxHP
. CompareBytes
compares the current HP with the Max HP to determine whether to apply healing or not, and since we're comparing two bytes at de
and hl
, we need to temporarily inc c
(to understand why, read in the code how CompareBytes
works); after the comparison, we dec c
back to 1.
In Link battles the time of day isn't taken into account, but since we're modifying the code to also behave like this in normal gameplay, we no longer need the code block related to it.
The last change was made to the .Multipliers
jumptable, where we replaced both GetEightMaxHP
and GetMaxHP
for GetTwoThirdsMaxHP
to make it point to functions that heal between ¼ Max HP and ⅔ Max HP.
And that's it! Now Morning Sun, Synthesis and Moonlight behave like they do in Gen 3+, only taking the current weather into account.