summaryrefslogtreecommitdiff
path: root/engine/battle/moveEffects
diff options
context:
space:
mode:
Diffstat (limited to 'engine/battle/moveEffects')
-rw-r--r--engine/battle/moveEffects/conversion_effect.asm34
-rw-r--r--engine/battle/moveEffects/drain_hp_effect.asm104
-rw-r--r--engine/battle/moveEffects/focus_energy_effect.asm24
-rw-r--r--engine/battle/moveEffects/haze_effect.asm76
-rw-r--r--engine/battle/moveEffects/heal_effect.asm116
-rw-r--r--engine/battle/moveEffects/leech_seed_effect.asm39
-rw-r--r--engine/battle/moveEffects/mist_effect.asm21
-rw-r--r--engine/battle/moveEffects/one_hit_ko_effect.asm36
-rw-r--r--engine/battle/moveEffects/paralyze_effect.asm53
-rw-r--r--engine/battle/moveEffects/pay_day_effect.asm43
-rw-r--r--engine/battle/moveEffects/recoil_effect.asm68
-rw-r--r--engine/battle/moveEffects/reflect_light_screen_effect.asm45
-rw-r--r--engine/battle/moveEffects/substitute_effect.asm77
-rw-r--r--engine/battle/moveEffects/transform_effect.asm138
14 files changed, 874 insertions, 0 deletions
diff --git a/engine/battle/moveEffects/conversion_effect.asm b/engine/battle/moveEffects/conversion_effect.asm
new file mode 100644
index 00000000..511df2fd
--- /dev/null
+++ b/engine/battle/moveEffects/conversion_effect.asm
@@ -0,0 +1,34 @@
+ConversionEffect_: ; 139a3 (4:79a3)
+ ld hl, wEnemyMonType1
+ ld de, wBattleMonType1
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, [W_ENEMYBATTSTATUS1]
+ jr z, .asm_139b8
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+ ld a, [W_PLAYERBATTSTATUS1]
+.asm_139b8
+ bit Invulnerable, a ; is mon immune to typical attacks (dig/fly)
+ jr nz, PrintButItFailedText
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ld hl, PlayCurrentMoveAnimation
+ call CallBankF
+ ld hl, ConvertedTypeText
+ jp PrintText
+
+ConvertedTypeText: ; 139cd (4:79cd)
+ TX_FAR _ConvertedTypeText
+ db "@"
+
+PrintButItFailedText: ; 139d2 (4:79d2)
+ ld hl, PrintButItFailedText_
+CallBankF: ; 139d5 (4:79d5)
+ ld b, BANK(PrintButItFailedText_)
+ jp Bankswitch
diff --git a/engine/battle/moveEffects/drain_hp_effect.asm b/engine/battle/moveEffects/drain_hp_effect.asm
new file mode 100644
index 00000000..517d53d1
--- /dev/null
+++ b/engine/battle/moveEffects/drain_hp_effect.asm
@@ -0,0 +1,104 @@
+DrainHPEffect_: ; 783f (1:783f)
+ ld hl, W_DAMAGE
+ ld a, [hl]
+ srl a ; divide damage by 2
+ ld [hli], a
+ ld a, [hl]
+ rr a
+ ld [hld], a
+ or [hl] ; is damage 0?
+ jr nz, .getAttackerHP
+; if damage is 0, increase to 1 so that the attacker gains at least 1 HP
+ inc hl
+ inc [hl]
+.getAttackerHP
+ ld hl, wBattleMonHP
+ ld de, wBattleMonMaxHP
+ ld a, [H_WHOSETURN]
+ and a
+ jp z, .addDamageToAttackerHP
+ ld hl, wEnemyMonHP
+ ld de, wEnemyMonMaxHP
+.addDamageToAttackerHP
+ ld bc, wHPBarOldHP+1
+; copy current HP to wHPBarOldHP
+ ld a, [hli]
+ ld [bc], a
+ ld a, [hl]
+ dec bc
+ ld [bc], a
+; copy max HP to wHPBarMaxHP
+ ld a, [de]
+ dec bc
+ ld [bc], a
+ inc de
+ ld a, [de]
+ dec bc
+ ld [bc], a
+; add damage to attacker's HP and copy new HP to wHPBarNewHP
+ ld a, [W_DAMAGE + 1]
+ ld b, [hl]
+ add b
+ ld [hld], a
+ ld [wHPBarNewHP], a
+ ld a, [W_DAMAGE]
+ ld b, [hl]
+ adc b
+ ld [hli], a
+ ld [wHPBarNewHP+1], a
+ jr c, .capToMaxHP ; if HP > 65,535, cap to max HP
+; compare HP with max HP
+ ld a, [hld]
+ ld b, a
+ ld a, [de]
+ dec de
+ sub b
+ ld a, [hli]
+ ld b, a
+ ld a, [de]
+ inc de
+ sbc b
+ jr nc, .next
+.capToMaxHP
+ ld a, [de]
+ ld [hld], a
+ ld [wHPBarNewHP], a
+ dec de
+ ld a, [de]
+ ld [hli], a
+ ld [wHPBarNewHP+1], a
+ inc de
+.next
+ ld a, [H_WHOSETURN]
+ and a
+ hlCoord 10, 9
+ ld a, $1
+ jr z, .next2
+ hlCoord 2, 2
+ xor a
+.next2
+ ld [wHPBarType], a
+ predef UpdateHPBar2
+ predef DrawPlayerHUDAndHPBar
+ predef DrawEnemyHUDAndHPBar
+ callab ReadPlayerMonCurHPAndStatus
+ ld hl, SuckedHealthText
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, [W_PLAYERMOVEEFFECT]
+ jr z, .next3
+ ld a, [W_ENEMYMOVEEFFECT]
+.next3
+ cp DREAM_EATER_EFFECT
+ jr nz, .printText
+ ld hl, DreamWasEatenText
+.printText
+ jp PrintText
+
+SuckedHealthText: ; 78dc (1:78dc)
+ TX_FAR _SuckedHealthText
+ db "@"
+
+DreamWasEatenText: ; 78e1 (1:78e1)
+ TX_FAR _DreamWasEatenText
+ db "@"
diff --git a/engine/battle/moveEffects/focus_energy_effect.asm b/engine/battle/moveEffects/focus_energy_effect.asm
new file mode 100644
index 00000000..f01e61cc
--- /dev/null
+++ b/engine/battle/moveEffects/focus_energy_effect.asm
@@ -0,0 +1,24 @@
+FocusEnergyEffect_: ; 27f86 (9:7f86)
+ ld hl, W_PLAYERBATTSTATUS2
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .notEnemy
+ ld hl, W_ENEMYBATTSTATUS2
+.notEnemy
+ bit GettingPumped, [hl] ; is mon already using focus energy?
+ jr nz, .alreadyUsing
+ set GettingPumped, [hl] ; mon is now using focus energy
+ callab PlayCurrentMoveAnimation
+ ld hl, GettingPumpedText
+ jp PrintText
+.alreadyUsing
+ ld c, $32
+ call DelayFrames
+ ld hl, PrintButItFailedText_
+ ld b, BANK(PrintButItFailedText_)
+ jp Bankswitch
+
+GettingPumpedText: ; 27fb3 (9:7fb3)
+ db $0a
+ TX_FAR _GettingPumpedText
+ db "@"
diff --git a/engine/battle/moveEffects/haze_effect.asm b/engine/battle/moveEffects/haze_effect.asm
new file mode 100644
index 00000000..2343e784
--- /dev/null
+++ b/engine/battle/moveEffects/haze_effect.asm
@@ -0,0 +1,76 @@
+HazeEffect_: ; 139da (4:79da)
+ ld a, $7
+ ld hl, wPlayerMonAttackMod
+ call ResetStatMods
+ ld hl, wEnemyMonAttackMod
+ call ResetStatMods
+ ld hl, wPlayerMonUnmodifiedAttack
+ ld de, wBattleMonAttack
+ call ResetStats
+ ld hl, wEnemyMonUnmodifiedAttack
+ ld de, wEnemyMonAttack
+ call ResetStats
+ ld hl, wEnemyMonStatus
+ ld de, wEnemySelectedMove
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_13a09
+ ld hl, wBattleMonStatus
+ dec de
+
+.asm_13a09
+ ld a, [hl]
+ ld [hl], $0
+ and $27
+ jr z, .asm_13a13
+ ld a, $ff
+ ld [de], a
+
+.asm_13a13
+ xor a
+ ld [W_PLAYERDISABLEDMOVE], a
+ ld [W_ENEMYDISABLEDMOVE], a
+ ld hl, wccee
+ ld [hli], a
+ ld [hl], a
+ ld hl, W_PLAYERBATTSTATUS1
+ call CureStatuses
+ ld hl, W_ENEMYBATTSTATUS1
+ call CureStatuses
+ ld hl, PlayCurrentMoveAnimation
+ call CallBankF
+ ld hl, StatusChangesEliminatedText
+ jp PrintText
+
+CureStatuses: ; 13a37 (4:7a37)
+ res Confused, [hl]
+ inc hl ; BATTSTATUS2
+ ld a, [hl]
+ and (1 << UsingRage) | (1 << NeedsToRecharge) | (1 << HasSubstituteUp) | (1 << 3) ; clear all but these from BATTSTATUS2
+ ld [hli], a ; BATTSTATUS3
+ ld a, [hl]
+ and %11110000 | (1 << Transformed) ; clear Bad Poison, Reflect and Light Screen statuses
+ ld [hl], a
+ ret
+
+ResetStatMods: ; 13a43 (4:7a43)
+ ld b, $8
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+ResetStats: ; 13a4a (4:7a4a)
+ ld b, $8
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .loop
+ ret
+
+StatusChangesEliminatedText: ; 13a53 (4:7a53)
+ TX_FAR _StatusChangesEliminatedText
+ db "@"
diff --git a/engine/battle/moveEffects/heal_effect.asm b/engine/battle/moveEffects/heal_effect.asm
new file mode 100644
index 00000000..22d482e7
--- /dev/null
+++ b/engine/battle/moveEffects/heal_effect.asm
@@ -0,0 +1,116 @@
+HealEffect_: ; 3b9ec (e:79ec)
+ ld a, [H_WHOSETURN]
+ and a
+ ld de, wBattleMonHP
+ ld hl, wBattleMonMaxHP
+ ld a, [W_PLAYERMOVENUM]
+ jr z, .asm_3ba03
+ ld de, wEnemyMonHP
+ ld hl, wEnemyMonMaxHP
+ ld a, [W_ENEMYMOVENUM]
+.asm_3ba03
+ ld b, a
+ ld a, [de]
+ cp [hl]
+ inc de
+ inc hl
+ ld a, [de]
+ sbc [hl]
+ jp z, .failed
+ ld a, b
+ cp REST
+ jr nz, .asm_3ba37
+ push hl
+ push de
+ push af
+ ld c, 50
+ call DelayFrames
+ ld hl, wBattleMonStatus
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_3ba25
+ ld hl, wEnemyMonStatus
+.asm_3ba25
+ ld a, [hl]
+ and a
+ ld [hl], 2 ; Number of turns from Rest
+ ld hl, StartedSleepingEffect
+ jr z, .asm_3ba31
+ ld hl, FellAsleepBecameHealthyText
+.asm_3ba31
+ call PrintText
+ pop af
+ pop de
+ pop hl
+.asm_3ba37
+ ld a, [hld]
+ ld [wHPBarMaxHP], a
+ ld c, a
+ ld a, [hl]
+ ld [wHPBarMaxHP+1], a
+ ld b, a
+ jr z, .asm_3ba47
+ srl b
+ rr c
+.asm_3ba47
+ ld a, [de]
+ ld [wHPBarOldHP], a
+ add c
+ ld [de], a
+ ld [wHPBarNewHP], a
+ dec de
+ ld a, [de]
+ ld [wHPBarOldHP+1], a
+ adc b
+ ld [de], a
+ ld [wHPBarNewHP+1], a
+ inc hl
+ inc de
+ ld a, [de]
+ dec de
+ sub [hl]
+ dec hl
+ ld a, [de]
+ sbc [hl]
+ jr c, .asm_3ba6f
+ ld a, [hli]
+ ld [de], a
+ ld [wHPBarNewHP+1], a
+ inc de
+ ld a, [hl]
+ ld [de], a
+ ld [wHPBarNewHP], a
+.asm_3ba6f
+ ld hl, PlayCurrentMoveAnimation
+ call BankswitchEtoF
+ ld a, [H_WHOSETURN]
+ and a
+ hlCoord 10, 9
+ ld a, $1
+ jr z, .asm_3ba83
+ hlCoord 2, 2
+ xor a
+.asm_3ba83
+ ld [wHPBarType], a
+ predef UpdateHPBar2
+ ld hl, DrawHUDsAndHPBars
+ call BankswitchEtoF
+ ld hl, RegainedHealthText
+ jp PrintText
+.failed
+ ld c, 50
+ call DelayFrames
+ ld hl, PrintButItFailedText_
+ jp BankswitchEtoF
+
+StartedSleepingEffect: ; 3baa2 (e:7aa2)
+ TX_FAR _StartedSleepingEffect
+ db "@"
+
+FellAsleepBecameHealthyText: ; 3baa7 (e:7aa7)
+ TX_FAR _FellAsleepBecameHealthyText
+ db "@"
+
+RegainedHealthText: ; 3baac (e:7aac)
+ TX_FAR _RegainedHealthText
+ db "@"
diff --git a/engine/battle/moveEffects/leech_seed_effect.asm b/engine/battle/moveEffects/leech_seed_effect.asm
new file mode 100644
index 00000000..a257d143
--- /dev/null
+++ b/engine/battle/moveEffects/leech_seed_effect.asm
@@ -0,0 +1,39 @@
+LeechSeedEffect_: ; 2bea9 (a:7ea9)
+ callab MoveHitTest
+ ld a, [W_MOVEMISSED] ; W_MOVEMISSED
+ and a
+ jr nz, .asm_2bee7
+ ld hl, W_ENEMYBATTSTATUS2 ; W_ENEMYBATTSTATUS2
+ ld de, wEnemyMonType1 ; wcfea (aliases: wEnemyMonType)
+ ld a, [H_WHOSETURN] ; $fff3
+ and a
+ jr z, .asm_2bec8
+ ld hl, W_PLAYERBATTSTATUS2 ; W_PLAYERBATTSTATUS2
+ ld de, wBattleMonType1 ; wd019 (aliases: wBattleMonType)
+.asm_2bec8
+ ld a, [de]
+ cp GRASS
+ jr z, .asm_2bee7
+ inc de
+ ld a, [de]
+ cp GRASS
+ jr z, .asm_2bee7
+ bit Seeded, [hl]
+ jr nz, .asm_2bee7
+ set Seeded, [hl]
+ callab PlayCurrentMoveAnimation
+ ld hl, WasSeededText ; $7ef2
+ jp PrintText
+.asm_2bee7
+ ld c, $32
+ call DelayFrames
+ ld hl, EvadedAttackText ; $7ef7
+ jp PrintText
+
+WasSeededText: ; 2bef2 (a:7ef2)
+ TX_FAR _WasSeededText
+ db "@"
+
+EvadedAttackText: ; 2bef7 (a:7ef7)
+ TX_FAR _EvadedAttackText
+ db "@"
diff --git a/engine/battle/moveEffects/mist_effect.asm b/engine/battle/moveEffects/mist_effect.asm
new file mode 100644
index 00000000..adee1dfd
--- /dev/null
+++ b/engine/battle/moveEffects/mist_effect.asm
@@ -0,0 +1,21 @@
+MistEffect_: ; 33f2b (c:7f2b)
+ ld hl, W_PLAYERBATTSTATUS2
+ ld a, [$fff3]
+ and a
+ jr z, .asm_33f36
+ ld hl, W_ENEMYBATTSTATUS2
+.asm_33f36
+ bit ProtectedByMist, [hl] ; is mon protected by mist?
+ jr nz, .asm_33f4a
+ set ProtectedByMist, [hl] ; mon is now protected by mist
+ callab PlayCurrentMoveAnimation
+ ld hl, ShroudedInMistText
+ jp PrintText
+.asm_33f4a
+ ld hl, PrintButItFailedText_
+ ld b, BANK(PrintButItFailedText_)
+ jp Bankswitch
+
+ShroudedInMistText: ; 33f52 (c:7f52)
+ TX_FAR _ShroudedInMistText
+ db "@"
diff --git a/engine/battle/moveEffects/one_hit_ko_effect.asm b/engine/battle/moveEffects/one_hit_ko_effect.asm
new file mode 100644
index 00000000..84418e33
--- /dev/null
+++ b/engine/battle/moveEffects/one_hit_ko_effect.asm
@@ -0,0 +1,36 @@
+OneHitKOEffect_: ; 33f57 (c:7f57)
+ ld hl, W_DAMAGE
+ xor a
+ ld [hli], a
+ ld [hl], a ; set the damage output to zero
+ dec a
+ ld [wCriticalHitOrOHKO], a
+ ld hl, wBattleMonSpeed + 1
+ ld de, wEnemyMonSpeed + 1
+ ld a, [H_WHOSETURN] ; $fff3
+ and a
+ jr z, .asm_33f72
+ ld hl, wEnemyMonSpeed + 1
+ ld de, wBattleMonSpeed + 1
+.asm_33f72
+ ld a, [de]
+ dec de
+ ld b, a
+ ld a, [hld]
+ sub b
+ ld a, [de]
+ ld b, a
+ ld a, [hl]
+ sbc b
+ jr c, .asm_33f8a
+ ld hl, W_DAMAGE
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+ ld a, $2
+ ld [wCriticalHitOrOHKO], a
+ ret
+.asm_33f8a
+ ld a, $1
+ ld [W_MOVEMISSED], a
+ ret
diff --git a/engine/battle/moveEffects/paralyze_effect.asm b/engine/battle/moveEffects/paralyze_effect.asm
new file mode 100644
index 00000000..69acbb01
--- /dev/null
+++ b/engine/battle/moveEffects/paralyze_effect.asm
@@ -0,0 +1,53 @@
+ParalyzeEffect_: ; 52601 (14:6601)
+ ld hl, wEnemyMonStatus
+ ld de, W_PLAYERMOVETYPE
+ ld a, [H_WHOSETURN]
+ and a
+ jp z, .next
+ ld hl, wBattleMonStatus
+ ld de, W_ENEMYMOVETYPE
+.next
+ ld a, [hl]
+ and a ; does the target already have a status ailment?
+ jr nz, .didntAffect
+; check if the target is immune due to types
+ ld a, [de]
+ cp ELECTRIC
+ jr nz, .hitTest
+ ld b, h
+ ld c, l
+ inc bc
+ ld a, [bc]
+ cp GROUND
+ jr z, .doesntAffect
+ inc bc
+ ld a, [bc]
+ cp GROUND
+ jr z, .doesntAffect
+.hitTest
+ push hl
+ callab MoveHitTest
+ pop hl
+ ld a, [W_MOVEMISSED]
+ and a
+ jr nz, .didntAffect
+ set PAR, [hl]
+ callab QuarterSpeedDueToParalysis
+ ld c, 30
+ call DelayFrames
+ callab PlayCurrentMoveAnimation
+ ld hl, PrintMayNotAttackText
+ ld b, BANK(PrintMayNotAttackText)
+ jp Bankswitch
+.didntAffect
+ ld c, 50
+ call DelayFrames
+ ld hl, PrintDidntAffectText
+ ld b, BANK(PrintDidntAffectText)
+ jp Bankswitch
+.doesntAffect
+ ld c, 50
+ call DelayFrames
+ ld hl, PrintDoesntAffectText
+ ld b, BANK(PrintDoesntAffectText)
+ jp Bankswitch
diff --git a/engine/battle/moveEffects/pay_day_effect.asm b/engine/battle/moveEffects/pay_day_effect.asm
new file mode 100644
index 00000000..75a005ed
--- /dev/null
+++ b/engine/battle/moveEffects/pay_day_effect.asm
@@ -0,0 +1,43 @@
+PayDayEffect_ ; 2feb8 (b:7eb8)
+ xor a
+ ld hl, wcd6d
+ ld [hli], a
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, [wBattleMonLevel]
+ jr z, .asm_2fec8
+ ld a, [wEnemyMonLevel]
+.asm_2fec8
+ add a
+ ld [H_DIVIDEND + 3], a
+ xor a
+ ld [H_DIVIDEND], a
+ ld [H_DIVIDEND + 1], a
+ ld [H_DIVIDEND + 2], a
+ ld a, $64
+ ld [H_DIVISOR], a
+ ld b, $4
+ call Divide
+ ld a, [H_QUOTIENT + 3]
+ ld [hli], a
+ ld a, [H_REMAINDER]
+ ld [H_DIVIDEND + 3], a
+ ld a, $a
+ ld [H_DIVISOR], a
+ ld b, $4
+ call Divide
+ ld a, [H_QUOTIENT + 3]
+ swap a
+ ld b, a
+ ld a, [H_REMAINDER]
+ add b
+ ld [hl], a
+ ld de, wTotalPayDayMoney + 2
+ ld c, $3
+ predef AddBCDPredef
+ ld hl, CoinsScatteredText
+ jp PrintText
+
+CoinsScatteredText: ; 2ff04 (b:7f04)
+ TX_FAR _CoinsScatteredText
+ db "@"
diff --git a/engine/battle/moveEffects/recoil_effect.asm b/engine/battle/moveEffects/recoil_effect.asm
new file mode 100644
index 00000000..0460b208
--- /dev/null
+++ b/engine/battle/moveEffects/recoil_effect.asm
@@ -0,0 +1,68 @@
+RecoilEffect_: ; 1392c (4:792c)
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, [W_PLAYERMOVENUM]
+ ld hl, wBattleMonMaxHP
+ jr z, .asm_1393d
+ ld a, [W_ENEMYMOVENUM]
+ ld hl, wEnemyMonMaxHP
+.asm_1393d
+ ld d, a
+ ld a, [W_DAMAGE]
+ ld b, a
+ ld a, [W_DAMAGE + 1]
+ ld c, a
+ srl b
+ rr c
+ ld a, d
+ cp STRUGGLE
+ jr z, .asm_13953
+ srl b
+ rr c
+.asm_13953
+ ld a, b
+ or c
+ jr nz, .asm_13958
+ inc c
+.asm_13958
+ ld a, [hli]
+ ld [wHPBarMaxHP+1], a
+ ld a, [hl]
+ ld [wHPBarMaxHP], a
+ push bc
+ ld bc, $fff2
+ add hl, bc
+ pop bc
+ ld a, [hl]
+ ld [wHPBarOldHP], a
+ sub c
+ ld [hld], a
+ ld [wHPBarNewHP], a
+ ld a, [hl]
+ ld [wHPBarOldHP+1], a
+ sbc b
+ ld [hl], a
+ ld [wHPBarNewHP+1], a
+ jr nc, .asm_13982
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld hl, wHPBarNewHP
+ ld [hli], a
+ ld [hl], a
+.asm_13982
+ hlCoord 10, 9
+ ld a, [H_WHOSETURN]
+ and a
+ ld a, $1
+ jr z, .asm_13990
+ hlCoord 2, 2
+ xor a
+.asm_13990
+ ld [wHPBarType], a
+ predef UpdateHPBar2
+ ld hl, HitWithRecoilText
+ jp PrintText
+HitWithRecoilText: ; 1399e (4:799e)
+ TX_FAR _HitWithRecoilText
+ db "@"
diff --git a/engine/battle/moveEffects/reflect_light_screen_effect.asm b/engine/battle/moveEffects/reflect_light_screen_effect.asm
new file mode 100644
index 00000000..39a2c154
--- /dev/null
+++ b/engine/battle/moveEffects/reflect_light_screen_effect.asm
@@ -0,0 +1,45 @@
+ReflectLightScreenEffect_: ; 3bb97 (e:7b97)
+ ld hl, W_PLAYERBATTSTATUS3
+ ld de, W_PLAYERMOVEEFFECT
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_3bba8
+ ld hl, W_ENEMYBATTSTATUS3
+ ld de, W_ENEMYMOVEEFFECT
+.asm_3bba8
+ ld a, [de]
+ cp LIGHT_SCREEN_EFFECT
+ jr nz, .reflect
+ bit HasLightScreenUp, [hl] ; is mon already protected by light screen?
+ jr nz, .moveFailed
+ set HasLightScreenUp, [hl] ; mon is now protected by light screen
+ ld hl, LightScreenProtectedText
+ jr .asm_3bbc1
+.reflect
+ bit HasReflectUp, [hl] ; is mon already protected by reflect?
+ jr nz, .moveFailed
+ set HasReflectUp, [hl] ; mon is now protected by reflect
+ ld hl, ReflectGainedArmorText
+.asm_3bbc1
+ push hl
+ ld hl, PlayCurrentMoveAnimation
+ call BankswitchEtoF
+ pop hl
+ jp PrintText
+.moveFailed
+ ld c, $32
+ call DelayFrames
+ ld hl, PrintButItFailedText_
+ jp BankswitchEtoF
+
+LightScreenProtectedText: ; 3bbd7 (e:7bd7)
+ TX_FAR _LightScreenProtectedText
+ db "@"
+
+ReflectGainedArmorText: ; 3bbdc (e:7bdc)
+ TX_FAR _ReflectGainedArmorText
+ db "@"
+
+BankswitchEtoF: ; 3bbe1 (e:7be1)
+ ld b, BANK(BattleCore)
+ jp Bankswitch
diff --git a/engine/battle/moveEffects/substitute_effect.asm b/engine/battle/moveEffects/substitute_effect.asm
new file mode 100644
index 00000000..e88def4a
--- /dev/null
+++ b/engine/battle/moveEffects/substitute_effect.asm
@@ -0,0 +1,77 @@
+SubstituteEffect_: ; 17dad (5:7dad)
+ ld c, 50
+ call DelayFrames
+ ld hl, wBattleMonMaxHP
+ ld de, wPlayerSubstituteHP
+ ld bc, W_PLAYERBATTSTATUS2
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .notEnemy
+ ld hl, wEnemyMonMaxHP
+ ld de, wEnemySubstituteHP
+ ld bc, W_ENEMYBATTSTATUS2
+.notEnemy
+ ld a, [bc] ;load flags
+ bit HasSubstituteUp, a ;user already has substitute?
+ jr nz, .alreadyHasSubstitute ;skip this code if so
+ ;user doesn't have a substitute [yet]
+ push bc
+ ld a, [hli] ;load max hp
+ ld b, [hl]
+ srl a ;max hp / 4, [quarter health to remove from user]
+ rr b
+ srl a
+ rr b
+ push de
+ ld de, wBattleMonHP - wBattleMonMaxHP
+ add hl, de ; point hl to current HP
+ pop de
+ ld a, b
+ ld [de], a ;save copy of HP to subtract in ccd7/ccd8 [how much HP substitute has]
+ ld a, [hld] ;load current hp
+ sub b ;subtract [max hp / 4]
+ ld d, a ;save low byte result in D
+ ld a, [hl]
+ sbc a, 0 ;borrow from high byte if needed
+ pop bc
+ jr c, .notEnoughHP ;underflow means user would be left with negative health
+ ;bug: note since it only brances on carry, it will possibly leave user with 0HP
+.userHasZeroOrMoreHP
+ ldi [hl], a ;store high byte HP
+ ld [hl], d ;store low byte HP
+ ld h, b
+ ld l, c
+ set HasSubstituteUp, [hl] ;set bit 4 of flags, user now has substitute
+ ld a, [W_OPTIONS] ;load options
+ bit 7, a ;battle animation is enabled?
+ ld hl, PlayCurrentMoveAnimation ;animation enabled: 0F:7BA8
+ ld b, BANK(PlayCurrentMoveAnimation)
+ jr z, .animationEnabled
+ ld hl, AnimationSubstitute ;animation disabled: 1E:56E0
+ ld b, BANK(AnimationSubstitute)
+.animationEnabled
+ call Bankswitch ;jump to routine depending on animation setting
+ ld hl, SubstituteText
+ call PrintText
+ ld hl, DrawHUDsAndHPBars
+ ld b, BANK(DrawHUDsAndHPBars)
+ jp Bankswitch
+.alreadyHasSubstitute
+ ld hl, HasSubstituteText
+ jr .printText
+.notEnoughHP
+ ld hl, TooWeakSubstituteText
+.printText
+ jp PrintText
+
+SubstituteText: ; 17e1d (5:7e1d)
+ TX_FAR _SubstituteText
+ db "@"
+
+HasSubstituteText: ; 17e22 (5:7e22)
+ TX_FAR _HasSubstituteText
+ db "@"
+
+TooWeakSubstituteText: ; 17e27 (5:7e27)
+ TX_FAR _TooWeakSubstituteText
+ db "@"
diff --git a/engine/battle/moveEffects/transform_effect.asm b/engine/battle/moveEffects/transform_effect.asm
new file mode 100644
index 00000000..6e25712a
--- /dev/null
+++ b/engine/battle/moveEffects/transform_effect.asm
@@ -0,0 +1,138 @@
+TransformEffect_: ; 3bab1 (e:7ab1)
+ ld hl, wBattleMonSpecies
+ ld de, wEnemyMonSpecies
+ ld bc, W_ENEMYBATTSTATUS3
+ ld a, [W_ENEMYBATTSTATUS1]
+ ld a, [H_WHOSETURN]
+ and a
+ jr nz, .asm_3bad1
+ ld hl, wEnemyMonSpecies
+ ld de, wBattleMonSpecies
+ ld bc, W_PLAYERBATTSTATUS3
+ ld [wPlayerMoveListIndex], a
+ ld a, [W_PLAYERBATTSTATUS1]
+.asm_3bad1
+ bit Invulnerable, a ; is mon invulnerable to typical attacks? (fly/dig)
+ jp nz, .failed
+ push hl
+ push de
+ push bc
+ ld hl, W_PLAYERBATTSTATUS2
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_3bae4
+ ld hl, W_ENEMYBATTSTATUS2
+.asm_3bae4
+ bit HasSubstituteUp, [hl]
+ push af
+ ld hl, Func_79747
+ ld b, BANK(Func_79747)
+ call nz, Bankswitch
+ ld a, [W_OPTIONS]
+ add a
+ ld hl, PlayCurrentMoveAnimation
+ ld b, BANK(PlayCurrentMoveAnimation)
+ jr nc, .asm_3baff
+ ld hl, AnimationTransformMon
+ ld b, BANK(AnimationTransformMon)
+.asm_3baff
+ call Bankswitch
+ ld hl, Func_79771
+ ld b, BANK(Func_79771)
+ pop af
+ call nz, Bankswitch
+ pop bc
+ ld a, [bc]
+ set Transformed, a
+ ld [bc], a
+ pop de
+ pop hl
+ push hl
+ ld a, [hl]
+ ld [de], a
+ ld bc, $5
+ add hl, bc
+ inc de
+ inc de
+ inc de
+ inc de
+ inc de
+ inc bc
+ inc bc
+ call CopyData
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_3bb32
+ ld a, [de]
+ ld [wcceb], a
+ inc de
+ ld a, [de]
+ ld [wccec], a
+ dec de
+.asm_3bb32
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hli]
+ ld [de], a
+ inc de
+ inc hl
+ inc hl
+ inc hl
+ inc de
+ inc de
+ inc de
+ ld bc, $8
+ call CopyData
+ ld bc, $ffef
+ add hl, bc
+ ld b, $4
+.asm_3bb4a
+ ld a, [hli]
+ and a
+ jr z, .asm_3bb57
+ ld a, $5
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .asm_3bb4a
+ jr .asm_3bb5d
+.asm_3bb57
+ xor a
+ ld [de], a
+ inc de
+ dec b
+ jr nz, .asm_3bb57
+.asm_3bb5d
+ pop hl
+ ld a, [hl]
+ ld [wd11e], a
+ call GetMonName
+ ld hl, wEnemyMonUnmodifiedAttack
+ ld de, wPlayerMonUnmodifiedAttack
+ call .copyBasedOnTurn
+ ld hl, wEnemyMonStatMods
+ ld de, wPlayerMonStatMods
+ call .copyBasedOnTurn
+ ld hl, TransformedText
+ jp PrintText
+
+.copyBasedOnTurn
+ ld a, [H_WHOSETURN]
+ and a
+ jr z, .asm_3bb86
+ push hl
+ ld h, d
+ ld l, e
+ pop de
+.asm_3bb86
+ ld bc, $8
+ jp CopyData
+
+.failed
+ ld hl, PrintButItFailedText_
+ jp BankswitchEtoF
+
+TransformedText: ; 3bb92 (e:7b92)
+ TX_FAR _TransformedText
+ db "@"