-
Notifications
You must be signed in to change notification settings - Fork 806
Make new battle text to distinguish status move misses and fails
In Generation 2, it is hard to know whether a status move missed or didn't affect the opponent due to the ambiguity of the move failure text. With this tutorial, we can fix this.
- Use a separate prompt for move misses because of attack fail or Protect
- (Optional) Add text if the target for status conditions has a status already
In data/text/battle.asm there's a text for when the opponent evades a move, but it's only used by Leech Seed in case it fails:
EvadedText:
text "<TARGET>"
line "evaded the attack!"
prompt
We can use it for our purpose. Let's edit engine/battle/effect_commands.asm:
...
BattleCommand_Poison:
; poison
...
.dont_sample_failure
+ ld hl, ProtectingItselfText
call CheckSubstituteOpp
jr nz, .failed
+
+ ld hl, EvadedText
ld a, [wAttackMissed]
and a
jr nz, .failed
...
PrintDidntAffect2:
call AnimateFailedMove
- ld hl, DidntAffect1Text ; 'it didn't affect'
- ld de, DidntAffect2Text ; 'it didn't affect'
+ ld hl, EvadedText ; 'evaded the attack'
+ ld de, ProtectingItselfText ; 'protecting itself'
jp FailText_CheckOpponentProtect
You might have noticed we're also using ProtectingItselfText
. This is for moves being blocked by either Protect or Detect.
In generation 2 there are no moves that only apply the Burn or Freeze status, but in case your project has new moves which fulfill this function, this step is for you.
Let's edit data/text/battle.asm again and add text in case the Pokémon is already burned or frozen:
...
AlreadyAsleepText:
text "<TARGET>'s"
line "already asleep!"
prompt
+AlreadyBurnedText:
+ text "<TARGET>'s"
+ line "already burned!"
+ prompt
+
+AlreadyFrozenText:
+ text "<TARGET>'s"
+ line "already frozen!"
+ prompt
Next, edit engine/battle/effect_commands.asm to use our new created status texts:
...
UpdateMoveData:
ld a, BATTLE_VARS_MOVE_ANIM
call GetBattleVarAddr
ld d, h
ld e, l
ld a, BATTLE_VARS_MOVE
call GetBattleVar
ld [wCurSpecies], a
ld [wNamedObjectIndex], a
dec a
call GetMoveData
call GetMoveName
jp CopyName1
+CheckForStatusIfAlreadyHasAny:
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ ld d, h
+ ld e, l
+ and SLP_MASK
+ ld hl, AlreadyAsleepText
+ ret nz
+
+ ld a, [de]
+ bit FRZ, a
+ ld hl, AlreadyFrozenText
+ ret nz
+
+ bit PAR, a
+ ld hl, AlreadyParalyzedText
+ ret nz
+
+ bit PSN, a
+ ld hl, AlreadyPoisonedText
+ ret nz
+
+ bit BRN, a
+ ld hl, AlreadyBurnedText
+ ret
BattleCommand_SleepTarget:
...
.not_protected_by_item
- ld a, BATTLE_VARS_STATUS_OPP
- call GetBattleVarAddr
- ld d, h
- ld e, l
- ld a, [de]
- and SLP_MASK
- ld hl, AlreadyAsleepText
+ call CheckForStatusIfAlreadyHasAny
jr nz, .fail
ld a, [wAttackMissed]
and a
jp nz, PrintDidntAffect2
ld hl, DidntAffect1Text
call .CheckAIRandomFail
jr c, .fail
- ld a, [de]
- and a
- jr nz, .fail
BattleCommand_Poison:
...
call CheckIfTargetIsPoisonType
jp z, .failed
- ld a, BATTLE_VARS_STATUS_OPP
- call GetBattleVar
- ld b, a
- ld hl, AlreadyPoisonedText
- and 1 << PSN
+ call CheckForStatusIfAlreadyHasAny
jp nz, .failed
BattleCommand_Paralyze:
; paralyze
- ld a, BATTLE_VARS_STATUS_OPP
- call GetBattleVar
- bit PAR, a
+ call CheckForStatusIfAlreadyHasAny
jr nz, .paralyzed
...
.dont_sample_failure
- ld a, BATTLE_VARS_STATUS_OPP
- call GetBattleVarAddr
- and a
- jr nz, .failed
...
.paralyzed
+ push hl
call AnimateFailedMove
- ld hl, AlreadyParalyzedText
+ pop hl
jp StdBattleTextbox
CheckForStatusIfAlreadyHasAny
is a new function made to check whether the Pokémon has some status already applied and print the appropriate "Already [STATUS] text". Then we replaced every instance where it used to do an individual status check with our function.
That's it! Now we can know if the status move either missed or doesn't affect the opponent (either due to being statused already or status immunity)!