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
  2. Update the healing routine

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.