summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorentrpntr <entrpntr@gmail.com>2020-04-19 12:31:56 -0400
committerentrpntr <entrpntr@gmail.com>2020-04-19 12:31:56 -0400
commite953302d3f81f080fd5d8423000496ce2fad36d3 (patch)
treebb66787122ec1029524153c96c3f34b66780e5c7
parente10598eb204358343491c92348b9220185e3b33d (diff)
Continue with effect commands (about 50% complete).
-rw-r--r--constants/battle_constants.asm2
-rw-r--r--constants/type_constants.asm13
-rw-r--r--data/battle/accuracy_multipliers.asm17
-rw-r--r--data/moves/flail_reversal_power.asm8
-rw-r--r--data/pokemon/base_stats/abra.asm2
-rw-r--r--data/pokemon/base_stats/alakazam.asm2
-rw-r--r--data/pokemon/base_stats/celebi.asm2
-rw-r--r--data/pokemon/base_stats/drowzee.asm2
-rw-r--r--data/pokemon/base_stats/espeon.asm2
-rw-r--r--data/pokemon/base_stats/exeggcute.asm2
-rw-r--r--data/pokemon/base_stats/exeggutor.asm2
-rw-r--r--data/pokemon/base_stats/girafarig.asm2
-rw-r--r--data/pokemon/base_stats/hypno.asm2
-rw-r--r--data/pokemon/base_stats/jynx.asm2
-rw-r--r--data/pokemon/base_stats/kadabra.asm2
-rw-r--r--data/pokemon/base_stats/lugia.asm2
-rw-r--r--data/pokemon/base_stats/mew.asm2
-rw-r--r--data/pokemon/base_stats/mewtwo.asm2
-rw-r--r--data/pokemon/base_stats/mr__mime.asm2
-rw-r--r--data/pokemon/base_stats/natu.asm2
-rw-r--r--data/pokemon/base_stats/slowbro.asm2
-rw-r--r--data/pokemon/base_stats/slowking.asm2
-rw-r--r--data/pokemon/base_stats/slowpoke.asm2
-rw-r--r--data/pokemon/base_stats/smoochum.asm2
-rw-r--r--data/pokemon/base_stats/starmie.asm2
-rw-r--r--data/pokemon/base_stats/unown.asm2
-rw-r--r--data/pokemon/base_stats/wobbuffet.asm2
-rw-r--r--data/pokemon/base_stats/xatu.asm2
-rw-r--r--data/types/type_boost_items.asm19
-rw-r--r--data/types/type_matchups.asm118
-rw-r--r--engine/battle/effect_commands.asm2352
-rw-r--r--engine/battle/move_effects/beat_up.asm220
-rw-r--r--engine/battle/move_effects/conversion2.asm64
-rw-r--r--engine/battle/move_effects/counter.asm59
-rw-r--r--engine/battle/move_effects/destiny_bond.asm9
-rw-r--r--engine/battle/move_effects/encore.asm120
-rw-r--r--engine/battle/move_effects/false_swipe.asm48
-rw-r--r--engine/battle/move_effects/heal_bell.asm34
-rw-r--r--engine/battle/move_effects/lock_on.asm21
-rw-r--r--engine/battle/move_effects/pain_split.asm92
-rw-r--r--engine/battle/move_effects/sketch.asm117
-rw-r--r--engine/battle/move_effects/sleep_talk.asm143
-rw-r--r--engine/battle/move_effects/snore.asm11
-rw-r--r--engine/battle/move_effects/spite.asm86
-rwxr-xr-xengine/items/item_effects.asm8
-rw-r--r--main.asm112
-rw-r--r--wram.asm61
47 files changed, 3673 insertions, 109 deletions
diff --git a/constants/battle_constants.asm b/constants/battle_constants.asm
index 2c5e6b83..4fc3020b 100644
--- a/constants/battle_constants.asm
+++ b/constants/battle_constants.asm
@@ -66,6 +66,8 @@ NUM_BATTLE_STATS EQU NUM_STATS - 1 ; don't count HP
STAT_MIN_NORMAL EQU 5
STAT_MIN_HP EQU 10
+MAX_STAT_VALUE EQU 999
+
; shiny dvs
ATKDEFDV_SHINY EQU $EA
SPDSPCDV_SHINY EQU $AA
diff --git a/constants/type_constants.asm b/constants/type_constants.asm
index b7b350e3..3fb9649a 100644
--- a/constants/type_constants.asm
+++ b/constants/type_constants.asm
@@ -1,3 +1,9 @@
+; TypeNames indexes (see data/types/names.asm)
+; also used in:
+; - PokedexTypeSearchConversionTable (see data/types/search_types.asm)
+; - PokedexTypeSearchStrings (see data/types/search_strings.asm)
+; - TypeMatchups (see data/types/type_matchups.asm)
+; - TypeBoostItems (see data/types/type_boost_items.asm)
const_def
PHYSICAL EQU const_value
@@ -22,7 +28,7 @@ UNUSED_TYPES EQU const_value
const TYPE_16
const TYPE_17
const TYPE_18
- const CURSE_T
+ const CURSE_TYPE
UNUSED_TYPES_END EQU const_value
SPECIAL EQU const_value
@@ -30,9 +36,10 @@ SPECIAL EQU const_value
const WATER
const GRASS
const ELECTRIC
- const PSYCHIC
+ const PSYCHIC_TYPE
const ICE
const DRAGON
const DARK
-
TYPES_END EQU const_value
+
+NUM_TYPES EQU TYPES_END + UNUSED_TYPES - UNUSED_TYPES_END
diff --git a/data/battle/accuracy_multipliers.asm b/data/battle/accuracy_multipliers.asm
new file mode 100644
index 00000000..4b52a090
--- /dev/null
+++ b/data/battle/accuracy_multipliers.asm
@@ -0,0 +1,17 @@
+; Multiplier ratios for accuracy from modifier -6 to +6
+; (for other stats, see data/battle/stat_multipliers.asm).
+
+AccuracyLevelMultipliers:
+ db 33, 100 ; -6 = 33%
+ db 36, 100 ; -5 = 36%
+ db 43, 100 ; -4 = 43%
+ db 50, 100 ; -3 = 50%
+ db 60, 100 ; -2 = 60%
+ db 75, 100 ; -1 = 75%
+ db 1, 1 ; 0 = 100%
+ db 133, 100 ; +1 = 133%
+ db 166, 100 ; +2 = 166%
+ db 2, 1 ; +3 = 200%
+ db 233, 100 ; +4 = 233%
+ db 133, 50 ; +5 = 266%
+ db 3, 1 ; +6 = 300%
diff --git a/data/moves/flail_reversal_power.asm b/data/moves/flail_reversal_power.asm
new file mode 100644
index 00000000..fb915905
--- /dev/null
+++ b/data/moves/flail_reversal_power.asm
@@ -0,0 +1,8 @@
+FlailReversalPower:
+ ; hp bar pixels, power
+ db HP_BAR_LENGTH_PX / 48, 200
+ db HP_BAR_LENGTH_PX / 12, 150
+ db HP_BAR_LENGTH_PX / 5, 100
+ db HP_BAR_LENGTH_PX / 3, 80
+ db HP_BAR_LENGTH_PX * 2 / 3, 40
+ db HP_BAR_LENGTH_PX, 20
diff --git a/data/pokemon/base_stats/abra.asm b/data/pokemon/base_stats/abra.asm
index e43adeec..d5073235 100644
--- a/data/pokemon/base_stats/abra.asm
+++ b/data/pokemon/base_stats/abra.asm
@@ -3,7 +3,7 @@
db 25, 20, 15, 90, 105, 55
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 200 ; catch rate
db 73 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/alakazam.asm b/data/pokemon/base_stats/alakazam.asm
index 6524400b..673ae050 100644
--- a/data/pokemon/base_stats/alakazam.asm
+++ b/data/pokemon/base_stats/alakazam.asm
@@ -3,7 +3,7 @@
db 55, 50, 45, 120, 135, 85
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 50 ; catch rate
db 186 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/celebi.asm b/data/pokemon/base_stats/celebi.asm
index 49cb349d..cef8879f 100644
--- a/data/pokemon/base_stats/celebi.asm
+++ b/data/pokemon/base_stats/celebi.asm
@@ -3,7 +3,7 @@
db 100, 100, 100, 100, 100, 100
; hp atk def spd sat sdf
- db PSYCHIC, GRASS ; type
+ db PSYCHIC_TYPE, GRASS ; type
db 45 ; catch rate
db 64 ; base exp
db NO_ITEM, MIRACLEBERRY ; items
diff --git a/data/pokemon/base_stats/drowzee.asm b/data/pokemon/base_stats/drowzee.asm
index 614dd3d8..f6865872 100644
--- a/data/pokemon/base_stats/drowzee.asm
+++ b/data/pokemon/base_stats/drowzee.asm
@@ -3,7 +3,7 @@
db 60, 48, 45, 42, 43, 90
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 190 ; catch rate
db 102 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/espeon.asm b/data/pokemon/base_stats/espeon.asm
index 7913fc16..44126640 100644
--- a/data/pokemon/base_stats/espeon.asm
+++ b/data/pokemon/base_stats/espeon.asm
@@ -3,7 +3,7 @@
db 65, 65, 60, 110, 130, 95
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 45 ; catch rate
db 197 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/exeggcute.asm b/data/pokemon/base_stats/exeggcute.asm
index 6aad891f..8ec4ac50 100644
--- a/data/pokemon/base_stats/exeggcute.asm
+++ b/data/pokemon/base_stats/exeggcute.asm
@@ -3,7 +3,7 @@
db 60, 40, 80, 40, 60, 45
; hp atk def spd sat sdf
- db GRASS, PSYCHIC ; type
+ db GRASS, PSYCHIC_TYPE ; type
db 90 ; catch rate
db 98 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/exeggutor.asm b/data/pokemon/base_stats/exeggutor.asm
index f67ecf4a..7a217259 100644
--- a/data/pokemon/base_stats/exeggutor.asm
+++ b/data/pokemon/base_stats/exeggutor.asm
@@ -3,7 +3,7 @@
db 95, 95, 85, 55, 125, 65
; hp atk def spd sat sdf
- db GRASS, PSYCHIC ; type
+ db GRASS, PSYCHIC_TYPE ; type
db 45 ; catch rate
db 212 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/girafarig.asm b/data/pokemon/base_stats/girafarig.asm
index 93acd159..015b46ad 100644
--- a/data/pokemon/base_stats/girafarig.asm
+++ b/data/pokemon/base_stats/girafarig.asm
@@ -3,7 +3,7 @@
db 70, 80, 65, 85, 90, 65
; hp atk def spd sat sdf
- db NORMAL, PSYCHIC ; type
+ db NORMAL, PSYCHIC_TYPE ; type
db 60 ; catch rate
db 149 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/hypno.asm b/data/pokemon/base_stats/hypno.asm
index f19dd638..8490a106 100644
--- a/data/pokemon/base_stats/hypno.asm
+++ b/data/pokemon/base_stats/hypno.asm
@@ -3,7 +3,7 @@
db 85, 73, 70, 67, 73, 115
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 75 ; catch rate
db 165 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/jynx.asm b/data/pokemon/base_stats/jynx.asm
index 3e43e23b..6563aa28 100644
--- a/data/pokemon/base_stats/jynx.asm
+++ b/data/pokemon/base_stats/jynx.asm
@@ -3,7 +3,7 @@
db 65, 50, 35, 95, 115, 95
; hp atk def spd sat sdf
- db ICE, PSYCHIC ; type
+ db ICE, PSYCHIC_TYPE ; type
db 45 ; catch rate
db 137 ; base exp
db ICE_BERRY, ICE_BERRY ; items
diff --git a/data/pokemon/base_stats/kadabra.asm b/data/pokemon/base_stats/kadabra.asm
index da2f3bf4..48a34dde 100644
--- a/data/pokemon/base_stats/kadabra.asm
+++ b/data/pokemon/base_stats/kadabra.asm
@@ -3,7 +3,7 @@
db 40, 35, 30, 105, 120, 70
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 100 ; catch rate
db 145 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/lugia.asm b/data/pokemon/base_stats/lugia.asm
index 9fa2a759..f29ccc33 100644
--- a/data/pokemon/base_stats/lugia.asm
+++ b/data/pokemon/base_stats/lugia.asm
@@ -3,7 +3,7 @@
db 106, 90, 130, 110, 90, 154
; hp atk def spd sat sdf
- db PSYCHIC, FLYING ; type
+ db PSYCHIC_TYPE, FLYING ; type
db 3 ; catch rate
db 220 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/mew.asm b/data/pokemon/base_stats/mew.asm
index c910fa66..6236dc88 100644
--- a/data/pokemon/base_stats/mew.asm
+++ b/data/pokemon/base_stats/mew.asm
@@ -3,7 +3,7 @@
db 100, 100, 100, 100, 100, 100
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 45 ; catch rate
db 64 ; base exp
db NO_ITEM, MIRACLEBERRY ; items
diff --git a/data/pokemon/base_stats/mewtwo.asm b/data/pokemon/base_stats/mewtwo.asm
index 39f1fdbf..66a7bd72 100644
--- a/data/pokemon/base_stats/mewtwo.asm
+++ b/data/pokemon/base_stats/mewtwo.asm
@@ -3,7 +3,7 @@
db 106, 110, 90, 130, 154, 90
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 3 ; catch rate
db 220 ; base exp
db NO_ITEM, BERSERK_GENE ; items
diff --git a/data/pokemon/base_stats/mr__mime.asm b/data/pokemon/base_stats/mr__mime.asm
index 5d7d2bad..f690cec6 100644
--- a/data/pokemon/base_stats/mr__mime.asm
+++ b/data/pokemon/base_stats/mr__mime.asm
@@ -3,7 +3,7 @@
db 40, 45, 65, 90, 100, 120
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 45 ; catch rate
db 136 ; base exp
db NO_ITEM, MYSTERYBERRY ; items
diff --git a/data/pokemon/base_stats/natu.asm b/data/pokemon/base_stats/natu.asm
index 4eaa2677..e4906ab9 100644
--- a/data/pokemon/base_stats/natu.asm
+++ b/data/pokemon/base_stats/natu.asm
@@ -3,7 +3,7 @@
db 40, 50, 45, 70, 70, 45
; hp atk def spd sat sdf
- db PSYCHIC, FLYING ; type
+ db PSYCHIC_TYPE, FLYING ; type
db 190 ; catch rate
db 73 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/slowbro.asm b/data/pokemon/base_stats/slowbro.asm
index 2e256b36..ffe95d6c 100644
--- a/data/pokemon/base_stats/slowbro.asm
+++ b/data/pokemon/base_stats/slowbro.asm
@@ -3,7 +3,7 @@
db 95, 75, 110, 30, 100, 80
; hp atk def spd sat sdf
- db WATER, PSYCHIC ; type
+ db WATER, PSYCHIC_TYPE ; type
db 75 ; catch rate
db 164 ; base exp
db NO_ITEM, KINGS_ROCK ; items
diff --git a/data/pokemon/base_stats/slowking.asm b/data/pokemon/base_stats/slowking.asm
index 0c870f4a..d7e9b4af 100644
--- a/data/pokemon/base_stats/slowking.asm
+++ b/data/pokemon/base_stats/slowking.asm
@@ -3,7 +3,7 @@
db 95, 75, 80, 30, 100, 110
; hp atk def spd sat sdf
- db WATER, PSYCHIC ; type
+ db WATER, PSYCHIC_TYPE ; type
db 70 ; catch rate
db 164 ; base exp
db NO_ITEM, KINGS_ROCK ; items
diff --git a/data/pokemon/base_stats/slowpoke.asm b/data/pokemon/base_stats/slowpoke.asm
index e8c718b8..cc06c5b0 100644
--- a/data/pokemon/base_stats/slowpoke.asm
+++ b/data/pokemon/base_stats/slowpoke.asm
@@ -3,7 +3,7 @@
db 90, 65, 65, 15, 40, 40
; hp atk def spd sat sdf
- db WATER, PSYCHIC ; type
+ db WATER, PSYCHIC_TYPE ; type
db 190 ; catch rate
db 99 ; base exp
db NO_ITEM, KINGS_ROCK ; items
diff --git a/data/pokemon/base_stats/smoochum.asm b/data/pokemon/base_stats/smoochum.asm
index d8670632..548ad5f5 100644
--- a/data/pokemon/base_stats/smoochum.asm
+++ b/data/pokemon/base_stats/smoochum.asm
@@ -3,7 +3,7 @@
db 45, 30, 15, 65, 85, 65
; hp atk def spd sat sdf
- db ICE, PSYCHIC ; type
+ db ICE, PSYCHIC_TYPE ; type
db 45 ; catch rate
db 87 ; base exp
db ICE_BERRY, ICE_BERRY ; items
diff --git a/data/pokemon/base_stats/starmie.asm b/data/pokemon/base_stats/starmie.asm
index 262cd612..337afa76 100644
--- a/data/pokemon/base_stats/starmie.asm
+++ b/data/pokemon/base_stats/starmie.asm
@@ -3,7 +3,7 @@
db 60, 75, 85, 115, 100, 85
; hp atk def spd sat sdf
- db WATER, PSYCHIC ; type
+ db WATER, PSYCHIC_TYPE ; type
db 60 ; catch rate
db 207 ; base exp
db STARDUST, STAR_PIECE ; items
diff --git a/data/pokemon/base_stats/unown.asm b/data/pokemon/base_stats/unown.asm
index bf3d0f1f..b8db2883 100644
--- a/data/pokemon/base_stats/unown.asm
+++ b/data/pokemon/base_stats/unown.asm
@@ -3,7 +3,7 @@
db 48, 72, 48, 48, 72, 48
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 225 ; catch rate
db 61 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/wobbuffet.asm b/data/pokemon/base_stats/wobbuffet.asm
index e04d443a..855a7d99 100644
--- a/data/pokemon/base_stats/wobbuffet.asm
+++ b/data/pokemon/base_stats/wobbuffet.asm
@@ -3,7 +3,7 @@
db 190, 33, 58, 33, 33, 58
; hp atk def spd sat sdf
- db PSYCHIC, PSYCHIC ; type
+ db PSYCHIC_TYPE, PSYCHIC_TYPE ; type
db 45 ; catch rate
db 177 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/pokemon/base_stats/xatu.asm b/data/pokemon/base_stats/xatu.asm
index d0fe363f..f1fc7a55 100644
--- a/data/pokemon/base_stats/xatu.asm
+++ b/data/pokemon/base_stats/xatu.asm
@@ -3,7 +3,7 @@
db 65, 75, 70, 95, 95, 70
; hp atk def spd sat sdf
- db PSYCHIC, FLYING ; type
+ db PSYCHIC_TYPE, FLYING ; type
db 75 ; catch rate
db 171 ; base exp
db NO_ITEM, NO_ITEM ; items
diff --git a/data/types/type_boost_items.asm b/data/types/type_boost_items.asm
new file mode 100644
index 00000000..85a58db1
--- /dev/null
+++ b/data/types/type_boost_items.asm
@@ -0,0 +1,19 @@
+TypeBoostItems:
+ db HELD_NORMAL_BOOST, NORMAL ; PINK_BOW/POLKADOT_BOW
+ db HELD_FIGHTING_BOOST, FIGHTING ; BLACKBELT_I
+ db HELD_FLYING_BOOST, FLYING ; SHARP_BEAK
+ db HELD_POISON_BOOST, POISON ; POISON BARB
+ db HELD_GROUND_BOOST, GROUND ; SOFT_SAND
+ db HELD_ROCK_BOOST, ROCK ; HARD_STONE
+ db HELD_BUG_BOOST, BUG ; SILVERPOWDER
+ db HELD_GHOST_BOOST, GHOST ; SPELL_TAG
+ db HELD_FIRE_BOOST, FIRE ; CHARCOAL
+ db HELD_WATER_BOOST, WATER ; MYSTIC WATER
+ db HELD_GRASS_BOOST, GRASS ; MIRACLE_SEED
+ db HELD_ELECTRIC_BOOST, ELECTRIC ; MAGNET
+ db HELD_PSYCHIC_BOOST, PSYCHIC_TYPE ; TWISTEDSPOON
+ db HELD_ICE_BOOST, ICE ; NEVERMELTICE
+ db HELD_DRAGON_BOOST, DRAGON ; DRAGON_SCALE
+ db HELD_DARK_BOOST, DARK ; BLACKGLASSES
+ db HELD_STEEL_BOOST, STEEL ; METAL_COAT
+ db -1
diff --git a/data/types/type_matchups.asm b/data/types/type_matchups.asm
new file mode 100644
index 00000000..81906b0f
--- /dev/null
+++ b/data/types/type_matchups.asm
@@ -0,0 +1,118 @@
+TypeMatchups:
+ ; attacker, defender, *=
+ db NORMAL, ROCK, NOT_VERY_EFFECTIVE
+ db NORMAL, STEEL, NOT_VERY_EFFECTIVE
+ db FIRE, FIRE, NOT_VERY_EFFECTIVE
+ db FIRE, WATER, NOT_VERY_EFFECTIVE
+ db FIRE, GRASS, SUPER_EFFECTIVE
+ db FIRE, ICE, SUPER_EFFECTIVE
+ db FIRE, BUG, SUPER_EFFECTIVE
+ db FIRE, ROCK, NOT_VERY_EFFECTIVE
+ db FIRE, DRAGON, NOT_VERY_EFFECTIVE
+ db FIRE, STEEL, SUPER_EFFECTIVE
+ db WATER, FIRE, SUPER_EFFECTIVE
+ db WATER, WATER, NOT_VERY_EFFECTIVE
+ db WATER, GRASS, NOT_VERY_EFFECTIVE
+ db WATER, GROUND, SUPER_EFFECTIVE
+ db WATER, ROCK, SUPER_EFFECTIVE
+ db WATER, DRAGON, NOT_VERY_EFFECTIVE
+ db ELECTRIC, WATER, SUPER_EFFECTIVE
+ db ELECTRIC, ELECTRIC, NOT_VERY_EFFECTIVE
+ db ELECTRIC, GRASS, NOT_VERY_EFFECTIVE
+ db ELECTRIC, GROUND, NO_EFFECT
+ db ELECTRIC, FLYING, SUPER_EFFECTIVE
+ db ELECTRIC, DRAGON, NOT_VERY_EFFECTIVE
+ db GRASS, FIRE, NOT_VERY_EFFECTIVE
+ db GRASS, WATER, SUPER_EFFECTIVE
+ db GRASS, GRASS, NOT_VERY_EFFECTIVE
+ db GRASS, POISON, NOT_VERY_EFFECTIVE
+ db GRASS, GROUND, SUPER_EFFECTIVE
+ db GRASS, FLYING, NOT_VERY_EFFECTIVE
+ db GRASS, BUG, NOT_VERY_EFFECTIVE
+ db GRASS, ROCK, SUPER_EFFECTIVE
+ db GRASS, DRAGON, NOT_VERY_EFFECTIVE
+ db GRASS, STEEL, NOT_VERY_EFFECTIVE
+ db ICE, WATER, NOT_VERY_EFFECTIVE
+ db ICE, GRASS, SUPER_EFFECTIVE
+ db ICE, ICE, NOT_VERY_EFFECTIVE
+ db ICE, GROUND, SUPER_EFFECTIVE
+ db ICE, FLYING, SUPER_EFFECTIVE
+ db ICE, DRAGON, SUPER_EFFECTIVE
+ db ICE, STEEL, NOT_VERY_EFFECTIVE
+ db ICE, FIRE, NOT_VERY_EFFECTIVE
+ db FIGHTING, NORMAL, SUPER_EFFECTIVE
+ db FIGHTING, ICE, SUPER_EFFECTIVE
+ db FIGHTING, POISON, NOT_VERY_EFFECTIVE
+ db FIGHTING, FLYING, NOT_VERY_EFFECTIVE
+ db FIGHTING, PSYCHIC_TYPE, NOT_VERY_EFFECTIVE
+ db FIGHTING, BUG, NOT_VERY_EFFECTIVE
+ db FIGHTING, ROCK, SUPER_EFFECTIVE
+ db FIGHTING, DARK, SUPER_EFFECTIVE
+ db FIGHTING, STEEL, SUPER_EFFECTIVE
+ db POISON, GRASS, SUPER_EFFECTIVE
+ db POISON, POISON, NOT_VERY_EFFECTIVE
+ db POISON, GROUND, NOT_VERY_EFFECTIVE
+ db POISON, ROCK, NOT_VERY_EFFECTIVE
+ db POISON, GHOST, NOT_VERY_EFFECTIVE
+ db POISON, STEEL, NO_EFFECT
+ db GROUND, FIRE, SUPER_EFFECTIVE
+ db GROUND, ELECTRIC, SUPER_EFFECTIVE
+ db GROUND, GRASS, NOT_VERY_EFFECTIVE
+ db GROUND, POISON, SUPER_EFFECTIVE
+ db GROUND, FLYING, NO_EFFECT
+ db GROUND, BUG, NOT_VERY_EFFECTIVE
+ db GROUND, ROCK, SUPER_EFFECTIVE
+ db GROUND, STEEL, SUPER_EFFECTIVE
+ db FLYING, ELECTRIC, NOT_VERY_EFFECTIVE
+ db FLYING, GRASS, SUPER_EFFECTIVE
+ db FLYING, FIGHTING, SUPER_EFFECTIVE
+ db FLYING, BUG, SUPER_EFFECTIVE
+ db FLYING, ROCK, NOT_VERY_EFFECTIVE
+ db FLYING, STEEL, NOT_VERY_EFFECTIVE
+ db PSYCHIC_TYPE, FIGHTING, SUPER_EFFECTIVE
+ db PSYCHIC_TYPE, POISON, SUPER_EFFECTIVE
+ db PSYCHIC_TYPE, PSYCHIC_TYPE, NOT_VERY_EFFECTIVE
+ db PSYCHIC_TYPE, DARK, NO_EFFECT
+ db PSYCHIC_TYPE, STEEL, NOT_VERY_EFFECTIVE
+ db BUG, FIRE, NOT_VERY_EFFECTIVE
+ db BUG, GRASS, SUPER_EFFECTIVE
+ db BUG, FIGHTING, NOT_VERY_EFFECTIVE
+ db BUG, POISON, NOT_VERY_EFFECTIVE
+ db BUG, FLYING, NOT_VERY_EFFECTIVE
+ db BUG, PSYCHIC_TYPE, SUPER_EFFECTIVE
+ db BUG, GHOST, NOT_VERY_EFFECTIVE
+ db BUG, DARK, SUPER_EFFECTIVE
+ db BUG, STEEL, NOT_VERY_EFFECTIVE
+ db ROCK, FIRE, SUPER_EFFECTIVE
+ db ROCK, ICE, SUPER_EFFECTIVE
+ db ROCK, FIGHTING, NOT_VERY_EFFECTIVE
+ db ROCK, GROUND, NOT_VERY_EFFECTIVE
+ db ROCK, FLYING, SUPER_EFFECTIVE
+ db ROCK, BUG, SUPER_EFFECTIVE
+ db ROCK, STEEL, NOT_VERY_EFFECTIVE
+ db GHOST, NORMAL, NO_EFFECT
+ db GHOST, PSYCHIC_TYPE, SUPER_EFFECTIVE
+ db GHOST, DARK, NOT_VERY_EFFECTIVE
+ db GHOST, STEEL, NOT_VERY_EFFECTIVE
+ db GHOST, GHOST, SUPER_EFFECTIVE
+ db DRAGON, DRAGON, SUPER_EFFECTIVE
+ db DRAGON, STEEL, NOT_VERY_EFFECTIVE
+ db DARK, FIGHTING, NOT_VERY_EFFECTIVE
+ db DARK, PSYCHIC_TYPE, SUPER_EFFECTIVE
+ db DARK, GHOST, SUPER_EFFECTIVE
+ db DARK, DARK, NOT_VERY_EFFECTIVE
+ db DARK, STEEL, NOT_VERY_EFFECTIVE
+ db STEEL, FIRE, NOT_VERY_EFFECTIVE
+ db STEEL, WATER, NOT_VERY_EFFECTIVE
+ db STEEL, ELECTRIC, NOT_VERY_EFFECTIVE
+ db STEEL, ICE, SUPER_EFFECTIVE
+ db STEEL, ROCK, SUPER_EFFECTIVE
+ db STEEL, STEEL, NOT_VERY_EFFECTIVE
+
+ db -2 ; end (with Foresight)
+
+; Foresight removes Ghost's immunities.
+ db NORMAL, GHOST, NO_EFFECT
+ db FIGHTING, GHOST, NO_EFFECT
+
+ db -1 ; end
diff --git a/engine/battle/effect_commands.asm b/engine/battle/effect_commands.asm
index 023730ac..7734c66f 100644
--- a/engine/battle/effect_commands.asm
+++ b/engine/battle/effect_commands.asm
@@ -1219,3 +1219,2355 @@ INCLUDE "data/moves/critical_hit_moves.asm"
INCLUDE "data/battle/critical_hit_chances.asm"
INCLUDE "engine/battle/move_effects/triple_kick.asm"
+
+BattleCommand_Stab:
+; STAB = Same Type Attack Bonus
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp STRUGGLE
+ ret z
+
+ ld hl, wBattleMonType1
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wEnemyMonType1
+ ld a, [hli]
+ ld d, a
+ ld e, [hl]
+
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .go ; Who Attacks and who Defends
+
+ ld hl, wEnemyMonType1
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wBattleMonType1
+ ld a, [hli]
+ ld d, a
+ ld e, [hl]
+
+.go
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVarAddr
+ ld [wCurType], a
+
+ push hl
+ push de
+ push bc
+ farcall DoWeatherModifiers
+ pop bc
+ pop de
+ pop hl
+
+ push de
+ push bc
+ farcall DoBadgeTypeBoosts
+ pop bc
+ pop de
+
+ ld a, [wCurType]
+ cp b
+ jr z, .stab
+ cp c
+ jr z, .stab
+
+ jr .SkipStab
+
+.stab
+ ld hl, wCurDamage + 1
+ ld a, [hld]
+ ld h, [hl]
+ ld l, a
+
+ ld b, h
+ ld c, l
+ srl b
+ rr c
+ add hl, bc
+
+ ld a, h
+ ld [wCurDamage], a
+ ld a, l
+ ld [wCurDamage + 1], a
+
+ ld hl, wTypeModifier
+ set 7, [hl]
+
+.SkipStab:
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVar
+ ld b, a
+ ld hl, TypeMatchups
+
+.TypesLoop:
+ ld a, [hli]
+
+ cp -1
+ jr z, .end
+
+ ; foresight
+ cp -2
+ jr nz, .SkipForesightCheck
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_IDENTIFIED, a
+ jr nz, .end
+
+ jr .TypesLoop
+
+.SkipForesightCheck:
+ cp b
+ jr nz, .SkipType
+ ld a, [hl]
+ cp d
+ jr z, .GotMatchup
+ cp e
+ jr z, .GotMatchup
+ jr .SkipType
+
+.GotMatchup:
+ push hl
+ push bc
+ inc hl
+ ld a, [wTypeModifier]
+ and %10000000
+ ld b, a
+; If the target is immune to the move, treat it as a miss and calculate the damage as 0
+ ld a, [hl]
+ and a
+ jr nz, .NotImmune
+ inc a
+ ld [wAttackMissed], a
+ xor a
+.NotImmune:
+ ldh [hMultiplier], a
+ add b
+ ld [wTypeModifier], a
+
+ xor a
+ ldh [hMultiplicand + 0], a
+
+ ld hl, wCurDamage
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hld]
+ ldh [hMultiplicand + 2], a
+
+ call Multiply
+
+ ldh a, [hProduct + 1]
+ ld b, a
+ ldh a, [hProduct + 2]
+ or b
+ ld b, a
+ ldh a, [hProduct + 3]
+ or b
+ jr z, .ok ; This is a very convoluted way to get back that we've essentially dealt no damage.
+
+; Take the product and divide it by 10.
+ ld a, 10
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+ ldh a, [hQuotient + 2]
+ ld b, a
+ ldh a, [hQuotient + 3]
+ or b
+ jr nz, .ok
+
+ ld a, 1
+ ldh [hMultiplicand + 2], a
+
+.ok
+ ldh a, [hMultiplicand + 1]
+ ld [hli], a
+ ldh a, [hMultiplicand + 2]
+ ld [hl], a
+ pop bc
+ pop hl
+
+.SkipType:
+ inc hl
+ inc hl
+ jr .TypesLoop
+
+.end
+ call BattleCheckTypeMatchup
+ ld a, [wTypeMatchup]
+ ld b, a
+ ld a, [wTypeModifier]
+ and %10000000
+ or b
+ ld [wTypeModifier], a
+ ret
+
+BattleCheckTypeMatchup:
+ ld hl, wEnemyMonType1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, CheckTypeMatchup
+ ld hl, wBattleMonType1
+CheckTypeMatchup:
+; There is an incorrect assumption about this function made in the AI related code: when
+; the AI calls CheckTypeMatchup (not BattleCheckTypeMatchup), it assumes that placing the
+; offensive type in a will make this function do the right thing. Since a is overwritten,
+; this assumption is incorrect. A simple fix would be to load the move type for the
+; current move into a in BattleCheckTypeMatchup, before falling through, which is
+; consistent with how the rest of the code assumes this code works like.
+ push hl
+ push de
+ push bc
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVar
+ ld d, a
+ ld b, [hl]
+ inc hl
+ ld c, [hl]
+ ld a, 10 ; 1.0
+ ld [wTypeMatchup], a
+ ld hl, TypeMatchups
+.TypesLoop:
+ ld a, [hli]
+ cp -1
+ jr z, .End
+ cp -2
+ jr nz, .Next
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_IDENTIFIED, a
+ jr nz, .End
+ jr .TypesLoop
+
+.Next:
+ cp d
+ jr nz, .Nope
+ ld a, [hli]
+ cp b
+ jr z, .Yup
+ cp c
+ jr z, .Yup
+ jr .Nope2
+
+.Nope:
+ inc hl
+.Nope2:
+ inc hl
+ jr .TypesLoop
+
+.Yup:
+ xor a
+ ldh [hDividend + 0], a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, [hli]
+ ldh [hMultiplicand + 2], a
+ ld a, [wTypeMatchup]
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, 10
+ ldh [hDivisor], a
+ push bc
+ ld b, 4
+ call Divide
+ pop bc
+ ldh a, [hQuotient + 3]
+ ld [wTypeMatchup], a
+ jr .TypesLoop
+
+.End:
+ pop bc
+ pop de
+ pop hl
+ ret
+
+BattleCommand_ResetTypeMatchup:
+; Reset the type matchup multiplier to 1.0, if the type matchup is not 0.
+; If there is immunity in play, the move automatically misses.
+ call BattleCheckTypeMatchup
+ ld a, [wTypeMatchup]
+ and a
+ ld a, 10 ; 1.0
+ jr nz, .reset
+ call ResetDamage
+ xor a
+ ld [wTypeModifier], a
+ inc a
+ ld [wAttackMissed], a
+ ret
+
+.reset
+ ld [wTypeMatchup], a
+ ret
+
+INCLUDE "engine/battle/ai/switch.asm"
+
+INCLUDE "data/types/type_matchups.asm"
+
+BattleCommand_DamageVariation:
+; damagevariation
+
+; Modify the damage spread between 85% and 100%.
+
+; Because of the method of division the probability distribution
+; is not consistent. This makes the highest damage multipliers
+; rarer than normal.
+
+; No point in reducing 1 or 0 damage.
+ ld hl, wCurDamage
+ ld a, [hli]
+ and a
+ jr nz, .go
+ ld a, [hl]
+ cp 2
+ ret c
+
+.go
+; Start with the maximum damage.
+ xor a
+ ldh [hMultiplicand + 0], a
+ dec hl
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hl]
+ ldh [hMultiplicand + 2], a
+
+; Multiply by 85-100%...
+.loop
+ call BattleRandom
+ rrca
+ cp 85 percent + 1
+ jr c, .loop
+
+ ldh [hMultiplier], a
+ call Multiply
+
+; ...divide by 100%...
+ ld a, $ff ; 100%
+ ldh [hDivisor], a
+ ld b, $4
+ call Divide
+
+; ...to get .85-1.00x damage.
+ ldh a, [hQuotient + 2]
+ ld hl, wCurDamage
+ ld [hli], a
+ ldh a, [hQuotient + 3]
+ ld [hl], a
+ ret
+
+BattleCommand_CheckHit:
+; checkhit
+
+ call .DreamEater
+ jp z, .Miss
+
+ call .Protect
+ jp nz, .Miss
+
+ call .DrainSub
+ jp z, .Miss
+
+ call .LockOn
+ ret nz
+
+ call .FlyDigMoves
+ jp nz, .Miss
+
+ call .ThunderRain
+ ret z
+
+ call .XAccuracy
+ ret nz
+
+ ; Perfect-accuracy moves
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_ALWAYS_HIT
+ ret z
+
+ call .StatModifiers
+
+ ld a, [wPlayerMoveStruct + MOVE_ACC]
+ ld b, a
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .BrightPowder
+ ld a, [wEnemyMoveStruct + MOVE_ACC]
+ ld b, a
+
+.BrightPowder:
+ push bc
+ call GetOpponentItem
+ ld a, b
+ cp HELD_BRIGHTPOWDER
+ ld a, c ; % miss
+ pop bc
+ jr nz, .skip_brightpowder
+
+ ld c, a
+ ld a, b
+ sub c
+ ld b, a
+ jr nc, .skip_brightpowder
+ ld b, 0
+
+.skip_brightpowder
+ ld a, b
+ cp -1
+ jr z, .Hit
+
+ call BattleRandom
+ cp b
+ jr nc, .Miss
+
+.Hit:
+ ret
+
+.Miss:
+; Keep the damage value intact if we're using (Hi) Jump Kick.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_JUMP_KICK
+ jr z, .Missed
+ call ResetDamage
+
+.Missed:
+ ld a, 1
+ ld [wAttackMissed], a
+ ret
+
+.DreamEater:
+; Return z if we're trying to eat the dream of
+; a monster that isn't sleeping.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_DREAM_EATER
+ ret nz
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVar
+ and SLP
+ ret
+
+.Protect:
+; Return nz if the opponent is protected.
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_PROTECT, a
+ ret z
+
+ ld c, 40
+ call DelayFrames
+
+; 'protecting itself!'
+ ld hl, ProtectingItselfText
+ call StdBattleTextbox
+
+ ld c, 40
+ call DelayFrames
+
+ ld a, 1
+ and a
+ ret
+
+.LockOn:
+; Return nz if we are locked-on and aren't trying to use Earthquake,
+; Fissure or Magnitude on a monster that is flying.
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_LOCK_ON, [hl]
+ res SUBSTATUS_LOCK_ON, [hl]
+ ret z
+
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ bit SUBSTATUS_FLYING, a
+ jr z, .LockedOn
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+
+ cp EARTHQUAKE
+ ret z
+ cp FISSURE
+ ret z
+ cp MAGNITUDE
+ ret z
+
+.LockedOn:
+ ld a, 1
+ and a
+ ret
+
+.DrainSub:
+; Return z if using an HP drain move on a substitute.
+ call CheckSubstituteOpp
+ jr z, .not_draining_sub
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+
+ cp EFFECT_LEECH_HIT
+ ret z
+ cp EFFECT_DREAM_EATER
+ ret z
+
+.not_draining_sub
+ ld a, 1
+ and a
+ ret
+
+.FlyDigMoves:
+; Check for moves that can hit underground/flying opponents.
+; Return z if the current move can hit the opponent.
+
+ ld a, BATTLE_VARS_SUBSTATUS3_OPP
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret z
+
+ bit SUBSTATUS_FLYING, a
+ jr z, .DigMoves
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+
+ cp GUST
+ ret z
+ cp WHIRLWIND
+ ret z
+ cp THUNDER
+ ret z
+ cp TWISTER
+ ret
+
+.DigMoves:
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+
+ cp EARTHQUAKE
+ ret z
+ cp FISSURE
+ ret z
+ cp MAGNITUDE
+ ret
+
+.ThunderRain:
+; Return z if the current move always hits in rain, and it is raining.
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_THUNDER
+ ret nz
+
+ ld a, [wBattleWeather]
+ cp WEATHER_RAIN
+ ret
+
+.XAccuracy:
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_X_ACCURACY, a
+ ret
+
+.StatModifiers:
+ ldh a, [hBattleTurn]
+ and a
+
+ ; load the user's accuracy into b and the opponent's evasion into c.
+ ld hl, wPlayerMoveStruct + MOVE_ACC
+ ld a, [wPlayerAccLevel]
+ ld b, a
+ ld a, [wEnemyEvaLevel]
+ ld c, a
+
+ jr z, .got_acc_eva
+
+ ld hl, wEnemyMoveStruct + MOVE_ACC
+ ld a, [wEnemyAccLevel]
+ ld b, a
+ ld a, [wPlayerEvaLevel]
+ ld c, a
+
+.got_acc_eva
+ cp b
+ jr c, .skip_foresight_check
+
+ ; if the target's evasion is greater than the user's accuracy,
+ ; check the target's foresight status
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_IDENTIFIED, a
+ ret nz
+
+.skip_foresight_check
+ ; subtract evasion from 14
+ ld a, MAX_STAT_LEVEL + 1
+ sub c
+ ld c, a
+ ; store the base move accuracy for math ops
+ xor a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, [hl]
+ ldh [hMultiplicand + 2], a
+ push hl
+ ld d, 2 ; do this twice, once for the user's accuracy and once for the target's evasion
+
+.accuracy_loop
+ ; look up the multiplier from the table
+ push bc
+ ld hl, AccuracyLevelMultipliers
+ dec b
+ sla b
+ ld c, b
+ ld b, 0
+ add hl, bc
+ pop bc
+ ; multiply by the first byte in that row...
+ ld a, [hli]
+ ldh [hMultiplier], a
+ call Multiply
+ ; ... and divide by the second byte
+ ld a, [hl]
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+ ; minimum accuracy is $0001
+ ldh a, [hQuotient + 3]
+ ld b, a
+ ldh a, [hQuotient + 2]
+ or b
+ jr nz, .min_accuracy
+ ldh [hQuotient + 2], a
+ ld a, 1
+ ldh [hQuotient + 3], a
+
+.min_accuracy
+ ; do the same thing to the target's evasion
+ ld b, c
+ dec d
+ jr nz, .accuracy_loop
+
+ ; if the result is more than 2 bytes, max out at 100%
+ ldh a, [hQuotient + 2]
+ and a
+ ldh a, [hQuotient + 3]
+ jr z, .finish_accuracy
+ ld a, $ff
+
+.finish_accuracy
+ pop hl
+ ld [hl], a
+ ret
+
+INCLUDE "data/battle/accuracy_multipliers.asm"
+
+BattleCommand_EffectChance:
+; effectchance
+
+ xor a
+ ld [wEffectFailed], a
+ call CheckSubstituteOpp
+ jr nz, .failed
+
+ push hl
+ ld hl, wPlayerMoveStruct + MOVE_CHANCE
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_move_chance
+ ld hl, wEnemyMoveStruct + MOVE_CHANCE
+.got_move_chance
+
+ ; BUG: 1/256 chance to fail even for a 100% effect chance,
+ ; since carry is not set if BattleRandom == [hl] == 255
+ call BattleRandom
+ cp [hl]
+ pop hl
+ ret c
+
+.failed
+ ld a, 1
+ ld [wEffectFailed], a
+ and a
+ ret
+
+BattleCommand_LowerSub:
+; lowersub
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret z
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ bit SUBSTATUS_CHARGED, a
+ jr nz, .already_charged
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_RAZOR_WIND
+ jr z, .charge_turn
+ cp EFFECT_SKY_ATTACK
+ jr z, .charge_turn
+ cp EFFECT_SKULL_BASH
+ jr z, .charge_turn
+ cp EFFECT_SOLARBEAM
+ jr z, .charge_turn
+ cp EFFECT_FLY
+ jr z, .charge_turn
+
+.already_charged
+ call .Rampage
+ jr z, .charge_turn
+
+ call CheckUserIsCharging
+ ret nz
+
+.charge_turn
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ jr c, .mimic_anims
+
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ inc a
+ ld [wKickCounter], a
+ ld a, SUBSTITUTE
+ jp LoadAnim
+
+.mimic_anims
+ call BattleCommand_LowerSubNoAnim
+ jp BattleCommand_MoveDelay
+
+.Rampage:
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_ROLLOUT
+ jr z, .rollout_rampage
+ cp EFFECT_RAMPAGE
+ jr z, .rollout_rampage
+
+ ld a, 1
+ and a
+ ret
+
+.rollout_rampage
+ ld a, [wSomeoneIsRampaging]
+ and a
+ ld a, 0
+ ld [wSomeoneIsRampaging], a
+ ret
+
+BattleCommand_MoveAnim:
+; moveanim
+ call BattleCommand_LowerSub
+ call BattleCommand_MoveAnimNoSub
+ jp BattleCommand_RaiseSub
+
+BattleCommand_MoveAnimNoSub:
+ ld a, [wAttackMissed]
+ and a
+ jp nz, BattleCommand_MoveDelay
+
+ ldh a, [hBattleTurn]
+ and a
+ ld de, wPlayerRolloutCount
+ ld a, BATTLEANIM_ENEMY_DAMAGE
+ jr z, .got_rollout_count
+ ld de, wEnemyRolloutCount
+ ld a, BATTLEANIM_PLAYER_DAMAGE
+
+.got_rollout_count
+ ld [wNumHits], a
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_MULTI_HIT
+ jr z, .alternate_anim
+ cp EFFECT_CONVERSION
+ jr z, .alternate_anim
+ cp EFFECT_DOUBLE_HIT
+ jr z, .alternate_anim
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .alternate_anim
+ cp EFFECT_TRIPLE_KICK
+ jr z, .triplekick
+ xor a
+ ld [wKickCounter], a
+
+.triplekick
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld e, a
+ ld d, 0
+ call PlayFXAnimID
+
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp FLY
+ jr z, .clear_sprite
+ cp DIG
+ ret nz
+.clear_sprite
+ jp AppearUserLowerSub
+
+.alternate_anim
+ ld a, [wKickCounter]
+ and 1
+ xor 1
+ ld [wKickCounter], a
+ ld a, [de]
+ cp 1
+ push af
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld e, a
+ ld d, 0
+ pop af
+ jp z, PlayFXAnimID
+ xor a
+ ld [wNumHits], a
+ jp PlayFXAnimID
+
+BattleCommand_StatUpAnim:
+ ld a, [wAttackMissed]
+ and a
+ jp nz, BattleCommand_MoveDelay
+
+ xor a
+ jr BattleCommand_StatUpDownAnim
+
+BattleCommand_StatDownAnim:
+ ld a, [wAttackMissed]
+ and a
+ jp nz, BattleCommand_MoveDelay
+
+ ldh a, [hBattleTurn]
+ and a
+ ld a, BATTLEANIM_ENEMY_STAT_DOWN
+ jr z, BattleCommand_StatUpDownAnim
+ ld a, BATTLEANIM_WOBBLE
+
+ ; fallthrough
+
+BattleCommand_StatUpDownAnim:
+ ld [wNumHits], a
+ xor a
+ ld [wKickCounter], a
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ ld e, a
+ ld d, 0
+ jp PlayFXAnimID
+
+BattleCommand_SwitchTurn:
+; switchturn
+
+ ldh a, [hBattleTurn]
+ xor 1
+ ldh [hBattleTurn], a
+ ret
+
+BattleCommand_RaiseSub:
+; raisesub
+
+ ld a, BATTLE_VARS_SUBSTATUS4
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret z
+
+ ; check battle scene
+ ld a, [wOptions]
+ add a
+ jp c, BattleCommand_RaiseSubNoAnim
+
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ ld a, $2
+ ld [wKickCounter], a
+ ld a, SUBSTITUTE
+ jp LoadAnim
+
+BattleCommand_FailureText:
+; failuretext
+; If the move missed or failed, load the appropriate
+; text, and end the effects of multi-turn or multi-
+; hit moves.
+ ld a, [wAttackMissed]
+ and a
+ ret z
+
+ call GetFailureResultText
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVarAddr
+
+ cp FLY
+ jr z, .fly_dig
+ cp DIG
+ jr z, .fly_dig
+
+; Move effect:
+ inc hl
+ ld a, [hl]
+
+ cp EFFECT_MULTI_HIT
+ jr z, .multihit
+ cp EFFECT_DOUBLE_HIT
+ jr z, .multihit
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .multihit
+ jp EndMoveEffect
+
+.multihit
+ call BattleCommand_RaiseSub
+ jp EndMoveEffect
+
+.fly_dig
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ res SUBSTATUS_UNDERGROUND, [hl]
+ res SUBSTATUS_FLYING, [hl]
+ call AppearUserRaiseSub
+ jp EndMoveEffect
+
+BattleCommand_ApplyDamage:
+; applydamage
+
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_ENDURE, a
+ jr z, .focus_band
+
+ call BattleCommand_FalseSwipe
+ ld b, 0
+ jr nc, .damage
+ ld b, 1
+ jr .damage
+
+.focus_band
+ call GetOpponentItem
+ ld a, b
+ cp HELD_FOCUS_BAND
+ ld b, 0
+ jr nz, .damage
+
+ call BattleRandom
+ cp c
+ jr nc, .damage
+ call BattleCommand_FalseSwipe
+ ld b, 0
+ jr nc, .damage
+ ld b, 2
+
+.damage
+ push bc
+ call .update_damage_taken
+ ld c, FALSE
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .damage_player
+ call DoEnemyDamage
+ jr .done_damage
+
+.damage_player
+ call DoPlayerDamage
+
+.done_damage
+ pop bc
+ ld a, b
+ and a
+ ret z
+
+ dec a
+ jr nz, .focus_band_text
+ ld hl, EnduredText
+ jp StdBattleTextbox
+
+.focus_band_text
+ call GetOpponentItem
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+ ld hl, HungOnText
+ jp StdBattleTextbox
+
+.update_damage_taken
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVar
+ bit SUBSTATUS_SUBSTITUTE, a
+ ret nz
+
+ ld de, wPlayerDamageTaken + 1
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .got_damage_taken
+ ld de, wEnemyDamageTaken + 1
+
+.got_damage_taken
+ ld a, [wCurDamage + 1]
+ ld b, a
+ ld a, [de]
+ add b
+ ld [de], a
+ dec de
+ ld a, [wCurDamage]
+ ld b, a
+ ld a, [de]
+ adc b
+ ld [de], a
+ ret nc
+ ld a, $ff
+ ld [de], a
+ inc de
+ ld [de], a
+ ret
+
+GetFailureResultText:
+ ld hl, DoesntAffectText
+ ld de, DoesntAffectText
+ ld a, [wTypeModifier]
+ and $7f
+ jr z, .got_text
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_FUTURE_SIGHT
+ ld hl, ButItFailedText
+ ld de, ItFailedText
+ jr z, .got_text
+ ld hl, AttackMissedText
+ ld de, AttackMissed2Text
+ ld a, [wCriticalHit]
+ cp -1
+ jr nz, .got_text
+ ld hl, UnaffectedText
+.got_text
+ call FailText_CheckOpponentProtect
+ xor a
+ ld [wCriticalHit], a
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_JUMP_KICK
+ ret nz
+
+ ld a, [wTypeModifier]
+ and $7f
+ ret z
+
+ ld hl, wCurDamage
+ ld a, [hli]
+ ld b, [hl]
+rept 3
+ srl a
+ rr b
+endr
+ ld [hl], b
+ dec hl
+ ld [hli], a
+ or b
+ jr nz, .do_at_least_1_damage
+ inc a
+ ld [hl], a
+.do_at_least_1_damage
+ ld hl, CrashedText
+ call StdBattleTextbox
+ ld a, $1
+ ld [wKickCounter], a
+ call LoadMoveAnim
+ ld c, TRUE
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, DoEnemyDamage
+ jp DoPlayerDamage
+
+FailText_CheckOpponentProtect:
+ ld a, BATTLE_VARS_SUBSTATUS1_OPP
+ call GetBattleVar
+ bit SUBSTATUS_PROTECT, a
+ jr z, .not_protected
+ ld h, d
+ ld l, e
+.not_protected
+ jp StdBattleTextbox
+
+BattleCommand_BideFailText:
+ ld a, [wAttackMissed]
+ and a
+ ret z
+
+ ld a, [wTypeModifier]
+ and $7f
+ jp z, PrintDoesntAffect
+ jp PrintButItFailed
+
+BattleCommand_CriticalText:
+; criticaltext
+; Prints the message for critical hits or one-hit KOs.
+
+; If there is no message to be printed, wait 20 frames.
+ ld a, [wCriticalHit]
+ and a
+ jr z, .wait
+
+ dec a
+ add a
+ ld hl, .texts
+ ld b, 0
+ ld c, a
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call StdBattleTextbox
+
+ xor a
+ ld [wCriticalHit], a
+
+.wait
+ ld c, 20
+ jp DelayFrames
+
+.texts
+ dw CriticalHitText
+ dw OneHitKOText
+
+BattleCommand_StartLoop:
+; startloop
+
+ ld hl, wPlayerRolloutCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wEnemyRolloutCount
+.ok
+ xor a
+ ld [hl], a
+ ret
+
+BattleCommand_SuperEffectiveLoopText:
+; supereffectivelooptext
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVarAddr
+ bit SUBSTATUS_IN_LOOP, a
+ ret nz
+
+ ; fallthrough
+
+BattleCommand_SuperEffectiveText:
+; supereffectivetext
+
+ ld a, [wTypeModifier]
+ and $7f
+ cp 10 ; 1.0
+ ret z
+ ld hl, SuperEffectiveText
+ jr nc, .print
+ ld hl, NotVeryEffectiveText
+.print
+ jp StdBattleTextbox
+
+BattleCommand_CheckFaint:
+; checkfaint
+
+; Faint the opponent if its HP reached zero
+; and faint the user along with it if it used Destiny Bond.
+; Ends the move effect if the opponent faints.
+
+ ld hl, wEnemyMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wBattleMonHP
+
+.got_hp
+ ld a, [hli]
+ or [hl]
+ ret nz
+
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVar
+ bit SUBSTATUS_DESTINY_BOND, a
+ jr z, .no_dbond
+
+ ld hl, TookDownWithItText
+ call StdBattleTextbox
+
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wEnemyMonMaxHP + 1
+ bccoord 2, 2 ; hp bar
+ ld a, 0
+ jr nz, .got_max_hp
+ ld hl, wBattleMonMaxHP + 1
+ bccoord 10, 9 ; hp bar
+ ld a, 1
+
+.got_max_hp
+ ld [wWhichHPBar], a
+ ld a, [hld]
+ ld [wBuffer1], a
+ ld a, [hld]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer3], a
+ xor a
+ ld [hld], a
+ ld a, [hl]
+ ld [wBuffer4], a
+ xor a
+ ld [hl], a
+ ld [wBuffer5], a
+ ld [wBuffer6], a
+ ld h, b
+ ld l, c
+ predef AnimateHPBar
+ call RefreshBattleHuds
+
+ call BattleCommand_SwitchTurn
+ xor a
+ ld [wNumHits], a
+ ld [wFXAnimID + 1], a
+ inc a
+ ld [wKickCounter], a
+ ld a, DESTINY_BOND
+ call LoadAnim
+ call BattleCommand_SwitchTurn
+
+ jr .finish
+
+.no_dbond
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_MULTI_HIT
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_DOUBLE_HIT
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_TRIPLE_KICK
+ jr z, .multiple_hit_raise_sub
+ cp EFFECT_BEAT_UP
+ jr nz, .finish
+
+.multiple_hit_raise_sub
+ call BattleCommand_RaiseSub
+
+.finish
+ jp EndMoveEffect
+
+BattleCommand_BuildOpponentRage:
+; buildopponentrage
+
+ jp .start
+
+.start
+ ld a, [wAttackMissed]
+ and a
+ ret nz
+
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVar
+ bit SUBSTATUS_RAGE, a
+ ret z
+
+ ld de, wEnemyRageCounter
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .player
+ ld de, wPlayerRageCounter
+.player
+ ld a, [de]
+ inc a
+ ret z
+ ld [de], a
+
+ call BattleCommand_SwitchTurn
+ ld hl, RageBuildingText
+ call StdBattleTextbox
+ jp BattleCommand_SwitchTurn
+
+BattleCommand_RageDamage:
+; ragedamage
+
+ ld a, [wCurDamage]
+ ld h, a
+ ld b, a
+ ld a, [wCurDamage + 1]
+ ld l, a
+ ld c, a
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wPlayerRageCounter]
+ jr z, .rage_loop
+ ld a, [wEnemyRageCounter]
+.rage_loop
+ and a
+ jr z, .done
+ dec a
+ add hl, bc
+ jr nc, .rage_loop
+ ld hl, $ffff
+.done
+ ld a, h
+ ld [wCurDamage], a
+ ld a, l
+ ld [wCurDamage + 1], a
+ ret
+
+EndMoveEffect:
+ ld a, [wBattleScriptBufferAddress]
+ ld l, a
+ ld a, [wBattleScriptBufferAddress + 1]
+ ld h, a
+ ld a, $ff
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+DittoMetalPowder:
+ ld a, MON_SPECIES
+ call BattlePartyAttr
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [hl]
+ jr nz, .Ditto
+ ld a, [wTempEnemyMonSpecies]
+
+.Ditto:
+ cp DITTO
+ ret nz
+
+ push bc
+ call GetOpponentItem
+ ld a, [hl]
+ cp METAL_POWDER
+ pop bc
+ ret nz
+
+ ld a, c
+ srl a
+ add c
+ ld c, a
+ ret nc
+
+ srl b
+ ld a, b
+ and a
+ jr nz, .done
+ inc b
+.done
+ scf
+ rr c
+ ret
+
+BattleCommand_DamageStats:
+; damagestats
+
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, EnemyAttackDamage
+
+ ; fallthrough
+
+PlayerAttackDamage:
+; Return move power d, player level e, enemy defense c and player attack b.
+
+ call ResetDamage
+
+ ld hl, wPlayerMoveStructPower
+ ld a, [hli]
+ and a
+ ld d, a
+ ret z
+
+ ld a, [hl]
+ cp SPECIAL
+ jr nc, .special
+
+.physical
+ ld hl, wEnemyMonDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wEnemyScreens]
+ bit SCREENS_REFLECT, a
+ jr z, .physicalcrit
+ sla c
+ rl b
+
+.physicalcrit
+ ld hl, wBattleMonAttack
+ call CheckDamageStatsCritical
+ jr c, .thickclub
+
+ ld hl, wEnemyDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wPlayerAttack
+ jr .thickclub
+
+.special
+ ld hl, wEnemyMonSpclDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wEnemyScreens]
+ bit SCREENS_LIGHT_SCREEN, a
+ jr z, .specialcrit
+ sla c
+ rl b
+
+.specialcrit
+ ld hl, wBattleMonSpclAtk
+ call CheckDamageStatsCritical
+ jr c, .lightball
+
+ ld hl, wEnemySpDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wPlayerSpAtk
+
+.lightball
+; Note: Returns player special attack at hl in hl.
+ call LightBallBoost
+ jr .done
+
+.thickclub
+; Note: Returns player attack at hl in hl.
+ call ThickClubBoost
+
+.done
+ call TruncateHL_BC
+
+ ld a, [wBattleMonLevel]
+ ld e, a
+ call DittoMetalPowder
+
+ ld a, 1
+ and a
+ ret
+
+TruncateHL_BC:
+.loop
+; Truncate 16-bit values hl and bc to 8-bit values b and c respectively.
+; b = hl, c = bc
+
+ ld a, h
+ or b
+ jr z, .done
+
+ srl b
+ rr c
+ srl b
+ rr c
+
+ ld a, c
+ or b
+ jr nz, .done_bc
+ inc c
+
+.done_bc
+ srl h
+ rr l
+ srl h
+ rr l
+
+ ld a, l
+ or h
+ jr nz, .done
+ inc l
+
+.done
+ ld b, l
+ ret
+
+CheckDamageStatsCritical:
+; Return carry if boosted stats should be used in damage calculations.
+; Unboosted stats should be used if the attack is a critical hit,
+; and the stage of the opponent's defense is higher than the user's attack.
+
+ ld a, [wCriticalHit]
+ and a
+ scf
+ ret z
+
+ push hl
+ push bc
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .enemy
+ ld a, [wPlayerMoveStructType]
+ cp SPECIAL
+; special
+ ld a, [wPlayerSAtkLevel]
+ ld b, a
+ ld a, [wEnemySDefLevel]
+ jr nc, .end
+; physical
+ ld a, [wPlayerAtkLevel]
+ ld b, a
+ ld a, [wEnemyDefLevel]
+ jr .end
+
+.enemy
+ ld a, [wEnemyMoveStructType]
+ cp SPECIAL
+; special
+ ld a, [wEnemySAtkLevel]
+ ld b, a
+ ld a, [wPlayerSDefLevel]
+ jr nc, .end
+; physical
+ ld a, [wEnemyAtkLevel]
+ ld b, a
+ ld a, [wPlayerDefLevel]
+.end
+ cp b
+ pop bc
+ pop hl
+ ret
+
+ThickClubBoost:
+; Return in hl the stat value at hl.
+
+; If the attacking monster is Cubone or Marowak and
+; it's holding a Thick Club, double it.
+ push bc
+ push de
+ ld b, CUBONE
+ ld c, MAROWAK
+ ld d, THICK_CLUB
+ call SpeciesItemBoost
+ pop de
+ pop bc
+ ret
+
+LightBallBoost:
+; Return in hl the stat value at hl.
+
+; If the attacking monster is Pikachu and it's
+; holding a Light Ball, double it.
+ push bc
+ push de
+ ld b, PIKACHU
+ ld c, PIKACHU
+ ld d, LIGHT_BALL
+ call SpeciesItemBoost
+ pop de
+ pop bc
+ ret
+
+SpeciesItemBoost:
+; Return in hl the stat value at hl.
+
+; If the attacking monster is species b or c and
+; it's holding item d, double it.
+
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+
+ push hl
+ ld a, MON_SPECIES
+ call BattlePartyAttr
+
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [hl]
+ jr z, .CompareSpecies
+ ld a, [wTempEnemyMonSpecies]
+.CompareSpecies:
+ pop hl
+
+ cp b
+ jr z, .GetItemHeldEffect
+ cp c
+ ret nz
+
+.GetItemHeldEffect:
+ push hl
+ call GetUserItem
+ ld a, [hl]
+ pop hl
+ cp d
+ ret nz
+
+; Double the stat
+ sla l
+ rl h
+ ret
+
+EnemyAttackDamage:
+ call ResetDamage
+
+; No damage dealt with 0 power.
+ ld hl, wEnemyMoveStructPower
+ ld a, [hli] ; hl = wEnemyMoveStructType
+ ld d, a
+ and a
+ ret z
+
+ ld a, [hl]
+ cp SPECIAL
+ jr nc, .Special
+
+.physical
+ ld hl, wBattleMonDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wPlayerScreens]
+ bit SCREENS_REFLECT, a
+ jr z, .physicalcrit
+ sla c
+ rl b
+
+.physicalcrit
+ ld hl, wEnemyMonAttack
+ call CheckDamageStatsCritical
+ jr c, .thickclub
+
+ ld hl, wPlayerDefense
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wEnemyAttack
+ jr .thickclub
+
+.Special:
+ ld hl, wBattleMonSpclDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+
+ ld a, [wPlayerScreens]
+ bit SCREENS_LIGHT_SCREEN, a
+ jr z, .specialcrit
+ sla c
+ rl b
+
+.specialcrit
+ ld hl, wEnemyMonSpclAtk
+ call CheckDamageStatsCritical
+ jr c, .lightball
+ ld hl, wPlayerSpDef
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wEnemySpAtk
+
+.lightball
+ call LightBallBoost
+ jr .done
+
+.thickclub
+ call ThickClubBoost
+
+.done
+ call TruncateHL_BC
+
+ ld a, [wEnemyMonLevel]
+ ld e, a
+ call DittoMetalPowder
+
+ ld a, 1
+ and a
+ ret
+
+INCLUDE "engine/battle/move_effects/beat_up.asm"
+
+BattleCommand_ClearMissDamage:
+; clearmissdamage
+ ld a, [wAttackMissed]
+ and a
+ ret z
+
+ jp ResetDamage
+
+HitSelfInConfusion:
+ call ResetDamage
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wBattleMonDefense
+ ld de, wPlayerScreens
+ ld a, [wBattleMonLevel]
+ jr z, .got_it
+
+ ld hl, wEnemyMonDefense
+ ld de, wEnemyScreens
+ ld a, [wEnemyMonLevel]
+.got_it
+ push af
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld a, [de]
+ bit SCREENS_REFLECT, a
+ jr z, .mimic_screen
+
+ sla c
+ rl b
+.mimic_screen
+ dec hl
+ dec hl
+ dec hl
+ ld a, [hli]
+ ld l, [hl]
+ ld h, a
+ call TruncateHL_BC
+ ld d, 40
+ pop af
+ ld e, a
+ ret
+
+BattleCommand_DamageCalc:
+; damagecalc
+
+; Return a damage value for move power d, player level e, enemy defense c and player attack b.
+
+; Return 1 if successful, else 0.
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+
+; Selfdestruct and Explosion halve defense.
+ cp EFFECT_SELFDESTRUCT
+ jr nz, .dont_selfdestruct
+
+ srl c
+ jr nz, .dont_selfdestruct
+ inc c
+
+.dont_selfdestruct
+
+; Variable-hit moves and Conversion can have a power of 0.
+ cp EFFECT_MULTI_HIT
+ jr z, .skip_zero_damage_check
+
+ cp EFFECT_CONVERSION
+ jr z, .skip_zero_damage_check
+
+; No damage if move power is 0.
+ ld a, d
+ and a
+ ret z
+
+.skip_zero_damage_check
+; Minimum defense value is 1.
+ ld a, c
+ and a
+ jr nz, .not_dividing_by_zero
+ ld c, 1
+.not_dividing_by_zero
+
+ xor a
+ ld hl, hDividend
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+
+; Level * 2
+ ld a, e
+ add a
+ jr nc, .level_not_overflowing
+ ld [hl], 1
+.level_not_overflowing
+ inc hl
+ ld [hli], a
+
+; / 5
+ ld a, 5
+ ld [hld], a
+ push bc
+ ld b, 4
+ call Divide
+ pop bc
+
+; + 2
+ inc [hl]
+ inc [hl]
+
+; * bp
+ inc hl
+ ld [hl], d
+ call Multiply
+
+; * Attack
+ ld [hl], b
+ call Multiply
+
+; / Defense
+ ld [hl], c
+ ld b, 4
+ call Divide
+
+; / 50
+ ld [hl], 50
+ ld b, $4
+ call Divide
+
+; Item boosts
+ call GetUserItem
+
+ ld a, b
+ and a
+ jr z, .DoneItem
+
+ ld hl, TypeBoostItems
+
+.NextItem:
+ ld a, [hli]
+ cp -1
+ jr z, .DoneItem
+
+; Item effect
+ cp b
+ ld a, [hli]
+ jr nz, .NextItem
+
+; Type
+ ld b, a
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVar
+ cp b
+ jr nz, .DoneItem
+
+; * 100 + item effect amount
+ ld a, c
+ add 100
+ ldh [hMultiplier], a
+ call Multiply
+
+; / 100
+ ld a, 100
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+
+.DoneItem:
+; Critical hits
+ call .CriticalMultiplier
+
+; Update wCurDamage (capped at 997).
+ ld hl, wCurDamage
+ ld b, [hl]
+ ldh a, [hProduct + 3]
+ add b
+ ldh [hProduct + 3], a
+ jr nc, .dont_cap_1
+
+ ldh a, [hProduct + 2]
+ inc a
+ ldh [hProduct + 2], a
+ and a
+ jr z, .Cap
+
+.dont_cap_1
+ ldh a, [hProduct]
+ ld b, a
+ ldh a, [hProduct + 1]
+ or a
+ jr nz, .Cap
+
+ ldh a, [hProduct + 2]
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr c, .dont_cap_2
+
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + 1
+ jr nc, .Cap
+
+ ldh a, [hProduct + 3]
+ cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr nc, .Cap
+
+.dont_cap_2
+ inc hl
+
+ ldh a, [hProduct + 3]
+ ld b, [hl]
+ add b
+ ld [hld], a
+
+ ldh a, [hProduct + 2]
+ ld b, [hl]
+ adc b
+ ld [hl], a
+ jr c, .Cap
+
+ ld a, [hl]
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr c, .dont_cap_3
+
+ cp HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1) + 1
+ jr nc, .Cap
+
+ inc hl
+ ld a, [hld]
+ cp LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE + 1)
+ jr c, .dont_cap_3
+
+.Cap:
+ ld a, HIGH(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE)
+ ld [hli], a
+ ld a, LOW(MAX_STAT_VALUE - MIN_NEUTRAL_DAMAGE)
+ ld [hld], a
+
+.dont_cap_3
+; Minimum neutral damage is 2 (bringing the cap to 999).
+ inc hl
+ ld a, [hl]
+ add MIN_NEUTRAL_DAMAGE
+ ld [hld], a
+ jr nc, .dont_floor
+ inc [hl]
+.dont_floor
+
+ ld a, 1
+ and a
+ ret
+
+.CriticalMultiplier:
+ ld a, [wCriticalHit]
+ and a
+ ret z
+
+; x2
+ ldh a, [hQuotient + 3]
+ sla a
+ ldh [hProduct + 3], a
+
+ ldh a, [hQuotient + 2]
+ rl a
+ ldh [hProduct + 2], a
+
+; Cap at $ffff.
+ ret nc
+
+ ld a, $ff
+ ldh [hProduct + 2], a
+ ldh [hProduct + 3], a
+
+ ret
+
+INCLUDE "data/types/type_boost_items.asm"
+
+BattleCommand_ConstantDamage:
+; constantdamage
+
+ ld hl, wBattleMonLevel
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_turn
+ ld hl, wEnemyMonLevel
+
+.got_turn
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_LEVEL_DAMAGE
+ ld b, [hl]
+ ld a, 0
+ jr z, .got_power
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVar
+ cp EFFECT_PSYWAVE
+ jr z, .psywave
+
+ cp EFFECT_SUPER_FANG
+ jr z, .super_fang
+
+ cp EFFECT_REVERSAL
+ jr z, .reversal
+
+ ld a, BATTLE_VARS_MOVE_POWER
+ call GetBattleVar
+ ld b, a
+ ld a, $0
+ jr .got_power
+
+.psywave
+ ld a, b
+ srl a
+ add b
+ ld b, a
+.psywave_loop
+ call BattleRandom
+ and a
+ jr z, .psywave_loop
+ cp b
+ jr nc, .psywave_loop
+ ld b, a
+ ld a, 0
+ jr .got_power
+
+.super_fang
+ ld hl, wEnemyMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wBattleMonHP
+.got_hp
+ ld a, [hli]
+ srl a
+ ld b, a
+ ld a, [hl]
+ rr a
+ push af
+ ld a, b
+ pop bc
+ and a
+ jr nz, .got_power
+ or b
+ ld a, 0
+ jr nz, .got_power
+ ld b, 1
+ jr .got_power
+
+.got_power
+ ld hl, wCurDamage
+ ld [hli], a
+ ld [hl], b
+ ret
+
+.reversal
+ ld hl, wBattleMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .reversal_got_hp
+ ld hl, wEnemyMonHP
+.reversal_got_hp
+ xor a
+ ldh [hDividend], a
+ ldh [hMultiplicand + 0], a
+ ld a, [hli]
+ ldh [hMultiplicand + 1], a
+ ld a, [hli]
+ ldh [hMultiplicand + 2], a
+ ld a, 48
+ ldh [hMultiplier], a
+ call Multiply
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ ldh [hDivisor], a
+ ld a, b
+ and a
+ jr z, .skip_to_divide
+
+ ldh a, [hProduct + 4]
+ srl b
+ rr a
+ srl b
+ rr a
+ ldh [hDivisor], a
+ ldh a, [hProduct + 2]
+ ld b, a
+ srl b
+ ldh a, [hProduct + 3]
+ rr a
+ srl b
+ rr a
+ ldh [hDividend + 3], a
+ ld a, b
+ ldh [hDividend + 2], a
+
+.skip_to_divide
+ ld b, 4
+ call Divide
+ ldh a, [hQuotient + 3]
+ ld b, a
+ ld hl, FlailReversalPower
+
+.reversal_loop
+ ld a, [hli]
+ cp b
+ jr nc, .break_loop
+ inc hl
+ jr .reversal_loop
+
+.break_loop
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [hl]
+ jr nz, .notPlayersTurn
+
+ ld hl, wPlayerMoveStructPower
+ ld [hl], a
+ push hl
+ call PlayerAttackDamage
+ jr .notEnemysTurn
+
+.notPlayersTurn
+ ld hl, wEnemyMoveStructPower
+ ld [hl], a
+ push hl
+ call EnemyAttackDamage
+
+.notEnemysTurn
+ call BattleCommand_DamageCalc
+ pop hl
+ ld [hl], 1
+ ret
+
+INCLUDE "data/moves/flail_reversal_power.asm"
+
+INCLUDE "engine/battle/move_effects/counter.asm"
+
+INCLUDE "engine/battle/move_effects/encore.asm"
+
+INCLUDE "engine/battle/move_effects/pain_split.asm"
+
+INCLUDE "engine/battle/move_effects/snore.asm"
+
+INCLUDE "engine/battle/move_effects/conversion2.asm"
+
+INCLUDE "engine/battle/move_effects/lock_on.asm"
+
+INCLUDE "engine/battle/move_effects/sketch.asm"
+
+BattleCommand_DefrostOpponent:
+; defrostopponent
+; Thaw the opponent if frozen, and
+; raise the user's Attack one stage.
+
+ call AnimateCurrentMove
+
+ ld a, BATTLE_VARS_STATUS_OPP
+ call GetBattleVarAddr
+ call Defrost
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVarAddr
+ ld a, [hl]
+ push hl
+ push af
+
+ ld a, EFFECT_ATTACK_UP
+ ld [hl], a
+ call BattleCommand_StatUp
+
+ pop af
+ pop hl
+ ld [hl], a
+ ret
+
+INCLUDE "engine/battle/move_effects/sleep_talk.asm"
+
+INCLUDE "engine/battle/move_effects/destiny_bond.asm"
+
+INCLUDE "engine/battle/move_effects/spite.asm"
+
+INCLUDE "engine/battle/move_effects/false_swipe.asm"
+
+INCLUDE "engine/battle/move_effects/heal_bell.asm"
+
+FarPlayBattleAnimation:
+; play animation de
+
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ ret nz
+
+ ; fallthrough
+
+PlayFXAnimID:
+ ld a, e
+ ld [wFXAnimID], a
+ ld a, d
+ ld [wFXAnimID + 1], a
+
+ ld c, 3
+ call DelayFrames
+ callfar PlayBattleAnim
+ ret
+
+DoEnemyDamage:
+ ld hl, wCurDamage
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ or b
+ jr z, .did_no_damage
+
+ ld a, c
+ and a
+ jr nz, .ignore_substitute
+ ld a, [wEnemySubStatus4]
+ bit SUBSTATUS_SUBSTITUTE, a
+ jp nz, DoSubstituteDamage
+
+.ignore_substitute
+ ; Substract wCurDamage from wEnemyMonHP.
+ ; store original HP in little endian wBuffer3/4
+ ld a, [hld]
+ ld b, a
+ ld a, [wEnemyMonHP + 1]
+ ld [wBuffer3], a
+ sub b
+ ld [wEnemyMonHP + 1], a
+ ld a, [hl]
+ ld b, a
+ ld a, [wEnemyMonHP]
+ ld [wBuffer4], a
+ sbc b
+ ld [wEnemyMonHP], a
+ jr nc, .no_underflow
+
+ ld a, [wBuffer4]
+ ld [hli], a
+ ld a, [wBuffer3]
+ ld [hl], a
+ xor a
+ ld hl, wEnemyMonHP
+ ld [hli], a
+ ld [hl], a
+
+.no_underflow
+ ld hl, wEnemyMonMaxHP
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ ld [wBuffer6], a
+ ld a, [hl]
+ ld [wBuffer5], a
+
+ hlcoord 2, 2
+ xor a
+ ld [wWhichHPBar], a
+ predef AnimateHPBar
+.did_no_damage
+ jp RefreshBattleHuds
+
+DoPlayerDamage:
+ ld hl, wCurDamage
+ ld a, [hli]
+ ld b, a
+ ld a, [hl]
+ or b
+ jr z, .did_no_damage
+
+ ld a, c
+ and a
+ jr nz, .ignore_substitute
+ ld a, [wPlayerSubStatus4]
+ bit SUBSTATUS_SUBSTITUTE, a
+ jp nz, DoSubstituteDamage
+
+.ignore_substitute
+ ; Substract wCurDamage from wBattleMonHP.
+ ; store original HP in little endian wBuffer3/4
+ ; store new HP in little endian wBuffer5/6
+ ld a, [hld]
+ ld b, a
+ ld a, [wBattleMonHP + 1]
+ ld [wBuffer3], a
+ sub b
+ ld [wBattleMonHP + 1], a
+ ld [wBuffer5], a
+ ld b, [hl]
+ ld a, [wBattleMonHP]
+ ld [wBuffer4], a
+ sbc b
+ ld [wBattleMonHP], a
+ ld [wBuffer6], a
+ jr nc, .no_underflow
+
+ ld a, [wBuffer4]
+ ld [hli], a
+ ld a, [wBuffer3]
+ ld [hl], a
+ xor a
+ ld hl, wBattleMonHP
+ ld [hli], a
+ ld [hl], a
+ ld hl, wBuffer5
+ ld [hli], a
+ ld [hl], a
+
+.no_underflow
+ ld hl, wBattleMonMaxHP
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+
+ hlcoord 10, 9
+ ld a, 1
+ ld [wWhichHPBar], a
+ predef AnimateHPBar
+.did_no_damage
+ jp RefreshBattleHuds
+
+DoSubstituteDamage:
+ ld hl, SubTookDamageText
+ call StdBattleTextbox
+
+ ld de, wEnemySubstituteHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld de, wPlayerSubstituteHP
+.got_hp
+
+ ld hl, wCurDamage
+ ld a, [hli]
+ and a
+ jr nz, .broke
+
+ ld a, [de]
+ sub [hl]
+ ld [de], a
+ jr z, .broke
+ jr nc, .done
+
+.broke
+ ld a, BATTLE_VARS_SUBSTATUS4_OPP
+ call GetBattleVarAddr
+ res SUBSTATUS_SUBSTITUTE, [hl]
+
+ ld hl, SubFadedText
+ call StdBattleTextbox
+
+ call BattleCommand_SwitchTurn
+ call BattleCommand_LowerSubNoAnim
+ ld a, BATTLE_VARS_SUBSTATUS3
+ call GetBattleVar
+ and 1 << SUBSTATUS_FLYING | 1 << SUBSTATUS_UNDERGROUND
+ call z, AppearUserLowerSub
+ call BattleCommand_SwitchTurn
+
+ ld a, BATTLE_VARS_MOVE_EFFECT
+ call GetBattleVarAddr
+ cp EFFECT_MULTI_HIT
+ jr z, .ok
+ cp EFFECT_DOUBLE_HIT
+ jr z, .ok
+ cp EFFECT_POISON_MULTI_HIT
+ jr z, .ok
+ cp EFFECT_TRIPLE_KICK
+ jr z, .ok
+ cp EFFECT_BEAT_UP
+ jr z, .ok
+ xor a
+ ld [hl], a
+.ok
+ call RefreshBattleHuds
+.done
+ jp ResetDamage
diff --git a/engine/battle/move_effects/beat_up.asm b/engine/battle/move_effects/beat_up.asm
new file mode 100644
index 00000000..8546c37d
--- /dev/null
+++ b/engine/battle/move_effects/beat_up.asm
@@ -0,0 +1,220 @@
+BattleCommand_BeatUp:
+; beatup
+
+ call ResetDamage
+ ldh a, [hBattleTurn]
+ and a
+ jp nz, .enemy_beats_up
+
+ ld a, [wPlayerSubStatus3]
+ bit SUBSTATUS_IN_LOOP, a
+ jr nz, .next_mon
+
+ ld c, 20
+ call DelayFrames
+ xor a
+ ld [wPlayerRolloutCount], a
+ ld [wceed], a
+ ld [wBeatUpHitAtLeastOnce], a
+ jr .got_mon
+
+.next_mon
+ ld a, [wPlayerRolloutCount]
+ ld b, a
+ ld a, [wPartyCount]
+ sub b
+ ld [wceed], a
+
+.got_mon
+ ld a, [wceed]
+ ld hl, wPartyMonNicknames
+ call GetNick
+ ld a, MON_HP
+ call GetBeatupMonLocation
+ ld a, [hli]
+ or [hl]
+ jp z, .beatup_fail ; fainted
+ ld a, [wceed]
+ ld c, a
+ ld a, [wCurBattleMon]
+ ; BUG: this can desynchronize link battles
+ ; Change "cp [hl]" to "cp c" to fix
+ cp [hl]
+ ld hl, wBattleMonStatus
+ jr z, .active_mon
+ ld a, MON_STATUS
+ call GetBeatupMonLocation
+.active_mon
+ ld a, [hl]
+ and a
+ jp nz, .beatup_fail
+
+ ld a, $1
+ ld [wBeatUpHitAtLeastOnce], a
+ ld hl, BeatUpAttackText
+ call StdBattleTextbox
+
+ ld a, [wEnemyMonSpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseDefense]
+ ld c, a
+
+ push bc
+ ld a, MON_SPECIES
+ call GetBeatupMonLocation
+ ld a, [hl]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseAttack]
+ pop bc
+ ld b, a
+
+ push bc
+ ld a, MON_LEVEL
+ call GetBeatupMonLocation
+ ld a, [hl]
+ ld e, a
+ pop bc
+
+ ld a, [wPlayerMoveStructPower]
+ ld d, a
+ ret
+
+.enemy_beats_up
+ ld a, [wEnemySubStatus3]
+ bit SUBSTATUS_IN_LOOP, a
+ jr nz, .enemy_next_mon
+
+ xor a
+ ld [wEnemyRolloutCount], a
+ ld [wceed], a
+ ld [wBeatUpHitAtLeastOnce], a
+ jr .enemy_got_mon
+
+.enemy_next_mon
+ ld a, [wEnemyRolloutCount]
+ ld b, a
+ ld a, [wOTPartyCount]
+ sub b
+ ld [wceed], a
+
+.enemy_got_mon
+ ld a, [wBattleMode]
+ dec a
+ jr z, .wild
+
+ ld a, [wLinkMode]
+ and a
+ jr nz, .linked
+
+ ld a, [wceed]
+ ld c, a
+ ld b, 0
+ ld hl, wOTPartySpecies
+ add hl, bc
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ jr .got_enemy_nick
+
+.linked
+ ld a, [wceed]
+ ld hl, wOTPartyMonNicknames
+ ld bc, NAME_LENGTH
+ call AddNTimes
+ ld de, wStringBuffer1
+ call CopyBytes
+
+.got_enemy_nick
+ ld a, MON_HP
+ call GetBeatupMonLocation
+ ld a, [hli]
+ or [hl]
+ jp z, .beatup_fail
+
+ ld a, [wceed]
+ ld b, a
+ ld a, [wCurOTMon]
+ cp b
+ ld hl, wEnemyMonStatus
+ jr z, .active_enemy
+ ld a, MON_STATUS
+ call GetBeatupMonLocation
+.active_enemy
+ ld a, [hl]
+ and a
+ jr nz, .beatup_fail
+
+ ld a, $1
+ ld [wBeatUpHitAtLeastOnce], a
+ jr .finish_beatup
+
+.wild
+ ld a, [wEnemyMonSpecies]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ ld hl, BeatUpAttackText
+ call StdBattleTextbox
+ jp EnemyAttackDamage
+
+.finish_beatup
+ ld hl, BeatUpAttackText
+ call StdBattleTextbox
+
+ ld a, [wBattleMonSpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseDefense]
+ ld c, a
+
+ push bc
+ ld a, MON_SPECIES
+ call GetBeatupMonLocation
+ ld a, [hl]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld a, [wBaseAttack]
+ pop bc
+ ld b, a
+
+ push bc
+ ld a, MON_LEVEL
+ call GetBeatupMonLocation
+ ld a, [hl]
+ ld e, a
+ pop bc
+
+ ld a, [wEnemyMoveStructPower]
+ ld d, a
+ ret
+
+.beatup_fail
+ ld b, buildopponentrage_command
+ jp SkipToBattleCommand
+
+BattleCommand_BeatUpFailText:
+; beatupfailtext
+
+ ld a, [wBeatUpHitAtLeastOnce]
+ and a
+ ret nz
+
+ jp PrintButItFailed
+
+GetBeatupMonLocation:
+ push bc
+ ld c, a
+ ld b, 0
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wPartyMon1Species
+ jr z, .got_species
+ ld hl, wOTPartyMon1Species
+
+.got_species
+ ld a, [wceed]
+ add hl, bc
+ call GetPartyLocation
+ pop bc
+ ret
diff --git a/engine/battle/move_effects/conversion2.asm b/engine/battle/move_effects/conversion2.asm
new file mode 100644
index 00000000..bc866727
--- /dev/null
+++ b/engine/battle/move_effects/conversion2.asm
@@ -0,0 +1,64 @@
+BattleCommand_Conversion2:
+; conversion2
+
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .failed
+ ld hl, wBattleMonType1
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_type
+ ld hl, wEnemyMonType1
+.got_type
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ and a
+ jr z, .failed
+ push hl
+ dec a
+ ld hl, Moves + MOVE_TYPE
+ call GetMoveAttr
+ ld d, a
+ pop hl
+ cp CURSE_TYPE
+ jr z, .failed
+ call AnimateCurrentMove
+ call BattleCommand_SwitchTurn
+
+.loop
+ call BattleRandom
+ maskbits NUM_TYPES
+ cp UNUSED_TYPES
+ jr c, .okay
+ cp UNUSED_TYPES_END
+ jr c, .loop
+ cp TYPES_END
+ jr nc, .loop
+.okay
+ ld [hli], a
+ ld [hld], a
+ push hl
+ ld a, BATTLE_VARS_MOVE_TYPE
+ call GetBattleVarAddr
+ push af
+ push hl
+ ld a, d
+ ld [hl], a
+ call BattleCheckTypeMatchup
+ pop hl
+ pop af
+ ld [hl], a
+ pop hl
+ ld a, [wTypeMatchup]
+ cp EFFECTIVE
+ jr nc, .loop
+ call BattleCommand_SwitchTurn
+
+ ld a, [hl]
+ ld [wNamedObjectIndexBuffer], a
+ predef GetTypeName
+ ld hl, TransformedTypeText
+ jp StdBattleTextbox
+
+.failed
+ jp FailMove
diff --git a/engine/battle/move_effects/counter.asm b/engine/battle/move_effects/counter.asm
new file mode 100644
index 00000000..031c399a
--- /dev/null
+++ b/engine/battle/move_effects/counter.asm
@@ -0,0 +1,59 @@
+BattleCommand_Counter:
+; counter
+
+ ld a, 1
+ ld [wAttackMissed], a
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ and a
+ ret z
+
+ ld b, a
+ callfar GetMoveEffect
+ ld a, b
+ cp EFFECT_COUNTER
+ ret z
+
+ call BattleCommand_ResetTypeMatchup
+ ld a, [wTypeMatchup]
+ and a
+ ret z
+
+ call CheckOpponentWentFirst
+ ret z
+
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ dec a
+ ld de, wStringBuffer1
+ call GetMoveData
+
+ ld a, [wStringBuffer1 + MOVE_POWER]
+ and a
+ ret z
+
+ ld a, [wStringBuffer1 + MOVE_TYPE]
+ cp SPECIAL
+ ret nc
+
+ ; BUG: Move should fail with all non-damaging battle actions
+ ld hl, wCurDamage
+ ld a, [hli]
+ or [hl]
+ ret z
+
+ ld a, [hl]
+ add a
+ ld [hld], a
+ ld a, [hl]
+ adc a
+ ld [hl], a
+ jr nc, .capped
+ ld a, $ff
+ ld [hli], a
+ ld [hl], a
+.capped
+
+ xor a
+ ld [wAttackMissed], a
+ ret
diff --git a/engine/battle/move_effects/destiny_bond.asm b/engine/battle/move_effects/destiny_bond.asm
new file mode 100644
index 00000000..6a03b9a7
--- /dev/null
+++ b/engine/battle/move_effects/destiny_bond.asm
@@ -0,0 +1,9 @@
+BattleCommand_DestinyBond:
+; destinybond
+
+ ld a, BATTLE_VARS_SUBSTATUS5
+ call GetBattleVarAddr
+ set SUBSTATUS_DESTINY_BOND, [hl]
+ call AnimateCurrentMove
+ ld hl, DestinyBondEffectText
+ jp StdBattleTextbox
diff --git a/engine/battle/move_effects/encore.asm b/engine/battle/move_effects/encore.asm
new file mode 100644
index 00000000..8ca3595f
--- /dev/null
+++ b/engine/battle/move_effects/encore.asm
@@ -0,0 +1,120 @@
+BattleCommand_Encore:
+; encore
+
+ ld hl, wEnemyMonMoves
+ ld de, wEnemyEncoreCount
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .ok
+ ld hl, wBattleMonMoves
+ ld de, wPlayerEncoreCount
+.ok
+ ld a, BATTLE_VARS_LAST_MOVE_OPP
+ call GetBattleVar
+ and a
+ jp z, .failed
+ cp STRUGGLE
+ jp z, .failed
+ cp ENCORE
+ jp z, .failed
+ cp MIRROR_MOVE
+ jp z, .failed
+ ld b, a
+
+.got_move
+ ld a, [hli]
+ cp b
+ jr nz, .got_move
+
+ ld bc, wBattleMonPP - wBattleMonMoves - 1
+ add hl, bc
+ ld a, [hl]
+ and PP_MASK
+ jp z, .failed
+ ld a, [wAttackMissed]
+ and a
+ jp nz, .failed
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_ENCORED, [hl]
+ jp nz, .failed
+ set SUBSTATUS_ENCORED, [hl]
+ call BattleRandom
+ and $3
+ inc a
+ inc a
+ inc a
+ ld [de], a
+ call CheckOpponentWentFirst
+ jr nz, .finish_move
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .force_last_enemy_move
+
+ push hl
+ ld a, [wLastPlayerMove]
+ ld b, a
+ ld c, 0
+ ld hl, wBattleMonMoves
+.find_player_move
+ ld a, [hli]
+ cp b
+ jr z, .got_player_move
+ inc c
+ ld a, c
+ cp NUM_MOVES
+ jr c, .find_player_move
+ pop hl
+ res SUBSTATUS_ENCORED, [hl]
+ xor a
+ ld [de], a
+ jr .failed
+
+.got_player_move
+ pop hl
+ ld a, c
+ ld [wCurMoveNum], a
+ ld a, b
+ ld [wCurPlayerMove], a
+ dec a
+ ld de, wPlayerMoveStruct
+ call GetMoveData
+ jr .finish_move
+
+.force_last_enemy_move
+ push hl
+ ld a, [wLastEnemyMove]
+ ld b, a
+ ld c, 0
+ ld hl, wEnemyMonMoves
+.find_enemy_move
+ ld a, [hli]
+ cp b
+ jr z, .got_enemy_move
+ inc c
+ ld a, c
+ cp NUM_MOVES
+ jr c, .find_enemy_move
+ pop hl
+ res SUBSTATUS_ENCORED, [hl]
+ xor a
+ ld [de], a
+ jr .failed
+
+.got_enemy_move
+ pop hl
+ ld a, c
+ ld [wCurEnemyMoveNum], a
+ ld a, b
+ ld [wCurEnemyMove], a
+ dec a
+ ld de, wEnemyMoveStruct
+ call GetMoveData
+
+.finish_move
+ call AnimateCurrentMove
+ ld hl, GotAnEncoreText
+ jp StdBattleTextbox
+
+.failed
+ jp PrintDidntAffect2
diff --git a/engine/battle/move_effects/false_swipe.asm b/engine/battle/move_effects/false_swipe.asm
new file mode 100644
index 00000000..e2e0c6f1
--- /dev/null
+++ b/engine/battle/move_effects/false_swipe.asm
@@ -0,0 +1,48 @@
+BattleCommand_FalseSwipe:
+; falseswipe
+
+; Makes sure wCurDamage < MonHP
+
+ ld hl, wEnemyMonHP
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_hp
+ ld hl, wBattleMonHP
+.got_hp
+ ld de, wCurDamage
+ ld c, 2
+ push hl
+ push de
+ call CompareBytes
+ pop de
+ pop hl
+ jr c, .done
+
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ dec a
+ ld [de], a
+
+ inc a
+ jr nz, .okay
+ dec de
+ ld a, [de]
+ dec a
+ ld [de], a
+.okay
+
+ ld a, [wCriticalHit]
+ cp 2
+ jr nz, .carry
+ xor a
+ ld [wCriticalHit], a
+
+.carry
+ scf
+ ret
+
+.done
+ and a
+ ret
diff --git a/engine/battle/move_effects/heal_bell.asm b/engine/battle/move_effects/heal_bell.asm
new file mode 100644
index 00000000..62309f1d
--- /dev/null
+++ b/engine/battle/move_effects/heal_bell.asm
@@ -0,0 +1,34 @@
+BattleCommand_HealBell:
+; healbell
+
+ ld a, BATTLE_VARS_SUBSTATUS1
+ call GetBattleVarAddr
+ res SUBSTATUS_NIGHTMARE, [hl]
+ ld de, wPartyMon1Status
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_status
+ ld de, wOTPartyMon1Status
+.got_status
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVarAddr
+ xor a
+ ld [hl], a
+ ld h, d
+ ld l, e
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld d, PARTY_LENGTH
+.loop
+ ld [hl], a
+ add hl, bc
+ dec d
+ jr nz, .loop
+ call AnimateCurrentMove
+
+ ld hl, BellChimedText
+ call StdBattleTextbox
+
+ ldh a, [hBattleTurn]
+ and a
+ jp z, CalcPlayerStats
+ jp CalcEnemyStats
diff --git a/engine/battle/move_effects/lock_on.asm b/engine/battle/move_effects/lock_on.asm
new file mode 100644
index 00000000..1de3e14b
--- /dev/null
+++ b/engine/battle/move_effects/lock_on.asm
@@ -0,0 +1,21 @@
+BattleCommand_LockOn:
+; lockon
+
+ call CheckSubstituteOpp
+ jr nz, .fail
+
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .fail
+
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ set SUBSTATUS_LOCK_ON, [hl]
+ call AnimateCurrentMove
+
+ ld hl, TookAimText
+ jp StdBattleTextbox
+
+.fail
+ call AnimateFailedMove
+ jp PrintDidntAffect
diff --git a/engine/battle/move_effects/pain_split.asm b/engine/battle/move_effects/pain_split.asm
new file mode 100644
index 00000000..68d7cfb4
--- /dev/null
+++ b/engine/battle/move_effects/pain_split.asm
@@ -0,0 +1,92 @@
+BattleCommand_PainSplit:
+; painsplit
+
+ ld a, [wAttackMissed]
+ and a
+ jp nz, .ButItFailed
+ call CheckSubstituteOpp
+ jp nz, .ButItFailed
+ call AnimateCurrentMove
+ ld hl, wBattleMonMaxHP + 1
+ ld de, wEnemyMonMaxHP + 1
+ call .PlayerShareHP
+ ld a, $1
+ ld [wWhichHPBar], a
+ hlcoord 10, 9
+ predef AnimateHPBar
+ ld hl, wEnemyMonHP
+ ld a, [hli]
+ ld [wBuffer4], a
+ ld a, [hli]
+ ld [wBuffer3], a
+ ld a, [hli]
+ ld [wBuffer2], a
+ ld a, [hl]
+ ld [wBuffer1], a
+ call .EnemyShareHP
+ xor a
+ ld [wWhichHPBar], a
+ call ResetDamage
+ hlcoord 2, 2
+ predef AnimateHPBar
+
+ ld hl, SharedPainText
+ jp StdBattleTextbox
+
+.PlayerShareHP:
+ ld a, [hld]
+ ld [wBuffer1], a
+ ld a, [hld]
+ ld [wBuffer2], a
+ ld a, [hld]
+ ld b, a
+ ld [wBuffer3], a
+ ld a, [hl]
+ ld [wBuffer4], a
+ dec de
+ dec de
+ ld a, [de]
+ dec de
+ add b
+ ld [wCurDamage + 1], a
+ ld b, [hl]
+ ld a, [de]
+ adc b
+ srl a
+ ld [wCurDamage], a
+ ld a, [wCurDamage + 1]
+ rr a
+ ld [wCurDamage + 1], a
+ inc hl
+ inc hl
+ inc hl
+ inc de
+ inc de
+ inc de
+
+.EnemyShareHP:
+ ld c, [hl]
+ dec hl
+ ld a, [wCurDamage + 1]
+ sub c
+ ld b, [hl]
+ dec hl
+ ld a, [wCurDamage]
+ sbc b
+ jr nc, .skip
+
+ ld a, [wCurDamage]
+ ld b, a
+ ld a, [wCurDamage + 1]
+ ld c, a
+.skip
+ ld a, c
+ ld [hld], a
+ ld [wBuffer5], a
+ ld a, b
+ ld [hli], a
+ ld [wBuffer6], a
+ ret
+
+.ButItFailed:
+ jp PrintDidntAffect2
diff --git a/engine/battle/move_effects/sketch.asm b/engine/battle/move_effects/sketch.asm
new file mode 100644
index 00000000..654fb3f5
--- /dev/null
+++ b/engine/battle/move_effects/sketch.asm
@@ -0,0 +1,117 @@
+BattleCommand_Sketch:
+; sketch
+
+ call ClearLastMove
+; Don't sketch during a link battle
+ ld a, [wLinkMode]
+ and a
+ jr z, .not_linked
+ call AnimateFailedMove
+ jp PrintNothingHappened
+
+.not_linked
+; If the opponent has a substitute up, fail.
+ call CheckSubstituteOpp
+ jp nz, .fail
+; If the opponent is transformed, fail.
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVarAddr
+ bit SUBSTATUS_TRANSFORMED, [hl]
+ jp nz, .fail
+; Get the user's moveset in its party struct.
+; This move replacement shall be permanent.
+; Pointer will be in de.
+ ld a, MON_MOVES
+ call UserPartyAttr
+ ld d, h
+ ld e, l
+; Get the battle move structs.
+ ld hl, wBattleMonMoves
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .get_last_move
+ ld hl, wEnemyMonMoves
+.get_last_move
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ ld [wNamedObjectIndexBuffer], a
+ ld b, a
+; Fail if move is invalid or is Struggle.
+ and a
+ jr z, .fail
+ cp STRUGGLE
+ jr z, .fail
+; Fail if user already knows that move
+ ld c, NUM_MOVES
+.does_user_already_know_move
+ ld a, [hli]
+ cp b
+ jr z, .fail
+ dec c
+ jr nz, .does_user_already_know_move
+; Find Sketch in the user's moveset.
+; Pointer in hl, and index in c.
+ dec hl
+ ld c, NUM_MOVES
+.find_sketch
+ dec c
+ ld a, [hld]
+ cp SKETCH
+ jr nz, .find_sketch
+ inc hl
+; The Sketched move is loaded to that slot.
+ ld a, b
+ ld [hl], a
+; Copy the base PP from that move.
+ push bc
+ push hl
+ dec a
+ ld hl, Moves + MOVE_PP
+ call GetMoveAttr
+ pop hl
+ ld bc, wBattleMonPP - wBattleMonMoves
+ add hl, bc
+ ld [hl], a
+ pop bc
+
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .user_trainer
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .user_trainer
+; wildmon
+ ld a, [hl]
+ push bc
+ ld hl, wWildMonPP
+ ld b, 0
+ add hl, bc
+ ld [hl], a
+ ld hl, wWildMonMoves
+ add hl, bc
+ pop bc
+ ld [hl], b
+ jr .done_copy
+
+.user_trainer
+ ld a, [hl]
+ push af
+ ld l, c
+ ld h, 0
+ add hl, de
+ ld a, b
+ ld [hl], a
+ pop af
+ ld de, MON_PP - MON_MOVES
+ add hl, de
+ ld [hl], a
+.done_copy
+ call GetMoveName
+ call AnimateCurrentMove
+
+ ld hl, SketchedText
+ jp StdBattleTextbox
+
+.fail
+ call AnimateFailedMove
+ jp PrintDidntAffect
diff --git a/engine/battle/move_effects/sleep_talk.asm b/engine/battle/move_effects/sleep_talk.asm
new file mode 100644
index 00000000..92bff260
--- /dev/null
+++ b/engine/battle/move_effects/sleep_talk.asm
@@ -0,0 +1,143 @@
+BattleCommand_SleepTalk:
+; sleeptalk
+
+ call ClearLastMove
+ ld a, [wAttackMissed]
+ and a
+ jr nz, .fail
+ ldh a, [hBattleTurn]
+ and a
+ ld hl, wBattleMonMoves + 1
+ ld a, [wDisabledMove]
+ ld d, a
+ jr z, .got_moves
+ ld hl, wEnemyMonMoves + 1
+ ld a, [wEnemyDisabledMove]
+ ld d, a
+.got_moves
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVar
+ and SLP
+ jr z, .fail
+ ld a, [hl]
+ and a
+ jr z, .fail
+ call .safely_check_has_usable_move
+ jr c, .fail
+ dec hl
+.sample_move
+ push hl
+ call BattleRandom
+ maskbits NUM_MOVES
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hl]
+ pop hl
+ and a
+ jr z, .sample_move
+ ld e, a
+ ld a, BATTLE_VARS_MOVE_ANIM
+ call GetBattleVar
+ cp e
+ jr z, .sample_move
+ ld a, e
+ cp d
+ jr z, .sample_move
+ call .check_two_turn_move
+ jr z, .sample_move
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVarAddr
+ ld a, e
+ ld [hl], a
+ call CheckUserIsCharging
+ jr nz, .charging
+ ld a, [wKickCounter]
+ push af
+ call BattleCommand_LowerSub
+ pop af
+ ld [wKickCounter], a
+.charging
+ call LoadMoveAnim
+ call UpdateMoveData
+ jp ResetTurn
+
+.fail
+ call AnimateFailedMove
+ jp TryPrintButItFailed
+
+.safely_check_has_usable_move
+ push hl
+ push de
+ push bc
+ call .check_has_usable_move
+ pop bc
+ pop de
+ pop hl
+ ret
+
+.check_has_usable_move
+ ldh a, [hBattleTurn]
+ and a
+ ld a, [wDisabledMove]
+ jr z, .got_move_2
+
+ ld a, [wEnemyDisabledMove]
+.got_move_2
+ ld b, a
+ ld a, BATTLE_VARS_MOVE
+ call GetBattleVar
+ ld c, a
+ dec hl
+ ld d, NUM_MOVES
+.loop2
+ ld a, [hl]
+ and a
+ jr z, .carry
+
+ cp c
+ jr z, .nope
+ cp b
+ jr z, .nope
+
+ call .check_two_turn_move
+ jr nz, .no_carry
+
+.nope
+ inc hl
+ dec d
+ jr nz, .loop2
+
+.carry
+ scf
+ ret
+
+.no_carry
+ and a
+ ret
+
+.check_two_turn_move
+ push hl
+ push de
+ push bc
+
+ ld b, a
+ callfar GetMoveEffect
+ ld a, b
+
+ pop bc
+ pop de
+ pop hl
+
+ cp EFFECT_SKULL_BASH
+ ret z
+ cp EFFECT_RAZOR_WIND
+ ret z
+ cp EFFECT_SKY_ATTACK
+ ret z
+ cp EFFECT_SOLARBEAM
+ ret z
+ cp EFFECT_FLY
+ ret z
+ cp EFFECT_BIDE
+ ret
diff --git a/engine/battle/move_effects/snore.asm b/engine/battle/move_effects/snore.asm
new file mode 100644
index 00000000..e2432c59
--- /dev/null
+++ b/engine/battle/move_effects/snore.asm
@@ -0,0 +1,11 @@
+BattleCommand_Snore:
+; snore
+ ld a, BATTLE_VARS_STATUS
+ call GetBattleVar
+ and SLP
+ ret nz
+ call ResetDamage
+ ld a, $1
+ ld [wAttackMissed], a
+ call FailMove
+ jp EndMoveEffect
diff --git a/engine/battle/move_effects/spite.asm b/engine/battle/move_effects/spite.asm
new file mode 100644
index 00000000..06627268
--- /dev/null
+++ b/engine/battle/move_effects/spite.asm
@@ -0,0 +1,86 @@
+BattleCommand_Spite:
+; spite
+
+ ld a, [wAttackMissed]
+ and a
+ jp nz, .failed
+ ld bc, PARTYMON_STRUCT_LENGTH ; ????
+ ld hl, wEnemyMonMoves
+ ldh a, [hBattleTurn]
+ and a
+ jr z, .got_moves
+ ld hl, wBattleMonMoves
+.got_moves
+ ld a, BATTLE_VARS_LAST_COUNTER_MOVE_OPP
+ call GetBattleVar
+ and a
+ jr z, .failed
+ cp STRUGGLE
+ jr z, .failed
+ ld b, a
+ ld c, -1
+.loop
+ inc c
+ ld a, [hli]
+ cp b
+ jr nz, .loop
+ ld [wNamedObjectIndexBuffer], a
+ dec hl
+ ld b, 0
+ push bc
+ ld c, wBattleMonPP - wBattleMonMoves
+ add hl, bc
+ pop bc
+ ld a, [hl]
+ and PP_MASK
+ jr z, .failed
+ push bc
+ call GetMoveName
+ ; lose 2-5 PP
+ call BattleRandom
+ and %11
+ inc a
+ inc a
+ ld b, a
+ ld a, [hl]
+ and PP_MASK
+ cp b
+ jr nc, .deplete_pp
+ ld b, a
+.deplete_pp
+ ld a, [hl]
+ sub b
+ ld [hl], a
+ push af
+ ld a, MON_PP
+ call OpponentPartyAttr
+ ld d, b
+ pop af
+ pop bc
+ add hl, bc
+ ld e, a
+ ld a, BATTLE_VARS_SUBSTATUS5_OPP
+ call GetBattleVar
+ bit SUBSTATUS_TRANSFORMED, a
+ jr nz, .transformed
+ ldh a, [hBattleTurn]
+ and a
+ jr nz, .not_wildmon
+ ld a, [wBattleMode]
+ dec a
+ jr nz, .not_wildmon
+ ld hl, wWildMonPP
+ add hl, bc
+.not_wildmon
+ ld [hl], e
+.transformed
+ push de
+ call AnimateCurrentMove
+ pop de
+ ld a, d
+ ld [wDeciramBuffer], a
+ ld hl, SpiteEffectText
+ jp StdBattleTextbox
+
+.failed
+ jp PrintDidntAffect2
diff --git a/engine/items/item_effects.asm b/engine/items/item_effects.asm
index 8d694eac..46713dfe 100755
--- a/engine/items/item_effects.asm
+++ b/engine/items/item_effects.asm
@@ -390,9 +390,9 @@ UltraBall: ; e926
ld [wBattleAnimParam], a
ld de, ANIM_THROW_POKE_BALL
ld a, e
- ld [wcf3e], a
+ ld [wFXAnimID], a
ld a, d
- ld [wcf3f], a
+ ld [wFXAnimID + 1], a
xor a
ldh [hBattleTurn], a
ld [wBuffer2], a
@@ -2537,9 +2537,9 @@ Functionf7e7: ; f7e7 (3:77e7)
call ReturnToBattle_UseBall
ld de, Start
ld a, e
- ld [wcf3e], a
+ ld [wFXAnimID], a
ld a, d
- ld [wcf3f], a
+ ld [wFXAnimID + 1], a
xor a
ld [wBattleAnimParam], a
ldh [hBattleTurn], a
diff --git a/main.asm b/main.asm
index 010e79b4..6d5e031e 100644
--- a/main.asm
+++ b/main.asm
@@ -279,67 +279,83 @@ SECTION "bankc", ROMX
SECTION "Effect Commands", ROMX
INCLUDE "engine/battle/effect_commands.asm"
-BattleCommand_Stab:
- dr $34822, $34918
-BattleCheckTypeMatchup::
- dr $34918, $34923
-CheckTypeMatchup::
- dr $34923, $3499e
-INCLUDE "engine/battle/ai/switch.asm"
- dr $34d01, $3503e
-
-BattleCommand_LowerSub:
- dr $3503e, $3514e
-BattleCommand_SwitchTurn:
- dr $3514e, $35155
-BattleCommand_RaiseSub:
- dr $35155, $353f5
-EndMoveEffect:
- dr $353f5, $3553d
-EnemyAttackDamage::
- dr $3553d, $3571e
-HitSelfInConfusion:
- dr $3571e, $35753
-BattleCommand_DamageCalc::
- dr $35753, $35868
-BattleCommand_ConstantDamage::
- dr $35868, $35e3c
-FarPlayBattleAnimation:
- dr $35e3c, $35e44
-PlayFXAnimID:
- dr $35e44, $35e58
-DoEnemyDamage:
- dr $35e58, $35eba
-DoPlayerDamage:
- dr $35eba, $35f7c
+
UpdateMoveData:
- dr $35f7c, $36313
+ dr $35f7c, $36201
+Defrost:
+ dr $36201, $36308
+BattleCommand_StatUp:
+ dr $36308, $36313
RaiseStat:
dr $36313, $364d7
BattleCommand_StatUpMessage:
dr $364d7, $3656b
BattleCommand_StatUpFailText:
- dr $3656b, $366f6
+ dr $3656b, $366ce
+BattleCommand_RaiseSubNoAnim:
+ dr $366ce, $366e2
+BattleCommand_LowerSubNoAnim:
+ dr $366e2, $366f6
CalcPlayerStats:
- dr $366f6, $378bd
-
+ dr $366f6, $3671c
+CalcEnemyStats:
+ dr $3671c, $36bcd
+CheckOpponentWentFirst:
+ dr $36bcd, $373dc
+
+ClearLastMove:
+ dr $373dc, $37441
+PrintDoesntAffect:
+ dr $37441, $37447
+PrintNothingHappened:
+ dr $37447, $3744d
+TryPrintButItFailed:
+ dr $3744d, $37452
+PrintButItFailed:
+ dr $37452, $37458
+FailMove:
+ dr $37458, $37464
+PrintDidntAffect:
+ dr $37464, $3746a
+PrintDidntAffect2:
+ dr $3746a, $3747c
+CheckSubstituteOpp:
+ dr $3747c, $3757a
+ResetTurn:
+ dr $3757a, $378bd
ResetFuryCutterCount:
dr $378bd, $378f4
CheckOppositeGender:
dr $378f4, $37e7d
GetUserItem:
- dr $37e7d, $37e9b
+ dr $37e7d, $37e8c
+GetOpponentItem:
+ dr $37e8c, $37e9b
GetItemHeldEffect:
- dr $37e9b, $37f3e
+ dr $37e9b, $37ecc
+AnimateCurrentMove:
+ dr $37ecc, $37f01
+LoadMoveAnim:
+ dr $37f01, $37f0f
+LoadAnim:
+ dr $37f0f, $37f3e
CallBattleCore:
- dr $37f3e, $37f4b
+ dr $37f3e, $37f42
+AnimateFailedMove:
+ dr $37f42, $37f4b
BattleCommand_MoveDelay:
- dr $37f4b, $37f6c
+ dr $37f4b, $37f57
+SkipToBattleCommand:
+ dr $37f57, $37f6c
GetMoveAttr:
- dr $37f6c, $37f86
+ dr $37f6c, $37f78
+GetMoveData:
+ dr $37f78, $37f86
GetMoveByte:
- dr $37f86, $37f99
+ dr $37f86, $37f92
+AppearUserLowerSub:
+ dr $37f92, $37f99
AppearUserRaiseSub:
dr $37f99, $37fa0
@@ -355,7 +371,9 @@ INCLUDE "engine/battle/read_trainer_party.asm"
SECTION "Battle Core", ROMX
dr $3c000, $3c551
FleeMons::
- dr $3c551, $3d39f
+ dr $3c551, $3c5a4
+GetMoveEffect:
+ dr $3c5a4, $3d39f
EnemySwitch:
dr $3d39f, $3d438
@@ -825,7 +843,11 @@ CheckMagikarpLength:
MagikarpHouseSign:
dr $fbdd6, $fbdf1
HiddenPowerDamage:
- dr $fbdf1, $fbf93
+ dr $fbdf1, $fbeaa
+DoWeatherModifiers:
+ dr $fbeaa, $fbf2b
+DoBadgeTypeBoosts:
+ dr $fbf2b, $fbf93
SECTION "bank3f", ROMX
nop
diff --git a/wram.asm b/wram.asm
index f9feb64b..97a827e2 100644
--- a/wram.asm
+++ b/wram.asm
@@ -1698,11 +1698,11 @@ wPlayerEncoreCount:: db ; cb54
wcb55:: ds 1 ; cb55
wPlayerFuryCutterCount:: db ; cb56
wcb57:: ds 1 ; cb57
-wcb58:: ds 1 ; cb58
+wEnemyRolloutCount:: db ; cb58
wEnemyConfuseCount:: db ; cb59
wEnemyToxicCount:: db ; cb5a
wEnemyDisableCount:: db ; cb5b
-wcb5c:: ds 1 ; cb5c
+wEnemyEncoreCount:: db ; cb5c
wEnemyPerishCount:: db ; cb5d
wEnemyFuryCutterCount:: db ; cb5e
wEnemyProtectCount:: db ; cb5f
@@ -1761,29 +1761,25 @@ wcb8e:: ds 1 ; cb8e
wcb8f:: ds 1 ; cb8f
wBattleScriptBufferAddress:: dw ; cb90
wTurnEnded:: db ; cb92
-wcb93:: ds 1 ; cb93
-wcb94:: ds 1 ; cb94
-wcb95:: ds 1 ; cb95
-wcb96:: ds 1 ; cb96
-wcb97:: ds 1 ; cb97
-wcb98:: ds 1 ; cb98
-wcb99:: ds 1 ; cb99
-wcb9a:: ds 1 ; cb9a
-wcb9b:: ds 1 ; cb9b
-wcb9c:: ds 1 ; cb9c
-wcb9d:: ds 1 ; cb9d
-wcb9e:: ds 1 ; cb9e
-wcb9f:: ds 1 ; cb9f
-wcba0:: ds 1 ; cba0
-wcba1:: ds 1 ; cba1
-wcba2:: ds 1 ; cba2
-wcba3:: ds 1 ; cba3
-wcba4:: ds 1 ; cba4
-wcba5:: ds 1 ; cba5
-wcba6:: ds 1 ; cba6
-wcba7:: ds 1 ; cba7
-wcba8:: ds 1 ; cba8
-wcba9:: ds 1 ; cba9
+
+ ds 1
+
+wPlayerStats:: ; cb94
+wPlayerAttack:: dw
+wPlayerDefense:: dw
+wPlayerSpeed:: dw
+wPlayerSpAtk:: dw
+wPlayerSpDef:: dw
+ ds 1
+
+wEnemyStats:: ; cb9f
+wEnemyAttack:: dw
+wEnemyDefense:: dw
+wEnemySpeed:: dw
+wEnemySpAtk:: dw
+wEnemySpDef:: dw
+ ds 1
+
wPlayerAtkLevel:: db ; cbaa
wPlayerDefLevel:: db ; cbab
wPlayerSpdLevel:: db ; cbac
@@ -1803,8 +1799,8 @@ wEnemyEvaLevel:: db ; cbb8
wEnemyTurnsTaken:: db ; cbba
wPlayerTurnsTaken:: db ; cbbb
wcbbc:: ds 1 ; cbbc
-wcbbd:: ds 1 ; cbbd
-wcbbe:: ds 1 ; cbbe
+wPlayerSubstituteHP:: db ; cbbd
+wEnemySubstituteHP:: db ; cbbe
wcbbf:: ds 1 ; cbbf
wcbc0:: ds 1 ; cbc0
wCurPlayerMove:: ds 1 ; cbc1
@@ -1882,9 +1878,9 @@ wcc05:: ds 1 ; cc05
wcc06:: ds 1 ; cc06
wcc07:: ds 1 ; cc07
wcc08:: ds 1 ; cc08
-wcc09:: ds 1 ; cc09
+wPlayerRageCounter:: db ; cc09
wEnemyRageCounter:: db ; cc0a
-wcc0b:: ds 1 ; cc0b
+wBeatUpHitAtLeastOnce:: db ; cc0b
wcc0c:: ds 1 ; cc0c
wcc0d:: ds 1 ; cc0d
wPlayerWrapCount:: db ; cc0e
@@ -2490,8 +2486,7 @@ wcf3a:: ds 1
wBoxAlignment:: db
wcf3c:: ds 1
wcf3d:: ds 1
-wcf3e:: ds 1
-wcf3f:: ds 1
+wFXAnimID:: dw
ENDU
wcf40:: ds 1 ; cf40
@@ -2864,8 +2859,8 @@ wBaseDexNo:: ; d120
wCurBaseData:: ; d120
wd120:: ds 1 ; d120
wd121:: ds 1 ; d121
-wd122:: ds 1 ; d122
-wd123:: ds 1 ; d123
+wBaseAttack:: db ; d122
+wBaseDefense:: db ; d123
wd124:: ds 1 ; d124
wd125:: ds 1 ; d125
wd126:: ds 1 ; d126