diff options
34 files changed, 11632 insertions, 1627 deletions
@@ -1,12 +1,52 @@ +# Build Red/Blue. Yellow is WIP. +roms := pokered.gbc pokeblue.gbc + + +.PHONY: all clean red blue yellow compare + +all: $(roms) +red: pokered.gbc +blue: pokeblue.gbc +yellow: pokeyellow.gbc + +versions := red blue yellow + + +# Header options for rgbfix. +dmg_opt = -jsv -k 01 -l 0x33 -m 0x13 -p 0 -r 03 +cgb_opt = -cjsv -k 01 -l 0x33 -m 0x1b -p 0 -r 03 + +red_opt = $(dmg_opt) -t "POKEMON RED" +blue_opt = $(dmg_opt) -t "POKEMON BLUE" +yellow_opt = $(cgb_opt) -t "POKEMON YELLOW" + + + +# If your default python is 3, you may want to change this to python27. PYTHON := python -MD5 := md5sum -c --quiet +# md5sum -c is used to compare rom hashes. The options may vary across platforms. +MD5 := md5sum -c --quiet + + +# The compare target is a shortcut to check that the build matches the original roms exactly. +# This is for contributors to make sure a change didn't affect the contents of the rom. +# More thorough comparison can be made by diffing the output of hexdump -C against both roms. +compare: + @$(MD5) roms.md5 + + +# Clear the default suffixes. .SUFFIXES: -.SUFFIXES: .asm .tx .o .gbc -.PHONY: all clean red blue yellow compare -.PRECIOUS: %.2bpp +.SUFFIXES: .asm .tx .o .gbc .png .2bpp .1bpp .pic + +# Secondary expansion is required for dependency variables in object rules. .SECONDEXPANSION: +# Suppress annoying intermediate file deletion messages. +.PRECIOUS: %.2bpp + +# Filepath shortcuts to avoid overly long recipes. poketools := extras/pokemontools gfx := $(PYTHON) $(poketools)/gfx.py pic := $(PYTHON) $(poketools)/pic.py @@ -14,8 +54,9 @@ includes := $(PYTHON) $(poketools)/scan_includes.py pre := $(PYTHON) prequeue.py -versions := red blue yellow +# Collect file dependencies for objects in red/, blue/ and yellow/. +# These aren't provided by rgbds by default, so we have to look for file includes ourselves. $(foreach ver, $(versions), \ $(eval $(ver)_asm := $(shell find $(ver) -iname '*.asm')) \ $(eval $(ver)_obj := $($(ver)_asm:.asm=.o)) \ @@ -26,25 +67,22 @@ $(foreach obj, $(all_obj), \ ) -roms := pokered.gbc pokeblue.gbc - -all: $(roms) -red: pokered.gbc -blue: pokeblue.gbc -yellow: pokeyellow.gbc - -compare: - @$(MD5) roms.md5 -clean: - rm -f $(roms) $(all_obj) - find . \( -iname '*.tx' -o -iname '*.1bpp' -o -iname '*.2bpp' -o -iname '*.pic' \) -exec rm {} + - +# Image files are added to a queue to reduce build time. They're converted when building parent objects. +%.png: ; +%.2bpp: %.png ; $(eval 2bppq += $<) @rm -f $@ +%.1bpp: %.png ; $(eval 1bppq += $<) @rm -f $@ +%.pic: %.2bpp ; $(eval picq += $<) @rm -f $@ +# Source files are not fed directly into rgbasm. +# A python preprocessor runs over them first, replacing ascii strings with correct character codes. +# It spits out the new file with extension .tx. +# The text preprocessor also uses a queue. %.asm: ; -%.tx: %.asm - $(eval txq += $<) - @rm -f $@ +%.tx: %.asm ; $(eval txq += $<) @rm -f $@ +# Assemble source files into objects. +# Queue payloads are here. These are made silent since there may be hundreds of targets. +# Use rgbasm -h to use halts without nops. $(all_obj): $$*.tx $$(patsubst %.asm, %.tx, $$($$*_dep)) @$(pre) $(txq); $(eval txq :=) @$(gfx) 2bpp $(2bppq); $(eval 2bppq :=) @@ -53,29 +91,16 @@ $(all_obj): $$*.tx $$(patsubst %.asm, %.tx, $$($$*_dep)) rgbasm -h -o $@ $*.tx -link = rgblink -n $*.sym -m $*.map -dmg_opt := -jsv -k 01 -l 0x33 -m 0x13 -p 0 -r 03 -cgb_opt := -cjsv -k 01 -l 0x33 -m 0x1b -p 0 -r 03 +# Link objects together to build a rom. -pokered.gbc: $(red_obj) - $(link) -o $@ $^ - rgbfix $(dmg_opt) -t "POKEMON RED" $@ +# Make a symfile for debugging. rgblink will segfault if a mapfile isn't made too. +link = rgblink -n poke$*.sym -m poke$*.map -pokeblue.gbc: $(blue_obj) +poke%.gbc: $$(%_obj) $(link) -o $@ $^ - rgbfix $(dmg_opt) -t "POKEMON BLUE" $@ + rgbfix $($*_opt) $@ -pokeyellow.gbc: $(yellow_obj) - $(link) -o $@ $^ - rgbfix $(cgb_opt) -t "POKEMON YELLOW" $@ - - -%.2bpp: %.png - $(eval 2bppq += $<) - @rm -f $@ -%.1bpp: %.png - $(eval 1bppq += $<) - @rm -f $@ -%.pic: %.2bpp - $(eval picq += $<) - @rm -f $@ + +clean: + rm -f $(roms) $(all_obj) + find . \( -iname '*.tx' -o -iname '*.1bpp' -o -iname '*.2bpp' -o -iname '*.pic' \) -exec rm {} + diff --git a/constants/misc_constants.asm b/constants/misc_constants.asm index 65144c1e..b864ab85 100644 --- a/constants/misc_constants.asm +++ b/constants/misc_constants.asm @@ -1,12 +1,3 @@ -A_BUTTON EQU %00000001 -B_BUTTON EQU %00000010 -SELECT EQU %00000100 -START EQU %00001000 -D_RIGHT EQU %00010000 -D_LEFT EQU %00100000 -D_UP EQU %01000000 -D_DOWN EQU %10000000 - MAX_LEVEL EQU 100 NUM_MOVES EQU 4 @@ -19,6 +10,19 @@ HOF_MON EQU $10 HOF_TEAM EQU PARTY_LENGTH * HOF_MON NUM_HOF_TEAMS EQU 50 + +A_BUTTON EQU %00000001 +B_BUTTON EQU %00000010 +SELECT EQU %00000100 +START EQU %00001000 +D_RIGHT EQU %00010000 +D_LEFT EQU %00100000 +D_UP EQU %01000000 +D_DOWN EQU %10000000 + +SCREEN_WIDTH EQU 20 +SCREEN_HEIGHT EQU 18 + NPC_MOVEMENT_DOWN EQU $00 NPC_MOVEMENT_UP EQU $40 NPC_MOVEMENT_LEFT EQU $80 diff --git a/constants/move_constants.asm b/constants/move_constants.asm index 816bd115..0899c594 100644 --- a/constants/move_constants.asm +++ b/constants/move_constants.asm @@ -1,184 +1,210 @@ -NUM_ATTACKS EQU $A4 +const_value = 1 -POUND EQU $01 -KARATE_CHOP EQU $02 -DOUBLESLAP EQU $03 -COMET_PUNCH EQU $04 -MEGA_PUNCH EQU $05 -PAY_DAY EQU $06 -FIRE_PUNCH EQU $07 -ICE_PUNCH EQU $08 -THUNDERPUNCH EQU $09 -SCRATCH EQU $0A -VICEGRIP EQU $0B -GUILLOTINE EQU $0C -RAZOR_WIND EQU $0D -SWORDS_DANCE EQU $0E -CUT EQU $0F -GUST EQU $10 -WING_ATTACK EQU $11 -WHIRLWIND EQU $12 -FLY EQU $13 -BIND EQU $14 -SLAM EQU $15 -VINE_WHIP EQU $16 -STOMP EQU $17 -DOUBLE_KICK EQU $18 -MEGA_KICK EQU $19 -JUMP_KICK EQU $1A -ROLLING_KICK EQU $1B -SAND_ATTACK EQU $1C -HEADBUTT EQU $1D -HORN_ATTACK EQU $1E -FURY_ATTACK EQU $1F -HORN_DRILL EQU $20 -TACKLE EQU $21 -BODY_SLAM EQU $22 -WRAP EQU $23 -TAKE_DOWN EQU $24 -THRASH EQU $25 -DOUBLE_EDGE EQU $26 -TAIL_WHIP EQU $27 -POISON_STING EQU $28 -TWINEEDLE EQU $29 -PIN_MISSILE EQU $2A -LEER EQU $2B -BITE EQU $2C -GROWL EQU $2D -ROAR EQU $2E -SING EQU $2F -SUPERSONIC EQU $30 -SONICBOOM EQU $31 -DISABLE EQU $32 -ACID EQU $33 -EMBER EQU $34 -FLAMETHROWER EQU $35 -MIST EQU $36 -WATER_GUN EQU $37 -HYDRO_PUMP EQU $38 -SURF EQU $39 -ICE_BEAM EQU $3A -BLIZZARD EQU $3B -PSYBEAM EQU $3C -BUBBLEBEAM EQU $3D -AURORA_BEAM EQU $3E -HYPER_BEAM EQU $3F -PECK EQU $40 -DRILL_PECK EQU $41 -SUBMISSION EQU $42 -LOW_KICK EQU $43 -COUNTER EQU $44 -SEISMIC_TOSS EQU $45 -STRENGTH EQU $46 -ABSORB EQU $47 -MEGA_DRAIN EQU $48 -LEECH_SEED EQU $49 -GROWTH EQU $4A -RAZOR_LEAF EQU $4B -SOLARBEAM EQU $4C -POISONPOWDER EQU $4D -STUN_SPORE EQU $4E -SLEEP_POWDER EQU $4F -PETAL_DANCE EQU $50 -STRING_SHOT EQU $51 -DRAGON_RAGE EQU $52 -FIRE_SPIN EQU $53 -THUNDERSHOCK EQU $54 -THUNDERBOLT EQU $55 -THUNDER_WAVE EQU $56 -THUNDER EQU $57 -ROCK_THROW EQU $58 -EARTHQUAKE EQU $59 -FISSURE EQU $5A -DIG EQU $5B -TOXIC EQU $5C -CONFUSION EQU $5D -PSYCHIC_M EQU $5E -HYPNOSIS EQU $5F -MEDITATE EQU $60 -AGILITY EQU $61 -QUICK_ATTACK EQU $62 -RAGE EQU $63 -TELEPORT EQU $64 -NIGHT_SHADE EQU $65 -MIMIC EQU $66 -SCREECH EQU $67 -DOUBLE_TEAM EQU $68 -RECOVER EQU $69 -HARDEN EQU $6A -MINIMIZE EQU $6B -SMOKESCREEN EQU $6C -CONFUSE_RAY EQU $6D -WITHDRAW EQU $6E -DEFENSE_CURL EQU $6F -BARRIER EQU $70 -LIGHT_SCREEN EQU $71 -HAZE EQU $72 -REFLECT EQU $73 -FOCUS_ENERGY EQU $74 -BIDE EQU $75 -METRONOME EQU $76 -MIRROR_MOVE EQU $77 -SELFDESTRUCT EQU $78 -EGG_BOMB EQU $79 -LICK EQU $7A -SMOG EQU $7B -SLUDGE EQU $7C -BONE_CLUB EQU $7D -FIRE_BLAST EQU $7E -WATERFALL EQU $7F -CLAMP EQU $80 -SWIFT EQU $81 -SKULL_BASH EQU $82 -SPIKE_CANNON EQU $83 -CONSTRICT EQU $84 -AMNESIA EQU $85 -KINESIS EQU $86 -SOFTBOILED EQU $87 -HI_JUMP_KICK EQU $88 -GLARE EQU $89 -DREAM_EATER EQU $8A -POISON_GAS EQU $8B -BARRAGE EQU $8C -LEECH_LIFE EQU $8D -LOVELY_KISS EQU $8E -SKY_ATTACK EQU $8F -TRANSFORM EQU $90 -BUBBLE EQU $91 -DIZZY_PUNCH EQU $92 -SPORE EQU $93 -FLASH EQU $94 -PSYWAVE EQU $95 -SPLASH EQU $96 -ACID_ARMOR EQU $97 -CRABHAMMER EQU $98 -EXPLOSION EQU $99 -FURY_SWIPES EQU $9A -BONEMERANG EQU $9B -REST EQU $9C -ROCK_SLIDE EQU $9D -HYPER_FANG EQU $9E -SHARPEN EQU $9F -CONVERSION EQU $A0 -TRI_ATTACK EQU $A1 -SUPER_FANG EQU $A2 -SLASH EQU $A3 -SUBSTITUTE EQU $A4 -STRUGGLE EQU $A5 + const POUND + const KARATE_CHOP + const DOUBLESLAP + const COMET_PUNCH + const MEGA_PUNCH + const PAY_DAY + const FIRE_PUNCH + const ICE_PUNCH + const THUNDERPUNCH + const SCRATCH + const VICEGRIP + const GUILLOTINE + const RAZOR_WIND + const SWORDS_DANCE + const CUT + const GUST + const WING_ATTACK + const WHIRLWIND + const FLY + const BIND + const SLAM + const VINE_WHIP + const STOMP + const DOUBLE_KICK + const MEGA_KICK + const JUMP_KICK + const ROLLING_KICK + const SAND_ATTACK + const HEADBUTT + const HORN_ATTACK + const FURY_ATTACK + const HORN_DRILL + const TACKLE + const BODY_SLAM + const WRAP + const TAKE_DOWN + const THRASH + const DOUBLE_EDGE + const TAIL_WHIP + const POISON_STING + const TWINEEDLE + const PIN_MISSILE + const LEER + const BITE + const GROWL + const ROAR + const SING + const SUPERSONIC + const SONICBOOM + const DISABLE + const ACID + const EMBER + const FLAMETHROWER + const MIST + const WATER_GUN + const HYDRO_PUMP + const SURF + const ICE_BEAM + const BLIZZARD + const PSYBEAM + const BUBBLEBEAM + const AURORA_BEAM + const HYPER_BEAM + const PECK + const DRILL_PECK + const SUBMISSION + const LOW_KICK + const COUNTER + const SEISMIC_TOSS + const STRENGTH + const ABSORB + const MEGA_DRAIN + const LEECH_SEED + const GROWTH + const RAZOR_LEAF + const SOLARBEAM + const POISONPOWDER + const STUN_SPORE + const SLEEP_POWDER + const PETAL_DANCE + const STRING_SHOT + const DRAGON_RAGE + const FIRE_SPIN + const THUNDERSHOCK + const THUNDERBOLT + const THUNDER_WAVE + const THUNDER + const ROCK_THROW + const EARTHQUAKE + const FISSURE + const DIG + const TOXIC + const CONFUSION + const PSYCHIC_M + const HYPNOSIS + const MEDITATE + const AGILITY + const QUICK_ATTACK + const RAGE + const TELEPORT + const NIGHT_SHADE + const MIMIC + const SCREECH + const DOUBLE_TEAM + const RECOVER + const HARDEN + const MINIMIZE + const SMOKESCREEN + const CONFUSE_RAY + const WITHDRAW + const DEFENSE_CURL + const BARRIER + const LIGHT_SCREEN + const HAZE + const REFLECT + const FOCUS_ENERGY + const BIDE + const METRONOME + const MIRROR_MOVE + const SELFDESTRUCT + const EGG_BOMB + const LICK + const SMOG + const SLUDGE + const BONE_CLUB + const FIRE_BLAST + const WATERFALL + const CLAMP + const SWIFT + const SKULL_BASH + const SPIKE_CANNON + const CONSTRICT + const AMNESIA + const KINESIS + const SOFTBOILED + const HI_JUMP_KICK + const GLARE + const DREAM_EATER + const POISON_GAS + const BARRAGE + const LEECH_LIFE + const LOVELY_KISS + const SKY_ATTACK + const TRANSFORM + const BUBBLE + const DIZZY_PUNCH + const SPORE + const FLASH + const PSYWAVE + const SPLASH + const ACID_ARMOR + const CRABHAMMER + const EXPLOSION + const FURY_SWIPES + const BONEMERANG + const REST + const ROCK_SLIDE + const HYPER_FANG + const SHARPEN + const CONVERSION + const TRI_ATTACK + const SUPER_FANG + const SLASH + const SUBSTITUTE -; these do double duty as animation identifiers -SHOWPIC_ANIM EQU $A6 ; redraw monster pic -STATUS_AFFECTED_ANIM EQU $A7 ; effect when monster receives a status aliment -XSTATITEM_ANIM EQU $AE ; use X Attack/Defense/Speed/Special -BURN_PSN_ANIM EQU $BA ; Plays when a monster is burned or poisoned -SLP_ANIM EQU $BD ; sleeping monster -CONF_ANIM EQU $BF ; confused monster -TOSS_ANIM EQU $C1 ; toss Poké Ball -SHAKE_ANIM EQU $C2 ; shaking Poké Ball when catching monster -POOF_ANIM EQU $C3 ; puff of smoke -BLOCKBALL_ANIM EQU $C4 ; trainer knocks away Poké Ball -GREATTOSS_ANIM EQU $C5 ; toss Great Ball -ULTRATOSS_ANIM EQU $C6 ; toss Ultra Ball or Master Ball -HIDEPIC_ANIM EQU $C8 ; monster disappears -ROCK_ANIM EQU $C9 ; throw rock -BAIT_ANIM EQU $CA ; throw bait +NUM_ATTACKS EQU const_value + -1 + + const STRUGGLE + + ; Moves do double duty as animation identifiers. + + const SHOWPIC_ANIM + const STATUS_AFFECTED_ANIM + const ANIM_A8 + const ANIM_A9 + const ANIM_AA + const ANIM_AB + const ANIM_AC + const ANIM_AD + const XSTATITEM_ANIM ; use X Attack/Defense/Speed/Special + const ANIM_AF + const ANIM_B0 + const ANIM_B1 + const ANIM_B2 + const ANIM_B3 + const ANIM_B4 + const ANIM_B5 + const ANIM_B6 + const ANIM_B7 + const ANIM_B8 + const ANIM_B9 + const BURN_PSN_ANIM ; Plays when a monster is burned or poisoned + const ANIM_BB + const ANIM_BC + const SLP_ANIM ; sleeping monster + const ANIM_BE + const CONF_ANIM ; confused monster + const ANIM_C0 + const TOSS_ANIM ; toss Poké Ball + const SHAKE_ANIM ; shaking Poké Ball when catching monster + const POOF_ANIM ; puff of smoke + const BLOCKBALL_ANIM ; trainer knocks away Poké Ball + const GREATTOSS_ANIM ; toss Great Ball + const ULTRATOSS_ANIM ; toss Ultra Ball or Master Ball + const ANIM_C7 + const HIDEPIC_ANIM ; monster disappears + const ROCK_ANIM ; throw rock + const BAIT_ANIM ; throw bait diff --git a/data/moves.asm b/data/moves.asm index 08da533d..22165b7d 100755 --- a/data/moves.asm +++ b/data/moves.asm @@ -1,168 +1,177 @@ -Moves: ; 38000 (e:4000) -; characteristics of each move -; animation, effect, power, type, accuracy, PP - db POUND ,NO_ADDITIONAL_EFFECT ,$28,NORMAL, $FF,35 - db KARATE_CHOP ,NO_ADDITIONAL_EFFECT ,$32,NORMAL, $FF,25 - db DOUBLESLAP ,TWO_TO_FIVE_ATTACKS_EFFECT,$0F,NORMAL, $D8,10 - db COMET_PUNCH ,TWO_TO_FIVE_ATTACKS_EFFECT,$12,NORMAL, $D8,15 - db MEGA_PUNCH ,NO_ADDITIONAL_EFFECT ,$50,NORMAL, $D8,20 - db PAY_DAY ,PAY_DAY_EFFECT ,$28,NORMAL, $FF,20 - db FIRE_PUNCH ,BURN_SIDE_EFFECT1 ,$4B,FIRE, $FF,15 - db ICE_PUNCH ,FREEZE_SIDE_EFFECT ,$4B,ICE, $FF,15 - db THUNDERPUNCH,PARALYZE_SIDE_EFFECT1 ,$4B,ELECTRIC,$FF,15 - db SCRATCH ,NO_ADDITIONAL_EFFECT ,$28,NORMAL, $FF,35 - db VICEGRIP ,NO_ADDITIONAL_EFFECT ,$37,NORMAL, $FF,30 - db GUILLOTINE ,OHKO_EFFECT ,$01,NORMAL, $4C,5 - db RAZOR_WIND ,CHARGE_EFFECT ,$50,NORMAL, $BF,10 - db SWORDS_DANCE,ATTACK_UP2_EFFECT ,$00,NORMAL, $FF,30 - db CUT ,NO_ADDITIONAL_EFFECT ,$32,NORMAL, $F2,30 - db GUST ,NO_ADDITIONAL_EFFECT ,$28,NORMAL, $FF,35 - db WING_ATTACK ,NO_ADDITIONAL_EFFECT ,$23,FLYING, $FF,35 - db WHIRLWIND ,SWITCH_AND_TELEPORT_EFFECT,$00,NORMAL, $D8,20 - db FLY ,FLY_EFFECT ,$46,FLYING, $F2,15 - db BIND ,TRAPPING_EFFECT ,$0F,NORMAL, $BF,20 - db SLAM ,NO_ADDITIONAL_EFFECT ,$50,NORMAL, $BF,20 - db VINE_WHIP ,NO_ADDITIONAL_EFFECT ,$23,GRASS, $FF,10 - db STOMP ,FLINCH_SIDE_EFFECT2 ,$41,NORMAL, $FF,20 - db DOUBLE_KICK ,ATTACK_TWICE_EFFECT ,$1E,FIGHTING,$FF,30 - db MEGA_KICK ,NO_ADDITIONAL_EFFECT ,$78,NORMAL, $BF,5 - db JUMP_KICK ,JUMP_KICK_EFFECT ,$46,FIGHTING,$F2,25 - db ROLLING_KICK,FLINCH_SIDE_EFFECT2 ,$3C,FIGHTING,$D8,15 - db SAND_ATTACK ,ACCURACY_DOWN1_EFFECT ,$00,NORMAL, $FF,15 - db HEADBUTT ,FLINCH_SIDE_EFFECT2 ,$46,NORMAL, $FF,15 - db HORN_ATTACK ,NO_ADDITIONAL_EFFECT ,$41,NORMAL, $FF,25 - db FURY_ATTACK ,TWO_TO_FIVE_ATTACKS_EFFECT,$0F,NORMAL, $D8,20 - db HORN_DRILL ,OHKO_EFFECT ,$01,NORMAL, $4C,5 - db TACKLE ,NO_ADDITIONAL_EFFECT ,$23,NORMAL, $F2,35 - db BODY_SLAM ,PARALYZE_SIDE_EFFECT2 ,$55,NORMAL, $FF,15 - db WRAP ,TRAPPING_EFFECT ,$0F,NORMAL, $D8,20 - db TAKE_DOWN ,RECOIL_EFFECT ,$5A,NORMAL, $D8,20 - db THRASH ,THRASH_PETAL_DANCE_EFFECT ,$5A,NORMAL, $FF,20 - db DOUBLE_EDGE ,RECOIL_EFFECT ,$64,NORMAL, $FF,15 - db TAIL_WHIP ,DEFENSE_DOWN1_EFFECT ,$00,NORMAL, $FF,30 - db POISON_STING,POISON_SIDE_EFFECT1 ,$0F,POISON, $FF,35 - db TWINEEDLE ,TWINEEDLE_EFFECT ,$19,BUG, $FF,20 - db PIN_MISSILE ,TWO_TO_FIVE_ATTACKS_EFFECT,$0E,BUG, $D8,20 - db LEER ,DEFENSE_DOWN1_EFFECT ,$00,NORMAL, $FF,30 - db BITE ,FLINCH_SIDE_EFFECT1 ,$3C,NORMAL, $FF,25 - db GROWL ,ATTACK_DOWN1_EFFECT ,$00,NORMAL, $FF,40 - db ROAR ,SWITCH_AND_TELEPORT_EFFECT,$00,NORMAL, $FF,20 - db SING ,SLEEP_EFFECT ,$00,NORMAL, $8C,15 - db SUPERSONIC ,CONFUSION_EFFECT ,$00,NORMAL, $8C,20 - db SONICBOOM ,SPECIAL_DAMAGE_EFFECT ,$01,NORMAL, $E5,20 - db DISABLE ,DISABLE_EFFECT ,$00,NORMAL, $8C,20 - db ACID ,DEFENSE_DOWN_SIDE_EFFECT ,$28,POISON, $FF,30 - db EMBER ,BURN_SIDE_EFFECT1 ,$28,FIRE, $FF,25 - db FLAMETHROWER,BURN_SIDE_EFFECT1 ,$5F,FIRE, $FF,15 - db MIST ,MIST_EFFECT ,$00,ICE, $FF,30 - db WATER_GUN ,NO_ADDITIONAL_EFFECT ,$28,WATER, $FF,25 - db HYDRO_PUMP ,NO_ADDITIONAL_EFFECT ,$78,WATER, $CC,5 - db SURF ,NO_ADDITIONAL_EFFECT ,$5F,WATER, $FF,15 - db ICE_BEAM ,FREEZE_SIDE_EFFECT ,$5F,ICE, $FF,10 - db BLIZZARD ,FREEZE_SIDE_EFFECT ,$78,ICE, $E5,5 - db PSYBEAM ,CONFUSION_SIDE_EFFECT ,$41,PSYCHIC, $FF,20 - db BUBBLEBEAM ,SPEED_DOWN_SIDE_EFFECT ,$41,WATER, $FF,20 - db AURORA_BEAM ,ATTACK_DOWN_SIDE_EFFECT ,$41,ICE, $FF,20 - db HYPER_BEAM ,HYPER_BEAM_EFFECT ,$96,NORMAL, $E5,5 - db PECK ,NO_ADDITIONAL_EFFECT ,$23,FLYING, $FF,35 - db DRILL_PECK ,NO_ADDITIONAL_EFFECT ,$50,FLYING, $FF,20 - db SUBMISSION ,RECOIL_EFFECT ,$50,FIGHTING,$CC,25 - db LOW_KICK ,FLINCH_SIDE_EFFECT2 ,$32,FIGHTING,$E5,20 - db COUNTER ,NO_ADDITIONAL_EFFECT ,$01,FIGHTING,$FF,20 - db SEISMIC_TOSS,SPECIAL_DAMAGE_EFFECT ,$01,FIGHTING,$FF,20 - db STRENGTH ,NO_ADDITIONAL_EFFECT ,$50,NORMAL, $FF,15 - db ABSORB ,DRAIN_HP_EFFECT ,$14,GRASS, $FF,20 - db MEGA_DRAIN ,DRAIN_HP_EFFECT ,$28,GRASS, $FF,10 - db LEECH_SEED ,LEECH_SEED_EFFECT ,$00,GRASS, $E5,10 - db GROWTH ,SPECIAL_UP1_EFFECT ,$00,NORMAL, $FF,40 - db RAZOR_LEAF ,NO_ADDITIONAL_EFFECT ,$37,GRASS, $F2,25 - db SOLARBEAM ,CHARGE_EFFECT ,$78,GRASS, $FF,10 - db POISONPOWDER,POISON_EFFECT ,$00,POISON, $BF,35 - db STUN_SPORE ,PARALYZE_EFFECT ,$00,GRASS, $BF,30 - db SLEEP_POWDER,SLEEP_EFFECT ,$00,GRASS, $BF,15 - db PETAL_DANCE ,THRASH_PETAL_DANCE_EFFECT ,$46,GRASS, $FF,20 - db STRING_SHOT ,SPEED_DOWN1_EFFECT ,$00,BUG, $F2,40 - db DRAGON_RAGE ,SPECIAL_DAMAGE_EFFECT ,$01,DRAGON, $FF,10 - db FIRE_SPIN ,TRAPPING_EFFECT ,$0F,FIRE, $B2,15 - db THUNDERSHOCK,PARALYZE_SIDE_EFFECT1 ,$28,ELECTRIC,$FF,30 - db THUNDERBOLT ,PARALYZE_SIDE_EFFECT1 ,$5F,ELECTRIC,$FF,15 - db THUNDER_WAVE,PARALYZE_EFFECT ,$00,ELECTRIC,$FF,20 - db THUNDER ,PARALYZE_SIDE_EFFECT1 ,$78,ELECTRIC,$B2,10 - db ROCK_THROW ,NO_ADDITIONAL_EFFECT ,$32,ROCK, $A5,15 - db EARTHQUAKE ,NO_ADDITIONAL_EFFECT ,$64,GROUND, $FF,10 - db FISSURE ,OHKO_EFFECT ,$01,GROUND, $4C,5 - db DIG ,CHARGE_EFFECT ,$64,GROUND, $FF,10 - db TOXIC ,POISON_EFFECT ,$00,POISON, $D8,10 - db CONFUSION ,CONFUSION_SIDE_EFFECT ,$32,PSYCHIC, $FF,25 - db PSYCHIC_M ,SPECIAL_DOWN_SIDE_EFFECT ,$5A,PSYCHIC, $FF,10 - db HYPNOSIS ,SLEEP_EFFECT ,$00,PSYCHIC, $99,20 - db MEDITATE ,ATTACK_UP1_EFFECT ,$00,PSYCHIC, $FF,40 - db AGILITY ,SPEED_UP2_EFFECT ,$00,PSYCHIC, $FF,30 - db QUICK_ATTACK,NO_ADDITIONAL_EFFECT ,$28,NORMAL, $FF,30 - db RAGE ,RAGE_EFFECT ,$14,NORMAL, $FF,20 - db TELEPORT ,SWITCH_AND_TELEPORT_EFFECT,$00,PSYCHIC, $FF,20 - db NIGHT_SHADE ,SPECIAL_DAMAGE_EFFECT ,$00,GHOST, $FF,15 - db MIMIC ,MIMIC_EFFECT ,$00,NORMAL, $FF,10 - db SCREECH ,DEFENSE_DOWN2_EFFECT ,$00,NORMAL, $D8,40 - db DOUBLE_TEAM ,EVASION_UP1_EFFECT ,$00,NORMAL, $FF,15 - db RECOVER ,HEAL_EFFECT ,$00,NORMAL, $FF,20 - db HARDEN ,DEFENSE_UP1_EFFECT ,$00,NORMAL, $FF,30 - db MINIMIZE ,EVASION_UP1_EFFECT ,$00,NORMAL, $FF,20 - db SMOKESCREEN ,ACCURACY_DOWN1_EFFECT ,$00,NORMAL, $FF,20 - db CONFUSE_RAY ,CONFUSION_EFFECT ,$00,GHOST, $FF,10 - db WITHDRAW ,DEFENSE_UP1_EFFECT ,$00,WATER, $FF,40 - db DEFENSE_CURL,DEFENSE_UP1_EFFECT ,$00,NORMAL, $FF,40 - db BARRIER ,DEFENSE_UP2_EFFECT ,$00,PSYCHIC, $FF,30 - db LIGHT_SCREEN,LIGHT_SCREEN_EFFECT ,$00,PSYCHIC, $FF,30 - db HAZE ,HAZE_EFFECT ,$00,ICE, $FF,30 - db REFLECT ,REFLECT_EFFECT ,$00,PSYCHIC, $FF,20 - db FOCUS_ENERGY,FOCUS_ENERGY_EFFECT ,$00,NORMAL, $FF,30 - db BIDE ,BIDE_EFFECT ,$00,NORMAL, $FF,10 - db METRONOME ,METRONOME_EFFECT ,$00,NORMAL, $FF,10 - db MIRROR_MOVE ,MIRROR_MOVE_EFFECT ,$00,FLYING, $FF,20 - db SELFDESTRUCT,EXPLODE_EFFECT ,$82,NORMAL, $FF,5 - db EGG_BOMB ,NO_ADDITIONAL_EFFECT ,$64,NORMAL, $BF,10 - db LICK ,PARALYZE_SIDE_EFFECT2 ,$14,GHOST, $FF,30 - db SMOG ,POISON_SIDE_EFFECT2 ,$14,POISON, $B2,20 - db SLUDGE ,POISON_SIDE_EFFECT2 ,$41,POISON, $FF,20 - db BONE_CLUB ,FLINCH_SIDE_EFFECT1 ,$41,GROUND, $D8,20 - db FIRE_BLAST ,BURN_SIDE_EFFECT2 ,$78,FIRE, $D8,5 - db WATERFALL ,NO_ADDITIONAL_EFFECT ,$50,WATER, $FF,15 - db CLAMP ,TRAPPING_EFFECT ,$23,WATER, $BF,10 - db SWIFT ,SWIFT_EFFECT ,$3C,NORMAL, $FF,20 - db SKULL_BASH ,CHARGE_EFFECT ,$64,NORMAL, $FF,15 - db SPIKE_CANNON,TWO_TO_FIVE_ATTACKS_EFFECT,$14,NORMAL, $FF,15 - db CONSTRICT ,SPEED_DOWN_SIDE_EFFECT ,$0A,NORMAL, $FF,35 - db AMNESIA ,SPECIAL_UP2_EFFECT ,$00,PSYCHIC, $FF,20 - db KINESIS ,ACCURACY_DOWN1_EFFECT ,$00,PSYCHIC, $CC,15 - db SOFTBOILED ,HEAL_EFFECT ,$00,NORMAL, $FF,10 - db HI_JUMP_KICK,JUMP_KICK_EFFECT ,$55,FIGHTING,$E5,20 - db GLARE ,PARALYZE_EFFECT ,$00,NORMAL, $BF,30 - db DREAM_EATER ,DREAM_EATER_EFFECT ,$64,PSYCHIC, $FF,15 - db POISON_GAS ,POISON_EFFECT ,$00,POISON, $8C,40 - db BARRAGE ,TWO_TO_FIVE_ATTACKS_EFFECT,$0F,NORMAL, $D8,20 - db LEECH_LIFE ,DRAIN_HP_EFFECT ,$14,BUG, $FF,15 - db LOVELY_KISS ,SLEEP_EFFECT ,$00,NORMAL, $BF,10 - db SKY_ATTACK ,CHARGE_EFFECT ,$8C,FLYING, $E5,5 - db TRANSFORM ,TRANSFORM_EFFECT ,$00,NORMAL, $FF,10 - db BUBBLE ,SPEED_DOWN_SIDE_EFFECT ,$14,WATER, $FF,30 - db DIZZY_PUNCH ,NO_ADDITIONAL_EFFECT ,$46,NORMAL, $FF,10 - db SPORE ,SLEEP_EFFECT ,$00,GRASS, $FF,15 - db FLASH ,ACCURACY_DOWN1_EFFECT ,$00,NORMAL, $B2,20 - db PSYWAVE ,SPECIAL_DAMAGE_EFFECT ,$01,PSYCHIC, $CC,15 - db SPLASH ,SPLASH_EFFECT ,$00,NORMAL, $FF,40 - db ACID_ARMOR ,DEFENSE_UP2_EFFECT ,$00,POISON, $FF,40 - db CRABHAMMER ,NO_ADDITIONAL_EFFECT ,$5A,WATER, $D8,10 - db EXPLOSION ,EXPLODE_EFFECT ,$AA,NORMAL, $FF,5 - db FURY_SWIPES ,TWO_TO_FIVE_ATTACKS_EFFECT,$12,NORMAL, $CC,15 - db BONEMERANG ,ATTACK_TWICE_EFFECT ,$32,GROUND, $E5,10 - db REST ,HEAL_EFFECT ,$00,PSYCHIC, $FF,10 - db ROCK_SLIDE ,NO_ADDITIONAL_EFFECT ,$4B,ROCK, $E5,10 - db HYPER_FANG ,FLINCH_SIDE_EFFECT1 ,$50,NORMAL, $E5,15 - db SHARPEN ,ATTACK_UP1_EFFECT ,$00,NORMAL, $FF,30 - db CONVERSION ,CONVERSION_EFFECT ,$00,NORMAL, $FF,30 - db TRI_ATTACK ,NO_ADDITIONAL_EFFECT ,$50,NORMAL, $FF,10 - db SUPER_FANG ,SUPER_FANG_EFFECT ,$01,NORMAL, $E5,10 - db SLASH ,NO_ADDITIONAL_EFFECT ,$46,NORMAL, $FF,20 - db SUBSTITUTE ,SUBSTITUTE_EFFECT ,$00,NORMAL, $FF,10 - db STRUGGLE ,RECOIL_EFFECT ,$32,NORMAL, $FF,10 +Moves: +; Characteristics of each move. + +move: macro + db \1 ; animation (interchangeable with move id) + db \2 ; effect + db \3 ; power + db \4 ; type + db \5 percent ; accuracy + db \6 ; pp +endm + + move POUND, NO_ADDITIONAL_EFFECT, 40, NORMAL, 100, 35 + move KARATE_CHOP, NO_ADDITIONAL_EFFECT, 50, NORMAL, 100, 25 + move DOUBLESLAP, TWO_TO_FIVE_ATTACKS_EFFECT, 15, NORMAL, 85, 10 + move COMET_PUNCH, TWO_TO_FIVE_ATTACKS_EFFECT, 18, NORMAL, 85, 15 + move MEGA_PUNCH, NO_ADDITIONAL_EFFECT, 80, NORMAL, 85, 20 + move PAY_DAY, PAY_DAY_EFFECT, 40, NORMAL, 100, 20 + move FIRE_PUNCH, BURN_SIDE_EFFECT1, 75, FIRE, 100, 15 + move ICE_PUNCH, FREEZE_SIDE_EFFECT, 75, ICE, 100, 15 + move THUNDERPUNCH, PARALYZE_SIDE_EFFECT1, 75, ELECTRIC, 100, 15 + move SCRATCH, NO_ADDITIONAL_EFFECT, 40, NORMAL, 100, 35 + move VICEGRIP, NO_ADDITIONAL_EFFECT, 55, NORMAL, 100, 30 + move GUILLOTINE, OHKO_EFFECT, 1, NORMAL, 30, 5 + move RAZOR_WIND, CHARGE_EFFECT, 80, NORMAL, 75, 10 + move SWORDS_DANCE, ATTACK_UP2_EFFECT, 0, NORMAL, 100, 30 + move CUT, NO_ADDITIONAL_EFFECT, 50, NORMAL, 95, 30 + move GUST, NO_ADDITIONAL_EFFECT, 40, NORMAL, 100, 35 + move WING_ATTACK, NO_ADDITIONAL_EFFECT, 35, FLYING, 100, 35 + move WHIRLWIND, SWITCH_AND_TELEPORT_EFFECT, 0, NORMAL, 85, 20 + move FLY, FLY_EFFECT, 70, FLYING, 95, 15 + move BIND, TRAPPING_EFFECT, 15, NORMAL, 75, 20 + move SLAM, NO_ADDITIONAL_EFFECT, 80, NORMAL, 75, 20 + move VINE_WHIP, NO_ADDITIONAL_EFFECT, 35, GRASS, 100, 10 + move STOMP, FLINCH_SIDE_EFFECT2, 65, NORMAL, 100, 20 + move DOUBLE_KICK, ATTACK_TWICE_EFFECT, 30, FIGHTING, 100, 30 + move MEGA_KICK, NO_ADDITIONAL_EFFECT, 120, NORMAL, 75, 5 + move JUMP_KICK, JUMP_KICK_EFFECT, 70, FIGHTING, 95, 25 + move ROLLING_KICK, FLINCH_SIDE_EFFECT2, 60, FIGHTING, 85, 15 + move SAND_ATTACK, ACCURACY_DOWN1_EFFECT, 0, NORMAL, 100, 15 + move HEADBUTT, FLINCH_SIDE_EFFECT2, 70, NORMAL, 100, 15 + move HORN_ATTACK, NO_ADDITIONAL_EFFECT, 65, NORMAL, 100, 25 + move FURY_ATTACK, TWO_TO_FIVE_ATTACKS_EFFECT, 15, NORMAL, 85, 20 + move HORN_DRILL, OHKO_EFFECT, 1, NORMAL, 30, 5 + move TACKLE, NO_ADDITIONAL_EFFECT, 35, NORMAL, 95, 35 + move BODY_SLAM, PARALYZE_SIDE_EFFECT2, 85, NORMAL, 100, 15 + move WRAP, TRAPPING_EFFECT, 15, NORMAL, 85, 20 + move TAKE_DOWN, RECOIL_EFFECT, 90, NORMAL, 85, 20 + move THRASH, THRASH_PETAL_DANCE_EFFECT, 90, NORMAL, 100, 20 + move DOUBLE_EDGE, RECOIL_EFFECT, 100, NORMAL, 100, 15 + move TAIL_WHIP, DEFENSE_DOWN1_EFFECT, 0, NORMAL, 100, 30 + move POISON_STING, POISON_SIDE_EFFECT1, 15, POISON, 100, 35 + move TWINEEDLE, TWINEEDLE_EFFECT, 25, BUG, 100, 20 + move PIN_MISSILE, TWO_TO_FIVE_ATTACKS_EFFECT, 14, BUG, 85, 20 + move LEER, DEFENSE_DOWN1_EFFECT, 0, NORMAL, 100, 30 + move BITE, FLINCH_SIDE_EFFECT1, 60, NORMAL, 100, 25 + move GROWL, ATTACK_DOWN1_EFFECT, 0, NORMAL, 100, 40 + move ROAR, SWITCH_AND_TELEPORT_EFFECT, 0, NORMAL, 100, 20 + move SING, SLEEP_EFFECT, 0, NORMAL, 55, 15 + move SUPERSONIC, CONFUSION_EFFECT, 0, NORMAL, 55, 20 + move SONICBOOM, SPECIAL_DAMAGE_EFFECT, 1, NORMAL, 90, 20 + move DISABLE, DISABLE_EFFECT, 0, NORMAL, 55, 20 + move ACID, DEFENSE_DOWN_SIDE_EFFECT, 40, POISON, 100, 30 + move EMBER, BURN_SIDE_EFFECT1, 40, FIRE, 100, 25 + move FLAMETHROWER, BURN_SIDE_EFFECT1, 95, FIRE, 100, 15 + move MIST, MIST_EFFECT, 0, ICE, 100, 30 + move WATER_GUN, NO_ADDITIONAL_EFFECT, 40, WATER, 100, 25 + move HYDRO_PUMP, NO_ADDITIONAL_EFFECT, 120, WATER, 80, 5 + move SURF, NO_ADDITIONAL_EFFECT, 95, WATER, 100, 15 + move ICE_BEAM, FREEZE_SIDE_EFFECT, 95, ICE, 100, 10 + move BLIZZARD, FREEZE_SIDE_EFFECT, 120, ICE, 90, 5 + move PSYBEAM, CONFUSION_SIDE_EFFECT, 65, PSYCHIC, 100, 20 + move BUBBLEBEAM, SPEED_DOWN_SIDE_EFFECT, 65, WATER, 100, 20 + move AURORA_BEAM, ATTACK_DOWN_SIDE_EFFECT, 65, ICE, 100, 20 + move HYPER_BEAM, HYPER_BEAM_EFFECT, 150, NORMAL, 90, 5 + move PECK, NO_ADDITIONAL_EFFECT, 35, FLYING, 100, 35 + move DRILL_PECK, NO_ADDITIONAL_EFFECT, 80, FLYING, 100, 20 + move SUBMISSION, RECOIL_EFFECT, 80, FIGHTING, 80, 25 + move LOW_KICK, FLINCH_SIDE_EFFECT2, 50, FIGHTING, 90, 20 + move COUNTER, NO_ADDITIONAL_EFFECT, 1, FIGHTING, 100, 20 + move SEISMIC_TOSS, SPECIAL_DAMAGE_EFFECT, 1, FIGHTING, 100, 20 + move STRENGTH, NO_ADDITIONAL_EFFECT, 80, NORMAL, 100, 15 + move ABSORB, DRAIN_HP_EFFECT, 20, GRASS, 100, 20 + move MEGA_DRAIN, DRAIN_HP_EFFECT, 40, GRASS, 100, 10 + move LEECH_SEED, LEECH_SEED_EFFECT, 0, GRASS, 90, 10 + move GROWTH, SPECIAL_UP1_EFFECT, 0, NORMAL, 100, 40 + move RAZOR_LEAF, NO_ADDITIONAL_EFFECT, 55, GRASS, 95, 25 + move SOLARBEAM, CHARGE_EFFECT, 120, GRASS, 100, 10 + move POISONPOWDER, POISON_EFFECT, 0, POISON, 75, 35 + move STUN_SPORE, PARALYZE_EFFECT, 0, GRASS, 75, 30 + move SLEEP_POWDER, SLEEP_EFFECT, 0, GRASS, 75, 15 + move PETAL_DANCE, THRASH_PETAL_DANCE_EFFECT, 70, GRASS, 100, 20 + move STRING_SHOT, SPEED_DOWN1_EFFECT, 0, BUG, 95, 40 + move DRAGON_RAGE, SPECIAL_DAMAGE_EFFECT, 1, DRAGON, 100, 10 + move FIRE_SPIN, TRAPPING_EFFECT, 15, FIRE, 70, 15 + move THUNDERSHOCK, PARALYZE_SIDE_EFFECT1, 40, ELECTRIC, 100, 30 + move THUNDERBOLT, PARALYZE_SIDE_EFFECT1, 95, ELECTRIC, 100, 15 + move THUNDER_WAVE, PARALYZE_EFFECT, 0, ELECTRIC, 100, 20 + move THUNDER, PARALYZE_SIDE_EFFECT1, 120, ELECTRIC, 70, 10 + move ROCK_THROW, NO_ADDITIONAL_EFFECT, 50, ROCK, 65, 15 + move EARTHQUAKE, NO_ADDITIONAL_EFFECT, 100, GROUND, 100, 10 + move FISSURE, OHKO_EFFECT, 1, GROUND, 30, 5 + move DIG, CHARGE_EFFECT, 100, GROUND, 100, 10 + move TOXIC, POISON_EFFECT, 0, POISON, 85, 10 + move CONFUSION, CONFUSION_SIDE_EFFECT, 50, PSYCHIC, 100, 25 + move PSYCHIC_M, SPECIAL_DOWN_SIDE_EFFECT, 90, PSYCHIC, 100, 10 + move HYPNOSIS, SLEEP_EFFECT, 0, PSYCHIC, 60, 20 + move MEDITATE, ATTACK_UP1_EFFECT, 0, PSYCHIC, 100, 40 + move AGILITY, SPEED_UP2_EFFECT, 0, PSYCHIC, 100, 30 + move QUICK_ATTACK, NO_ADDITIONAL_EFFECT, 40, NORMAL, 100, 30 + move RAGE, RAGE_EFFECT, 20, NORMAL, 100, 20 + move TELEPORT, SWITCH_AND_TELEPORT_EFFECT, 0, PSYCHIC, 100, 20 + move NIGHT_SHADE, SPECIAL_DAMAGE_EFFECT, 0, GHOST, 100, 15 + move MIMIC, MIMIC_EFFECT, 0, NORMAL, 100, 10 + move SCREECH, DEFENSE_DOWN2_EFFECT, 0, NORMAL, 85, 40 + move DOUBLE_TEAM, EVASION_UP1_EFFECT, 0, NORMAL, 100, 15 + move RECOVER, HEAL_EFFECT, 0, NORMAL, 100, 20 + move HARDEN, DEFENSE_UP1_EFFECT, 0, NORMAL, 100, 30 + move MINIMIZE, EVASION_UP1_EFFECT, 0, NORMAL, 100, 20 + move SMOKESCREEN, ACCURACY_DOWN1_EFFECT, 0, NORMAL, 100, 20 + move CONFUSE_RAY, CONFUSION_EFFECT, 0, GHOST, 100, 10 + move WITHDRAW, DEFENSE_UP1_EFFECT, 0, WATER, 100, 40 + move DEFENSE_CURL, DEFENSE_UP1_EFFECT, 0, NORMAL, 100, 40 + move BARRIER, DEFENSE_UP2_EFFECT, 0, PSYCHIC, 100, 30 + move LIGHT_SCREEN, LIGHT_SCREEN_EFFECT, 0, PSYCHIC, 100, 30 + move HAZE, HAZE_EFFECT, 0, ICE, 100, 30 + move REFLECT, REFLECT_EFFECT, 0, PSYCHIC, 100, 20 + move FOCUS_ENERGY, FOCUS_ENERGY_EFFECT, 0, NORMAL, 100, 30 + move BIDE, BIDE_EFFECT, 0, NORMAL, 100, 10 + move METRONOME, METRONOME_EFFECT, 0, NORMAL, 100, 10 + move MIRROR_MOVE, MIRROR_MOVE_EFFECT, 0, FLYING, 100, 20 + move SELFDESTRUCT, EXPLODE_EFFECT, 130, NORMAL, 100, 5 + move EGG_BOMB, NO_ADDITIONAL_EFFECT, 100, NORMAL, 75, 10 + move LICK, PARALYZE_SIDE_EFFECT2, 20, GHOST, 100, 30 + move SMOG, POISON_SIDE_EFFECT2, 20, POISON, 70, 20 + move SLUDGE, POISON_SIDE_EFFECT2, 65, POISON, 100, 20 + move BONE_CLUB, FLINCH_SIDE_EFFECT1, 65, GROUND, 85, 20 + move FIRE_BLAST, BURN_SIDE_EFFECT2, 120, FIRE, 85, 5 + move WATERFALL, NO_ADDITIONAL_EFFECT, 80, WATER, 100, 15 + move CLAMP, TRAPPING_EFFECT, 35, WATER, 75, 10 + move SWIFT, SWIFT_EFFECT, 60, NORMAL, 100, 20 + move SKULL_BASH, CHARGE_EFFECT, 100, NORMAL, 100, 15 + move SPIKE_CANNON, TWO_TO_FIVE_ATTACKS_EFFECT, 20, NORMAL, 100, 15 + move CONSTRICT, SPEED_DOWN_SIDE_EFFECT, 10, NORMAL, 100, 35 + move AMNESIA, SPECIAL_UP2_EFFECT, 0, PSYCHIC, 100, 20 + move KINESIS, ACCURACY_DOWN1_EFFECT, 0, PSYCHIC, 80, 15 + move SOFTBOILED, HEAL_EFFECT, 0, NORMAL, 100, 10 + move HI_JUMP_KICK, JUMP_KICK_EFFECT, 85, FIGHTING, 90, 20 + move GLARE, PARALYZE_EFFECT, 0, NORMAL, 75, 30 + move DREAM_EATER, DREAM_EATER_EFFECT, 100, PSYCHIC, 100, 15 + move POISON_GAS, POISON_EFFECT, 0, POISON, 55, 40 + move BARRAGE, TWO_TO_FIVE_ATTACKS_EFFECT, 15, NORMAL, 85, 20 + move LEECH_LIFE, DRAIN_HP_EFFECT, 20, BUG, 100, 15 + move LOVELY_KISS, SLEEP_EFFECT, 0, NORMAL, 75, 10 + move SKY_ATTACK, CHARGE_EFFECT, 140, FLYING, 90, 5 + move TRANSFORM, TRANSFORM_EFFECT, 0, NORMAL, 100, 10 + move BUBBLE, SPEED_DOWN_SIDE_EFFECT, 20, WATER, 100, 30 + move DIZZY_PUNCH, NO_ADDITIONAL_EFFECT, 70, NORMAL, 100, 10 + move SPORE, SLEEP_EFFECT, 0, GRASS, 100, 15 + move FLASH, ACCURACY_DOWN1_EFFECT, 0, NORMAL, 70, 20 + move PSYWAVE, SPECIAL_DAMAGE_EFFECT, 1, PSYCHIC, 80, 15 + move SPLASH, SPLASH_EFFECT, 0, NORMAL, 100, 40 + move ACID_ARMOR, DEFENSE_UP2_EFFECT, 0, POISON, 100, 40 + move CRABHAMMER, NO_ADDITIONAL_EFFECT, 90, WATER, 85, 10 + move EXPLOSION, EXPLODE_EFFECT, 170, NORMAL, 100, 5 + move FURY_SWIPES, TWO_TO_FIVE_ATTACKS_EFFECT, 18, NORMAL, 80, 15 + move BONEMERANG, ATTACK_TWICE_EFFECT, 50, GROUND, 90, 10 + move REST, HEAL_EFFECT, 0, PSYCHIC, 100, 10 + move ROCK_SLIDE, NO_ADDITIONAL_EFFECT, 75, ROCK, 90, 10 + move HYPER_FANG, FLINCH_SIDE_EFFECT1, 80, NORMAL, 90, 15 + move SHARPEN, ATTACK_UP1_EFFECT, 0, NORMAL, 100, 30 + move CONVERSION, CONVERSION_EFFECT, 0, NORMAL, 100, 30 + move TRI_ATTACK, NO_ADDITIONAL_EFFECT, 80, NORMAL, 100, 10 + move SUPER_FANG, SUPER_FANG_EFFECT, 1, NORMAL, 90, 10 + move SLASH, NO_ADDITIONAL_EFFECT, 70, NORMAL, 100, 20 + move SUBSTITUTE, SUBSTITUTE_EFFECT, 0, NORMAL, 100, 10 + move STRUGGLE, RECOIL_EFFECT, 50, NORMAL, 100, 10 diff --git a/engine/battle/4_2.asm b/engine/battle/4_2.asm index 133acdcc..aaada492 100755 --- a/engine/battle/4_2.asm +++ b/engine/battle/4_2.asm @@ -392,7 +392,7 @@ GetTrainerName_: ; 13a58 (4:7a58) ld [wd0b5], a ld a, TRAINER_NAME ld [W_LISTTYPE], a - ld a, $e + ld a, BANK(TrainerNames) ld [wPredefBank], a call GetName ld hl, wcd6d diff --git a/engine/battle/animations.asm b/engine/battle/animations.asm index 15d94f05..58d4e60a 100755 --- a/engine/battle/animations.asm +++ b/engine/battle/animations.asm @@ -525,9 +525,9 @@ Func_78e23: ; 78e23 (1e:4e23) ld [wcc79], a ld b, $e4 ld a, [W_ANIMATIONID] ; W_ANIMATIONID - cp $aa + cp ANIM_AA jr c, .asm_78e3f - cp $ae + cp ANIM_AD + 1 jr nc, .asm_78e3f ld b, $f0 .asm_78e3f @@ -697,13 +697,13 @@ AnimationIdSpecialEffects: ; 78ef5 (1e:4ef5) db ROCK_SLIDE dw DoRockSlideSpecialEffects - db $AA + db ANIM_AA dw Func_79041 - db $AB + db ANIM_AB dw Func_7904c - db $AC + db ANIM_AC dw Func_7907c db TOSS_ANIM @@ -2855,10 +2855,10 @@ TossBallAnimation: ; 79e16 (1e:5e16) .PokeBallAnimations: ; 79e50 (1e:5e50) ; sequence of animations that make up the Poké Ball toss - db POOF_ANIM,HIDEPIC_ANIM,$C2,POOF_ANIM,SHOWPIC_ANIM + db POOF_ANIM,HIDEPIC_ANIM,SHAKE_ANIM,POOF_ANIM,SHOWPIC_ANIM .BlockBall ; 5E55 - ld a,$C1 + ld a,TOSS_ANIM ld [W_ANIMATIONID],a call PlayAnimation ld a,(SFX_08_43 - SFX_Headers_08) / 3 diff --git a/engine/battle/core.asm b/engine/battle/core.asm index 7b1c1d12..c2616ff7 100755 --- a/engine/battle/core.asm +++ b/engine/battle/core.asm @@ -2221,53 +2221,66 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) .throwSafariBallWasSelected ld a, SAFARI_BALL ld [wcf91], a - jr .useItem + jr UseBagItem + .upperLeftMenuItemWasNotSelected ; a menu item other than the upper left item was selected cp $2 - jp nz, .partyMenuOrRockOrRunWasSelected + jp nz, PartyMenuOrRockOrRun + ; either the bag (normal battle) or bait (safari battle) was selected ld a, [W_ISLINKBATTLE] cp $4 jr nz, .notLinkBattle + ; can't use items in link battles - ld hl, .itemsCantBeUsedHereText + ld hl, ItemsCantBeUsedHereText call PrintText jp DisplayBattleMenu + .notLinkBattle call SaveScreenTilesToBuffer2 ld a, [W_BATTLETYPE] cp $2 ; is it a safari battle? - jr nz, .bagWasSelected + jr nz, BagWasSelected + ; bait was selected ld a, SAFARI_BAIT ld [wcf91], a - jr .useItem -.bagWasSelected + jr UseBagItem + +BagWasSelected: call LoadScreenTilesFromBuffer1 ld a, [W_BATTLETYPE] and a ; is it a normal battle? jr nz, .next + ; normal battle call DrawHUDsAndHPBars .next ld a, [W_BATTLETYPE] dec a ; is it the old man tutorial? - jr nz, .getPlayerBagPointer ; no, it is a normal battle - ld hl, .oldManItemList + jr nz, DisplayPlayerBag ; no, it is a normal battle + ld hl, OldManItemList ld a, l ld [wcf8b], a ld a, h ld [wcf8c], a - jr .displayBagMenu -.oldManItemList - db $01, POKE_BALL, 50, $ff -.getPlayerBagPointer ; get the pointer to player's bag when in a normal battle + jr DisplayBagMenu + +OldManItemList: + db 1 ; # items + db POKE_BALL, 50 + db -1 + +DisplayPlayerBag: + ; get the pointer to player's bag when in a normal battle ld hl, wNumBagItems ld a, l ld [wcf8b], a ld a, h ld [wcf8c], a -.displayBagMenu + +DisplayBagMenu: xor a ld [wcf93], a ld a, ITEMLISTMENU @@ -2281,7 +2294,9 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) ld [wcc37], a ld [wMenuItemToSwap], a jp c, DisplayBattleMenu ; go back to battle menu if an item was not selected -.useItem ; either use an item from the bag or use a safari zone item + +UseBagItem: + ; either use an item from the bag or use a safari zone item ld a, [wcf91] ld [wd11e], a call GetItemName @@ -2296,9 +2311,11 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) ld a, [W_BATTLETYPE] cp $2 ; is it a safari battle? jr z, .checkIfMonCaptured + ld a, [wcd6a] and a ; was the item used successfully? - jp z, .bagWasSelected ; if not, go back to the bag menu + jp z, BagWasSelected ; if not, go back to the bag menu + ld a, [W_PLAYERBATTSTATUS1] bit 5, a ; is the player using a multi-turn move like wrap? jr z, .checkIfMonCaptured @@ -2307,10 +2324,12 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) jr nz, .checkIfMonCaptured ld hl, W_PLAYERBATTSTATUS1 res 5, [hl] ; not using multi-turn move any more + .checkIfMonCaptured ld a, [wd11c] and a ; was the enemy mon captured with a ball? jr nz, .returnAfterCapturingMon + ld a, [W_BATTLETYPE] cp $2 ; is it a safari battle? jr z, .returnAfterUsingItem_NoCapture @@ -2319,9 +2338,11 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) call DrawHUDsAndHPBars call Delay3 .returnAfterUsingItem_NoCapture + call GBPalNormal and a ; reset carry ret + .returnAfterCapturingMon call GBPalNormal xor a @@ -2331,11 +2352,11 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) scf ; set carry ret -.itemsCantBeUsedHereText +ItemsCantBeUsedHereText: TX_FAR _ItemsCantBeUsedHereText db "@" -.partyMenuOrRockOrRunWasSelected +PartyMenuOrRockOrRun: dec a ; was Run selected? jp nz, BattleMenu_RunWasSelected ; party menu or rock was selected @@ -2346,7 +2367,7 @@ DisplayBattleMenu: ; 3ceb3 (f:4eb3) ; safari battle ld a, SAFARI_ROCK ld [wcf91], a - jp .useItem + jp UseBagItem .partyMenuWasSelected call LoadScreenTilesFromBuffer1 xor a @@ -5595,7 +5616,7 @@ asm_3e70b: ; 3e70b (f:670b) res 6, [hl] ; no longer invulnerable to typical attacks ld a, [W_ENEMYMOVENUM] ld [wd0b5], a - ld a, $2c + ld a, BANK(MoveNames) ld [wPredefBank], a ld a, MOVE_NAME ld [W_LISTTYPE], a @@ -6070,10 +6091,11 @@ GetCurrentMove: ; 3eabe (f:6abe) call AddNTimes ld a, BANK(Moves) call FarCopyData - ld a, $2c + + ld a, BANK(MoveNames) ld [wPredefBank], a - ld a, $2 - ld [W_LISTTYPE], a ; list type 2 = move name + ld a, MOVE_NAME + ld [W_LISTTYPE], a call GetName ld de, wcd6d jp CopyStringToCF4B @@ -7203,16 +7225,16 @@ PoisonEffect: ; 3f24f (f:724f) dec de ld a, [H_WHOSETURN] and a - ld b, $c7 + ld b, ANIM_C7 ld hl, W_PLAYERBATTSTATUS3 ld a, [de] ld de, W_PLAYERTOXICCOUNTER jr nz, .asm_3f2b0 - ld b, $a9 + ld b, ANIM_A9 ld hl, W_ENEMYBATTSTATUS3 ld de, W_ENEMYTOXICCOUNTER .asm_3f2b0 - cp $5c + cp TOXIC jr nz, .asm_3f2bd set 0, [hl] xor a @@ -7314,14 +7336,14 @@ FreezeBurnParalyzeEffect: ; 3f30c (f:730c) ld a, 1 << PAR ld [wEnemyMonStatus], a call QuarterSpeedDueToParalysis ;quarter speed of affected monster - ld a, $a9 + ld a, ANIM_A9 call Func_3fbb9 ;animation jp PrintMayNotAttackText ;print paralysis text .burn ld a, 1 << BRN ld [wEnemyMonStatus], a call HalveAttackDueToBurn - ld a, $a9 + ld a, ANIM_A9 call Func_3fbb9 ;animation ld hl, BurnedText jp PrintText @@ -7329,7 +7351,7 @@ FreezeBurnParalyzeEffect: ; 3f30c (f:730c) call Func_3f9cf ;resets bit 5 of the D063/D068 flags ld a, 1 << FRZ ld [wEnemyMonStatus], a - ld a, $a9 + ld a, ANIM_A9 call Func_3fbb9 ;animation ld hl, FrozenText jp PrintText @@ -7867,7 +7889,7 @@ BideEffect: ; 3f6e5 (f:76e5) inc a ld [bc], a ld a, [H_WHOSETURN] - add $ae + add XSTATITEM_ANIM jp Func_3fb96 ThrashPetalDanceEffect: ; 3f717 (f:7717) @@ -7886,7 +7908,7 @@ ThrashPetalDanceEffect: ; 3f717 (f:7717) inc a ld [de], a ld a, [H_WHOSETURN] - add $b0 + add ANIM_B0 jp Func_3fb96 SwitchAndTeleportEffect: ; 3f739 (f:7739) @@ -8082,11 +8104,11 @@ ChargeEffect: ; 3f88c (f:788c) ld de, W_PLAYERMOVEEFFECT ld a, [H_WHOSETURN] and a - ld b, $ae + ld b, XSTATITEM_ANIM jr z, .asm_3f8a1 ld hl, W_ENEMYBATTSTATUS1 ld de, W_ENEMYMOVEEFFECT - ld b, $af + ld b, ANIM_AF .asm_3f8a1 set 4, [hl] ld a, [de] @@ -8094,13 +8116,13 @@ ChargeEffect: ; 3f88c (f:788c) cp FLY_EFFECT jr nz, .asm_3f8ad set 6, [hl] ; mon is now invulnerable to typical attacks (fly/dig) - ld b, $64 + ld b, TELEPORT .asm_3f8ad ld a, [de] cp DIG jr nz, .asm_3f8b6 set 6, [hl] ; mon is now invulnerable to typical attacks (fly/dig) - ld b, $c0 + ld b, ANIM_C0 .asm_3f8b6 xor a ld [wcc5b], a diff --git a/engine/battle/core.asm.orig b/engine/battle/core.asm.orig new file mode 100755 index 00000000..b8314a82 --- /dev/null +++ b/engine/battle/core.asm.orig @@ -0,0 +1,8639 @@ +BattleCore: + +; These are move effects (second value from the Moves table in bank $E). +EffectsArray1: ; 3c000 (f:4000) + db CONVERSION_EFFECT + db HAZE_EFFECT + db SWITCH_AND_TELEPORT_EFFECT + db MIST_EFFECT + db FOCUS_ENERGY_EFFECT + db CONFUSION_EFFECT + db HEAL_EFFECT + db TRANSFORM_EFFECT + db LIGHT_SCREEN_EFFECT + db REFLECT_EFFECT + db POISON_EFFECT + db PARALYZE_EFFECT + db SUBSTITUTE_EFFECT + db MIMIC_EFFECT + db LEECH_SEED_EFFECT + db SPLASH_EFFECT + db -1 +EffectsArray2: ; 3c011 (f:4011) +; moves that do damage but not through normal calculations +; e.g., Super Fang, Psywave + db SUPER_FANG_EFFECT + db SPECIAL_DAMAGE_EFFECT + db -1 +EffectsArray3: ; 3c014 (f:4014) +; non-damaging, stat‐affecting or status‐causing moves? +; e.g., Meditate, Bide, Hypnosis + db $01 + db ATTACK_UP1_EFFECT + db DEFENSE_UP1_EFFECT + db SPEED_UP1_EFFECT + db SPECIAL_UP1_EFFECT + db ACCURACY_UP1_EFFECT + db EVASION_UP1_EFFECT + db ATTACK_DOWN1_EFFECT + db DEFENSE_DOWN1_EFFECT + db SPEED_DOWN1_EFFECT + db SPECIAL_DOWN1_EFFECT + db ACCURACY_DOWN1_EFFECT + db EVASION_DOWN1_EFFECT + db BIDE_EFFECT + db SLEEP_EFFECT + db ATTACK_UP2_EFFECT + db DEFENSE_UP2_EFFECT + db SPEED_UP2_EFFECT + db SPECIAL_UP2_EFFECT + db ACCURACY_UP2_EFFECT + db EVASION_UP2_EFFECT + db ATTACK_DOWN2_EFFECT + db DEFENSE_DOWN2_EFFECT + db SPEED_DOWN2_EFFECT + db SPECIAL_DOWN2_EFFECT + db ACCURACY_DOWN2_EFFECT + db EVASION_DOWN2_EFFECT + db -1 +EffectsArray4: ; 3c030 (f:4030) +; Attacks that aren't finished after they faint the opponent. + db DRAIN_HP_EFFECT + db EXPLODE_EFFECT + db DREAM_EATER_EFFECT + db PAY_DAY_EFFECT + db TWO_TO_FIVE_ATTACKS_EFFECT + db $1E + db ATTACK_TWICE_EFFECT + db RECOIL_EFFECT + db TWINEEDLE_EFFECT + db RAGE_EFFECT + db -1 +EffectsArray5: ; 3c03b (f:403b) + db DRAIN_HP_EFFECT + db EXPLODE_EFFECT + db DREAM_EATER_EFFECT + db PAY_DAY_EFFECT + db SWIFT_EFFECT + db TWO_TO_FIVE_ATTACKS_EFFECT + db $1E + db CHARGE_EFFECT + db SUPER_FANG_EFFECT + db SPECIAL_DAMAGE_EFFECT + db FLY_EFFECT + db ATTACK_TWICE_EFFECT + db JUMP_KICK_EFFECT + db RECOIL_EFFECT + ; fallthrough to Next EffectsArray +EffectsArray5B: ; 3c049 (f:4049) +; moves that prevent the player from switching moves? + db THRASH_PETAL_DANCE_EFFECT + db TRAPPING_EFFECT + db -1 + +SlidePlayerAndEnemySilhouettesOnScreen: ; 3c04c (f:404c) + call LoadPlayerBackPic + ld a, $1 ; the usual text box at the bottom of the screen + ld [wd125], a + call DisplayTextBoxID + hlCoord 1, 5 + ld bc, $307 + call ClearScreenArea + call DisableLCD + call LoadFontTilePatterns + call LoadHudAndHpBarAndStatusTilePatterns + ld hl, vBGMap0 + ld bc, $400 +.clearBackgroundLoop + ld a, $7f + ld [hli], a + dec bc + ld a, b + or c + jr nz, .clearBackgroundLoop +; copy the work RAM tile map to VRAM + ld hl, wTileMap + ld de, vBGMap0 + ld b, 18 ; number of rows +.copyRowLoop + ld c, 20 ; number of columns +.copyColumnLoop + ld a, [hli] + ld [de], a + inc e + dec c + jr nz, .copyColumnLoop + ld a, 12 ; number of off screen tiles to the right of screen in VRAM + add e ; skip the off screen tiles + ld e, a + jr nc, .noCarry + inc d +.noCarry + dec b + jr nz, .copyRowLoop + call EnableLCD + ld a, $90 + ld [hVBlankWY], a + ld [rWY], a + xor a + ld [hTilesetType], a + ld [hVBlankSCY], a + dec a + ld [wUpdateSpritesEnabled], a + call Delay3 + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld b, $70 + ld c, $90 + ld a, c + ld [hVBlankSCX], a + call DelayFrame + ld a, %11100100 ; inverted palette for silhouette effect + ld [rBGP], a + ld [rOBP0], a + ld [rOBP1], a +.slideSilhouettesLoop ; slide silhouettes of the player's pic and the enemy's pic onto the screen + ld h, b + ld l, $40 + call SetScrollXForSlidingPlayerBodyLeft ; begin background scrolling on line $40 + inc b + inc b + ld h, $0 + ld l, $60 + call SetScrollXForSlidingPlayerBodyLeft ; end background scrolling on line $60 + call SlidePlayerHeadLeft + ld a, c + ld [hVBlankSCX], a + dec c + dec c + jr nz, .slideSilhouettesLoop + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld a, $31 + ld [$ffe1], a + hlCoord 1, 5 + predef Func_3f0c6 + xor a + ld [hVBlankWY], a + ld [rWY], a + inc a + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + ld b, $1 + call GoPAL_SET + call HideSprites + ld hl, PrintBeginningBattleText + ld b, BANK(PrintBeginningBattleText) + jp Bankswitch + +; when a battle is starting, silhouettes of the player's pic and the enemy's pic are slid onto the screen +; the lower of the player's pic (his body) is part of the background, but his head is a sprite +; the reason for this is that it shares Y coordinates with the lower part of the enemy pic, so background scrolling wouldn't work for both pics +; instead, the enemy pic is part of the background and uses the scroll register, while the player's head is a sprite and is slid by changing its X coordinates in a loop +SlidePlayerHeadLeft: ; 3c0ff (f:40ff) + push bc + ld hl, wOAMBuffer + $01 + ld c, $15 ; number of OAM entries + ld de, $4 ; size of OAM entry +.loop + dec [hl] ; decrement X + dec [hl] ; decrement X + add hl, de ; next OAM entry + dec c + jr nz, .loop + pop bc + ret + +SetScrollXForSlidingPlayerBodyLeft: ; 3c110 (f:4110) + ld a, [rLY] + cp l + jr nz, SetScrollXForSlidingPlayerBodyLeft + ld a, h + ld [rSCX], a +.loop + ld a, [rLY] + cp h + jr z, .loop + ret + +StartBattle: ; 3c11e (f:411e) + xor a + ld [wPartyGainExpFlags], a + ld [wPartyFoughtCurrentEnemyFlags], a + ld [wcd6a], a + inc a + ld [wd11d], a + ld hl, wEnemyMon1HP + ld bc, wEnemyMon2 - wEnemyMon1 - 1 + ld d, $3 +.findFirstAliveEnemyMonLoop + inc d + ld a, [hli] + or [hl] + jr nz, .foundFirstAliveEnemyMon + add hl, bc + jr .findFirstAliveEnemyMonLoop +.foundFirstAliveEnemyMon + ld a, d + ld [wcc3e], a + ld a, [W_ISINBATTLE] + dec a ; is it a trainer battle? + call nz, EnemySendOutFirstMon ; if it is a trainer battle, send out enemy mon + ld c, 40 + call DelayFrames + call SaveScreenTilesToBuffer1 +.checkAnyPartyAlive + call AnyPartyAlive + ld a, d + and a + jp z, HandlePlayerBlackOut ; jump if no mon is alive + call LoadScreenTilesFromBuffer1 + ld a, [W_BATTLETYPE] + and a ; is it a normal battle? + jp z, .playerSendOutFirstMon ; if so, send out player mon +; safari zone battle +.displaySafariZoneBattleMenu + call DisplayBattleMenu + ret c ; return if the player ran from battle + ld a, [wcd6a] + and a ; was the item used successfully? + jr z, .displaySafariZoneBattleMenu ; if not, display the menu again; XXX does this ever jump? + ld a, [W_NUMSAFARIBALLS] + and a + jr nz, .notOutOfSafariBalls + call LoadScreenTilesFromBuffer1 + ld hl, .outOfSafariBallsText + jp PrintText +.notOutOfSafariBalls + callab PrintSafariZoneBattleText + ld a, [wEnemyMonSpeed + 1] + add a + ld b, a ; init b (which is later compared with random value) to (enemy speed % 256) * 2 + jp c, EnemyRan ; if (enemy speed % 256) > 127, the enemy runs + ld a, [wSafariBaitFactor] + and a ; is bait factor 0? + jr z, .checkEscapeFactor +; bait factor is not 0 +; divide b by 4 (making the mon less likely to run) + srl b + srl b +.checkEscapeFactor + ld a, [wSafariEscapeFactor] + and a ; is escape factor 0? + jr z, .compareWithRandomValue +; escape factor is not 0 +; multiply b by 2 (making the mon more likely to run) + sla b + jr nc, .compareWithRandomValue +; cap b at 255 + ld b, $ff +.compareWithRandomValue + call Random + cp b + jr nc, .checkAnyPartyAlive + jr EnemyRan ; if b was greater than the random value, the enemy runs + +.outOfSafariBallsText + TX_FAR _OutOfSafariBallsText + db "@" + +.playerSendOutFirstMon + xor a + ld [wWhichPokemon], a +.findFirstAliveMonLoop + call HasMonFainted + jr nz, .foundFirstAliveMon +; fainted, go to the next one + ld hl, wWhichPokemon + inc [hl] + jr .findFirstAliveMonLoop +.foundFirstAliveMon + ld a, [wWhichPokemon] + ld [wPlayerMonNumber], a + inc a + ld hl, wPartySpecies - 1 + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] ; species + ld [wcf91], a + ld [wBattleMonSpecies2], a + call LoadScreenTilesFromBuffer1 + hlCoord 1, 5 + ld a, $9 + call SlideTrainerPicOffScreen + call SaveScreenTilesToBuffer1 + ld a, [wWhichPokemon] + ld c, a + ld b, $1 + push bc + ld hl, wPartyGainExpFlags + predef FlagActionPredef + ld hl, wPartyFoughtCurrentEnemyFlags + pop bc + predef FlagActionPredef + call LoadBattleMonFromParty + call LoadScreenTilesFromBuffer1 + call SendOutMon + jr MainInBattleLoop + +; wild mon or link battle enemy ran from battle +EnemyRan: ; 3c202 (f:4202) + call LoadScreenTilesFromBuffer1 + ld a, [W_ISLINKBATTLE] + cp $4 + ld hl, WildRanText + jr nz, .printText +; link battle + xor a + ld [wBattleResult], a + ld hl, EnemyRanText +.printText + call PrintText + ld a, (SFX_08_44 - SFX_Headers_08) / 3 + call PlaySoundWaitForCurrent + xor a + ld [H_WHOSETURN], a + ld hl, AnimationSlideEnemyMonOut + ld b, BANK(AnimationSlideEnemyMonOut) + jp Bankswitch + +WildRanText: ; 3c229 (f:4229) + TX_FAR _WildRanText + db "@" + +EnemyRanText: ; 3c22e (f:422e) + TX_FAR _EnemyRanText + db "@" + +MainInBattleLoop: ; 3c233 (f:4233) + call ReadPlayerMonCurHPAndStatus + ld hl, wBattleMonHP + ld a, [hli] + or [hl] ; is battle mon HP 0? + jp z, HandlePlayerMonFainted ; if battle mon HP is 0, jump + ld hl, wEnemyMonHP + ld a, [hli] + or [hl] ; is enemy mon HP 0? + jp z, HandleEnemyMonFainted ; if enemy mon HP is 0, jump + call SaveScreenTilesToBuffer1 + xor a + ld [wd11d], a + ld a, [W_PLAYERBATTSTATUS2] + and %01100000 ; check if the player is using Rage or needs to recharge + jr nz, .selectEnemyMove +; the player is not using Rage and doesn't need to recharge + ld hl, W_ENEMYBATTSTATUS1 + res 3, [hl] ; reset flinch bit + ld hl, W_PLAYERBATTSTATUS1 + res 3, [hl] ; reset flinch bit + ld a, [hl] + and %00010010 ; check if the player is thrashing about or charging for an attack + jr nz, .selectEnemyMove ; if so, jump +; the player is neither thrashing about nor charging for an attack + call DisplayBattleMenu ; show battle menu + ret c ; return if player ran from battle + ld a, [wEscapedFromBattle] + and a + ret nz ; return if pokedoll was used to escape from battle + ld a, [wBattleMonStatus] + and (1 << FRZ) | SLP ; is mon frozen or asleep? + jr nz, .selectEnemyMove ; if so, jump + ld a, [W_PLAYERBATTSTATUS1] + and %00100001 ; check player is using Bide or using a multi-turn attack like wrap + jr nz, .selectEnemyMove ; if so, jump + ld a, [W_ENEMYBATTSTATUS1] + bit 5, a ; check if enemy is using a multi-turn attack like wrap + jr z, .selectPlayerMove ; if not, jump +; enemy is using a mult-turn attack like wrap, so player is trapped and cannot select a move + ld a, $ff + ld [wPlayerSelectedMove], a + jr .selectEnemyMove +.selectPlayerMove + ld a, [wcd6a] + and a + jr nz, .selectEnemyMove + ld [wMoveMenuType], a + inc a + ld [W_ANIMATIONID], a + xor a + ld [wMenuItemToSwap], a + call MoveSelectionMenu + push af + call LoadScreenTilesFromBuffer1 + call DrawHUDsAndHPBars + pop af + jr nz, MainInBattleLoop ; if the player didn't select a move, jump +.selectEnemyMove + call SelectEnemyMove + ld a, [W_ISLINKBATTLE] + cp $4 + jr nz, .noLinkBattle +; link battle + ld a, [wcc3e] + cp $f + jp z, EnemyRan + cp $e + jr z, .noLinkBattle + cp $d + jr z, .noLinkBattle + sub $4 + jr c, .noLinkBattle +; the link battle enemy has switched mons + ld a, [W_PLAYERBATTSTATUS1] + bit 5, a ; check if using multi-turn move like Wrap + jr z, .asm_3c2dd + ld a, [wPlayerMoveListIndex] + ld hl, wBattleMonMoves + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + cp METRONOME + jr nz, .asm_3c2dd + ld [wPlayerSelectedMove], a +.asm_3c2dd + callab SwitchEnemyMon +.noLinkBattle + ld a, [wPlayerSelectedMove] + cp QUICK_ATTACK + jr nz, .playerDidNotUseQuickAttack + ld a, [wEnemySelectedMove] + cp QUICK_ATTACK + jr z, .compareSpeed ; if both used Quick Attack + jp .playerMovesFirst ; if player used Quick Attack and enemy didn't +.playerDidNotUseQuickAttack + ld a, [wEnemySelectedMove] + cp QUICK_ATTACK + jr z, .enemyMovesFirst ; if enemy used Quick Attack and player didn't + ld a, [wPlayerSelectedMove] + cp COUNTER + jr nz, .playerDidNotUseCounter + ld a, [wEnemySelectedMove] + cp COUNTER + jr z, .compareSpeed ; if both used Counter + jr .enemyMovesFirst ; if player used Counter and enemy didn't +.playerDidNotUseCounter + ld a, [wEnemySelectedMove] + cp COUNTER + jr z, .playerMovesFirst ; if enemy used Counter and player didn't +.compareSpeed + ld de, wBattleMonSpeed ; player speed value + ld hl, wEnemyMonSpeed ; enemy speed value + ld c, $2 + call StringCmp ; compare speed values + jr z, .speedEqual + jr nc, .playerMovesFirst ; if player is faster + jr .enemyMovesFirst ; if enemy is faster +.speedEqual + ld a, [$ffaa] + cp $2 + jr z, .invertOutcome + call BattleRandom + cp $80 + jr c, .playerMovesFirst + jr .enemyMovesFirst +.invertOutcome + call BattleRandom + cp $80 + jr c, .enemyMovesFirst + jr .playerMovesFirst +.enemyMovesFirst + ld a, $1 + ld [H_WHOSETURN], a + callab TrainerAI + jr c, .AIActionUsedEnemyFirst + call ExecuteEnemyMove + ld a, [wEscapedFromBattle] + and a ; was Teleport, Road, or Whirlwind used to escape from battle? + ret nz ; if so, return + ld a, b + and a + jp z, HandlePlayerMonFainted +.AIActionUsedEnemyFirst + call HandlePoisonBurnLeechSeed + jp z, HandleEnemyMonFainted + call DrawHUDsAndHPBars + call ExecutePlayerMove + ld a, [wEscapedFromBattle] + and a ; was Teleport, Road, or Whirlwind used to escape from battle? + ret nz ; if so, return + ld a, b + and a + jp z, HandleEnemyMonFainted + call HandlePoisonBurnLeechSeed + jp z, HandlePlayerMonFainted + call DrawHUDsAndHPBars + call CheckNumAttacksLeft + jp MainInBattleLoop +.playerMovesFirst + call ExecutePlayerMove + ld a, [wEscapedFromBattle] + and a ; was Teleport, Road, or Whirlwind used to escape from battle? + ret nz ; if so, return + ld a, b + and a + jp z, HandleEnemyMonFainted + call HandlePoisonBurnLeechSeed + jp z, HandlePlayerMonFainted + call DrawHUDsAndHPBars + ld a, $1 + ld [H_WHOSETURN], a + callab TrainerAI + jr c, .AIActionUsedPlayerFirst + call ExecuteEnemyMove + ld a, [wEscapedFromBattle] + and a ; was Teleport, Road, or Whirlwind used to escape from battle? + ret nz ; if so, return + ld a, b + and a + jp z, HandlePlayerMonFainted +.AIActionUsedPlayerFirst + call HandlePoisonBurnLeechSeed + jp z, HandleEnemyMonFainted + call DrawHUDsAndHPBars + call CheckNumAttacksLeft + jp MainInBattleLoop + +HandlePoisonBurnLeechSeed: ; 3c3bd (f:43bd) + ld hl, wBattleMonHP + ld de, wBattleMonStatus + ld a, [H_WHOSETURN] + and a + jr z, .playersTurn + ld hl, wEnemyMonHP + ld de, wEnemyMonStatus +.playersTurn + ld a, [de] + and (1 << BRN) | (1 << PSN) + jr z, .notBurnedOrPoisoned + push hl + ld hl, HurtByPoisonText + ld a, [de] + and 1 << BRN + jr z, .poisoned + ld hl, HurtByBurnText +.poisoned + call PrintText + xor a + ld [wcc5b], a + ld a,BURN_PSN_ANIM + call PlayMoveAnimation ; play burn/poison animation + pop hl + call HandlePoisonBurnLeechSeed_DecreaseOwnHP +.notBurnedOrPoisoned + ld de, W_PLAYERBATTSTATUS2 + ld a, [H_WHOSETURN] + and a + jr z, .playersTurn2 + ld de, W_ENEMYBATTSTATUS2 +.playersTurn2 + ld a, [de] + add a + jr nc, .notLeechSeeded + push hl + ld a, [H_WHOSETURN] + push af + xor $1 + ld [H_WHOSETURN], a + xor a + ld [wcc5b], a + ld a,ABSORB + call PlayMoveAnimation ; play leech seed animation (from opposing mon) + pop af + ld [H_WHOSETURN], a + pop hl + call HandlePoisonBurnLeechSeed_DecreaseOwnHP + call HandlePoisonBurnLeechSeed_IncreaseEnemyHP + push hl + ld hl, HurtByLeechSeedText + call PrintText + pop hl +.notLeechSeeded + ld a, [hli] + or [hl] + ret nz ; test if fainted + call DrawHUDsAndHPBars + ld c, $14 + call DelayFrames + xor a + ret + +HurtByPoisonText: ; 3c42e (f:442e) + TX_FAR _HurtByPoisonText + db "@" + +HurtByBurnText: ; 3c433 (f:4433) + TX_FAR _HurtByBurnText + db "@" + +HurtByLeechSeedText: ; 3c438 (f:4438) + TX_FAR _HurtByLeechSeedText + db "@" + +; decreases the mon's current HP by 1/16 of the Max HP (multiplied by number of toxic ticks if active) +; note that the toxic ticks are considered even if the damage is not poison (hence the Leech Seed glitch) +; hl: HP pointer +; bc (out): total damage +HandlePoisonBurnLeechSeed_DecreaseOwnHP: ; 3c43d (f:443d) + push hl + push hl + ld bc, $e ; skip to max HP + add hl, bc + ld a, [hli] ; load max HP + ld [wHPBarMaxHP+1], a + ld b, a + ld a, [hl] + ld [wHPBarMaxHP], a + ld c, a + srl b + rr c + srl b + rr c + srl c + srl c ; c = max HP/16 (assumption: HP < 1024) + ld a, c + and a + jr nz, .nonZeroDamage + inc c ; damage is at least 1 +.nonZeroDamage + ld hl, W_PLAYERBATTSTATUS3 + ld de, W_PLAYERTOXICCOUNTER + ld a, [H_WHOSETURN] + and a + jr z, .playersTurn + ld hl, W_ENEMYBATTSTATUS3 + ld de, W_ENEMYTOXICCOUNTER +.playersTurn + bit 0, [hl] + jr z, .noToxic + ld a, [de] ; increment toxic counter + inc a + ld [de], a + ld hl, $0000 +.toxicTicksLoop + add hl, bc + dec a + jr nz, .toxicTicksLoop + ld b, h ; bc = damage * toxic counter + ld c, l +.noToxic + pop hl + inc hl + ld a, [hl] ; subtract total damage from current HP + 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, .noOverkill + xor a ; overkill: zero HP + ld [hli], a + ld [hl], a + ld [wHPBarNewHP], a + ld [wHPBarNewHP+1], a +.noOverkill + call UpdateCurMonHPBar + pop hl + ret + +; adds bc to enemy HP +HandlePoisonBurnLeechSeed_IncreaseEnemyHP: ; 3c4a3 (f:44a3) + push hl + ld hl, wEnemyMonMaxHP + ld a, [H_WHOSETURN] + and a + jr z, .playersTurn + ld hl, wBattleMonMaxHP +.playersTurn + ld a, [hli] + ld [wHPBarMaxHP+1], a + ld a, [hl] + ld [wHPBarMaxHP], a + ld de, $fff2 + add hl, de ; skip back fomr max hp to current hp + ld a, [hl] + ld [wHPBarOldHP], a ; add bc to current HP + add c + ld [hld], a + ld [wHPBarNewHP], a + ld a, [hl] + ld [wHPBarOldHP+1], a + adc b + ld [hli], a + ld [wHPBarNewHP+1], a + ld a, [wHPBarMaxHP] + ld c, a + ld a, [hld] + sub c + ld a, [wHPBarMaxHP+1] + ld b, a + ld a, [hl] + sbc b + jr c, .noOverfullHeal + ld a, b ; overfull heal, set HP to max HP + ld [hli], a + ld [wHPBarNewHP+1], a + ld a, c + ld [hl], a + ld [wHPBarNewHP], a +.noOverfullHeal + ld a, [H_WHOSETURN] + xor $1 + ld [H_WHOSETURN], a + call UpdateCurMonHPBar + ld a, [H_WHOSETURN] + xor $1 + ld [H_WHOSETURN], a + pop hl + ret + +UpdateCurMonHPBar: ; 3c4f6 (f:44f6) + hlCoord 10, 9 ; tile pointer to player HP bar + ld a, [H_WHOSETURN] + and a + ld a, $1 + jr z, .playersTurn + hlCoord 2, 2 ; tile pointer to enemy HP bar + xor a +.playersTurn + push bc + ld [wListMenuID], a + predef UpdateHPBar2 + pop bc + ret + +CheckNumAttacksLeft: ; 3c50f (f:450f) + ld a, [wPlayerNumAttacksLeft] + and a + jr nz, .checkEnemy +; player has 0 attacks left + ld hl, W_PLAYERBATTSTATUS1 + res 5, [hl] ; player not using multi-turn attack like wrap any more +.checkEnemy + ld a, [wEnemyNumAttacksLeft] + and a + ret nz +; enemy has 0 attacks left + ld hl, W_ENEMYBATTSTATUS1 + res 5, [hl] ; enemy not using multi-turn attack like wrap any more + ret + +HandleEnemyMonFainted: ; 3c525 (f:4525) + xor a + ld [wccf0], a + call FaintEnemyPokemon + call AnyPartyAlive + ld a, d + and a + jp z, HandlePlayerBlackOut ; if no party mons are alive, the player blacks out + ld hl, wBattleMonHP + ld a, [hli] + or [hl] ; is battle mon HP zero? + call nz, DrawPlayerHUDAndHPBar ; if battle mon HP is not zero, draw player HD and HP bar + ld a, [W_ISINBATTLE] + dec a + ret z ; return if it's a wild battle + call AnyEnemyPokemonAliveCheck + jp z, TrainerBattleVictory + ld hl, wBattleMonHP + ld a, [hli] + or [hl] ; does battle mon have 0 HP? + jr nz, .skipReplacingBattleMon ; if not, skip replacing battle mon + call DoUseNextMonDialogue ; this call is useless in a trainer battle. it shouldn't be here + ret c + call ChooseNextMon +.skipReplacingBattleMon + ld a, $1 + ld [wcd6a], a + call ReplaceFaintedEnemyMon + jp z, EnemyRan + xor a + ld [wcd6a], a + jp MainInBattleLoop + +FaintEnemyPokemon ; 0x3c567 + call ReadPlayerMonCurHPAndStatus + ld a, [W_ISINBATTLE] + dec a + jr z, .wild + ld a, [wEnemyMonPartyPos] + ld hl, wEnemyMon1HP + ld bc, wEnemyMon2 - wEnemyMon1 + call AddNTimes + xor a + ld [hli], a + ld [hl], a +.wild + ld hl, W_PLAYERBATTSTATUS1 + res 2, [hl] + xor a + ld [W_NUMHITS], a + ld hl, wd065 ; enemy statuses + ld [hli], a + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ld [W_ENEMYDISABLEDMOVE], a + ld [wccef], a + ld [wccf3], a + ld hl, wccf1 + ld [hli], a + ld [hl], a + hlCoord 12, 5 + deCoord 12, 6 + call SlideDownFaintedMonPic + ld hl, wTileMap + ld bc, $40b + call ClearScreenArea + ld a, [W_ISINBATTLE] + dec a + jr z, .wild_win + xor a + ld [wc0f1], a + ld [wc0f2], a + ld a, (SFX_08_48 - SFX_Headers_08) / 3 ; SFX_FALL? + call PlaySoundWaitForCurrent +.sfxwait + ld a, [wc02a] + cp (SFX_08_48 - SFX_Headers_08) / 3 + jr z, .sfxwait + ld a, (SFX_08_43 - SFX_Headers_08) / 3 ; SFX_DROP + call PlaySound + call WaitForSoundToFinish + jr .sfxplayed +.wild_win + call Func_3c643 + ld a, MUSIC_DEFEATED_WILD_MON + call PlayBattleVictoryMusic +.sfxplayed + ld hl, wBattleMonHP + ld a, [hli] + or [hl] + jr nz, .playermonnotfaint + ld a, [wccf0] + and a + jr nz, .playermonnotfaint + call RemoveFaintedPlayerMon +.playermonnotfaint + call AnyPartyAlive + ld a, d + and a + ret z + ld hl, EnemyMonFaintedText + call PrintText + call PrintEmptyString + call SaveScreenTilesToBuffer1 + xor a + ld [wBattleResult], a + ld b, EXP__ALL + call IsItemInBag + push af + jr z, .giveExpToMonsThatFought ; if no exp all, then jump + +; the player has exp all +; first, we halve the values that determine exp gain +; the enemy mon base stats are added to stat exp, so they are halved +; the base exp (which determines normal exp) is also halved + ld hl, wEnemyMonBaseStats + ld b, $7 +.halveExpDataLoop + srl [hl] + inc hl + dec b + jr nz, .halveExpDataLoop + +; give exp (divided evenly) to the mons that actually fought in battle against the enemy mon that has fainted +; if exp all is in the bag, this will be only be half of the stat exp and normal exp, due to the above loop +.giveExpToMonsThatFought + xor a + ld [wcc5b], a + callab GainExperience + pop af + ret z ; return if no exp all + +; the player has exp all +; now, set the gain exp flag for every party member +; half of the total stat exp and normal exp will divided evenly amongst every party member + ld a, $1 + ld [wcc5b], a + ld a, [wPartyCount] + ld b, 0 +.gainExpFlagsLoop + scf + rl b + dec a + jr nz, .gainExpFlagsLoop + ld a, b + ld [wPartyGainExpFlags], a + ld hl, GainExperience + ld b, BANK(GainExperience) + jp Bankswitch + +EnemyMonFaintedText: ; 0x3c63e + TX_FAR _EnemyMonFaintedText + db "@" + +Func_3c643: ; 3c643 (f:4643) + xor a + ld [wd083], a + ld [wc02a], a + inc a + ld [wccf6], a + ret + +AnyEnemyPokemonAliveCheck: ; 3c64f (f:464f) + ld a, [wEnemyPartyCount] + ld b, a + xor a + ld hl, wEnemyMon1HP + ld de, $2c +.asm_3c65a + or [hl] + inc hl + or [hl] + dec hl + add hl, de + dec b + jr nz, .asm_3c65a + and a + ret + +; stores whether enemy ran in Z flag +ReplaceFaintedEnemyMon: ; 3c664 (f:4664) + ld hl, wcf1e + ld e, $30 + call GetBattleHealthBarColor + callab DrawEnemyPokeballs + ld a, [W_ISLINKBATTLE] + cp $4 + jr nz, .asm_3c687 +; link battle + call LinkBattleExchangeData + ld a, [wcc3e] + cp $f + ret z + call LoadScreenTilesFromBuffer1 +.asm_3c687 + call EnemySendOut + xor a + ld [W_ENEMYMOVENUM], a + ld [wcd6a], a + ld [wccd5], a + inc a ; reset Z flag + ret + +TrainerBattleVictory: ; 3c696 (f:4696) + call Func_3c643 + ld b, MUSIC_DEFEATED_GYM_LEADER + ld a, [W_GYMLEADERNO] + and a + jr nz, .gymleader + ld b, MUSIC_DEFEATED_TRAINER +.gymleader + ld a, [W_TRAINERCLASS] + cp SONY3 ; final battle against rival + jr nz, .notrival + ld b, MUSIC_DEFEATED_GYM_LEADER + ld hl, W_FLAGS_D733 + set 1, [hl] +.notrival + ld a, [W_ISLINKBATTLE] + cp $4 + ld a, b + call nz, PlayBattleVictoryMusic + ld hl, TrainerDefeatedText + call PrintText + ld a, [W_ISLINKBATTLE] + cp $4 + ret z + call ScrollTrainerPicAfterBattle + ld c, $28 + call DelayFrames + call PrintEndBattleText + ld hl, MoneyForWinningText + call PrintText + ld de, wPlayerMoney + 2 + ld hl, wd07b + ld c, $3 + predef_jump AddBCDPredef + +MoneyForWinningText: ; 3c6e4 (f:46e4) + TX_FAR _MoneyForWinningText + db "@" + +TrainerDefeatedText: ; 3c6e9 (f:46e9) + TX_FAR _TrainerDefeatedText + db "@" + +PlayBattleVictoryMusic: ; 3c6ee (f:46ee) + push af + ld a, $ff + ld [wc0ee], a + call PlaySoundWaitForCurrent + ld c, BANK(Music_DefeatedTrainer) + pop af + call PlayMusic + jp Delay3 + +HandlePlayerMonFainted: ; 3c700 (f:4700) + ld a, $1 + ld [wccf0], a + call RemoveFaintedPlayerMon + call AnyPartyAlive ; test if any more mons are alive + ld a, d + and a + jp z, HandlePlayerBlackOut + ld hl, wEnemyMonHP + ld a, [hli] + or [hl] ; is enemy mon's HP 0? + jr nz, .doUseNextMonDialogue ; if not, jump +; the enemy mon has 0 HP + call FaintEnemyPokemon + ld a, [W_ISINBATTLE] + dec a + ret z ; if wild encounter, battle is over + call AnyEnemyPokemonAliveCheck + jp z, TrainerBattleVictory +.doUseNextMonDialogue + call DoUseNextMonDialogue + ret c ; return if the player ran from battle + call ChooseNextMon + jp nz, MainInBattleLoop ; if the enemy mon has more than 0 HP, go back to battle loop +; the enemy mon has 0 HP + ld a, $1 + ld [wcd6a], a + call ReplaceFaintedEnemyMon + jp z, EnemyRan ; if enemy ran from battle rather than sending out another mon, jump + xor a + ld [wcd6a], a + jp MainInBattleLoop + +; resets flags, slides mon's pic down, plays cry, and prints fainted message +RemoveFaintedPlayerMon: ; 3c741 (f:4741) + ld a, [wPlayerMonNumber] + ld c, a + ld hl, wPartyGainExpFlags + ld b, $0 + predef FlagActionPredef ; clear gain exp flag for fainted mon + ld hl, W_ENEMYBATTSTATUS1 + res 2, [hl] ; reset "attacking multiple times" flag + ld a, [wd083] + bit 7, a ; skip sound flag (red bar (?)) + jr z, .skipWaitForSound + ld a, $ff + ld [wd083], a + call WaitForSoundToFinish +.skipWaitForSound + ld hl, wcd05 + ld [hli], a + ld [hl], a + ld [wBattleMonStatus], a + call ReadPlayerMonCurHPAndStatus + hlCoord 9, 7 + ld bc, $50b + call ClearScreenArea + hlCoord 1, 10 + deCoord 1, 11 + call SlideDownFaintedMonPic + ld a, $1 + ld [wBattleResult], a + ld a, [wccf0] + and a + ret z + ld a, [wBattleMonSpecies] + call PlayCry + ld hl, PlayerMonFaintedText + jp PrintText + +PlayerMonFaintedText: ; 3c796 (f:4796) + TX_FAR _PlayerMonFaintedText + db "@" + +; asks if you want to use next mon +; stores whether you ran in C flag +DoUseNextMonDialogue: ; 3c79b (f:479b) + call PrintEmptyString + call SaveScreenTilesToBuffer1 + ld a, [W_ISINBATTLE] + and a + dec a + ret nz ; return if it's a trainer battle + ld hl, UseNextMonText + call PrintText +.displayYesNoBox + hlCoord 13, 9 + ld bc, $a0e + ld a, $14 ; yes/no text box + ld [wd125], a + call DisplayTextBoxID + ld a, [wd12e] + cp $2 ; did the player choose NO? + jr z, .tryRunning ; if the player chose NO, try running + and a ; reset carry + ret +.tryRunning + ld a, [wCurrentMenuItem] + and a + jr z, .displayYesNoBox ; xxx when does this happen? + ld hl, wPartyMon1Speed + ld de, wEnemyMonSpeed + jp TryRunningFromBattle + +UseNextMonText: ; 3c7d3 (f:47d3) + TX_FAR _UseNextMonText + db "@" + +; choose next player mon to send out +; stores whether enemy mon has no HP left in Z flag +ChooseNextMon: ; 3c7d8 (f:47d8) + ld a, $2 + ld [wd07d], a + call DisplayPartyMenu +.checkIfMonChosen + jr nc, .monChosen +.goBackToPartyMenu + call GoBackToPartyMenu + jr .checkIfMonChosen +.monChosen + call HasMonFainted + jr z, .goBackToPartyMenu ; if mon fainted, you have to choose another + ld a, [W_ISLINKBATTLE] + cp $4 + jr nz, .asm_3c7fa + inc a + ld [wcd6a], a + call LinkBattleExchangeData +.asm_3c7fa + xor a + ld [wcd6a], a + call ClearSprites + ld a, [wWhichPokemon] + ld [wPlayerMonNumber], a + ld c, a + ld hl, wPartyGainExpFlags + ld b, $1 + push bc + predef FlagActionPredef + pop bc + ld hl, wPartyFoughtCurrentEnemyFlags + predef FlagActionPredef + call LoadBattleMonFromParty + call GBPalWhiteOut + call LoadHudTilePatterns + call LoadScreenTilesFromBuffer1 + call GoPAL_SET_CF1C + call GBPalNormal + call SendOutMon + ld hl, wEnemyMonHP + ld a, [hli] + or [hl] + ret + +; called when player is out of usable mons. +; prints approriate lose message, sets carry flag if player blacked out (special case for initial rival fight) +HandlePlayerBlackOut: ; 3c837 (f:4837) + ld a, [W_ISLINKBATTLE] + cp $4 + jr z, .notSony1Battle + ld a, [W_CUROPPONENT] + cp $c8 + SONY1 + jr nz, .notSony1Battle + ld hl, wTileMap ; sony 1 battle + ld bc, $815 + call ClearScreenArea + call ScrollTrainerPicAfterBattle + ld c, $28 + call DelayFrames + ld hl, Sony1WinText + call PrintText + ld a, [W_CURMAP] + cp OAKS_LAB + ret z ; starter battle in oak's lab: don't black out +.notSony1Battle + ld b, $0 + call GoPAL_SET + ld hl, PlayerBlackedOutText2 + ld a, [W_ISLINKBATTLE] + cp $4 + jr nz, .noLinkBattle + ld hl, LinkBattleLostText +.noLinkBattle + call PrintText + ld a, [wd732] + res 5, a + ld [wd732], a + call ClearScreen + scf + ret + +Sony1WinText: ; 3c884 (f:4884) + TX_FAR _Sony1WinText + db "@" + +PlayerBlackedOutText2: ; 3c889 (f:4889) + TX_FAR _PlayerBlackedOutText2 + db "@" + +LinkBattleLostText: ; 3c88e (f:488e) + TX_FAR _LinkBattleLostText + db "@" + +; slides pic of fainted mon downwards until it disappears +; bug: when this is called, [H_AUTOBGTRANSFERENABLED] is non-zero, so there is screen tearing +SlideDownFaintedMonPic: ; 3c893 (f:4893) + ld a, [wd730] + push af + set 6, a + ld [wd730], a + ld b, 7 ; number of times to slide +.slideStepLoop ; each iteration, the mon is slid down one row + push bc + push de + push hl + ld b, 6 ; number of rows +.rowLoop + push bc + push hl + push de + ld bc, $7 + call CopyData + pop de + pop hl + ld bc, -20 + add hl, bc + push hl + ld h, d + ld l, e + add hl, bc + ld d, h + ld e, l + pop hl + pop bc + dec b + jr nz, .rowLoop + ld bc, 20 + add hl, bc + ld de, SevenSpacesText + call PlaceString + ld c, 2 + call DelayFrames + pop hl + pop de + pop bc + dec b + jr nz, .slideStepLoop + pop af + ld [wd730], a + ret + +SevenSpacesText: ; 3c8d7 (f:48d7) + db " @" + +; slides the player or enemy trainer off screen +; a is the number of tiles to slide it horizontally (always 9 for the player trainer or 8 for the enemy trainer) +; if a is 8, the slide is to the right, else it is to the left +; bug: when this is called, [H_AUTOBGTRANSFERENABLED] is non-zero, so there is screen tearing +SlideTrainerPicOffScreen: ; 3c8df (f:48df) + ld [$FF8B], a + ld c, a +.slideStepLoop ; each iteration, the trainer pic is slid one tile left/right + push bc + push hl + ld b, 7 ; number of rows +.rowLoop + push hl + ld a, [$FF8B] + ld c, a +.columnLoop + ld a, [$FF8B] + cp 8 + jr z, .slideRight +.slideLeft ; slide player sprite off screen + ld a, [hld] + ld [hli], a + inc hl + jr .nextColumn +.slideRight ; slide enemy trainer sprite off screen + ld a, [hli] + ld [hld], a + dec hl +.nextColumn + dec c + jr nz, .columnLoop + pop hl + ld de, 20 + add hl, de + dec b + jr nz, .rowLoop + ld c, 2 + call DelayFrames + pop hl + pop bc + dec c + jr nz, .slideStepLoop + ret + +; send out a trainer's mon +EnemySendOut: ; 3c90e (f:490e) + ld hl,wPartyGainExpFlags + xor a + ld [hl],a + ld a,[wPlayerMonNumber] + ld c,a + ld b,1 + push bc + predef FlagActionPredef + ld hl,wPartyFoughtCurrentEnemyFlags + xor a + ld [hl],a + pop bc + predef FlagActionPredef + +; don't change wPartyGainExpFlags or wPartyFoughtCurrentEnemyFlags +EnemySendOutFirstMon: ; 3c92a (f:492a) + xor a + ld hl,wd065 + ld [hli],a + ld [hli],a + ld [hli],a + ld [hli],a + ld [hl],a + ld [W_ENEMYDISABLEDMOVE],a + ld [wccef],a + ld [wccf3],a + ld hl,wccf1 + ld [hli],a + ld [hl],a + dec a + ld [wAICount],a + ld hl,W_PLAYERBATTSTATUS1 + res 5,[hl] + hlCoord 18, 0 + ld a,8 + call SlideTrainerPicOffScreen + call PrintEmptyString + call SaveScreenTilesToBuffer1 + ld a,[W_ISLINKBATTLE] + cp 4 + jr nz,.next + ld a,[wcc3e] + sub 4 + ld [wWhichPokemon],a + jr .next3 +.next + ld b,$FF +.next2 + inc b + ld a,[wEnemyMonPartyPos] + cp b + jr z,.next2 + ld hl,wEnemyMon1 + ld a,b + ld [wWhichPokemon],a + push bc + ld bc,wEnemyMon2 - wEnemyMon1 + call AddNTimes + pop bc + inc hl + ld a,[hli] + ld c,a + ld a,[hl] + or c + jr z,.next2 +.next3 + ld a,[wWhichPokemon] + ld hl,wEnemyMon1Level + ld bc,wEnemyMon2 - wEnemyMon1 + call AddNTimes + ld a,[hl] + ld [W_CURENEMYLVL],a + ld a,[wWhichPokemon] + inc a + ld hl,wEnemyPartyCount + ld c,a + ld b,0 + add hl,bc + ld a,[hl] + ld [wEnemyMonSpecies2],a + ld [wcf91],a + call LoadEnemyMonData + ld hl,wEnemyMonHP + ld a,[hli] + ld [wcce3],a + ld a,[hl] + ld [wcce4],a + ld a,1 + ld [wCurrentMenuItem],a + ld a,[wd11d] + dec a + jr z,.next4 + ld a,[wPartyCount] + dec a + jr z,.next4 + ld a,[W_ISLINKBATTLE] + cp 4 + jr z,.next4 + ld a,[W_OPTIONS] + bit 6,a + jr nz,.next4 + ld hl, TrainerAboutToUseText + call PrintText + hlCoord 0, 7 + ld bc,$0801 + ld a,$14 + ld [wd125],a + call DisplayTextBoxID + ld a,[wCurrentMenuItem] + and a + jr nz,.next4 + ld a,2 + ld [wd07d],a + call DisplayPartyMenu +.next9 + ld a,1 + ld [wCurrentMenuItem],a + jr c,.next7 + ld hl,wPlayerMonNumber + ld a,[wWhichPokemon] + cp [hl] + jr nz,.next6 + ld hl,AlreadyOutText + call PrintText +.next8 + call GoBackToPartyMenu + jr .next9 +.next6 + call HasMonFainted + jr z,.next8 + xor a + ld [wCurrentMenuItem],a +.next7 + call GBPalWhiteOut + call LoadHudTilePatterns + call LoadScreenTilesFromBuffer1 +.next4 + call ClearSprites + ld hl,wTileMap + ld bc,$040B + call ClearScreenArea + ld b,1 + call GoPAL_SET + call GBPalNormal + ld hl,TrainerSentOutText + call PrintText + ld a,[wEnemyMonSpecies2] + ld [wcf91],a + ld [wd0b5],a + call GetMonHeader + ld de,vFrontPic + call LoadMonFrontSprite + ld a,$CF + ld [$FFE1],a + hlCoord 15, 6 + predef Func_3f073 + ld a,[wEnemyMonSpecies2] + call PlayCry + call DrawEnemyHUDAndHPBar + ld a,[wCurrentMenuItem] + and a + ret nz + xor a + ld [wPartyGainExpFlags],a + ld [wPartyFoughtCurrentEnemyFlags],a + call SaveScreenTilesToBuffer1 + jp SwitchPlayerMon + +TrainerAboutToUseText: ; 3ca79 (f:4a79) + TX_FAR _TrainerAboutToUseText + db "@" + +TrainerSentOutText: ; 3ca7e (f:4a7e) + TX_FAR _TrainerSentOutText + db "@" + +; tests if the player has any pokemon that are not fainted +; sets d = 0 if all fainted, d != 0 if some mons are still alive +AnyPartyAlive: ; 3ca83 (f:4a83) + ld a, [wPartyCount] + ld e, a + xor a + ld hl, wPartyMon1HP + ld bc, wPartyMon2 - wPartyMon1 - 1 +.partyMonsLoop + or [hl] + inc hl + or [hl] + add hl, bc + dec e + jr nz, .partyMonsLoop + ld d, a + ret + +; tests if player mon has fainted +; stores whether mon has fainted in Z flag +HasMonFainted: ; 3ca97 (f:4a97) + ld a, [wWhichPokemon] + ld hl, wPartyMon1HP + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld a, [hli] + or [hl] + ret nz + ld a, [wd11d] + and a + jr nz, .done + ld hl, NoWillText + call PrintText +.done + xor a + ret + +NoWillText: ; 3cab4 (f:4ab4) + TX_FAR _NoWillText + db "@" + +; try to run from battle (hl = player speed, de = enemy speed) +; stores whether the attempt was successful in carry flag +TryRunningFromBattle: ; 3cab9 (f:4ab9) + call IsGhostBattle + jp z, .canEscape ; jump if it's a ghost battle + ld a, [W_BATTLETYPE] + cp $2 + jp z, .canEscape ; jump if it's a safari battle + ld a, [W_ISLINKBATTLE] + cp $4 + jp z, .canEscape + ld a, [W_ISINBATTLE] + dec a + jr nz, .trainerBattle ; jump if it's a trainer battle + ld a, [wNumRunAttempts] + inc a + ld [wNumRunAttempts], a + ld a, [hli] + ld [H_MULTIPLICAND + 1], a + ld a, [hl] + ld [H_MULTIPLICAND + 2], a + ld a, [de] + ld [$ff8d], a + inc de + ld a, [de] + ld [$ff8e], a + call LoadScreenTilesFromBuffer1 + ld de, H_MULTIPLICAND + 1 + ld hl, $ff8d + ld c, $2 + call StringCmp + jr nc, .canEscape ; jump if player speed greater than enemy speed + xor a + ld [H_MULTIPLICAND], a + ld a, 32 + ld [H_MULTIPLIER], a + call Multiply ; multiply player speed by 32 + ld a, [H_PRODUCT + 2] + ld [H_DIVIDEND], a + ld a, [H_PRODUCT + 3] + ld [H_DIVIDEND + 1], a + ld a, [$ff8d] + ld b, a + ld a, [$ff8e] +; divide enemy speed by 4 + srl b + rr a + srl b + rr a + and a + jr z, .canEscape ; jump if enemy speed divided by 4, mod 256 is 0 + ld [H_DIVISOR], a ; ((enemy speed / 4) % 256) + ld b, $2 + call Divide ; divide (player speed * 32) by ((enemy speed / 4) % 256) + ld a, [H_QUOTIENT + 2] + and a ; is the quotient greater than 256? + jr nz, .canEscape ; if so, the player can escape + ld a, [wNumRunAttempts] + ld c, a +; add 30 to the quotient for each run attempt +.loop + dec c + jr z, .compareWithRandomValue + ld b, 30 + ld a, [H_QUOTIENT + 3] + add b + ld [H_QUOTIENT + 3], a + jr c, .canEscape + jr .loop +.compareWithRandomValue + call BattleRandom + ld b, a + ld a, [H_QUOTIENT + 3] + cp b + jr nc, .canEscape ; if the random value was less than or equal to the quotient plus 30 times the number of attempts, the player can escape +; can't escape + ld a, $1 + ld [wcd6a], a + ld hl, CantEscapeText + jr .printCantEscapeOrNoRunningText +.trainerBattle + ld hl, NoRunningText +.printCantEscapeOrNoRunningText + call PrintText + ld a, $1 + ld [wd11f], a + call SaveScreenTilesToBuffer1 + and a ; reset carry + ret +.canEscape + ld a, [W_ISLINKBATTLE] + cp $4 + ld a, $2 + jr nz, .playSound +; link battle + call SaveScreenTilesToBuffer1 + xor a + ld [wcd6a], a + ld a, $f + ld [wPlayerMoveListIndex], a + call LinkBattleExchangeData + call LoadScreenTilesFromBuffer1 + ld a, [wcc3e] + cp $f + ld a, $2 + jr z, .playSound + dec a +.playSound + ld [wBattleResult], a + ld a, (SFX_08_44 - SFX_Headers_08) / 3 + call PlaySoundWaitForCurrent + ld hl, GotAwayText + call PrintText + call WaitForSoundToFinish + call SaveScreenTilesToBuffer1 + scf ; set carry + ret + +CantEscapeText: ; 3cb97 (f:4b97) + TX_FAR _CantEscapeText + db "@" + +NoRunningText: ; 3cb9c (f:4b9c) + TX_FAR _NoRunningText + db "@" + +GotAwayText: ; 3cba1 (f:4ba1) + TX_FAR _GotAwayText + db "@" + +; copies from party data to battle mon data when sending out a new player mon +LoadBattleMonFromParty: ; 3cba6 (f:4ba6) + ld a, [wWhichPokemon] + ld bc, $2c + ld hl, wPartyMon1Species + call AddNTimes + ld de, wBattleMonSpecies + ld bc, $c + call CopyData + ld bc, $f + add hl, bc + ld de, wBattleMonDVs + ld bc, $2 + call CopyData + ld de, wBattleMonPP + ld bc, $4 + call CopyData + ld de, wBattleMonLevel + ld bc, $b + call CopyData + ld a, [wBattleMonSpecies2] + ld [wd0b5], a + call GetMonHeader + ld hl, wPartyMonNicks + ld a, [wPlayerMonNumber] + call SkipFixedLengthTextEntries + ld de, wBattleMonNick + ld bc, $b + call CopyData + ld hl, wBattleMonLevel + ld de, wPlayerMonUnmodifiedLevel ; block of memory used for unmodified stats + ld bc, $b + call CopyData + call ApplyBurnAndParalysisPenaltiesToPlayer + call ApplyBadgeStatBoosts + ld a, $7 ; default stat modifier + ld b, $8 + ld hl, wPlayerMonAttackMod +.statModLoop + ld [hli], a + dec b + jr nz, .statModLoop + ret + +; copies from enemy party data to current enemy mon data when sending out a new enemy mon +LoadEnemyMonFromParty: ; 3cc13 (f:4c13) + ld a, [wWhichPokemon] + ld bc, $2c + ld hl, wEnemyMons + call AddNTimes + ld de, wEnemyMonSpecies + ld bc, $c + call CopyData + ld bc, $f + add hl, bc + ld de, wEnemyMonDVs + ld bc, $2 + call CopyData + ld de, wEnemyMonPP + ld bc, $4 + call CopyData + ld de, wEnemyMonLevel + ld bc, $b + call CopyData + ld a, [wEnemyMonSpecies] + ld [wd0b5], a + call GetMonHeader + ld hl, wEnemyMonNicks + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries + ld de, wEnemyMonNick + ld bc, $b + call CopyData + ld hl, wEnemyMonLevel + ld de, wEnemyMonUnmodifiedLevel ; block of memory used for unmodified stats + ld bc, $b + call CopyData + call ApplyBurnAndParalysisPenaltiesToEnemy + ld hl, W_MONHBASESTATS + ld de, wEnemyMonBaseStats + ld b, $5 +.copyBaseStatsLoop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .copyBaseStatsLoop + ld a, $7 ; default stat modifier + ld b, $8 + ld hl, wEnemyMonStatMods +.statModLoop + ld [hli], a + dec b + jr nz, .statModLoop + ld a, [wWhichPokemon] + ld [wEnemyMonPartyPos], a + ret + +SendOutMon: ; 3cc91 (f:4c91) + callab PrintSendOutMonMessage + ld hl, wEnemyMonHP + ld a, [hli] + or [hl] ; is enemy mon HP zero? + jp z, .skipDrawingEnemyHUDAndHPBar; if HP is zero, skip drawing the HUD and HP bar + call DrawEnemyHUDAndHPBar +.skipDrawingEnemyHUDAndHPBar + call DrawPlayerHUDAndHPBar + predef LoadMonBackPic + xor a + ld [$ffe1], a + ld hl, wcc2d + ld [hli], a + ld [hl], a + ld [wcc5b], a + ld [wd05b], a + ld [W_PLAYERMOVENUM], a + ld hl, wccf1 + ld [hli], a + ld [hl], a + ld hl, wd060 + ld [hli], a + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ld [W_PLAYERDISABLEDMOVE], a + ld [wccee], a + ld [wccf7], a + ld b, $1 + call GoPAL_SET + ld hl, W_ENEMYBATTSTATUS1 + res 5, [hl] + ld a, $1 + ld [H_WHOSETURN], a + ld a, POOF_ANIM + call PlayMoveAnimation + hlCoord 4, 11 + predef Func_3f073 + ld a, [wcf91] + call PlayCry + call PrintEmptyString + jp SaveScreenTilesToBuffer1 + +; show 2 stages of the player getting smaller before disappearing +AnimateRetreatingPlayerMon: ; 3ccfa (f:4cfa) + hlCoord 1, 5 + ld bc, $707 + call ClearScreenArea + hlCoord 3, 7 + ld bc, $505 + xor a + ld [wcd6c], a + ld [H_DOWNARROWBLINKCNT1], a + predef Func_79aba + ld c, $4 + call DelayFrames + call .clearScreenArea + hlCoord 4, 9 + ld bc, $303 + ld a, $1 + ld [wcd6c], a + xor a + ld [H_DOWNARROWBLINKCNT1], a + predef Func_79aba + call Delay3 + call .clearScreenArea + ld a, $4c + Coorda 5, 11 +.clearScreenArea + hlCoord 1, 5 + ld bc, $707 + jp ClearScreenArea + +; reads player's current mon's HP into wBattleMonHP +ReadPlayerMonCurHPAndStatus: ; 3cd43 (f:4d43) + ld a, [wPlayerMonNumber] + ld hl, wPartyMon1HP + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld d, h + ld e, l + ld hl, wBattleMonHP + ld bc, $4 ; 2 bytes HP, 1 byte unknown (unused?), 1 byte status + jp CopyData + +DrawHUDsAndHPBars: ; 3cd5a (f:4d5a) + call DrawPlayerHUDAndHPBar + jp DrawEnemyHUDAndHPBar + +DrawPlayerHUDAndHPBar: ; 3cd60 (f:4d60) + xor a + ld [H_AUTOBGTRANSFERENABLED], a + hlCoord 9, 7 + ld bc, $50b + call ClearScreenArea + callab PlacePlayerHUDTiles + hlCoord 18, 9 + ld [hl], $73 + ld de, wBattleMonNick + hlCoord 10, 7 + call CenterMonName + call PlaceString + ld hl, wBattleMonSpecies + ld de, wcf98 + ld bc, $c + call CopyData + ld hl, wBattleMonLevel + ld de, wcfb9 + ld bc, $b + call CopyData + hlCoord 14, 8 + push hl + inc hl + ld de, wcf9c + call PrintStatusConditionNotFainted + pop hl + jr nz, .asm_3cdae + call PrintLevel +.asm_3cdae + ld a, [wcf98] + ld [wcf91], a + hlCoord 10, 9 + predef DrawHP + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld hl, wcf1d + call GetBattleHealthBarColor + ld hl, wBattleMonHP + ld a, [hli] + or [hl] + jr z, .asm_3cdd9 + ld a, [wccf6] + and a + ret nz + ld a, [wcf1d] + cp $2 + jr z, .asm_3cde6 +.asm_3cdd9 + ld hl, wd083 + bit 7, [hl] + ld [hl], $0 + ret z + xor a + ld [wc02a], a + ret +.asm_3cde6 + ld hl, wd083 + set 7, [hl] + ret + +DrawEnemyHUDAndHPBar: ; 3cdec (f:4dec) + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld hl, wTileMap + ld bc, $40c + call ClearScreenArea + callab PlaceEnemyHUDTiles + ld de, wEnemyMonNick + hlCoord 1, 0 + call CenterMonName + call PlaceString + hlCoord 4, 1 + push hl + inc hl + ld de, wEnemyMonStatus + call PrintStatusConditionNotFainted + pop hl + jr nz, .skipPrintLevel ; if the mon has a status condition, skip printing the level + ld a, [wEnemyMonLevel] + ld [wcfb9], a + call PrintLevel +.skipPrintLevel + ld hl, wEnemyMonHP + ld a, [hli] + ld [H_MULTIPLICAND + 1], a + ld a, [hld] + ld [H_MULTIPLICAND + 2], a + or [hl] ; is current HP zero? + jr nz, .hpNonzero +; current HP is 0 +; set variables for DrawHPBar + ld c, a + ld e, a + ld d, $6 + jp .drawHPBar +.hpNonzero + xor a + ld [H_MULTIPLICAND], a + ld a, 48 + ld [H_MULTIPLIER], a + call Multiply ; multiply current HP by 48 + ld hl, wEnemyMonMaxHP + ld a, [hli] + ld b, a + ld a, [hl] + ld [H_DIVISOR], a + ld a, b + and a ; is max HP > 255? + jr z, .doDivide +; if max HP > 255, scale both (current HP * 48) and max HP by dividing by 4 so that max HP fits in one byte +; (it needs to be one byte so it can be used as the divisor for the Divide function) + ld a, [H_DIVISOR] + srl b + rr a + srl b + rr a + ld [H_DIVISOR], a + ld a, [H_PRODUCT + 2] + ld b, a + srl b + ld a, [H_PRODUCT + 3] + rr a + srl b + rr a + ld [H_PRODUCT + 3], a + ld a, b + ld [H_PRODUCT + 2], a +.doDivide + ld a, [H_PRODUCT + 2] + ld [H_DIVIDEND], a + ld a, [H_PRODUCT + 3] + ld [H_DIVIDEND + 1], a + ld a, $2 + ld b, a + call Divide ; divide (current HP * 48) by max HP + ld a, [H_QUOTIENT + 3] +; set variables for DrawHPBar + ld e, a + ld a, $6 + ld d, a + ld c, a +.drawHPBar + xor a + ld [wListMenuID], a + hlCoord 2, 2 + call DrawHPBar + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld hl, wcf1e + +GetBattleHealthBarColor: ; 3ce90 (f:4e90) + ld b, [hl] + call GetHealthBarColor + ld a, [hl] + cp b + ret z + ld b, $1 + jp GoPAL_SET + +; center's mon's name on the battle screen +; if the name is 1 or 2 letters long, it is printed 2 spaces more to the right than usual (i.e. for names longer than 4 letters) +; if the name is 3 or 4 letters long, it is printed 1 space more to the right than usual (i.e. for names longer than 4 letters) +CenterMonName: ; 3ce9c (f:4e9c) + push de + inc hl + inc hl + ld b, $2 +.loop + inc de + ld a, [de] + cp $50 + jr z, .done + inc de + ld a, [de] + cp $50 + jr z, .done + dec hl + dec b + jr nz, .loop +.done + pop de + ret + +DisplayBattleMenu: ; 3ceb3 (f:4eb3) + call LoadScreenTilesFromBuffer1 ; restore saved screen + ld a, [W_BATTLETYPE] + and a + jr nz, .nonstandardbattle + call DrawHUDsAndHPBars + call PrintEmptyString + call SaveScreenTilesToBuffer1 +.nonstandardbattle + ld a, [W_BATTLETYPE] + cp $2 ; safari + ld a, $b ; safari menu id + jr nz, .menuselected + ld a, $1b ; regular menu id +.menuselected + ld [wd125], a + call DisplayTextBoxID + ld a, [W_BATTLETYPE] + dec a + jp nz, .handleBattleMenuInput ; handle menu input if it's not the old man tutorial +; the following happens for the old man tutorial + ld hl, wPlayerName + ld de, W_GRASSRATE + ld bc, $b + call CopyData ; temporarily save the player name in unused space, + ; which is supposed to get overwritten when entering a + ; map with wild pokémon. due to an oversight, the data + ; may not get overwritten (cinnabar) and the infamous + ; missingno. glitch can show up. + ld hl, .oldManName + ld de, wPlayerName + ld bc, $b + call CopyData + ; the following simulates the keystrokes by drawing menus on screen + hlCoord 9, 14 + ld [hl], "▶" + ld c, $50 + call DelayFrames + ld [hl], $7f + hlCoord 9, 16 + ld [hl], "▶" + ld c, $32 + call DelayFrames + ld [hl], $ec + ld a, $2 ; select the "ITEM" menu + jp .upperLeftMenuItemWasNotSelected +.oldManName + db "OLD MAN@" +.handleBattleMenuInput + ld a, [wcc2d] + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + sub 2 ; check if the cursor is in the left column + jr c, .leftColumn +; cursor is in the right column + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + jr .rightColumn +.leftColumn ; put cursor in left column of menu + ld a, [W_BATTLETYPE] + cp $2 + ld a, " " + jr z, .safariLeftColumn +; put cursor in left column for normal battle menu (i.e. when it's not a Safari battle) + Coorda 15, 14 ; clear upper cursor position in right column + Coorda 15, 16 ; clear lower cursor position in right column + ld b, $9 ; top menu item X + jr .leftColumn_WaitForInput +.safariLeftColumn + Coorda 13, 14 + Coorda 13, 16 + hlCoord 7, 14 + ld de, W_NUMSAFARIBALLS + ld bc, $102 + call PrintNumber + ld b, $1 ; top menu item X +.leftColumn_WaitForInput + ld hl, wTopMenuItemY + ld a, $e + ld [hli], a ; wTopMenuItemY + ld a, b + ld [hli], a ; wTopMenuItemX + inc hl + inc hl + ld a, $1 + ld [hli], a ; wMaxMenuItem + ld [hl], D_RIGHT | A_BUTTON ; wMenuWatchedKeys + call HandleMenuInput + bit 4, a ; check if right was pressed + jr nz, .rightColumn + jr .AButtonPressed ; the A button was pressed +.rightColumn ; put cursor in right column of menu + ld a, [W_BATTLETYPE] + cp $2 + ld a, " " + jr z, .safariRightColumn +; put cursor in right column for normal battle menu (i.e. when it's not a Safari battle) + Coorda 9, 14 ; clear upper cursor position in left column + Coorda 9, 16 ; clear lower cursor position in left column + ld b, $f ; top menu item X + jr .rightColumn_WaitForInput +.safariRightColumn + Coorda 1, 14 ; clear upper cursor position in left column + Coorda 1, 16 ; clear lower cursor position in left column + hlCoord 7, 14 + ld de, W_NUMSAFARIBALLS + ld bc, $102 + call PrintNumber + ld b, $d ; top menu item X +.rightColumn_WaitForInput + ld hl, wTopMenuItemY + ld a, $e + ld [hli], a ; wTopMenuItemY + ld a, b + ld [hli], a ; wTopMenuItemX + inc hl + inc hl + ld a, $1 + ld [hli], a ; wMaxMenuItem + ld a, D_LEFT | A_BUTTON + ld [hli], a ; wMenuWatchedKeys + call HandleMenuInput + bit 5, a ; check if left was pressed + jr nz, .leftColumn ; if left was pressed, jump + ld a, [wCurrentMenuItem] + add $2 ; if we're in the right column, the actual id is +2 + ld [wCurrentMenuItem], a +.AButtonPressed + call PlaceUnfilledArrowMenuCursor + ld a, [W_BATTLETYPE] + cp $2 ; is it a Safari battle? + ld a, [wCurrentMenuItem] + ld [wcc2d], a + jr z, .handleMenuSelection +; not Safari battle +; swap the IDs of the item menu and party menu (this is probably because they swapped the positions of these menu items in first generation English versions) + cp $1 ; was the item menu selected? + jr nz, .notItemMenu +; item menu was selected + inc a ; increment a to 2 + jr .handleMenuSelection +.notItemMenu + cp $2 ; was the party menu selected? + jr nz, .handleMenuSelection +; party menu selected + dec a ; decrement a to 1 +.handleMenuSelection + and a + jr nz, .upperLeftMenuItemWasNotSelected +; the upper left menu item was selected + ld a, [W_BATTLETYPE] + cp $2 + jr z, .throwSafariBallWasSelected +; the "FIGHT" menu was selected + xor a + ld [wNumRunAttempts], a + jp LoadScreenTilesFromBuffer1 ; restore saved screen and return +.throwSafariBallWasSelected + ld a, SAFARI_BALL + ld [wcf91], a + jr .useItem +.upperLeftMenuItemWasNotSelected ; a menu item other than the upper left item was selected + cp $2 + jp nz, .partyMenuOrRockOrRunWasSelected +; either the bag (normal battle) or bait (safari battle) was selected + ld a, [W_ISLINKBATTLE] + cp $4 + jr nz, .notLinkBattle +; can't use items in link battles + ld hl, .itemsCantBeUsedHereText + call PrintText + jp DisplayBattleMenu +.notLinkBattle + call SaveScreenTilesToBuffer2 + ld a, [W_BATTLETYPE] + cp $2 ; is it a safari battle? + jr nz, .bagWasSelected +; bait was selected + ld a, SAFARI_BAIT + ld [wcf91], a + jr .useItem +.bagWasSelected + call LoadScreenTilesFromBuffer1 + ld a, [W_BATTLETYPE] + and a ; is it a normal battle? + jr nz, .next +; normal battle + call DrawHUDsAndHPBars +.next + ld a, [W_BATTLETYPE] + dec a ; is it the old man tutorial? + jr nz, .getPlayerBagPointer ; no, it is a normal battle + ld hl, .oldManItemList + ld a, l + ld [wcf8b], a + ld a, h + ld [wcf8c], a +<<<<<<< HEAD + jr Func_3d03c + +OldManItemList: ; 3d02d (f:502d) + db 1 ; # items + db POKE_BALL, 50 + db -1 + +Func_3d031 + ld hl, wNumBagItems ; wNumBagItems +======= + jr .displayBagMenu +.oldManItemList + db $01, POKE_BALL, 50, $ff +.getPlayerBagPointer ; get the pointer to player's bag when in a normal battle + ld hl, wNumBagItems +>>>>>>> yama/master + ld a, l + ld [wcf8b], a + ld a, h + ld [wcf8c], a +.displayBagMenu + xor a + ld [wcf93], a + ld a, ITEMLISTMENU + ld [wListMenuID], a + ld a, [wcc2c] + ld [wCurrentMenuItem], a + call DisplayListMenuID + ld a, [wCurrentMenuItem] + ld [wcc2c], a + ld a, $0 + ld [wcc37], a + ld [wMenuItemToSwap], a + jp c, DisplayBattleMenu ; go back to battle menu if an item was not selected +.useItem ; either use an item from the bag or use a safari zone item + ld a, [wcf91] + ld [wd11e], a + call GetItemName + call CopyStringToCF4B ; copy name + xor a + ld [wd152], a + call UseItem + call LoadHudTilePatterns + call ClearSprites + xor a + ld [wCurrentMenuItem], a + ld a, [W_BATTLETYPE] + cp $2 ; is it a safari battle? + jr z, .checkIfMonCaptured + ld a, [wcd6a] + and a ; was the item used successfully? + jp z, .bagWasSelected ; if not, go back to the bag menu + ld a, [W_PLAYERBATTSTATUS1] + bit 5, a ; is the player using a multi-turn move like wrap? + jr z, .checkIfMonCaptured + ld hl, wPlayerNumAttacksLeft + dec [hl] + jr nz, .checkIfMonCaptured + ld hl, W_PLAYERBATTSTATUS1 + res 5, [hl] ; not using multi-turn move any more +.checkIfMonCaptured + ld a, [wd11c] + and a ; was the enemy mon captured with a ball? + jr nz, .returnAfterCapturingMon + ld a, [W_BATTLETYPE] + cp $2 ; is it a safari battle? + jr z, .returnAfterUsingItem_NoCapture +; not a safari battle + call LoadScreenTilesFromBuffer1 + call DrawHUDsAndHPBars + call Delay3 +.returnAfterUsingItem_NoCapture + call GBPalNormal + and a ; reset carry + ret +.returnAfterCapturingMon + call GBPalNormal + xor a + ld [wd11c], a + ld a, $2 + ld [wBattleResult], a + scf ; set carry + ret + +.itemsCantBeUsedHereText + TX_FAR _ItemsCantBeUsedHereText + db "@" + +.partyMenuOrRockOrRunWasSelected + dec a ; was Run selected? + jp nz, BattleMenu_RunWasSelected +; party menu or rock was selected + call SaveScreenTilesToBuffer2 + ld a, [W_BATTLETYPE] + cp $2 ; is it a safari battle? + jr nz, .partyMenuWasSelected +; safari battle + ld a, SAFARI_ROCK + ld [wcf91], a + jp .useItem +.partyMenuWasSelected + call LoadScreenTilesFromBuffer1 + xor a + ld [wd07d], a + ld [wMenuItemToSwap], a + call DisplayPartyMenu +.checkIfPartyMonWasSelected + jp nc, .partyMonWasSelected ; if a party mon was selected, jump, else we quit the party menu +.quitPartyMenu + call ClearSprites + call GBPalWhiteOut + call LoadHudTilePatterns + call LoadScreenTilesFromBuffer2 + call GoPAL_SET_CF1C + call GBPalNormal + jp DisplayBattleMenu +.partyMonDeselected + hlCoord 11, 11 + ld bc, $81 + ld a, $7f + call FillMemory + xor a + ld [wd07d], a + call GoBackToPartyMenu + jr .checkIfPartyMonWasSelected +.partyMonWasSelected + ld a, $c ; switch/stats/cancel menu + ld [wd125], a + call DisplayTextBoxID + ld hl, wTopMenuItemY + ld a, $c + ld [hli], a ; wTopMenuItemY + ld [hli], a ; wTopMenuItemX + xor a + ld [hli], a ; wCurrentMenuItem + inc hl + ld a, $2 + ld [hli], a ; wMaxMenuItem + ld a, B_BUTTON | A_BUTTON + ld [hli], a ; wMenuWatchedKeys + xor a + ld [hl], a ; wLastMenuItem + call HandleMenuInput + bit 1, a ; was A pressed? + jr nz, .partyMonDeselected ; if B was pressed, jump +; A was pressed + call PlaceUnfilledArrowMenuCursor + ld a, [wCurrentMenuItem] + cp $2 ; was Cancel selected? + jr z, .quitPartyMenu ; if so, quit the party menu entirely + and a ; was Switch selected? + jr z, .switchMon ; if so, jump +; Stats was selected + xor a + ld [wcc49], a + ld hl, wPartyMon1 + call ClearSprites +; display the two status screens + predef StatusScreen + predef StatusScreen2 +; now we need to reload the enemy mon pic + ld a, [W_ENEMYBATTSTATUS2] + bit 4, a ; does the enemy mon have a substitute? + ld hl, AnimationSubstitute + jr nz, .doEnemyMonAnimation +; enemy mon doesn't have substitute + ld a, [wccf3] + and a ; has the enemy mon used Minimise? + ld hl, AnimationMinimizeMon + jr nz, .doEnemyMonAnimation +; enemy mon is not minimised + ld a, [wEnemyMonSpecies] + ld [wcf91], a + ld [wd0b5], a + call GetMonHeader + ld de, vFrontPic + call LoadMonFrontSprite + jr .enemyMonPicReloaded +.doEnemyMonAnimation + ld b, BANK(AnimationSubstitute) ; BANK(AnimationMinimizeMon) + call Bankswitch +.enemyMonPicReloaded ; enemy mon pic has been reloaded, so return to the party menu + jp .partyMenuWasSelected +.switchMon + ld a, [wPlayerMonNumber] + ld d, a + ld a, [wWhichPokemon] + cp d ; check if the mon to switch to is already out + jr nz, .notAlreadyOut +; mon is already out + ld hl, AlreadyOutText + call PrintText + jp .partyMonDeselected +.notAlreadyOut + call HasMonFainted + jp z, .partyMonDeselected ; can't switch to fainted mon + ld a, $1 + ld [wcd6a], a + call GBPalWhiteOut + call ClearSprites + call LoadHudTilePatterns + call LoadScreenTilesFromBuffer1 + call GoPAL_SET_CF1C + call GBPalNormal +; fall through to SwitchPlayerMon + +SwitchPlayerMon: ; 3d1ba (f:51ba) + callab RetreatMon + ld c, $32 + call DelayFrames + call AnimateRetreatingPlayerMon + ld a, [wWhichPokemon] + ld [wPlayerMonNumber], a + ld c, a + ld b, $1 + push bc + ld hl, wPartyGainExpFlags + predef FlagActionPredef + pop bc + ld hl, wPartyFoughtCurrentEnemyFlags + predef FlagActionPredef + call LoadBattleMonFromParty + call SendOutMon + call SaveScreenTilesToBuffer1 + ld a, $2 + ld [wCurrentMenuItem], a + and a + ret + +AlreadyOutText: ; 3d1f5 (f:51f5) + TX_FAR _AlreadyOutText + db "@" + +BattleMenu_RunWasSelected: ; 3d1fa (f:51fa) + call LoadScreenTilesFromBuffer1 + ld a, $3 + ld [wCurrentMenuItem], a + ld hl, wBattleMonSpeed + ld de, wEnemyMonSpeed + call TryRunningFromBattle + ld a, $0 + ld [wd11f], a + ret c + ld a, [wcd6a] + and a + ret nz + jp DisplayBattleMenu + +MoveSelectionMenu: ; 3d219 (f:5219) + ld a, [wMoveMenuType] + dec a + jr z, .mimicmenu + dec a + jr z, .relearnmenu + jr .regularmenu + +.loadmoves + ld de, wd0dc + ld bc, $4 + call CopyData + callab Func_39b87 + ret + +.writemoves + ld de, wd0e1 + ld a, [$fff6] + set 2, a + ld [$fff6], a + call PlaceString + ld a, [$fff6] + res 2, a + ld [$fff6], a + ret + +.regularmenu + call Func_3d3f5 + ret z + ld hl, wBattleMonMoves + call .loadmoves + hlCoord 4, 12 + ld b, $4 + ld c, $e + di + call TextBoxBorder + hlCoord 4, 12 + ld [hl], $7a + hlCoord 10, 12 + ld [hl], $7e + ei + hlCoord 6, 13 + call .writemoves + ld b, $5 + ld a, $c + jr .menuset +.mimicmenu + ld hl, wEnemyMonMoves + call .loadmoves + hlCoord 0, 7 + ld b, $4 + ld c, $e + call TextBoxBorder + hlCoord 2, 8 + call .writemoves + ld b, $1 + ld a, $7 + jr .menuset +.relearnmenu + ld a, [wWhichPokemon] + ld hl, wPartyMon1Moves + ld bc, $2c + call AddNTimes + call .loadmoves + hlCoord 4, 7 + ld b, $4 + ld c, $e + call TextBoxBorder + hlCoord 6, 8 + call .writemoves + ld b, $5 + ld a, $7 +.menuset + ld hl, wTopMenuItemY + ld [hli], a + ld a, b + ld [hli], a + ld a, [wMoveMenuType] + cp $1 + jr z, .selectedmoveknown + ld a, $1 + jr nc, .selectedmoveknown + ld a, [wPlayerMoveListIndex] + inc a +.selectedmoveknown + ld [hli], a + inc hl ; wTileBehindCursor untouched + ld a, [wcd6c] + inc a + inc a + ld [hli], a + ld a, [wMoveMenuType] + dec a + ld b, $c1 ; can't use B + jr z, .matchedkeyspicked + dec a + ld b, $c3 + jr z, .matchedkeyspicked + ld a, [W_ISLINKBATTLE] + cp $4 + jr z, .matchedkeyspicked + ld a, [W_FLAGS_D733] + bit 0, a + ld b, $c7 + jr z, .matchedkeyspicked + ld b, $ff +.matchedkeyspicked + ld a, b + ld [hli], a + ld a, [wMoveMenuType] + cp $1 + jr z, .movelistindex1 + ld a, [wPlayerMoveListIndex] + inc a +.movelistindex1 + ld [hl], a + +Func_3d2fe: ; 3d2fe (f:52fe) + ld a, [wMoveMenuType] + and a + jr z, .battleselect + dec a + jr nz, .select + hlCoord 1, 14 + ld de, WhichTechniqueString + call PlaceString + jr .select +.battleselect + ld a, [W_FLAGS_D733] + bit 0, a + jr nz, .select + call Func_3d4b6 + ld a, [wMenuItemToSwap] + and a + jr z, .select + hlCoord 5, 13 + dec a + ld bc, $14 + call AddNTimes + ld [hl], $ec +.select + ld hl, $fff6 + set 1, [hl] + call HandleMenuInput + ld hl, $fff6 + res 1, [hl] + bit 6, a + jp nz, Func_3d3c9 ; up + bit 7, a + jp nz, Func_3d3dd ; down + bit 2, a + jp nz, SwapMovesInMenu ; select + bit 1, a ; B, but was it reset above? + push af + xor a + ld [wMenuItemToSwap], a + ld a, [wCurrentMenuItem] + dec a + ld [wCurrentMenuItem], a + ld b, a + ld a, [wMoveMenuType] + dec a ; if not mimic + jr nz, .nob + pop af + ret +.nob + dec a + ld a, b + ld [wPlayerMoveListIndex], a + jr nz, .moveselected + pop af + ret +.moveselected + pop af + ret nz + ld hl, wBattleMonPP + ld a, [wCurrentMenuItem] + ld c, a + ld b, $0 + add hl, bc + ld a, [hl] + and $3f + jr z, .nopp + ld a, [W_PLAYERDISABLEDMOVE] + swap a + and $f + dec a + cp c + jr z, .disabled + ld a, [W_PLAYERBATTSTATUS3] + bit 3, a ; transformed + jr nz, .dummy ; game freak derp +.dummy + ld a, [wCurrentMenuItem] + ld hl, wBattleMonMoves + ld c, a + ld b, $0 + add hl, bc + ld a, [hl] + ld [wPlayerSelectedMove], a + xor a + ret +.disabled + ld hl, MoveDisabledText + jr .print +.nopp + ld hl, MoveNoPPText +.print + call PrintText + call LoadScreenTilesFromBuffer1 + jp MoveSelectionMenu + +MoveNoPPText: ; 3d3ae (f:53ae) + TX_FAR _MoveNoPPText + db "@" + +MoveDisabledText: ; 3d3b3 (f:53b3) + TX_FAR _MoveDisabledText + db "@" + +WhichTechniqueString: ; 3d3b8 (f:53b8) + db "WHICH TECHNIQUE?@" + +Func_3d3c9: ; 3d3c9 (f:53c9) + ld a, [wCurrentMenuItem] + and a + jp nz, Func_3d2fe + call EraseMenuCursor + ld a, [wcd6c] + inc a + ld [wCurrentMenuItem], a + jp Func_3d2fe + +Func_3d3dd: ; 3d3dd (f:53dd) + ld a, [wCurrentMenuItem] + ld b, a + ld a, [wcd6c] + inc a + inc a + cp b + jp nz, Func_3d2fe + call EraseMenuCursor + ld a, $1 + ld [wCurrentMenuItem], a + jp Func_3d2fe + +Func_3d3f5: ; 3d3f5 (f:53f5) + ld a, STRUGGLE + ld [wPlayerSelectedMove], a + ld a, [W_PLAYERDISABLEDMOVE] + and a + ld hl, wBattleMonPP + jr nz, .asm_3d40e + ld a, [hli] + or [hl] + inc hl + or [hl] + inc hl + or [hl] + and $3f + ret nz + jr .asm_3d423 +.asm_3d40e + swap a + and $f + ld b, a + ld d, $5 + xor a +.asm_3d416 + dec d + jr z, .asm_3d421 + ld c, [hl] + inc hl + dec b + jr z, .asm_3d416 + or c + jr .asm_3d416 +.asm_3d421 + and a + ret nz +.asm_3d423 + ld hl, NoMovesLeftText + call PrintText + ld c, $3c + call DelayFrames + xor a + ret + +NoMovesLeftText: ; 3d430 (f:5430) + TX_FAR _NoMovesLeftText + db "@" + +SwapMovesInMenu: ; 3d435 (f:5435) + ld a, [wMenuItemToSwap] + and a + jr z, .noMenuItemSelected + ld hl, wBattleMonMoves + call .swapBytes ; swap moves + ld hl, wBattleMonPP + call .swapBytes ; swap move PP +; update the index of the disabled move if necessary + ld hl, W_PLAYERDISABLEDMOVE + ld a, [hl] + swap a + and $f + ld b, a + ld a, [wCurrentMenuItem] + cp b + jr nz, .next + ld a, [hl] + and $f + ld b, a + ld a, [wMenuItemToSwap] + swap a + add b + ld [hl], a + jr .swapMovesInPartyMon +.next + ld a, [wMenuItemToSwap] + cp b + jr nz, .swapMovesInPartyMon + ld a, [hl] + and $f + ld b, a + ld a, [wCurrentMenuItem] + swap a + add b + ld [hl], a +.swapMovesInPartyMon + ld hl, wPartyMon1Moves + ld a, [wPlayerMonNumber] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + push hl + call .swapBytes ; swap moves + pop hl + ld bc, $15 + add hl, bc + call .swapBytes ; swap move PP + xor a + ld [wMenuItemToSwap], a ; deselect the item + jp MoveSelectionMenu +.swapBytes + push hl + ld a, [wMenuItemToSwap] + dec a + ld c, a + ld b, 0 + add hl, bc + ld d, h + ld e, l + pop hl + ld a, [wCurrentMenuItem] + dec a + ld c, a + ld b, 0 + add hl, bc + ld a, [de] + ld b, [hl] + ld [hl], a + ld a, b + ld [de], a + ret +.noMenuItemSelected + ld a, [wCurrentMenuItem] + ld [wMenuItemToSwap], a ; select the current menu item for swapping + jp MoveSelectionMenu + +Func_3d4b6: ; 3d4b6 (f:54b6) + xor a + ld [H_AUTOBGTRANSFERENABLED], a + hlCoord 0, 8 + ld b, $3 + ld c, $9 + call TextBoxBorder + ld a, [W_PLAYERDISABLEDMOVE] + and a + jr z, .asm_3d4df + swap a + and $f + ld b, a + ld a, [wCurrentMenuItem] + cp b + jr nz, .asm_3d4df + hlCoord 1, 10 + ld de, DisabledText + call PlaceString + jr .asm_3d54e +.asm_3d4df + ld hl, wCurrentMenuItem + dec [hl] + xor a + ld [H_WHOSETURN], a + ld hl, wBattleMonMoves + ld a, [wCurrentMenuItem] + ld c, a + ld b, $0 + add hl, bc + ld a, [hl] + ld [wPlayerSelectedMove], a + ld a, [wPlayerMonNumber] + ld [wWhichPokemon], a + ld a, $4 + ld [wcc49], a + callab GetMaxPP + ld hl, wCurrentMenuItem + ld c, [hl] + inc [hl] + ld b, $0 + ld hl, wBattleMonPP + add hl, bc + ld a, [hl] + and $3f + ld [wcd6d], a + hlCoord 1, 9 + ld de, TypeText + call PlaceString + hlCoord 7, 11 + ld [hl], "/" + hlCoord 5, 9 + ld [hl], "/" + hlCoord 5, 11 + ld de, wcd6d + ld bc, $102 + call PrintNumber + hlCoord 8, 11 + ld de, wd11e + ld bc, $102 + call PrintNumber + call GetCurrentMove + hlCoord 2, 10 + predef Func_27d98 +.asm_3d54e + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + jp Delay3 + +DisabledText: ; 3d555 (f:5555) + db "disabled!@" + +TypeText: ; 3d55f (f:555f) + db "TYPE@" + +SelectEnemyMove: ; 3d564 (f:5564) + ld a, [W_ISLINKBATTLE] + sub $4 + jr nz, .noLinkBattle +; link battle + call SaveScreenTilesToBuffer1 + call LinkBattleExchangeData + call LoadScreenTilesFromBuffer1 + ld a, [wcc3e] + cp $e + jp z, .asm_3d601 + cp $d + jr z, .unableToMove + cp $4 + ret nc + ld [wEnemyMoveListIndex], a + ld c, a + ld hl, wEnemyMonMoves + ld b, $0 + add hl, bc + ld a, [hl] + jr .done +.noLinkBattle + ld a, [W_ENEMYBATTSTATUS2] + and $60 ; need to recharge or using rage + ret nz + ld hl, W_ENEMYBATTSTATUS1 + ld a, [hl] + and $12 ; using multi-turn move or bide + ret nz + ld a, [wEnemyMonStatus] + and SLP | 1 << FRZ ; sleeping or frozen + ret nz + ld a, [W_ENEMYBATTSTATUS1] + and $21 ; using fly/dig or thrash/petal dance + ret nz + ld a, [W_PLAYERBATTSTATUS1] + bit 5, a ; caught in player's multi-turn move (e.g. wrap) + jr z, .notCaughtInWrap +.unableToMove + ld a, $ff + jr .done +.notCaughtInWrap + ld hl, wEnemyMonMoves+1 ; 2nd enemy move + ld a, [hld] + and a + jr nz, .atLeastTwoMovesAvailable + ld a, [W_ENEMYDISABLEDMOVE] + and a + ld a, STRUGGLE ; struggle if the only move is disabled + jr nz, .done +.atLeastTwoMovesAvailable + ld a, [W_ISINBATTLE] + dec a + jr z, .chooseRandomMove ; wild encounter + callab AIEnemyTrainerChooseMoves +.chooseRandomMove + push hl + call BattleRandom + ld b, $1 + cp $3f ; select move 1 in [0,3e] (63/256 chance) + jr c, .moveChosen + inc hl + inc b + cp $7f ; select move 1 in [3f,7e] (64/256 chance) + jr c, .moveChosen + inc hl + inc b + cp $be ; select move 1 in [7f,bd] (63/256 chance) + jr c, .moveChosen + inc hl + inc b ; select move 4 in [be,ff] (66/256 chance) +.moveChosen + ld a, b + dec a + ld [wEnemyMoveListIndex], a + ld a, [W_ENEMYDISABLEDMOVE] + swap a + and $f + cp b + ld a, [hl] + pop hl + jr z, .chooseRandomMove ; move disabled, try again + and a + jr z, .chooseRandomMove ; move non-existant, try again +.done + ld [wEnemySelectedMove], a + ret +.asm_3d601 + ld a, STRUGGLE + jr .done + +; this appears to exchange data with the other gameboy during link battles +LinkBattleExchangeData: ; 3d605 (f:5605) + ld a, $ff + ld [wcc3e], a + ld a, [wPlayerMoveListIndex] + cp $f ; is the player running from battle? + jr z, .asm_3d630 + ld a, [wcd6a] + and a + jr nz, .asm_3d629 + ld a, [wPlayerSelectedMove] + cp STRUGGLE + ld b, $e + jr z, .asm_3d62f + dec b + inc a + jr z, .asm_3d62f + ld a, [wPlayerMoveListIndex] + jr .asm_3d630 +.asm_3d629 + ld a, [wWhichPokemon] + add $4 + ld b, a +.asm_3d62f + ld a, b +.asm_3d630 + ld [wcc42], a + callab PrintWaitingText +.asm_3d63b + call Func_22c3 + call DelayFrame + ld a, [wcc3e] + inc a + jr z, .asm_3d63b + ld b, $a +.asm_3d649 + call DelayFrame + call Func_22c3 + dec b + jr nz, .asm_3d649 + ld b, $a +.asm_3d654 + call DelayFrame + call Func_22ed + dec b + jr nz, .asm_3d654 + ret + +ExecutePlayerMove: ; 3d65e (f:565e) + xor a + ld [H_WHOSETURN], a + ld a, [wPlayerSelectedMove] + inc a + jp z, Func_3d80a + xor a + ld [W_MOVEMISSED], a + ld [wcced], a + ld [wccf4], a + ld a, $a + ld [wd05b], a + ld a, [wcd6a] + and a + jp nz, Func_3d80a + call PrintGhostText + jp z, Func_3d80a + call CheckPlayerStatusConditions + jr nz, .asm_3d68a + jp [hl] +.asm_3d68a + call GetCurrentMove + ld hl, W_PLAYERBATTSTATUS1 + bit 4, [hl] + jr nz, asm_3d6a9 + call CheckForDisobedience + jp z, Func_3d80a + +Func_3d69a: ; 3d69a (f:569a) + ld a, [W_PLAYERMOVEEFFECT] + cp CHARGE_EFFECT + jp z, JumpMoveEffect + cp FLY_EFFECT + jp z, JumpMoveEffect + jr asm_3d6b0 + +; in-battle stuff +asm_3d6a9: ; 3d6a9 (f:56a9) + ld hl,W_PLAYERBATTSTATUS1 + res 4,[hl] + res 6,[hl] +asm_3d6b0: ; 3d6b0 (f:56b0) + call PrintMonName1Text + ld hl,DecrementPP + ld de,wPlayerSelectedMove ; pointer to the move just used + ld b,BANK(DecrementPP) + call Bankswitch + ld a,[W_PLAYERMOVEEFFECT] ; effect of the move just used + ld hl,EffectsArray1 + ld de,1 + call IsInArray + jp c,JumpMoveEffect + ld a,[W_PLAYERMOVEEFFECT] + ld hl,EffectsArray5B + ld de,1 + call IsInArray + call c,JumpMoveEffect +asm_3d6dc: ; 3d6dc (f:56dc) + ld a,[W_PLAYERMOVEEFFECT] + ld hl,EffectsArray2 + ld de,1 + call IsInArray + jp c,.asm_3d702 + call CriticalHitTest + call HandleCounterMove + jr z,asm_3d705 + call GetDamageVarsForPlayerAttack + call CalculateDamage + jp z,asm_3d74b + call AdjustDamageForMoveType + call RandomizeDamage +.asm_3d702 + call MoveHitTest +asm_3d705 + ld a,[W_MOVEMISSED] + and a + jr z,asm_3d714 + ld a,[W_PLAYERMOVEEFFECT] + sub a,7 + jr z,asm_3d71e + jr asm_3d74b +asm_3d714 + ld a,[W_PLAYERMOVEEFFECT] + and a + ld a,4 + jr z,asm_3d71e + ld a,5 +asm_3d71e + push af + ld a,[W_PLAYERBATTSTATUS2] + bit 4,a + ld hl,Func_79747 + ld b,BANK(Func_79747) + call nz,Bankswitch + pop af + ld [wcc5b],a + ld a,[W_PLAYERMOVENUM] + call PlayMoveAnimation + call Func_3eed3 + call DrawPlayerHUDAndHPBar + ld a,[W_PLAYERBATTSTATUS2] + bit 4,a + ld hl,Func_79771 + ld b,BANK(Func_79771) + call nz,Bankswitch + jr asm_3d766 +asm_3d74b + ld c,$1E + call DelayFrames + ld a,[W_PLAYERMOVEEFFECT] + cp a,FLY_EFFECT + jr z,.next5 + cp a,CHARGE_EFFECT + jr z,.next5 + jr asm_3d766 +.next5 + xor a + ld [wcc5b],a + ld a,STATUS_AFFECTED_ANIM + call PlayMoveAnimation +asm_3d766 + ld a,[W_PLAYERMOVEEFFECT] + cp a,MIRROR_MOVE_EFFECT + jr nz,.next6 + call MirrorMoveCopyMove + jp z,Func_3d80a + xor a + ld [wcced],a + jp Func_3d69a +.next6 + cp a,METRONOME_EFFECT + jr nz,.next7 + call MetronomePickMove + jp Func_3d69a +.next7 + ld a,[W_PLAYERMOVEEFFECT] + ld hl,EffectsArray3 + ld de,1 + call IsInArray + jp c,JumpMoveEffect + ld a,[W_MOVEMISSED] + and a + jr z,.next8 + call PrintMoveFailureText + ld a,[W_PLAYERMOVEEFFECT] + cp a,EXPLODE_EFFECT + jr z,.next9 + jp Func_3d80a +.next8 + call ApplyAttackToEnemyPokemon + call PrintCriticalOHKOText + callab DisplayEffectiveness + ld a,1 + ld [wccf4],a +.next9 + ld a,[W_PLAYERMOVEEFFECT] + ld hl,EffectsArray4 + ld de,1 + call IsInArray + call c,JumpMoveEffect + ld hl,wEnemyMonHP + ld a,[hli] + ld b,[hl] + or b + ret z + call HandleBuildingRage + + ld hl,W_PLAYERBATTSTATUS1 + bit 2,[hl] + jr z,.next10 + ld a,[wPlayerNumAttacksLeft] + dec a + ld [wPlayerNumAttacksLeft],a + jp nz,asm_3d714 + + res 2,[hl] + ld hl,MultiHitText + call PrintText + xor a + ld [W_NUMHITS],a ; reset +.next10 + ld a,[W_PLAYERMOVEEFFECT] + and a + jp z,Func_3d80a + ld hl,EffectsArray5 + ld de,1 + call IsInArray + call nc,JumpMoveEffect + jp Func_3d80a + +MultiHitText: ; 3d805 (f:5805) + TX_FAR _MultiHitText + db "@" + +Func_3d80a: ; 3d80a (f:580a) + xor a + ld [wcd6a],a + ld b,1 + ret + +PrintGhostText: ; 3d811 (f:5811) +; print the ghost battle messages + call IsGhostBattle + ret nz + ld a,[H_WHOSETURN] + and a + jr nz,.Ghost + ld a,[wBattleMonStatus] ; player’s turn + and a,SLP | (1 << FRZ) + ret nz + ld hl,ScaredText + call PrintText + xor a + ret +.Ghost ; ghost’s turn + ld hl,GetOutText + call PrintText + xor a + ret + +ScaredText: ; 3d830 (f:5830) + TX_FAR _ScaredText + db "@" + +GetOutText: ; 3d835 (f:5835) + TX_FAR _GetOutText + db "@" + +IsGhostBattle: ; 3d83a (f:583a) + ld a,[W_ISINBATTLE] + dec a + ret nz + ld a,[W_CURMAP] + cp a,POKEMONTOWER_1 + jr c,.next + cp a,LAVENDER_HOUSE_1 + jr nc,.next + ld b,SILPH_SCOPE + call IsItemInBag + ret z +.next + ld a,1 + and a + ret + +; checks for various status conditions affecting the player mon +; stores whether the mon cannot use a move this turn in Z flag +CheckPlayerStatusConditions: ; 3d854 (f:5854) + ld hl,wBattleMonStatus + ld a,[hl] + and a,SLP ; sleep mask + jr z,.FrozenCheck + +; sleeping + dec a + ld [wBattleMonStatus],a ; decrement number of turns left + and a + jr z,.WakeUp ; if the number of turns hit 0, wake up +; fast asleep + xor a + ld [wcc5b],a + ld a,SLP_ANIM - 1 + call PlayMoveAnimation + ld hl,FastAsleepText + call PrintText + jr .sleepDone +.WakeUp + ld hl,WokeUpText + call PrintText +.sleepDone + xor a + ld [wccf1],a + ld hl,Func_3d80a + jp .CannotUseMove + +.FrozenCheck + bit FRZ,[hl] ; frozen? + jr z,.HeldInPlaceCheck + ld hl,IsFrozenText + call PrintText + xor a + ld [wccf1],a + ld hl,Func_3d80a + jp .CannotUseMove + +.HeldInPlaceCheck + ld a,[W_ENEMYBATTSTATUS1] + bit 5,a + jp z,.FlinchedCheck + ld hl,CantMoveText + call PrintText + ld hl,Func_3d80a + jp .CannotUseMove + +.FlinchedCheck + ld hl,W_PLAYERBATTSTATUS1 + bit 3,[hl] + jp z,.HyperBeamCheck + res 3,[hl] + ld hl,FlinchedText + call PrintText + ld hl,Func_3d80a + jp .CannotUseMove + +.HyperBeamCheck + ld hl,W_PLAYERBATTSTATUS2 + bit 5,[hl] + jr z,.AnyMoveDisabledCheck + res 5,[hl] + ld hl,MustRechargeText + call PrintText + ld hl,Func_3d80a + jp .CannotUseMove + +.AnyMoveDisabledCheck + ld hl,W_PLAYERDISABLEDMOVE + ld a,[hl] + and a + jr z,.ConfusedCheck + dec a + ld [hl],a + and a,$F + jr nz,.ConfusedCheck + ld [hl],a + ld [wccee],a + ld hl,DisabledNoMoreText + call PrintText + +.ConfusedCheck + ld a,[W_PLAYERBATTSTATUS1] + add a + jr nc,.TriedToUseDisabledMoveCheck + ld hl,wd06b + dec [hl] + jr nz,.IsConfused + ld hl,W_PLAYERBATTSTATUS1 + res 7,[hl] + ld hl,ConfusedNoMoreText + call PrintText + jr .TriedToUseDisabledMoveCheck +.IsConfused + ld hl,IsConfusedText + call PrintText + xor a + ld [wcc5b],a + ld a,CONF_ANIM - 1 + call PlayMoveAnimation + call BattleRandom + cp a,$80 + jr c,.TriedToUseDisabledMoveCheck + ld hl,W_PLAYERBATTSTATUS1 + ld a,[hl] + and a,$80 ; confused + ld [hl],a + call PrintHurtItselfText + jr .MonHurtItselfOrFullyParalysed + +.TriedToUseDisabledMoveCheck + ld a,[wccee] + and a + jr z,.ParalysisCheck + ld hl,wPlayerSelectedMove + cp [hl] + jr nz,.ParalysisCheck + call PrintMoveIsDisabledText + ld hl,Func_3d80a + jp .CannotUseMove + +.ParalysisCheck + ld hl,wBattleMonStatus + bit PAR,[hl] + jr z,.BideCheck + call BattleRandom + cp a,$3F + jr nc,.BideCheck + ld hl,FullyParalyzedText + call PrintText + +.MonHurtItselfOrFullyParalysed + ld hl,W_PLAYERBATTSTATUS1 + ld a,[hl] + and a,$CC ; clear bide, thrashing, charging up, and multi-turn moves such as warp + ld [hl],a + ld a,[W_PLAYERMOVEEFFECT] + cp a,FLY_EFFECT + jr z,.FlyOrChargeEffect + cp a,CHARGE_EFFECT + jr z,.FlyOrChargeEffect + jr .NotFlyOrChargeEffect + +.FlyOrChargeEffect + xor a + ld [wcc5b],a + ld a,STATUS_AFFECTED_ANIM + call PlayMoveAnimation +.NotFlyOrChargeEffect + ld hl,Func_3d80a + jp .CannotUseMove + +.BideCheck + ld hl,W_PLAYERBATTSTATUS1 + bit 0,[hl] ; is mon using bide? + jr z,.ThrashingAboutCheck + xor a + ld [W_PLAYERMOVENUM],a + ld hl,W_DAMAGE + ld a,[hli] + ld b,a + ld c,[hl] + ld hl,wd075 + ld a,[hl] + add c + ld [hld],a + ld a,[hl] + adc b + ld [hl],a + ld hl,wPlayerNumAttacksLeft + dec [hl] + jr z,.UnleashEnergy + ld hl,Func_3d80a + jp .CannotUseMove +.UnleashEnergy + ld hl,W_PLAYERBATTSTATUS1 + res 0,[hl] ; not using bide any more + ld hl,UnleashedEnergyText + call PrintText + ld a,1 + ld [W_PLAYERMOVEPOWER],a + ld hl,wd075 + ld a,[hld] + add a + ld b,a + ld [wd0d8],a + ld a,[hl] + rl a + ld [W_DAMAGE],a + or b + jr nz,.next + ld a,1 + ld [W_MOVEMISSED],a +.next + xor a + ld [hli],a + ld [hl],a + ld a,BIDE + ld [W_PLAYERMOVENUM],a + ld hl,asm_3d705 + jp .CannotUseMove + +.ThrashingAboutCheck + bit 1,[hl] ; is mon using thrash or petal dance? + jr z,.MultiturnMoveCheck + ld a,THRASH + ld [W_PLAYERMOVENUM],a + ld hl,ThrashingAboutText + call PrintText + ld hl,wPlayerNumAttacksLeft + dec [hl] + ld hl,asm_3d6dc + jp nz,.CannotUseMove + push hl + ld hl,W_PLAYERBATTSTATUS1 + res 1,[hl] + set 7,[hl] + call BattleRandom + and a,3 + inc a + inc a + ld [wd06b],a + pop hl + jp .CannotUseMove + +.MultiturnMoveCheck + bit 5,[hl] ; is mon using multi-turn move? + jp z,.RageCheck + ld hl,AttackContinuesText + call PrintText + ld a,[wPlayerNumAttacksLeft] + dec a + ld [wPlayerNumAttacksLeft],a + ld hl,asm_3d714 + jp nz,.CannotUseMove + jp .CannotUseMove + +.RageCheck + ld a, [W_PLAYERBATTSTATUS2] + bit 6, a ; is mon using rage? + jp z, .CanUseMove + ld a, RAGE + ld [wd11e], a + call GetMoveName + call CopyStringToCF4B + xor a + ld [W_PLAYERMOVEEFFECT], a + ld hl, asm_3d6b0 + jp .CannotUseMove + +.CannotUseMove + xor a + ret + +.CanUseMove + ld a, $1 + and a + ret + +FastAsleepText: ; 3da3d (f:5a3d) + TX_FAR _FastAsleepText + db "@" + +WokeUpText: ; 3da42 (f:5a42) + TX_FAR _WokeUpText + db "@" + +IsFrozenText: ; 3da47 (f:5a47) + TX_FAR _IsFrozenText + db "@" + +FullyParalyzedText: ; 3da4c (f:5a4c) + TX_FAR _FullyParalyzedText + db "@" + +FlinchedText: ; 3da51 (f:5a51) + TX_FAR _FlinchedText + db "@" + +MustRechargeText: ; 3da56 (f:5a56) + TX_FAR _MustRechargeText + db "@" + +DisabledNoMoreText: ; 3da5b (f:5a5b) + TX_FAR _DisabledNoMoreText + db "@" + +IsConfusedText: ; 3da60 (f:5a60) + TX_FAR _IsConfusedText + db "@" + +HurtItselfText: ; 3da65 (f:5a65) + TX_FAR _HurtItselfText + db "@" + +ConfusedNoMoreText: ; 3da6a (f:5a6a) + TX_FAR _ConfusedNoMoreText + db "@" + +SavingEnergyText: ; 3da6f (f:5a6f) + TX_FAR _SavingEnergyText + db "@" + +UnleashedEnergyText: ; 3da74 (f:5a74) + TX_FAR _UnleashedEnergyText + db "@" + +ThrashingAboutText: ; 3da79 (f:5a79) + TX_FAR _ThrashingAboutText + db "@" + +AttackContinuesText: ; 3da7e (f:5a7e) + TX_FAR _AttackContinuesText + db "@" + +CantMoveText: ; 3da83 (f:5a83) + TX_FAR _CantMoveText + db "@" + +PrintMoveIsDisabledText: ; 3da88 (f:5a88) + ld hl, wPlayerSelectedMove + ld de, W_PLAYERBATTSTATUS1 + ld a, [H_WHOSETURN] + and a + jr z, .asm_3da97 + inc hl + ld de, W_ENEMYBATTSTATUS1 +.asm_3da97 + ld a, [de] + res 4, a + ld [de], a + ld a, [hl] + ld [wd11e], a + call GetMoveName + ld hl, MoveIsDisabledText + jp PrintText + +MoveIsDisabledText: ; 3daa8 (f:5aa8) + TX_FAR _MoveIsDisabledText + db "@" + +PrintHurtItselfText: ; 3daad (f:5aad) + ld hl, HurtItselfText + call PrintText + ld hl, wEnemyMonDefense + ld a, [hli] + push af + ld a, [hld] + push af + ld a, [wBattleMonDefense] + ld [hli], a + ld a, [wBattleMonDefense + 1] + ld [hl], a + ld hl, W_PLAYERMOVEEFFECT + push hl + ld a, [hl] + push af + xor a + ld [hli], a + ld [wCriticalHitOrOHKO], a + ld a, $28 + ld [hli], a + xor a + ld [hl], a + call GetDamageVarsForPlayerAttack + call CalculateDamage + pop af + pop hl + ld [hl], a + ld hl, wEnemyMonDefense + 1 + pop af + ld [hld], a + pop af + ld [hl], a + xor a + ld [wcc5b], a + inc a + ld [H_WHOSETURN], a + call PlayMoveAnimation + call DrawPlayerHUDAndHPBar + xor a + ld [H_WHOSETURN], a + jp ApplyDamageToPlayerPokemon + +PrintMonName1Text: ; 3daf5 (f:5af5) + ld hl, MonName1Text + jp PrintText + +MonName1Text: ; 3dafb (f:5afb) + TX_FAR _MonName1Text + db $08 ; asm + ld a, [H_WHOSETURN] + and a + ld a, [W_PLAYERMOVENUM] + ld hl, wccf1 + jr z, .asm_3db11 + ld a, [W_ENEMYMOVENUM] + ld hl, wccf2 +.asm_3db11 + ld [hl], a + ld [wd11e], a + call Func_3db85 + ld a, [wcced] + and a + ld hl, Used2Text + ret nz + ld a, [wd11e] + cp DOUBLESLAP + ld hl, Used2Text + ret c + ld hl, Used1Text + ret + +Used1Text: ; 3db2d (f:5b2d) + TX_FAR _Used1Text + db $08 ; asm + jr PrintInsteadText + +Used2Text: ; 3db34 (f:5b34) + TX_FAR _Used2Text + db $08 ; asm + +PrintInsteadText: ; 3db39 (f:5b39) + ld a, [wcced] + and a + jr z, PrintCF4BText + ld hl, InsteadText + ret + +InsteadText: ; 3db43 (f:5b43) + TX_FAR _InsteadText + db $08 ; asm + +PrintCF4BText: ; 3db48 (f:5b48) + ld hl, CF4BText + ret + +CF4BText: ; 3db4c (f:5b4c) + TX_FAR _CF4BText + db $08 ; asm + ld hl, ExclamationPointPointerTable + ld a, [wd11e] + add a + push bc + ld b, $0 + ld c, a + add hl, bc + pop bc + ld a, [hli] + ld h, [hl] + ld l, a + ret + +ExclamationPointPointerTable: ; 3db62 (f:5b62) + dw ExclamationPoint1Text + dw ExclamationPoint2Text + dw ExclamationPoint3Text + dw ExclamationPoint4Text + dw ExclamationPoint5Text + +ExclamationPoint1Text: ; 3db6c (f:5b6c) + TX_FAR _ExclamationPoint1Text + db "@" + +ExclamationPoint2Text: ; 3db71 (f:5b71) + TX_FAR _ExclamationPoint2Text + db "@" + +ExclamationPoint3Text: ; 3db76 (f:5b76) + TX_FAR _ExclamationPoint3Text + db "@" + +ExclamationPoint4Text: ; 3db7b (f:5b7b) + TX_FAR _ExclamationPoint4Text + db "@" + +ExclamationPoint5Text: ; 3db80 (f:5b80) + TX_FAR _ExclamationPoint5Text + db "@" + +Func_3db85: ; 3db85 (f:5b85) + push bc + ld a, [wd11e] ; move number + ld c, a + ld b, $0 + ld hl, UnknownMovesList_3dba3 +.asm_3db8f + ld a, [hli] + cp $ff + jr z, .asm_3db9d + cp c + jr z, .asm_3db9d + and a + jr nz, .asm_3db8f + inc b + jr .asm_3db8f +.asm_3db9d + ld a, b + ld [wd11e], a + pop bc + ret + +UnknownMovesList_3dba3: ; 3dba3 (f:5ba3) + db SWORDS_DANCE, GROWTH + db $00 + db RECOVER, BIDE, SELFDESTRUCT, AMNESIA + db $00 + db MEDITATE, AGILITY, TELEPORT, MIMIC, DOUBLE_TEAM, BARRAGE + db $00 + db POUND, SCRATCH, VICEGRIP, WING_ATTACK, FLY, BIND, SLAM, HORN_ATTACK, BODY_SLAM + db WRAP, THRASH, TAIL_WHIP, LEER, BITE, GROWL, ROAR, SING, PECK, COUNTER + db STRENGTH, ABSORB, STRING_SHOT, EARTHQUAKE, FISSURE, DIG, TOXIC, SCREECH, HARDEN + db MINIMIZE, WITHDRAW, DEFENSE_CURL, METRONOME, LICK, CLAMP, CONSTRICT, POISON_GAS + db LEECH_LIFE, BUBBLE, FLASH, SPLASH, ACID_ARMOR, FURY_SWIPES, REST, SHARPEN, SLASH, SUBSTITUTE + db $00 + db $FF ; terminator + +PrintMoveFailureText: ; 3dbe2 (f:5be2) + ld de, W_PLAYERMOVEEFFECT + ld a, [H_WHOSETURN] + and a + jr z, .playersTurn + ld de, W_ENEMYMOVEEFFECT +.playersTurn + ld hl, DoesntAffectMonText + ld a, [wd05b] + and $7f + jr z, .asm_3dc04 + ld hl, AttackMissedText + ld a, [wCriticalHitOrOHKO] + cp $ff + jr nz, .asm_3dc04 + ld hl, UnaffectedText +.asm_3dc04 + push de + call PrintText + xor a + ld [wCriticalHitOrOHKO], a + pop de + ld a, [de] + cp JUMP_KICK_EFFECT + ret nz + + ; if you get here, the mon used hi jump kick and missed + ld hl, W_DAMAGE + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b + srl a + rr b + ld [hl], b + dec hl + ld [hli], a + or b + jr nz, .asm_3dc2a + inc a + ld [hl], a +.asm_3dc2a + ld hl, KeptGoingAndCrashedText + call PrintText + ld b, $4 + predef Func_48125 + ld a, [H_WHOSETURN] + and a + jr nz, .asm_3dc3f + jp ApplyDamageToPlayerPokemon +.asm_3dc3f + jp ApplyDamageToEnemyPokemon + +AttackMissedText: ; 3dc42 (f:5c42) + TX_FAR _AttackMissedText + db "@" + +KeptGoingAndCrashedText: ; 3dc47 (f:5c47) + TX_FAR _KeptGoingAndCrashedText + db "@" + +UnaffectedText: ; 3dc4c (f:5c4c) + TX_FAR _UnaffectedText + db "@" + +PrintDoesntAffectText: ; 3dc51 (f:5c51) + ld hl, DoesntAffectMonText + jp PrintText + +DoesntAffectMonText: ; 3dc57 (f:5c57) + TX_FAR _DoesntAffectMonText + db "@" + +; if there was a critical hit or an OHKO was successful, print the corresponding text +PrintCriticalOHKOText: ; 3dc5c (f:5c5c) + ld a, [wCriticalHitOrOHKO] + and a + jr z, .done ; do nothing if there was no critical hit or successful OHKO + dec a + add a + ld hl, CriticalOHKOTextPointers + ld b, $0 + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + call PrintText + xor a + ld [wCriticalHitOrOHKO], a +.done + ld c, $14 + jp DelayFrames + +CriticalOHKOTextPointers: ; 3dc7a (f:5c7a) + dw CriticalHitText + dw OHKOText + +CriticalHitText: ; 3dc7e (f:5c7e) + TX_FAR _CriticalHitText + db "@" + +OHKOText: ; 3dc83 (f:5c83) + TX_FAR _OHKOText + db "@" + +; checks if a traded mon will disobey due to lack of badges +; stores whether the mon will use a move in Z flag +CheckForDisobedience: ; 3dc88 (f:5c88) + xor a + ld [wcced], a + ld a, [W_ISLINKBATTLE] + cp $4 + jr nz, .checkIfMonIsTraded + ld a, $1 + and a + ret +; compare the mon's original trainer ID with the player's ID to see if it was traded +.checkIfMonIsTraded + ld hl, wPartyMon1OTID + ld bc, wPartyMon2 - wPartyMon1 + ld a, [wPlayerMonNumber] + call AddNTimes + ld a, [wPlayerID] + cp [hl] + jr nz, .monIsTraded + inc hl + ld a, [wPlayerID + 1] + cp [hl] + jp z, .canUseMove +; it was traded +.monIsTraded +; what level might disobey? + ld hl, W_OBTAINEDBADGES + bit 7, [hl] + ld a, 101 + jr nz, .next + bit 5, [hl] + ld a, 70 + jr nz, .next + bit 3, [hl] + ld a, 50 + jr nz, .next + bit 1, [hl] + ld a, 30 + jr nz, .next + ld a, 10 +.next + ld b, a + ld c, a + ld a, [wBattleMonLevel] + ld d, a + add b + ld b, a + jr nc, .noCarry + ld b, $ff ; cap b at $ff +.noCarry + ld a, c + cp d + jp nc, .canUseMove +.loop1 + call BattleRandom + swap a + cp b + jr nc, .loop1 + cp c + jp c, .canUseMove +.loop2 + call BattleRandom + cp b + jr nc, .loop2 + cp c + jr c, .useRandomMove + ld a, d + sub c + ld b, a + call BattleRandom + swap a + sub b + jr c, .monNaps + cp b + jr nc, .monDoesNothing + ld hl, WontObeyText + call PrintText + call PrintHurtItselfText + jp .cannotUseMove +.monNaps + call BattleRandom + add a + swap a + and SLP ; sleep mask + jr z, .monNaps ; keep trying until we get at least 1 turn of sleep + ld [wBattleMonStatus], a + ld hl, BeganToNapText + jr .printText +.monDoesNothing + call BattleRandom + and $3 + ld hl, LoafingAroundText + and a + jr z, .printText + ld hl, WontObeyText + dec a + jr z, .printText + ld hl, TurnedAwayText + dec a + jr z, .printText + ld hl, IgnoredOrdersText +.printText + call PrintText + jr .cannotUseMove +.useRandomMove + ld a, [wBattleMonMoves + 1] + and a ; is the second move slot empty? + jr z, .monDoesNothing ; mon will not use move if it only knows one move + ld a, [wccee] + and a + jr nz, .monDoesNothing + ld a, [wPlayerSelectedMove] + cp STRUGGLE + jr z, .monDoesNothing ; mon will not use move if struggling +; check if only one move has remaining PP + ld hl, wBattleMonPP + push hl + ld a, [hli] + and $3f + ld b, a + ld a, [hli] + and $3f + add b + ld b, a + ld a, [hli] + and $3f + add b + ld b, a + ld a, [hl] + and $3f + add b + pop hl + push af + ld a, [wCurrentMenuItem] + ld c, a + ld b, $0 + add hl, bc + ld a, [hl] + and $3f + ld b, a + pop af + cp b + jr z, .monDoesNothing ; mon will not use move if only one move has remaining PP + ld a, $1 + ld [wcced], a + ld a, [wMaxMenuItem] + ld b, a + ld a, [wCurrentMenuItem] + ld c, a +.chooseMove + call BattleRandom + and $3 + cp b + jr nc, .chooseMove ; if the random number is greater than the move count, choose another + cp c + jr z, .chooseMove ; if the random number matches the move the player selected, choose another + ld [wCurrentMenuItem], a + ld hl, wBattleMonPP + ld e, a + ld d, $0 + add hl, de + ld a, [hl] + and a ; does the move have any PP left? + jr z, .chooseMove ; if the move has no PP left, choose another + ld a, [wCurrentMenuItem] + ld c, a + ld b, $0 + ld hl, wBattleMonMoves + add hl, bc + ld a, [hl] + ld [wPlayerSelectedMove], a + call GetCurrentMove +.canUseMove + ld a, $1 + and a; clear Z flag + ret +.cannotUseMove + xor a ; set Z flag + ret + +LoafingAroundText: ; 3ddb6 (f:5db6) + TX_FAR _LoafingAroundText + db "@" + +BeganToNapText: ; 3ddbb (f:5dbb) + TX_FAR _BeganToNapText + db "@" + +WontObeyText: ; 3ddc0 (f:5dc0) + TX_FAR _WontObeyText + db "@" + +TurnedAwayText: ; 3ddc5 (f:5dc5) + TX_FAR _TurnedAwayText + db "@" + +IgnoredOrdersText: ; 3ddca (f:5dca) + TX_FAR _IgnoredOrdersText + db "@" + +; sets b, c, d, and e for the CalculateDamage routine in the case of an attack by the player mon +GetDamageVarsForPlayerAttack: ; 3ddcf (f:5dcf) + xor a + ld hl, W_DAMAGE ; damage to eventually inflict, initialise to zero + ldi [hl], a + ld [hl], a + ld hl, W_PLAYERMOVEPOWER + ld a, [hli] + and a + ld d, a ; d = move power + ret z ; return if move power is zero + ld a, [hl] ; a = [W_PLAYERMOVETYPE] + cp FIRE ; types >= FIRE are all special + jr nc, .specialAttack +.physicalAttack + ld hl, wEnemyMonDefense + ld a, [hli] + ld b, a + ld c, [hl] ; bc = enemy defense + ld a, [W_ENEMYBATTSTATUS3] + bit 2, a ; check for Reflect + jr z, .physicalAttackCritCheck +; if the enemy has used Reflect, double the enemy's defense + sla c + rl b +.physicalAttackCritCheck + ld hl, wBattleMonAttack + ld a, [wCriticalHitOrOHKO] + and a ; check for critical hit + jr z, .scaleStats +; in the case of a critical hit, reset the player's attack and the enemy's defense to their base values + ld c, 3 ; defense stat + call GetEnemyMonStat + ld a, [$ff97] + ld b, a + ld a, [$ff98] + ld c, a + push bc + ld hl, wPartyMon1Attack + ld a, [wPlayerMonNumber] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + pop bc + jr .scaleStats +.specialAttack + ld hl, wEnemyMonSpecial + ld a, [hli] + ld b, a + ld c, [hl] ; bc = enemy special + ld a, [W_ENEMYBATTSTATUS3] + bit 1, a ; check for Light Screen + jr z, .specialAttackCritCheck +; if the enemy has used Light Screen, double the enemy's special + sla c + rl b +.specialAttackCritCheck + ld hl, wBattleMonSpecial + ld a, [wCriticalHitOrOHKO] + and a ; check for critical hit + jr z, .scaleStats +; in the case of a critical hit, reset the player's and enemy's specials to their base values + ld c, 5 ; special stat + call GetEnemyMonStat + ld a, [$ff97] + ld b, a + ld a, [$ff98] + ld c, a + push bc + ld hl, wPartyMon1Special + ld a, [wPlayerMonNumber] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + pop bc +; if either the offensive or defensive stat is too large to store in a byte, scale both stats by dividing them by 4 +; this allows values with up to 10 bits (values up to 1023) to be handled +; anything larger will wrap around +.scaleStats + ld a, [hli] + ld l, [hl] + ld h, a ; hl = player's offensive stat + or b ; is either high byte nonzero? + jr z, .next ; if not, we don't need to scale + ; bc /= 4 (scale enemy's defensive stat) + srl b + rr c + srl b + rr c + ; hl /= 4 (scale player's offensive stat) + srl h + rr l + srl h + rr l + ld a, l + or h ; is the player's offensive stat 0? + jr nz, .next + inc l ; if the player's offensive stat is 0, bump it up to 1 +.next + ld b, l ; b = player's offensive stat (possibly scaled) (c already contains enemy's defensive stat (possibly scaled)) + ld a, [wBattleMonLevel] + ld e, a ; e = level + ld a, [wCriticalHitOrOHKO] + and a ; check for critical hit + jr z, .done + sla e ; double level if it was a critical hit +.done + ld a, 1 + and a + ret + +; sets b, c, d, and e for the CalculateDamage routine in the case of an attack by the enemy mon +GetDamageVarsForEnemyAttack: ; 3de75 (f:5e75) + ld hl, W_DAMAGE ; damage to eventually inflict, initialise to zero + xor a + ld [hli], a + ld [hl], a + ld hl, W_ENEMYMOVEPOWER + ld a, [hli] + ld d, a ; d = move power + and a + ret z ; return if move power is zero + ld a, [hl] ; a = [W_ENEMYMOVETYPE] + cp FIRE ; types >= FIRE are all special + jr nc, .specialAttack +.physicalAttack + ld hl, wBattleMonDefense + ld a, [hli] + ld b, a + ld c, [hl] ; bc = player defense + ld a, [W_PLAYERBATTSTATUS3] + bit 2, a ; check for Reflect + jr z, .physicalAttackCritCheck +; if the player has used Reflect, double the player's defense + sla c + rl b +.physicalAttackCritCheck + ld hl, wEnemyMonAttack + ld a, [wCriticalHitOrOHKO] + and a ; check for critical hit + jr z, .scaleStats +; in the case of a critical hit, reset the player's defense and the enemy's attack to their base values + ld hl, wPartyMon1Defense + ld a, [wPlayerMonNumber] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld a, [hli] + ld b, a + ld c, [hl] + push bc + ld c, 2 ; attack stat + call GetEnemyMonStat + ld hl, $ff97 + pop bc + jr .scaleStats +.specialAttack + ld hl, wBattleMonSpecial + ld a, [hli] + ld b, a + ld c, [hl] + ld a, [W_PLAYERBATTSTATUS3] + bit 1, a ; check for Light Screen + jr z, .specialAttackCritCheck +; if the player has used Light Screen, double the player's special + sla c + rl b +.specialAttackCritCheck + ld hl, wEnemyMonSpecial + ld a, [wCriticalHitOrOHKO] + and a ; check for critical hit + jr z, .scaleStats +; in the case of a critical hit, reset the player's and enemy's specials to their base values + ld hl, wPartyMon1Special + ld a, [wPlayerMonNumber] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld a, [hli] + ld b, a + ld c, [hl] + push bc + ld c, 5 ; special stat + call GetEnemyMonStat + ld hl, $ff97 + pop bc +; if either the offensive or defensive stat is too large to store in a byte, scale both stats by dividing them by 4 +; this allows values with up to 10 bits (values up to 1023) to be handled +; anything larger will wrap around +.scaleStats + ld a, [hli] + ld l, [hl] + ld h, a ; hl = enemy's offensive stat + or b ; is either high byte nonzero? + jr z, .next ; if not, we don't need to scale +; bc /= 4 (scale player's defensive stat) + srl b + rr c + srl b + rr c +; hl /= 4 (scale enemy's offensive stat) + srl h + rr l + srl h + rr l + ld a, l + or h ; is the enemy's offensive stat 0? + jr nz, .next + inc l ; if the enemy's offensive stat is 0, bump it up to 1 +.next + ld b, l ; b = enemy's offensive stat (possibly scaled) (c already contains player's defensive stat (possibly scaled)) + ld a, [wEnemyMonLevel] + ld e, a + ld a, [wCriticalHitOrOHKO] + and a ; check for critical hit + jr z, .done + sla e ; double level if it was a critical hit +.done + ld a, $1 + and a + and a + ret + +; get stat c of enemy mon +; c: stat to get (HP=1,Attack=2,Defense=3,Speed=4,Special=5) +GetEnemyMonStat: ; 3df1c (f:5f1c) + push de + push bc + ld a, [W_ISLINKBATTLE] + cp $4 + jr nz, .asm_3df40 + ld hl, wEnemyMon1Stats + dec c + sla c + ld b, $0 + add hl, bc + ld a, [wEnemyMonPartyPos] + ld bc, wEnemyMon2 - wEnemyMon1 + call AddNTimes + ld a, [hli] + ld [$ff97], a + ld a, [hl] + ld [$ff98], a + pop bc + pop de + ret +.asm_3df40 + ld a, [wEnemyMonLevel] + ld [W_CURENEMYLVL], a + ld a, [wEnemyMonSpecies] + ld [wd0b5], a + call GetMonHeader + ld hl, wEnemyMonDVs + ld de, wcfaf + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + pop bc + ld b, $0 + ld hl, wcfa4 + call CalcStat + pop de + ret + +CalculateDamage: ; 3df65 (f:5f65) +; input: +; b: attack +; c: opponent defense +; d: base power +; e: level + + ld a, [$fff3] ; whose turn? + and a + ld a, [W_PLAYERMOVEEFFECT] + jr z, .effect + ld a, [W_ENEMYMOVEEFFECT] +.effect + +; EXPLODE_EFFECT halves defense. + cp a, EXPLODE_EFFECT + jr nz, .ok + srl c + jr nz, .ok + inc c ; ...with a minimum value of 1 (used as a divisor later on) +.ok + +; Multi-hit attacks may or may not have 0 bp. + cp a, TWO_TO_FIVE_ATTACKS_EFFECT + jr z, .skipbp + cp a, $1e + jr z, .skipbp + +; Calculate OHKO damage based on remaining HP. + cp a, OHKO_EFFECT + jp z, Func_3e016 + +; Don't calculate damage for moves that don't do any. + ld a, d ; base power + and a + ret z +.skipbp + + xor a + ld hl, H_DIVIDEND + ldi [hl], a + ldi [hl], a + ld [hl], a + +; Multiply level by 2 + ld a, e ; level + add a + jr nc, .nc + push af + ld a, 1 + ld [hl], a + pop af +.nc + inc hl + ldi [hl], a + +; Divide by 5 + ld a, 5 + ldd [hl], a + push bc + ld b, 4 + call Divide + pop bc + +; Add 2 + inc [hl] + inc [hl] + + inc hl ; multiplier + +; Multiply by attack base power + ld [hl], d + call Multiply + +; Multiply by attack stat + ld [hl], b + call Multiply + +; Divide by defender's defense stat + ld [hl], c + ld b, 4 + call Divide + +; Divide by 50 + ld [hl], 50 + ld b, 4 + call Divide + + ld hl, W_DAMAGE + ld b, [hl] + ld a, [H_QUOTIENT + 3] + add b + ld [H_QUOTIENT + 3], a + jr nc, .asm_3dfd0 + + ld a, [H_QUOTIENT + 2] + inc a + ld [H_QUOTIENT + 2], a + and a + jr z, .asm_3e004 + +.asm_3dfd0 + ld a, [H_QUOTIENT] + ld b, a + ld a, [H_QUOTIENT + 1] + or a + jr nz, .asm_3e004 + + ld a, [H_QUOTIENT + 2] + cp 998 / $100 + jr c, .asm_3dfe8 + cp 998 / $100 + 1 + jr nc, .asm_3e004 + ld a, [H_QUOTIENT + 3] + cp 998 % $100 + jr nc, .asm_3e004 + +.asm_3dfe8 + inc hl + ld a, [H_QUOTIENT + 3] + ld b, [hl] + add b + ld [hld], a + + ld a, [H_QUOTIENT + 2] + ld b, [hl] + adc b + ld [hl], a + jr c, .asm_3e004 + + ld a, [hl] + cp 998 / $100 + jr c, .asm_3e00a + cp 998 / $100 + 1 + jr nc, .asm_3e004 + inc hl + ld a, [hld] + cp 998 % $100 + jr c, .asm_3e00a + +.asm_3e004 + ld a, 997 / $100 + ld [hli], a + ld a, 997 % $100 + ld [hld], a + +.asm_3e00a + inc hl + ld a, [hl] + add 2 + ld [hld], a + jr nc, .done + inc [hl] +.done + + ld a, 1 + and a + ret + +Func_3e016: ; 3e016 (f:6016) + call JumpMoveEffect + ld a, [W_MOVEMISSED] + dec a + ret + + +UnusedHighCriticalMoves: ; 3e01e (f:601e) + db KARATE_CHOP + db RAZOR_LEAF + db CRABHAMMER + db SLASH + db $FF +; 3e023 + +; determines if attack is a critical hit +; azure heights claims "the fastest pokémon (who are,not coincidentally, +; among the most popular) tend to CH about 20 to 25% of the time." +CriticalHitTest: ; 3e023 (f:6023) + xor a + ld [wCriticalHitOrOHKO], a + ld a, [H_WHOSETURN] + and a + ld a, [wEnemyMonSpecies] + jr nz, .asm_3e032 + ld a, [wBattleMonSpecies] +.asm_3e032 + ld [wd0b5], a + call GetMonHeader + ld a, [W_MONHBASESPEED] + ld b, a + srl b ; (effective (base speed/2)) + ld a, [H_WHOSETURN] + and a + ld hl, W_PLAYERMOVEPOWER + ld de, W_PLAYERBATTSTATUS2 + jr z, .calcCriticalHitProbability + ld hl, W_ENEMYMOVEPOWER + ld de, W_ENEMYBATTSTATUS2 +.calcCriticalHitProbability ; 0x3e04f + ld a, [hld] ; read base power from RAM + and a + ret z ; do nothing if zero + dec hl + ld c, [hl] ; read move id + ld a, [de] + bit 2, a ; test for focus energy + jr nz, .focusEnergyUsed ; bug: using focus energy causes a shift to the right instead of left, + ; resulting in 1/4 the usual crit chance + sla b ; (effective (base speed/2)*2) + jr nc, .noFocusEnergyUsed + ld b, $ff ; cap at 255/256 + jr .noFocusEnergyUsed +.focusEnergyUsed + srl b +.noFocusEnergyUsed + ld hl, HighCriticalMoves ; table of high critical hit moves +.Loop + ld a, [hli] ; read move from move table + cp c ; does it match the move about to be used? + jr z, .HighCritical ; if so, the move about to be used is a high critical hit ratio move + inc a ; move on to the next move, FF terminates loop + jr nz, .Loop ; check the next move in HighCriticalMoves + srl b ; /2 for regular move (effective (base speed / 2)) + jr .SkipHighCritical ; continue as a normal move +.HighCritical + sla b ; *2 for high critical hit moves + jr nc, .noCarry + ld b, $ff ; cap at 255/256 +.noCarry + sla b ; *4 for high critical move (effective (base speed/2)*8)) + jr nc, .SkipHighCritical + ld b, $ff +.SkipHighCritical + call BattleRandom ; generates a random value, in "a" + rlc a + rlc a + rlc a + cp b ; check a against calculated crit rate + ret nc ; no critical hit if no borrow + ld a, $1 + ld [wCriticalHitOrOHKO], a ; set critical hit flag + ret + +; high critical hit moves +HighCriticalMoves: ; 3e08e (f:608e) + db KARATE_CHOP + db RAZOR_LEAF + db CRABHAMMER + db SLASH + db $FF + + +; function to determine if Counter hits and if so, how much damage it does +HandleCounterMove: ; 3e093 (f:6093) + ld a,[H_WHOSETURN] ; whose turn + and a +; player's turn + ld hl,wEnemySelectedMove + ld de,W_ENEMYMOVEPOWER + ld a,[wPlayerSelectedMove] + jr z,.next +; enemy's turn + ld hl,wPlayerSelectedMove + ld de,W_PLAYERMOVEPOWER + ld a,[wEnemySelectedMove] +.next + cp a,COUNTER + ret nz ; return if not using Counter + ld a,$01 + ld [W_MOVEMISSED],a ; initialize the move missed variable to true (it is set to false below if the move hits) + ld a,[hl] + cp a,COUNTER + ret z ; if the target also used Counter, miss + ld a,[de] + and a + ret z ; if the move the target used has 0 power, miss +; check if the move the target used was Normal or Fighting type + inc de + ld a,[de] + and a ; normal type + jr z,.counterableType + cp a,FIGHTING + jr z,.counterableType +; if the move wasn't Normal or Fighting type, miss + xor a + ret +.counterableType + ld hl,W_DAMAGE + ld a,[hli] + or [hl] + ret z ; Counter misses if the target did no damage to the Counter user +; double the damage that the target did to the Counter user + ld a,[hl] + add a + ldd [hl],a + ld a,[hl] + adc a + ld [hl],a + jr nc,.noCarry +; damage is capped at 0xFFFF + ld a,$ff + ld [hli],a + ld [hl],a +.noCarry + xor a + ld [W_MOVEMISSED],a + call MoveHitTest ; do the normal move hit test in addition to Counter's special rules + xor a + ret + +ApplyAttackToEnemyPokemon: ; 3e0df (f:60df) + ld a,[W_PLAYERMOVEEFFECT] + cp a,OHKO_EFFECT + jr z,ApplyDamageToEnemyPokemon + cp a,SUPER_FANG_EFFECT + jr z,.superFangEffect + cp a,SPECIAL_DAMAGE_EFFECT + jr z,.specialDamage + ld a,[W_PLAYERMOVEPOWER] + and a + jp z,ApplyAttackToEnemyPokemonDone + jr ApplyDamageToEnemyPokemon +.superFangEffect +; set the damage to half the target's HP + ld hl,wEnemyMonHP + ld de,W_DAMAGE + ld a,[hli] + srl a + ld [de],a + inc de + ld b,a + ld a,[hl] + rr a + ld [de],a + or b + jr nz,ApplyDamageToEnemyPokemon +; make sure Super Fang's damage is always at least 1 + ld a,$01 + ld [de],a + jr ApplyDamageToEnemyPokemon +.specialDamage + ld hl,wBattleMonLevel + ld a,[hl] + ld b,a + ld a,[W_PLAYERMOVENUM] + cp a,SEISMIC_TOSS + jr z,.storeDamage + cp a,NIGHT_SHADE + jr z,.storeDamage + ld b,SONICBOOM_DAMAGE + cp a,SONICBOOM + jr z,.storeDamage + ld b,DRAGON_RAGE_DAMAGE + cp a,DRAGON_RAGE + jr z,.storeDamage +; Psywave + ld a,[hl] + ld b,a + srl a + add b + ld b,a ; b = level * 1.5 +; loop until a random number in the range [1, b) is found +.loop + call BattleRandom + and a + jr z,.loop + cp b + jr nc,.loop + ld b,a +.storeDamage + ld hl,W_DAMAGE + xor a + ld [hli],a + ld a,b + ld [hl],a + +ApplyDamageToEnemyPokemon: ; 3e142 (f:6142) + ld hl,W_DAMAGE + ld a,[hli] + ld b,a + ld a,[hl] + or b + jr z,ApplyAttackToEnemyPokemonDone ; we're done if damage is 0 + ld a,[W_ENEMYBATTSTATUS2] + bit 4,a ; does the enemy have a substitute? + jp nz,AttackSubstitute +; subtract the damage from the pokemon's current HP +; also, save the current HP at wHPBarOldHP + ld a,[hld] + ld b,a + ld a,[wEnemyMonHP + 1] + ld [wHPBarOldHP],a + sub b + ld [wEnemyMonHP + 1],a + ld a,[hl] + ld b,a + ld a,[wEnemyMonHP] + ld [wHPBarOldHP+1],a + sbc b + ld [wEnemyMonHP],a + jr nc,.animateHpBar +; if more damage was done than the current HP, zero the HP and set the damage +; equal to how much HP the pokemon had before the attack + ld a,[wHPBarOldHP+1] + ld [hli],a + ld a,[wHPBarOldHP] + ld [hl],a + xor a + ld hl,wEnemyMonHP + ld [hli],a + ld [hl],a +.animateHpBar + ld hl,wEnemyMonMaxHP + ld a,[hli] + ld [wHPBarMaxHP+1],a + ld a,[hl] + ld [wHPBarMaxHP],a + ld hl,wEnemyMonHP + ld a,[hli] + ld [wHPBarNewHP+1],a + ld a,[hl] + ld [wHPBarNewHP],a + hlCoord 2, 2 + xor a + ld [wListMenuID],a + predef UpdateHPBar2 ; animate the HP bar shortening +ApplyAttackToEnemyPokemonDone: ; 3e19d (f:619d) + jp DrawHUDsAndHPBars + +ApplyAttackToPlayerPokemon: ; 3e1a0 (f:61a0) + ld a,[W_ENEMYMOVEEFFECT] + cp a,OHKO_EFFECT + jr z,ApplyDamageToPlayerPokemon + cp a,SUPER_FANG_EFFECT + jr z,.superFangEffect + cp a,SPECIAL_DAMAGE_EFFECT + jr z,.specialDamage + ld a,[W_ENEMYMOVEPOWER] + and a + jp z,ApplyAttackToPlayerPokemonDone + jr ApplyDamageToPlayerPokemon +.superFangEffect +; set the damage to half the target's HP + ld hl,wBattleMonHP + ld de,W_DAMAGE + ld a,[hli] + srl a + ld [de],a + inc de + ld b,a + ld a,[hl] + rr a + ld [de],a + or b + jr nz,ApplyDamageToPlayerPokemon +; make sure Super Fang's damage is always at least 1 + ld a,$01 + ld [de],a + jr ApplyDamageToPlayerPokemon +.specialDamage + ld hl,wEnemyMonLevel + ld a,[hl] + ld b,a + ld a,[W_ENEMYMOVENUM] + cp a,SEISMIC_TOSS + jr z,.storeDamage + cp a,NIGHT_SHADE + jr z,.storeDamage + ld b,SONICBOOM_DAMAGE + cp a,SONICBOOM + jr z,.storeDamage + ld b,DRAGON_RAGE_DAMAGE + cp a,DRAGON_RAGE + jr z,.storeDamage +; Psywave + ld a,[hl] + ld b,a + srl a + add b + ld b,a ; b = attacker's level * 1.5 +; loop until a random number in the range [0, b) is found +; this differs from the range when the player attacks, which is [1, b) +; it's possible for the enemy to do 0 damage with Psywave, but the player always does at least 1 damage +.loop + call BattleRandom + cp b + jr nc,.loop + ld b,a +.storeDamage + ld hl,W_DAMAGE + xor a + ld [hli],a + ld a,b + ld [hl],a + +ApplyDamageToPlayerPokemon: ; 3e200 (f:6200) + ld hl,W_DAMAGE + ld a,[hli] + ld b,a + ld a,[hl] + or b + jr z,ApplyAttackToPlayerPokemonDone ; we're done if damage is 0 + ld a,[W_PLAYERBATTSTATUS2] + bit 4,a ; does the player have a substitute? + jp nz,AttackSubstitute +; subtract the damage from the pokemon's current HP +; also, save the current HP at wHPBarOldHP and the new HP at wHPBarNewHP + ld a,[hld] + ld b,a + ld a,[wBattleMonHP + 1] + ld [wHPBarOldHP],a + sub b + ld [wBattleMonHP + 1],a + ld [wHPBarNewHP],a + ld b,[hl] + ld a,[wBattleMonHP] + ld [wHPBarOldHP+1],a + sbc b + ld [wBattleMonHP],a + ld [wHPBarNewHP+1],a + jr nc,.animateHpBar +; if more damage was done than the current HP, zero the HP and set the damage +; equal to how much HP the pokemon had before the attack + ld a,[wHPBarOldHP+1] + ld [hli],a + ld a,[wHPBarOldHP] + ld [hl],a + xor a + ld hl,wBattleMonHP + ld [hli],a + ld [hl],a + ld hl,wHPBarNewHP + ld [hli],a + ld [hl],a +.animateHpBar + ld hl,wBattleMonMaxHP + ld a,[hli] + ld [wHPBarMaxHP+1],a + ld a,[hl] + ld [wHPBarMaxHP],a + hlCoord 10, 9 + ld a,$01 + ld [wListMenuID],a + predef UpdateHPBar2 ; animate the HP bar shortening +ApplyAttackToPlayerPokemonDone + jp DrawHUDsAndHPBars + +AttackSubstitute: ; 3e25e (f:625e) + ld hl,SubstituteTookDamageText + call PrintText +; values for player turn + ld de,wEnemySubstituteHP + ld bc,W_ENEMYBATTSTATUS2 + ld a,[H_WHOSETURN] + and a + jr z,.applyDamageToSubstitute +; values for enemy turn + ld de,wPlayerSubstituteHP + ld bc,W_PLAYERBATTSTATUS2 +.applyDamageToSubstitute + ld hl,W_DAMAGE + ld a,[hli] + and a + jr nz,.substituteBroke ; damage > 0xFF always breaks substitutes +; subtract damage from HP of substitute + ld a,[de] + sub [hl] + ld [de],a + ret nc +.substituteBroke + ld h,b + ld l,c + res 4,[hl] ; unset the substitute bit + ld hl,SubstituteBrokeText + call PrintText +; flip whose turn it is for the next function call + ld a,[H_WHOSETURN] + xor a,$01 + ld [H_WHOSETURN],a + callab Func_79747 ; animate the substitute breaking +; flip the turn back to the way it was + ld a,[H_WHOSETURN] + xor a,$01 + ld [H_WHOSETURN],a + ld hl,W_PLAYERMOVEEFFECT ; value for player's turn + and a + jr z,.nullifyEffect + ld hl,W_ENEMYMOVEEFFECT ; value for enemy's turn +.nullifyEffect + xor a + ld [hl],a ; zero the effect of the attacker's move + jp DrawHUDsAndHPBars + +SubstituteTookDamageText: ; 3e2ac (f:62ac) + TX_FAR _SubstituteTookDamageText + db "@" + +SubstituteBrokeText: ; 3e2b1 (f:62b1) + TX_FAR _SubstituteBrokeText + db "@" + +; this function raises the attack modifier of a pokemon using Rage when that pokemon is attacked +HandleBuildingRage: ; 3e2b6 (f:62b6) +; values for the player turn + ld hl,W_ENEMYBATTSTATUS2 + ld de,wEnemyMonStatMods + ld bc,W_ENEMYMOVENUM + ld a,[H_WHOSETURN] + and a + jr z,.next +; values for the enemy turn + ld hl,W_PLAYERBATTSTATUS2 + ld de,wPlayerMonStatMods + ld bc,W_PLAYERMOVENUM +.next + bit 6,[hl] ; is the pokemon being attacked under the effect of Rage? + ret z ; return if not + ld a,[de] + cp a,$0d ; maximum stat modifier value + ret z ; return if attack modifier is already maxed + ld a,[H_WHOSETURN] + xor a,$01 ; flip turn for the stat modifier raising function + ld [H_WHOSETURN],a +; change the target pokemon's move to $00 and the effect to the one +; that causes the attack modifier to go up one stage + ld h,b + ld l,c + ld [hl],$00 ; null move number + inc hl + ld [hl],ATTACK_UP1_EFFECT + push hl + ld hl,BuildingRageText + call PrintText + call StatModifierUpEffect ; stat modifier raising function + pop hl + xor a + ldd [hl],a ; null move effect + ld a,RAGE + ld [hl],a ; restore the target pokemon's move number to Rage + ld a,[H_WHOSETURN] + xor a,$01 ; flip turn back to the way it was + ld [H_WHOSETURN],a + ret + +BuildingRageText: ; 3e2f8 (f:62f8) + TX_FAR _BuildingRageText + db "@" + +; copy last move for Mirror Move +; sets zero flag on failure and unsets zero flag on success +MirrorMoveCopyMove: ; 3e2fd (f:62fd) + ld a,[H_WHOSETURN] + and a +; values for player turn + ld a,[wccf2] + ld hl,wPlayerSelectedMove + ld de,W_PLAYERMOVENUM + jr z,.next +; values for enemy turn + ld a,[wccf1] + ld de,W_ENEMYMOVENUM + ld hl,wEnemySelectedMove +.next + ld [hl],a + cp a,MIRROR_MOVE ; did the target pokemon also use Mirror Move? + jr z,.mirrorMoveFailed + and a ; null move? + jr nz,ReloadMoveData +.mirrorMoveFailed +; Mirror Move fails on itself and null moves + ld hl,MirrorMoveFailedText + call PrintText + xor a + ret + +MirrorMoveFailedText: ; 3e324 (f:6324) + TX_FAR _MirrorMoveFailedText + db "@" + +; function used to reload move data for moves like Mirror Move and Metronome +ReloadMoveData: ; 3e329 (f:6329) + ld [wd11e],a + dec a + ld hl,Moves + ld bc,$0006 + call AddNTimes + ld a,BANK(Moves) + call FarCopyData ; copy the move's stats + call IncrementMovePP +; the follow two function calls are used to reload the move name + call GetMoveName + call CopyStringToCF4B + ld a,$01 + and a + ret + +; function that picks a random move for metronome +MetronomePickMove: ; 3e348 (f:6348) + xor a + ld [wcc5b],a + ld a,METRONOME + call PlayMoveAnimation ; play Metronome's animation +; values for player turn + ld de,W_PLAYERMOVENUM + ld hl,wPlayerSelectedMove + ld a,[H_WHOSETURN] + and a + jr z,.pickMoveLoop +; values for enemy turn + ld de,W_ENEMYMOVENUM + ld hl,wEnemySelectedMove +; loop to pick a random number in the range [1, $a5) to be the move used by Metronome +.pickMoveLoop + call BattleRandom + and a + jr z,.pickMoveLoop + cp a,NUM_ATTACKS + 1 ; max normal move number + 1 (this is Struggle's move number) + jr nc,.pickMoveLoop + cp a,METRONOME + jr z,.pickMoveLoop + ld [hl],a + jr ReloadMoveData + +; this function increments the current move's PP +; it's used to prevent moves that run another move within the same turn +; (like Mirror Move and Metronome) from losing 2 PP +IncrementMovePP: ; 3e373 (f:6373) + ld a,[H_WHOSETURN] + and a +; values for player turn + ld hl,wBattleMonPP + ld de,wPartyMon1PP + ld a,[wPlayerMoveListIndex] + jr z,.next +; values for enemy turn + ld hl,wEnemyMonPP + ld de,wEnemyMon1PP + ld a,[wEnemyMoveListIndex] +.next + ld b,$00 + ld c,a + add hl,bc + inc [hl] ; increment PP in the currently battling pokemon memory location + ld h,d + ld l,e + add hl,bc + ld a,[H_WHOSETURN] + and a + ld a,[wPlayerMonNumber] ; value for player turn + jr z,.next2 + ld a,[wEnemyMonPartyPos] ; value for enemy turn +.next2 + ld bc,wEnemyMon2 - wEnemyMon1 + call AddNTimes + inc [hl] ; increment PP in the party memory location + ret + +; function to adjust the base damage of an attack to account for type effectiveness +AdjustDamageForMoveType: ; 3e3a5 (f:63a5) +; values for player turn + ld hl,wBattleMonType + ld a,[hli] + ld b,a ; b = type 1 of attacker + ld c,[hl] ; c = type 2 of attacker + ld hl,wEnemyMonType + ld a,[hli] + ld d,a ; d = type 1 of defender + ld e,[hl] ; e = type 2 of defender + ld a,[W_PLAYERMOVETYPE] + ld [wd11e],a + ld a,[H_WHOSETURN] + and a + jr z,.next +; values for enemy turn + ld hl,wEnemyMonType + ld a,[hli] + ld b,a ; b = type 1 of attacker + ld c,[hl] ; c = type 2 of attacker + ld hl,wBattleMonType + ld a,[hli] + ld d,a ; d = type 1 of defender + ld e,[hl] ; e = type 2 of defender + ld a,[W_ENEMYMOVETYPE] + ld [wd11e],a +.next + ld a,[wd11e] ; move type + cp b ; does the move type match type 1 of the attacker? + jr z,.sameTypeAttackBonus + cp c ; does the move type match type 2 of the attacker? + jr z,.sameTypeAttackBonus + jr .skipSameTypeAttackBonus +.sameTypeAttackBonus +; if the move type matches one of the attacker's types + ld hl,W_DAMAGE + 1 + ld a,[hld] + ld h,[hl] + ld l,a ; hl = damage + ld b,h + ld c,l ; bc = damage + srl b + rr c ; bc = floor(0.5 * damage) + add hl,bc ; hl = floor(1.5 * damage) +; store damage + ld a,h + ld [W_DAMAGE],a + ld a,l + ld [W_DAMAGE + 1],a + ld hl,wd05b + set 7,[hl] +.skipSameTypeAttackBonus + ld a,[wd11e] + ld b,a ; b = move type + ld hl,TypeEffects +.loop + ld a,[hli] ; a = "attacking type" of the current type pair + cp a,$ff + jr z,.done + cp b ; does move type match "attacking type"? + jr nz,.nextTypePair + ld a,[hl] ; a = "defending type" of the current type pair + cp d ; does type 1 of defender match "defending type"? + jr z,.matchingPairFound + cp e ; does type 2 of defender match "defending type"? + jr z,.matchingPairFound + jr .nextTypePair +.matchingPairFound +; if the move type matches the "attacking type" and one of the defender's types matches the "defending type" + push hl + push bc + inc hl + ld a,[wd05b] + and a,$80 + ld b,a + ld a,[hl] ; a = damage multiplier + ld [H_MULTIPLIER],a + add b + ld [wd05b],a + xor a + ld [H_MULTIPLICAND],a + ld hl,W_DAMAGE + ld a,[hli] + ld [H_MULTIPLICAND + 1],a + ld a,[hld] + ld [H_MULTIPLICAND + 2],a + call Multiply + ld a,10 + ld [H_DIVISOR],a + ld b,$04 + call Divide + ld a,[H_QUOTIENT + 2] + ld [hli],a + ld b,a + ld a,[H_QUOTIENT + 3] + ld [hl],a + or b ; is damage 0? + jr nz,.skipTypeImmunity +.typeImmunity +; if damage is 0, make the move miss + inc a + ld [W_MOVEMISSED],a +.skipTypeImmunity + pop bc + pop hl +.nextTypePair + inc hl + inc hl + jp .loop +.done + ret + +; function to tell how effective the type of an enemy attack is on the player's current pokemon +; this doesn't take into account the effects that dual types can have +; (e.g. 4x weakness / resistance, weaknesses and resistances canceling) +; the result is stored in [wd11e] +; ($05 is not very effective, $10 is neutral, $14 is super effective) +; as far is can tell, this is only used once in some AI code to help decide which move to use +AIGetTypeEffectiveness: ; 3e449 (f:6449) + ld a,[W_ENEMYMOVETYPE] + ld d,a ; d = type of enemy move + ld hl,wBattleMonType + ld b,[hl] ; b = type 1 of player's pokemon + inc hl + ld c,[hl] ; c = type 2 of player's pokemon + ld a,$10 + ld [wd11e],a ; initialize [wd11e] to neutral effectiveness + ld hl,TypeEffects +.loop + ld a,[hli] + cp a,$ff + ret z + cp d ; match the type of the move + jr nz,.nextTypePair1 + ld a,[hli] + cp b ; match with type 1 of pokemon + jr z,.done + cp c ; or match with type 2 of pokemon + jr z,.done + jr .nextTypePair2 +.nextTypePair1 + inc hl +.nextTypePair2 + inc hl + jr .loop +.done + ld a,[hl] + ld [wd11e],a ; store damage multiplier + ret + +INCLUDE "data/type_effects.asm" + +; some tests that need to pass for a move to hit +MoveHitTest: ; 3e56b (f:656b) +; player's turn + ld hl,W_ENEMYBATTSTATUS1 + ld de,W_PLAYERMOVEEFFECT + ld bc,wEnemyMonStatus + ld a,[H_WHOSETURN] + and a + jr z,.dreamEaterCheck +; enemy's turn + ld hl,W_PLAYERBATTSTATUS1 + ld de,W_ENEMYMOVEEFFECT + ld bc,wBattleMonStatus +.dreamEaterCheck + ld a,[de] + cp a,DREAM_EATER_EFFECT + jr nz,.swiftCheck + ld a,[bc] + and a,$07 ; is the target pokemon sleeping? + jp z,.moveMissed +.swiftCheck + ld a,[de] + cp a,SWIFT_EFFECT + ret z ; Swift never misses (interestingly, Azure Heights lists this is a myth, but it appears to be true) + call CheckTargetSubstitute ; substitute check (note that this overwrites a) + jr z,.checkForDigOrFlyStatus +; this code is buggy. it's supposed to prevent HP draining moves from working on substitutes. +; since $7b79 overwrites a with either $00 or $01, it never works. + cp a,DRAIN_HP_EFFECT + jp z,.moveMissed + cp a,DREAM_EATER_EFFECT + jp z,.moveMissed +.checkForDigOrFlyStatus + bit 6,[hl] + jp nz,.moveMissed + ld a,[H_WHOSETURN] + and a + jr nz,.enemyTurn +.playerTurn +; this checks if the move effect is disallowed by mist + ld a,[W_PLAYERMOVEEFFECT] + cp a,ATTACK_DOWN1_EFFECT + jr c,.skipEnemyMistCheck + cp a,BIDE_EFFECT + jr c,.enemyMistCheck + cp a,$3a + jr c,.skipEnemyMistCheck + cp a,POISON_EFFECT + jr c,.enemyMistCheck + jr .skipEnemyMistCheck +.enemyMistCheck +; if move effect is from $12 to $19 inclusive or $3a to $41 inclusive +; i.e. the following moves +; GROWL, TAIL WHIP, LEER, STRING SHOT, SAND-ATTACK, SMOKESCREEN, KINESIS, +; FLASH, CONVERSION, HAZE*, SCREECH, LIGHT SCREEN*, REFLECT* +; the moves that are marked with an asterisk are not affected since this +; function is not called when those moves are used +; XXX are there are any others like those three? + ld a,[W_ENEMYBATTSTATUS2] + bit 1,a ; is mon protected by mist? + jp nz,.moveMissed +.skipEnemyMistCheck + ld a,[W_PLAYERBATTSTATUS2] + bit 0,a ; is the player using X Accuracy? + ret nz ; if so, always hit regardless of accuracy/evasion + jr .calcHitChance +.enemyTurn + ld a,[W_ENEMYMOVEEFFECT] + cp a,ATTACK_DOWN1_EFFECT + jr c,.skipPlayerMistCheck + cp a,BIDE_EFFECT + jr c,.playerMistCheck + cp a,$3a + jr c,.skipPlayerMistCheck + cp a,POISON_EFFECT + jr c,.playerMistCheck + jr .skipPlayerMistCheck +.playerMistCheck +; similar to enemy mist check + ld a,[W_PLAYERBATTSTATUS2] + bit 1,a ; is mon protected by mist? + jp nz,.moveMissed +.skipPlayerMistCheck + ld a,[W_ENEMYBATTSTATUS2] + bit 0,a ; is the enemy using X Accuracy? + ret nz ; if so, always hit regardless of accuracy/evasion +.calcHitChance + call CalcHitChance ; scale the move accuracy according to attacker's accuracy and target's evasion + ld a,[W_PLAYERMOVEACCURACY] + ld b,a + ld a,[H_WHOSETURN] + and a + jr z,.doAccuracyCheck + ld a,[W_ENEMYMOVEACCURACY] + ld b,a +.doAccuracyCheck +; if the random number generated is greater than or equal to the scaled accuracy, the move misses +; note that this means that even the highest accuracy is still just a 255/256 chance, not 100% + call BattleRandom + cp b + jr nc,.moveMissed + ret +.moveMissed + xor a + ld hl,W_DAMAGE ; zero the damage + ld [hli],a + ld [hl],a + inc a + ld [W_MOVEMISSED],a + ld a,[H_WHOSETURN] + and a + jr z,.playerTurn2 +.enemyTurn2 + ld hl,W_ENEMYBATTSTATUS1 + res 5,[hl] ; end multi-turn attack e.g. wrap + ret +.playerTurn2 + ld hl,W_PLAYERBATTSTATUS1 + res 5,[hl] ; end multi-turn attack e.g. wrap + ret + +; values for player turn +CalcHitChance: ; 3e624 (f:6624) + ld hl,W_PLAYERMOVEACCURACY + ld a,[H_WHOSETURN] + and a + ld a,[wPlayerMonAccuracyMod] + ld b,a + ld a,[wEnemyMonEvasionMod] + ld c,a + jr z,.next +; values for enemy turn + ld hl,W_ENEMYMOVEACCURACY + ld a,[wEnemyMonAccuracyMod] + ld b,a + ld a,[wPlayerMonEvasionMod] + ld c,a +.next + ld a,$0e + sub c + ld c,a ; c = 14 - EVASIONMOD (this "reflects" the value over 7, so that an increase in the target's evasion decreases the hit chance instead of increasing the hit chance) +; zero the high bytes of the multiplicand + xor a + ld [H_MULTIPLICAND],a + ld [H_MULTIPLICAND + 1],a + ld a,[hl] + ld [H_MULTIPLICAND + 2],a ; set multiplicand to move accuracy + push hl + ld d,$02 ; loop has two iterations +; loop to do the calculations, the first iteration multiplies by the accuracy ratio and the second iteration multiplies by the evasion ratio +.loop + push bc + ld hl, StatModifierRatios ; $76cb ; stat modifier ratios + dec b + sla b + ld c,b + ld b,$00 + add hl,bc ; hl = address of stat modifier ratio + pop bc + ld a,[hli] + ld [H_MULTIPLIER],a ; set multiplier to the numerator of the ratio + call Multiply + ld a,[hl] + ld [H_DIVISOR],a ; set divisor to the the denominator of the ratio (the dividend is the product of the previous multiplication) + ld b,$04 ; number of bytes in the dividend + call Divide + ld a,[H_QUOTIENT + 3] + ld b,a + ld a,[H_QUOTIENT + 2] + or b + jp nz,.nextCalculation +; make sure the result is always at least one + ld [H_QUOTIENT + 2],a + ld a,$01 + ld [H_QUOTIENT + 3],a +.nextCalculation + ld b,c + dec d + jr nz,.loop + ld a,[H_QUOTIENT + 2] + and a ; is the calculated hit chance over 0xFF? + ld a,[H_QUOTIENT + 3] + jr z,.storeAccuracy +; if calculated hit chance over 0xFF + ld a,$ff ; set the hit chance to 0xFF +.storeAccuracy + pop hl + ld [hl],a ; store the hit chance in the move accuracy variable + ret + +; multiplies damage by a random percentage from ~85% to 100% +RandomizeDamage: ; 3e687 (f:6687) + ld hl, W_DAMAGE + ld a, [hli] + and a + jr nz, .DamageGreaterThanOne + ld a, [hl] + cp 2 + ret c +.DamageGreaterThanOne + xor a + ld [H_MULTIPLICAND], a + dec hl + ld a, [hli] + ld [H_MULTIPLICAND + 1], a + ld a, [hl] + ld [H_MULTIPLICAND + 2], a +; loop until a random number greater than or equal to 217 is generated +.loop + call BattleRandom + rrca + cp 217 + jr c, .loop + ld [H_MULTIPLIER], a + call Multiply ; multiply damage by the random number, which is in the range [217, 255] + ld a, 255 + ld [H_DIVISOR], a + ld b, $4 + call Divide ; divide the result by 255 +; store the modified damage + ld a, [H_QUOTIENT + 2] + ld hl, W_DAMAGE + ld [hli], a + ld a, [H_QUOTIENT + 3] + ld [hl], a + ret + +ExecuteEnemyMove: ; 3e6bc (f:66bc) + ld a, [wEnemySelectedMove] + inc a + jp z, Func_3e88c + call PrintGhostText + jp z, Func_3e88c + ld a, [W_ISLINKBATTLE] + cp $4 + jr nz, .asm_3e6dc + ld b, $1 + ld a, [wcc3e] + cp $e + jr z, .asm_3e6dc + cp $4 + ret nc +.asm_3e6dc + ld hl, wccd5 + inc [hl] + xor a + ld [W_MOVEMISSED], a + ld [wccf4], a + ld a, $a + ld [wd05b], a + call CheckEnemyStatusConditions + jr nz, .canUseMove + jp [hl] +.canUseMove + ld hl, W_ENEMYBATTSTATUS1 + bit 4, [hl] ; is the enemy charging up for attack? + jr nz, asm_3e70b ; if so, jump + call GetCurrentMove + +Func_3e6fc: ; 3e6fc (f:66fc) + ld a, [W_ENEMYMOVEEFFECT] + cp CHARGE_EFFECT + jp z, JumpMoveEffect + cp FLY_EFFECT + jp z, JumpMoveEffect + jr asm_3e72b +asm_3e70b: ; 3e70b (f:670b) + ld hl, W_ENEMYBATTSTATUS1 + res 4, [hl] ; no longer charging up for attack + res 6, [hl] ; no longer invulnerable to typical attacks + ld a, [W_ENEMYMOVENUM] + ld [wd0b5], a + ld a, BANK(MoveNames) + ld [wPredefBank], a + ld a, MOVE_NAME + ld [W_LISTTYPE], a + call GetName + ld de, wcd6d + call CopyStringToCF4B +asm_3e72b: ; 3e72b (f:672b) + xor a + ld [wcced], a + call PrintMonName1Text + ld a, [W_ENEMYMOVEEFFECT] + ld hl, EffectsArray1 + ld de, $1 + call IsInArray + jp c, JumpMoveEffect + ld a, [W_ENEMYMOVEEFFECT] + ld hl, EffectsArray5B + ld de, $1 + call IsInArray + call c, JumpMoveEffect +asm_3e750: ; 3e750 (f:6750) + call SwapPlayerAndEnemyLevels + ld a, [W_ENEMYMOVEEFFECT] + ld hl, EffectsArray2 + ld de, $1 + call IsInArray + jp c, Func_3e77f + call CriticalHitTest + call HandleCounterMove + jr z, asm_3e782 + call SwapPlayerAndEnemyLevels + call GetDamageVarsForEnemyAttack + call SwapPlayerAndEnemyLevels + call CalculateDamage + jp z, Func_3e7d1 + call AdjustDamageForMoveType + call RandomizeDamage + +Func_3e77f: ; 3e77f (f:677f) + call MoveHitTest +asm_3e782: ; 3e782 (f:6782) + ld a, [W_MOVEMISSED] + and a + jr z, .asm_3e791 + ld a, [W_ENEMYMOVEEFFECT] + cp EXPLODE_EFFECT + jr z, asm_3e7a0 + jr Func_3e7d1 +.asm_3e791 + call SwapPlayerAndEnemyLevels + +Func_3e794: ; 3e794 (f:6794) + ld a, [W_ENEMYMOVEEFFECT] + and a + ld a, $1 + jr z, asm_3e7a4 + ld a, $2 + jr asm_3e7a4 +asm_3e7a0: ; 3e7a0 (f:67a0) + call SwapPlayerAndEnemyLevels + xor a +asm_3e7a4: ; 3e7a4 (f:67a4) + push af + ld a, [W_ENEMYBATTSTATUS2] + bit 4, a ; does mon have a substitute? + ld hl, Func_79747 + ld b, BANK(Func_79747) + call nz, Bankswitch + pop af + ld [wcc5b], a + ld a, [W_ENEMYMOVENUM] + call PlayMoveAnimation + call Func_3eed3 + call DrawEnemyHUDAndHPBar + ld a, [W_ENEMYBATTSTATUS2] + bit 4, a ; does mon have a substitute? + ld hl, Func_79771 + ld b, BANK(Func_79771) + call nz, Bankswitch ; slide the substitute's sprite out + jr asm_3e7ef + +Func_3e7d1: ; 3e7d1 (f:67d1) + call SwapPlayerAndEnemyLevels + ld c, $1e + call DelayFrames + ld a, [W_ENEMYMOVEEFFECT] + cp FLY_EFFECT + jr z, .asm_3e7e6 + cp CHARGE_EFFECT + jr z, .asm_3e7e6 + jr asm_3e7ef +.asm_3e7e6 + xor a + ld [wcc5b], a + ld a,STATUS_AFFECTED_ANIM + call PlayMoveAnimation +asm_3e7ef: ; 3e7ef (f:67ef) + ld a, [W_ENEMYMOVEEFFECT] + cp MIRROR_MOVE_EFFECT + jr nz, .notMirrorMoveEffect + call MirrorMoveCopyMove + jp z, Func_3e88c + jp Func_3e6fc +.notMirrorMoveEffect + cp METRONOME_EFFECT + jr nz, .notMetronomeEffect + call MetronomePickMove + jp Func_3e6fc +.notMetronomeEffect + ld a, [W_ENEMYMOVEEFFECT] + ld hl, EffectsArray3 + ld de, $1 + call IsInArray + jp c, JumpMoveEffect + ld a, [W_MOVEMISSED] + and a + jr z, .asm_3e82b + call PrintMoveFailureText + ld a, [W_ENEMYMOVEEFFECT] + cp EXPLODE_EFFECT + jr z, .asm_3e83e + jp Func_3e88c +.asm_3e82b + call ApplyAttackToPlayerPokemon + call PrintCriticalOHKOText + callab DisplayEffectiveness + ld a, 1 + ld [wccf4], a +.asm_3e83e + ld a, [W_ENEMYMOVEEFFECT] + ld hl, EffectsArray4 + ld de, $1 + call IsInArray + call c, JumpMoveEffect + ld hl, wBattleMonHP + ld a, [hli] + ld b, [hl] + or b + ret z + call HandleBuildingRage + ld hl, W_ENEMYBATTSTATUS1 + bit 2, [hl] ; is mon hitting multiple times? (example: double kick) + jr z, .asm_3e873 + push hl + ld hl, wEnemyNumAttacksLeft + dec [hl] + pop hl + jp nz, Func_3e794 + res 2, [hl] ; mon is no longer hitting multiple times + ld hl, HitXTimesText + call PrintText + xor a + ld [wcd05], a +.asm_3e873 + ld a, [W_ENEMYMOVEEFFECT] + and a + jr z, Func_3e88c + ld hl, EffectsArray5 + ld de, $1 + call IsInArray + call nc, JumpMoveEffect + jr Func_3e88c + +HitXTimesText: ; 3e887 (f:6887) + TX_FAR _HitXTimesText + db "@" + +Func_3e88c: ; 3e88c (f:688c) + ld b, $1 + ret + +; checks for various status conditions affecting the enemy mon +; stores whether the mon cannot use a move this turn in Z flag +CheckEnemyStatusConditions: ; 3e88f (f:688f) + ld hl, wEnemyMonStatus + ld a, [hl] + and SLP ; sleep mask + jr z, .checkIfFrozen + dec a ; decrement number of turns left + ld [wEnemyMonStatus], a + and a + jr z, .wokeUp ; if the number of turns hit 0, wake up + ld hl, FastAsleepText + call PrintText + xor a + ld [wcc5b], a + ld a,SLP_ANIM + call PlayMoveAnimation + jr .next1 +.wokeUp + ld hl, WokeUpText + call PrintText +.next1 + xor a + ld [wccf2], a + ld hl, Func_3e88c + jp .cannotUseMove +.checkIfFrozen + bit FRZ, [hl] + jr z, .checkIfTrapped + ld hl, IsFrozenText + call PrintText + xor a + ld [wccf2], a + ld hl, Func_3e88c + jp .cannotUseMove +.checkIfTrapped + ld a, [W_PLAYERBATTSTATUS1] + bit 5, a ; is the player using a multi-turn attack like warp + jp z, .checkIfFlinched + ld hl, CantMoveText + call PrintText + ld hl, Func_3e88c + jp .cannotUseMove +.checkIfFlinched + ld hl, W_ENEMYBATTSTATUS1 + bit 3, [hl] ; check if enemy mon flinched + jp z, .checkIfMustRecharge + res 3, [hl] + ld hl, FlinchedText + call PrintText + ld hl, Func_3e88c + jp .cannotUseMove +.checkIfMustRecharge + ld hl, W_ENEMYBATTSTATUS2 + bit 5, [hl] ; check if enemy mon has to recharge after using a move + jr z, .checkIfAnyMoveDisabled + res 5, [hl] + ld hl, MustRechargeText + call PrintText + ld hl, Func_3e88c + jp .cannotUseMove +.checkIfAnyMoveDisabled + ld hl, W_ENEMYDISABLEDMOVE + ld a, [hl] + and a + jr z, .checkIfConfused + dec a + ld [hl], a + and $f + jr nz, .checkIfConfused + ld [hl], a + ld [wccef], a + ld hl, DisabledNoMoreText + call PrintText +.checkIfConfused + ld a, [W_ENEMYBATTSTATUS1] + add a ; check if enemy mon is confused + jp nc, .checkIfTriedToUseDisabledMove + ld hl, wd070 + dec [hl] + jr nz, .isConfused + ld hl, W_ENEMYBATTSTATUS1 + res 7, [hl] + ld hl, ConfusedNoMoreText + call PrintText + jp .checkIfTriedToUseDisabledMove +.isConfused + ld hl, IsConfusedText + call PrintText + xor a + ld [wcc5b], a + ld a,CONF_ANIM + call PlayMoveAnimation + call BattleRandom + cp $80 + jr c, .checkIfTriedToUseDisabledMove + ld hl, W_ENEMYBATTSTATUS1 + ld a, [hl] + and $80 + ld [hl], a + ld hl, HurtItselfText + call PrintText + ld hl, wBattleMonDefense + ld a, [hli] + push af + ld a, [hld] + push af + ld a, [wEnemyMonDefense] + ld [hli], a + ld a, [wEnemyMonDefense + 1] + ld [hl], a + ld hl, W_ENEMYMOVEEFFECT + push hl + ld a, [hl] + push af + xor a + ld [hli], a + ld [wCriticalHitOrOHKO], a + ld a, $28 + ld [hli], a + xor a + ld [hl], a + call GetDamageVarsForEnemyAttack + call CalculateDamage + pop af + pop hl + ld [hl], a + ld hl, wBattleMonDefense + 1 + pop af + ld [hld], a + pop af + ld [hl], a + xor a + ld [wcc5b], a + ld [H_WHOSETURN], a + ld a, POUND + call PlayMoveAnimation + ld a, $1 + ld [H_WHOSETURN], a + call ApplyDamageToEnemyPokemon + jr .monHurtItselfOrFullyParalysed +.checkIfTriedToUseDisabledMove + ld a, [wccef] + and a + jr z, .checkIfParalysed + ld hl, wEnemySelectedMove + cp [hl] + jr nz, .checkIfParalysed + call PrintMoveIsDisabledText + ld hl, Func_3e88c + jp .cannotUseMove +.checkIfParalysed + ld hl, wEnemyMonStatus + bit PAR, [hl] + jr z, .checkIfUsingBide + call BattleRandom + cp $3f + jr nc, .checkIfUsingBide + ld hl, FullyParalyzedText + call PrintText +.monHurtItselfOrFullyParalysed + ld hl, W_ENEMYBATTSTATUS1 + ld a, [hl] + and $cc ; clear bide, thrashing, charging up, and multi-turn moves such as warp + ld [hl], a + ld a, [W_ENEMYMOVEEFFECT] + cp FLY_EFFECT + jr z, .flyOrChargeEffect + cp CHARGE_EFFECT + jr z, .flyOrChargeEffect + jr .notFlyOrChargeEffect +.flyOrChargeEffect + xor a + ld [wcc5b], a + ld a, STATUS_AFFECTED_ANIM + call PlayMoveAnimation +.notFlyOrChargeEffect + ld hl, Func_3e88c + jp .cannotUseMove +.checkIfUsingBide + ld hl, W_ENEMYBATTSTATUS1 + bit 0, [hl] ; is mon using bide? + jr z, .checkIfThrashingAbout + xor a + ld [W_ENEMYMOVENUM], a + ld hl, W_DAMAGE + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, wcd06 + ld a, [hl] + add c + ld [hld], a + ld a, [hl] + adc b + ld [hl], a + ld hl, wEnemyNumAttacksLeft + dec [hl] + jr z, .unleashEnergy + ld hl, Func_3e88c + jp .cannotUseMove +.unleashEnergy + ld hl, W_ENEMYBATTSTATUS1 + res 0, [hl] ; not using bide any more + ld hl, UnleashedEnergyText + call PrintText + ld a, $1 + ld [W_ENEMYMOVEPOWER], a + ld hl, wcd06 + ld a, [hld] + add a + ld b, a + ld [wd0d8], a + ld a, [hl] + rl a + ld [W_DAMAGE], a + or b + jr nz, .next2 + ld a, $1 + ld [W_MOVEMISSED], a +.next2 + xor a + ld [hli], a + ld [hl], a + ld a, BIDE + ld [W_ENEMYMOVENUM], a + call SwapPlayerAndEnemyLevels + ld hl, asm_3e782 + jp .cannotUseMove +.checkIfThrashingAbout + bit 1, [hl] ; is mon using thrash or petal dance? + jr z, .checkIfUsingMultiturnMove + ld a, THRASH + ld [W_ENEMYMOVENUM], a + ld hl, ThrashingAboutText + call PrintText + ld hl, wEnemyNumAttacksLeft + dec [hl] + ld hl, asm_3e750 + jp nz, .cannotUseMove + push hl + ld hl, W_ENEMYBATTSTATUS1 + res 1, [hl] ; mon is no longer using thrash or petal dance + set 7, [hl] ; mon is now confused + call BattleRandom + and $3 + inc a + inc a + ld [wd070], a + pop hl + jp .cannotUseMove +.checkIfUsingMultiturnMove + bit 5, [hl] ; is mon using multi-turn move? + jp z, .checkIfUsingRage + ld hl, AttackContinuesText + call PrintText + ld hl, wEnemyNumAttacksLeft + dec [hl] + ld hl, Func_3e794 + jp nz, .cannotUseMove + jp .cannotUseMove +.checkIfUsingRage + ld a, [W_ENEMYBATTSTATUS2] + bit 6, a ; is mon using rage? + jp z, .canUseMove + ld a, RAGE + ld [wd11e], a + call GetMoveName + call CopyStringToCF4B + xor a + ld [W_ENEMYMOVEEFFECT], a + ld hl, asm_3e72b + jp .cannotUseMove +.cannotUseMove + xor a ; set Z flag + ret +.canUseMove + ld a, $1 + and a ; clear Z flag + ret + +GetCurrentMove: ; 3eabe (f:6abe) + ld a, [H_WHOSETURN] + and a + jp z, .player + ld de, W_ENEMYMOVENUM + ld a, [wEnemySelectedMove] + jr .selected +.player + ld de, W_PLAYERMOVENUM + ld a, [W_FLAGS_D733] + bit 0, a + ld a, [wccd9] + jr nz, .selected + ld a, [wPlayerSelectedMove] +.selected + ld [wd0b5], a + dec a + ld hl, Moves + ld bc, $6 + call AddNTimes + ld a, BANK(Moves) + call FarCopyData + + ld a, BANK(MoveNames) + ld [wPredefBank], a + ld a, MOVE_NAME + ld [W_LISTTYPE], a + call GetName + ld de, wcd6d + jp CopyStringToCF4B + +LoadEnemyMonData: ; 3eb01 (f:6b01) + ld a, [W_ISLINKBATTLE] + cp $4 + jp z, LoadEnemyMonFromParty + ld a, [wEnemyMonSpecies2] + ld [wEnemyMonSpecies], a + ld [wd0b5], a + call GetMonHeader + ld a, [W_ENEMYBATTSTATUS3] + bit 3, a ; is enemy mon transformed? + ld hl, wcceb ; copied DVs from when it used Transform + ld a, [hli] + ld b, [hl] + jr nz, .storeDVs + ld a, [W_ISINBATTLE] + cp $2 ; is it a trainer battle? +; fixed DVs for trainer mon + ld a, $98 + ld b, $88 + jr z, .storeDVs +; random DVs for wild mon + call BattleRandom + ld b, a + call BattleRandom +.storeDVs + ld hl, wEnemyMonDVs + ld [hli], a + ld [hl], b + ld de, wEnemyMonLevel + ld a, [W_CURENEMYLVL] + ld [de], a + inc de + ld b, $0 + ld hl, wEnemyMonHP + push hl + call CalcStats + pop hl + ld a, [W_ISINBATTLE] + cp $2 ; is it a trainer battle? + jr z, .copyHPAndStatusFromPartyData + ld a, [W_ENEMYBATTSTATUS3] + bit 3, a ; is enemy mon transformed? + jr nz, .copyTypes ; if transformed, jump +; if it's a wild mon and not transformed, init the current HP to max HP and the status to 0 + ld a, [wEnemyMonMaxHP] + ld [hli], a + ld a, [wEnemyMonMaxHP+1] + ld [hli], a + xor a + inc hl + ld [hl], a ; init status to 0 + jr .copyTypes +; if it's a trainer mon, copy the HP and status from the enemy party data +.copyHPAndStatusFromPartyData + ld hl, wEnemyMon1HP + ld a, [wWhichPokemon] + ld bc, wEnemyMon2 - wEnemyMon1 + call AddNTimes + ld a, [hli] + ld [wEnemyMonHP], a + ld a, [hli] + ld [wEnemyMonHP + 1], a + ld a, [wWhichPokemon] + ld [wEnemyMonPartyPos], a + inc hl + ld a, [hl] + ld [wEnemyMonStatus], a + jr .copyTypes +.copyTypes + ld hl, W_MONHTYPES + ld de, wEnemyMonType + ld a, [hli] ; copy type 1 + ld [de], a + inc de + ld a, [hli] ; copy type 2 + ld [de], a + inc de + ld a, [hli] ; copy catch rate + ld [de], a + inc de + ld a, [W_ISINBATTLE] + cp $2 ; is it a trainer battle? + jr nz, .copyStandardMoves +; if it's a trainer battle, copy moves from enemy party data + ld hl, wEnemyMon1Moves + ld a, [wWhichPokemon] + ld bc, wEnemyMon2 - wEnemyMon1 + call AddNTimes + ld bc, NUM_MOVES + call CopyData + jr .loadMovePPs +.copyStandardMoves +; for a wild mon, first copy default moves from the mon header + ld hl, W_MONHMOVES + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + dec de + dec de + dec de + xor a + ld [wHPBarMaxHP], a + predef WriteMonMoves ; get moves based on current level +.loadMovePPs + ld hl, wEnemyMonMoves + ld de, wEnemyMonSpecial + 1 + predef LoadMovePPs + ld hl, W_MONHBASESTATS + ld de, wEnemyMonBaseStats + ld b, $5 +.copyBaseStatsLoop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .copyBaseStatsLoop + ld hl, W_MONHCATCHRATE + ld a, [hli] + ld [de], a + inc de + ld a, [hl] ; base exp + ld [de], a + ld a, [wEnemyMonSpecies2] + ld [wd11e], a + call GetMonName + ld hl, wcd6d + ld de, wEnemyMonNick + ld bc, $b + call CopyData + ld a, [wEnemyMonSpecies2] + ld [wd11e], a + predef IndexToPokedex + ld a, [wd11e] + dec a + ld c, a + ld b, $1 + ld hl, wPokedexSeen + predef FlagActionPredef ; mark this mon as seen in the pokedex + ld hl, wEnemyMonLevel + ld de, wEnemyMonUnmodifiedLevel + ld bc, $b + call CopyData + ld a, $7 ; default stat mod + ld b, $8 ; number of stat mods + ld hl, wEnemyMonStatMods +.statModLoop + ld [hli], a + dec b + jr nz, .statModLoop + ret + +; calls BattleTransition to show the battle transition animation and initializes some battle variables +DoBattleTransitionAndInitBattleVariables: ; 3ec32 (f:6c32) + ld a, [W_ISLINKBATTLE] + cp $4 + jr nz, .next +; link battle + xor a + ld [wMenuJoypadPollCount], a + callab DisplayLinkBattleVersusTextBox + ld a, $1 + ld [wUpdateSpritesEnabled], a + call ClearScreen +.next + call DelayFrame + predef BattleTransition + callab LoadHudAndHpBarAndStatusTilePatterns + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld a, $ff + ld [wUpdateSpritesEnabled], a + call ClearSprites + call ClearScreen + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld [hVBlankWY], a + ld [rWY], a + ld [hTilesetType], a + ld hl, wd060 + ld [hli], a + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ld [W_PLAYERDISABLEDMOVE], a + ret + +; swaps the level values of the BattleMon and EnemyMon structs +SwapPlayerAndEnemyLevels: ; 3ec81 (f:6c81) + push bc + ld a, [wBattleMonLevel] + ld b, a + ld a, [wEnemyMonLevel] + ld [wBattleMonLevel], a + ld a, b + ld [wEnemyMonLevel], a + pop bc + ret + +; loads either red back pic or old man back pic +; also writes OAM data and loads tile patterns for the Red or Old Man back sprite's head +; (for use when scrolling the player sprite and enemy's silhouettes on screen) +LoadPlayerBackPic: ; 3ec92 (f:6c92) + ld a, [W_BATTLETYPE] + dec a ; is it the old man tutorial? + ld de, RedPicBack + jr nz, .next + ld de, OldManPic +.next + ld a, BANK(RedPicBack) + call UncompressSpriteFromDE + predef ScaleSpriteByTwo + ld hl, wOAMBuffer + xor a + ld [$FF8B], a ; initial tile number + ld b, $7 ; 7 columns + ld e, $a0 ; X for the left-most column +.loop ; each loop iteration writes 3 OAM entries in a vertical column + ld c, $3 ; 3 tiles per column + ld d, $38 ; Y for the top of each column +.innerLoop ; each loop iteration writes 1 OAM entry in the column + ld [hl], d ; OAM Y + inc hl + ld [hl], e ; OAM X + ld a, $8 ; height of tile + add d ; increase Y by height of tile + ld d, a + inc hl + ld a, [$FF8B] + ld [hli], a ; OAM tile number + inc a ; increment tile number + ld [$FF8B], a + inc hl + dec c + jr nz, .innerLoop + ld a, [$FF8B] + add $4 ; increase tile number by 4 + ld [$FF8B], a + ld a, $8 ; width of tile + add e ; increase X by width of tile + ld e, a + dec b + jr nz, .loop + ld de, vBackPic + call InterlaceMergeSpriteBuffers + ld a, $a + ld [$0], a + xor a + ld [$4000], a + ld hl, vSprites + ld de, S_SPRITEBUFFER1 + ld a, [H_LOADEDROMBANK] + ld b, a + ld c, 7 * 7 + call CopyVideoData + xor a + ld [$0], a + ld a, $31 + ld [$ffe1], a + hlCoord 1, 5 + predef_jump Func_3f0c6 + +Func_3ed02: ; 3ed02 (f:6d02) + callab Func_39680 + ld hl, Func_396a7 + ld b, BANK(Func_396a7) + jp Bankswitch + +ScrollTrainerPicAfterBattle: ; 3ed12 (f:6d12) + ld hl, _ScrollTrainerPicAfterBattle + ld b, BANK(_ScrollTrainerPicAfterBattle) + jp Bankswitch + +ApplyBurnAndParalysisPenaltiesToPlayer: ; 3ed1a (f:6d1a) + ld a, $1 + jr ApplyBurnAndParalysisPenalties + +ApplyBurnAndParalysisPenaltiesToEnemy: ; 3ed1e (f:6d1e) + xor a + +ApplyBurnAndParalysisPenalties: ; 3ed1f (f:6d1f) + ld [H_WHOSETURN], a + call QuarterSpeedDueToParalysis + jp HalveAttackDueToBurn + +QuarterSpeedDueToParalysis: ; 3ed27 (f:6d27) + ld a, [H_WHOSETURN] + and a + jr z, .playerTurn +.enemyTurn ; quarter the player's speed + ld a, [wBattleMonStatus] + and 1 << PAR + ret z ; return if player not paralysed + ld hl, wBattleMonSpeed + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + srl a + rr b + ld [hli], a + or b + jr nz, .storePlayerSpeed + ld b, 1 ; give the player a minimum of at least one speed point +.storePlayerSpeed + ld [hl], b + ret +.playerTurn ; quarter the enemy's speed + ld a, [wEnemyMonStatus] + and 1 << PAR + ret z ; return if enemy not paralysed + ld hl, wEnemyMonSpeed + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + srl a + rr b + ld [hli], a + or b + jr nz, .storeEnemySpeed + ld b, 1 ; give the enemy a minimum of at least one speed point +.storeEnemySpeed + ld [hl], b + ret + +HalveAttackDueToBurn: ; 3ed64 (f:6d64) + ld a, [H_WHOSETURN] + and a + jr z, .playerTurn +.enemyTurn ; halve the player's attack + ld a, [wBattleMonStatus] + and 1 << BRN + ret z ; return if player not burnt + ld hl, wBattleMonAttack + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + ld [hli], a + or b + jr nz, .storePlayerAttack + ld b, 1 ; give the player a minimum of at least one attack point +.storePlayerAttack + ld [hl], b + ret +.playerTurn ; halve the enemy's attack + ld a, [wEnemyMonStatus] + and 1 << BRN + ret z ; return if enemy not burnt + ld hl, wEnemyMonAttack + 1 + ld a, [hld] + ld b, a + ld a, [hl] + srl a + rr b + ld [hli], a + or b + jr nz, .storeEnemyAttack + ld b, 1 ; give the enemy a minimum of at least one attack point +.storeEnemyAttack + ld [hl], b + ret + +CalculateModifiedStats: ; 3ed99 (f:6d99) + ld c, 0 +.loop + call CalculateModifiedStat + inc c + ld a, c + cp 4 + jr nz, .loop + ret + +; calculate modified stat for stat c (0 = attack, 1 = defense, 2 = speed, 3 = special) +CalculateModifiedStat: ; 3eda5 (f:6da5) + push bc + push bc + ld a, [wd11e] + and a + ld a, c + ld hl, wBattleMonAttack + ld de, wPlayerMonUnmodifiedAttack + ld bc, wPlayerMonAttackMod + jr z, .next + ld hl, wEnemyMonAttack + ld de, wEnemyMonUnmodifiedAttack + ld bc, wEnemyMonStatMods +.next + add c + ld c, a + jr nc, .noCarry1 + inc b +.noCarry1 + ld a, [bc] + pop bc + ld b, a + push bc + sla c + ld b, 0 + add hl, bc + ld a, c + add e + ld e, a + jr nc, .noCarry2 + inc d +.noCarry2 + pop bc + push hl + ld hl, StatModifierRatios + dec b + sla b + ld c, b + ld b, 0 + add hl, bc + xor a + ld [H_MULTIPLICAND], a + ld a, [de] + ld [H_MULTIPLICAND + 1], a + inc de + ld a, [de] + ld [H_MULTIPLICAND + 2], a + ld a, [hli] + ld [H_MULTIPLIER], a + call Multiply + ld a, [hl] + ld [H_DIVISOR], a + ld b, $4 + call Divide + pop hl + ld a, [H_DIVIDEND + 3] + sub 999 % $100 + ld a, [H_DIVIDEND + 2] + sbc 999 / $100 + jp c, .storeNewStatValue +; cap the stat at 999 + ld a, 999 / $100 + ld [H_DIVIDEND + 2], a + ld a, 999 % $100 + ld [H_DIVIDEND + 3], a +.storeNewStatValue + ld a, [H_DIVIDEND + 2] + ld [hli], a + ld b, a + ld a, [H_DIVIDEND + 3] + ld [hl], a + or b + jr nz, .done + inc [hl] ; if the stat is 0, bump it up to 1 +.done + pop bc + ret + +ApplyBadgeStatBoosts: ; 3ee19 (f:6e19) + ld a, [W_ISLINKBATTLE] + cp $4 + ret z ; return if link battle + ld a, [W_OBTAINEDBADGES] + ld b, a + ld hl, wBattleMonAttack + ld c, $4 +; the boost is applied for badges whose bit position is even +; the order of boosts matches the order they are laid out in RAM +; Boulder (bit 0) - attack +; Thunder (bit 2) - defense +; Soul (bit 4) - speed +; Volcano (bit 6) - special +.loop + srl b + call c, .applyBoostToStat + inc hl + inc hl + srl b + dec c + jr nz, .loop + ret + +; multiply stat at hl by 1.125 +; cap stat at 999 +.applyBoostToStat + ld a, [hli] + ld d, a + ld e, [hl] + srl d + rr e + srl d + rr e + srl d + rr e + ld a, [hl] + add e + ld [hld], a + ld a, [hl] + adc d + ld [hli], a + ld a, [hld] + sub 999 % $100 + ld a, [hl] + sbc 999 / $100 + ret c + ld a, 999 / $100 + ld [hli], a + ld a, 999 % $100 + ld [hld], a + ret + +LoadHudAndHpBarAndStatusTilePatterns: ; 3ee58 (f:6e58) + call LoadHpBarAndStatusTilePatterns + +LoadHudTilePatterns: ; 3ee5b (f:6e5b) + ld a, [rLCDC] + add a ; is LCD disabled? + jr c, .lcdEnabled +.lcdDisabled + ld hl, BattleHudTiles1 + ld de, vChars2 + $6d0 + ld bc, $18 + ld a, BANK(BattleHudTiles1) + call FarCopyDataDouble + ld hl, BattleHudTiles2 + ld de, vChars2 + $730 + ld bc, $30 + ld a, BANK(BattleHudTiles2) + jp FarCopyDataDouble +.lcdEnabled + ld de, BattleHudTiles1 + ld hl, vChars2 + $6d0 + ld bc, (BANK(BattleHudTiles1) << 8) + $03 + call CopyVideoDataDouble + ld de, BattleHudTiles2 + ld hl, vChars2 + $730 + ld bc, (BANK(BattleHudTiles2) << 8) + $06 + jp CopyVideoDataDouble + +PrintEmptyString: ; 3ee94 (f:6e94) + ld hl, .emptyString + jp PrintText +.emptyString + db "@" + + +BattleRandom: +; Link battles use a shared PRNG. + + ld a, [W_ISLINKBATTLE] + cp $4 + jp nz, Random + + push hl + push bc + ld a, [wccde] + ld c, a + ld b, 0 + ld hl, wd148 + add hl, bc + inc a + ld [wccde], a + cp 9 + ld a, [hl] + pop bc + pop hl + ret c + + push hl + push bc + push af + + xor a + ld [wccde], a + + ld hl, wd148 + ld b, 9 +.loop + ld a, [hl] + ld c, a + add a + add a + add c + inc a + ld [hli], a + dec b + jr nz, .loop + + pop af + pop bc + pop hl + ret + + +Func_3eed3: ; 3eed3 (f:6ed3) + ld a, [H_WHOSETURN] + and a + ld hl, wEnemyMonType1 ; wcfea (aliases: wEnemyMonType) + ld de, W_ENEMYBATTSTATUS1 + ld a, [W_PLAYERMOVENUM] + jr z, .asm_3eeea + ld hl, wBattleMonType1 ; wd019 (aliases: wBattleMonType) + ld de, W_ENEMYBATTSTATUS1 + ld a, [W_ENEMYMOVENUM] +.asm_3eeea + cp SELFDESTRUCT + jr z, .asm_3eef1 + cp EXPLOSION + ret nz +.asm_3eef1 + ld a, [de] + bit 6, a ; fly/dig + ret nz + ld a, [hli] + cp GHOST + ret z + ld a, [hl] + cp GHOST + ret z + ld a, [W_MOVEMISSED] + and a + ret nz + ld a, MEGA_PUNCH + ld [wcc5b], a + +PlayMoveAnimation: ; 3ef07 (f:6f07) + ld [W_ANIMATIONID],a + call Delay3 + predef_jump MoveAnimation + +InitBattle: ; 3ef12 (f:6f12) + ld a, [W_CUROPPONENT] + and a + jr z, asm_3ef23 + +InitOpponent: ; 3ef18 (f:6f18) + ld a, [W_CUROPPONENT] + ld [wcf91], a + ld [wEnemyMonSpecies2], a + jr asm_3ef3d +asm_3ef23: ; 3ef23 (f:6f23) + ld a, [wd732] + bit 1, a + jr z, .asm_3ef2f + ld a, [hJoyHeld] + bit 1, a ; B button pressed? + ret nz +.asm_3ef2f + ld a, [wNumberOfNoRandomBattleStepsLeft] + and a + ret nz + callab Func_13870 + ret nz +asm_3ef3d: ; 3ef3d (f:6f3d) + ld a, [wMapPalOffset] + push af + ld hl, wd358 + ld a, [hl] + push af + res 1, [hl] + callab Func_525af + ld a, [wEnemyMonSpecies2] + sub $c8 + jp c, InitWildBattle + ld [W_TRAINERCLASS], a + call GetTrainerInformation + callab ReadTrainer + call DoBattleTransitionAndInitBattleVariables + call _LoadTrainerPic + xor a + ld [wEnemyMonSpecies2], a + ld [$ffe1], a + dec a + ld [wAICount], a + hlCoord 12, 0 + predef Func_3f0c6 + ld a, $ff + ld [wEnemyMonPartyPos], a + ld a, $2 + ld [W_ISINBATTLE], a + jp InitBattle_Common + +InitWildBattle: ; 3ef8b (f:6f8b) + ld a, $1 + ld [W_ISINBATTLE], a + call LoadEnemyMonData + call DoBattleTransitionAndInitBattleVariables + ld a, [W_CUROPPONENT] + cp MAROWAK + jr z, .isGhost + call IsGhostBattle + jr nz, .isNoGhost +.isGhost + ld hl, W_MONHSPRITEDIM + ld a, $66 + ld [hli], a ; write sprite dimensions + ld bc, GhostPic + ld a, c + ld [hli], a ; write front sprite pointer + ld [hl], b + ld hl, wEnemyMonNick ; set name to "GHOST" + ld a, "G" + ld [hli], a + ld a, "H" + ld [hli], a + ld a, "O" + ld [hli], a + ld a, "S" + ld [hli], a + ld a, "T" + ld [hli], a + ld [hl], "@" + ld a, [wcf91] + push af + ld a, MON_GHOST + ld [wcf91], a + ld de, vFrontPic + call LoadMonFrontSprite ; load ghost sprite + pop af + ld [wcf91], a + jr .spriteLoaded +.isNoGhost + ld de, vFrontPic + call LoadMonFrontSprite ; load mon sprite +.spriteLoaded + xor a + ld [W_TRAINERCLASS], a + ld [$ffe1], a + hlCoord 12, 0 + predef Func_3f0c6 + +; common code that executes after init battle code specific to trainer or wild battles +InitBattle_Common: ; 3efeb (f:6feb) + ld b, $0 + call GoPAL_SET + call SlidePlayerAndEnemySilhouettesOnScreen + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld hl, .emptyString + call PrintText + call SaveScreenTilesToBuffer1 + call ClearScreen + ld a, $98 + ld [$ffbd], a + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + ld a, $9c + ld [$ffbd], a + call LoadScreenTilesFromBuffer1 + hlCoord 9, 7 + ld bc, $50a + call ClearScreenArea + hlCoord 1, 0 + ld bc, $40a + call ClearScreenArea + call ClearSprites + ld a, [W_ISINBATTLE] + dec a ; is it a wild battle? + call z, DrawEnemyHUDAndHPBar ; draw enemy HUD and HP bar if it's a wild battle + call StartBattle + callab EndOfBattle + pop af + ld [wd358], a + pop af + ld [wMapPalOffset], a + ld a, [wd0d4] + ld [hTilesetType], a + scf + ret +.emptyString + db "@" + +_LoadTrainerPic: ; 3f04b (f:704b) +; wd033-wd034 contain pointer to pic + ld a, [wd033] + ld e, a + ld a, [wd034] + ld d, a ; de contains pointer to trainer pic + ld a, [W_ISLINKBATTLE] + and a + ld a, Bank(TrainerPics) ; this is where all the trainer pics are (not counting Red's) + jr z, .loadSprite + ld a, Bank(RedPicFront) +.loadSprite + call UncompressSpriteFromDE + ld de, vFrontPic + ld a, $77 + ld c, a + jp LoadUncompressedSpriteData + +Func_3f069: ; 3f069 (f:7069) + xor a + ld [wc0f1], a + ld [wc0f2], a + jp PlaySound + +Func_3f073: ; 3f073 (f:7073) + ld a, [wPredefRegisters] + ld h, a + ld a, [wPredefRegisters + 1] + ld l, a + ld a, [$ffe1] + ld [H_DOWNARROWBLINKCNT1], a + ld b, $4c + ld a, [W_ISINBATTLE] + and a + jr z, .asm_3f0bc + add b + ld [hl], a + call Delay3 + ld bc, -41 + add hl, bc + ld a, $1 + ld [wcd6c], a + ld bc, $303 + predef Func_79aba + ld c, $4 + call DelayFrames + ld bc, -41 + add hl, bc + xor a + ld [wcd6c], a + ld bc, $505 + predef Func_79aba + ld c, $5 + call DelayFrames + ld bc, -41 + jr .asm_3f0bf +.asm_3f0bc + ld bc, -123 +.asm_3f0bf + add hl, bc + ld a, [H_DOWNARROWBLINKCNT1] + add $31 + jr asm_3f0d0 + +Func_3f0c6: ; 3f0c6 (f:70c6) + ld a, [wPredefRegisters] + ld h, a + ld a, [wPredefRegisters + 1] + ld l, a + ld a, [$ffe1] +asm_3f0d0: ; 3f0d0 (f:70d0) + ld bc, $707 + ld de, $14 + push af + ld a, [W_SPRITEFLIPPED] + and a + jr nz, .asm_3f0ed + pop af +.asm_3f0de + push bc + push hl +.asm_3f0e0 + ld [hl], a + add hl, de + inc a + dec c + jr nz, .asm_3f0e0 + pop hl + inc hl + pop bc + dec b + jr nz, .asm_3f0de + ret +.asm_3f0ed + push bc + ld b, $0 + dec c + add hl, bc + pop bc + pop af +.asm_3f0f4 + push bc + push hl +.asm_3f0f6 + ld [hl], a + add hl, de + inc a + dec c + jr nz, .asm_3f0f6 + pop hl + dec hl + pop bc + dec b + jr nz, .asm_3f0f4 + ret + +LoadMonBackPic: +; Assumes the monster's attributes have +; been loaded with GetMonHeader. + ld a, [wBattleMonSpecies2] + ld [wcf91], a + hlCoord 1, 5 + ld b, $7 + ld c, $8 + call ClearScreenArea + ld hl, W_MONHBACKSPRITE - W_MONHEADER + call UncompressMonSprite + predef ScaleSpriteByTwo + ld de, vBackPic + call InterlaceMergeSpriteBuffers ; combine the two buffers to a single 2bpp sprite + ld hl, vSprites + ld de, vBackPic + ld c, (2*SPRITEBUFFERSIZE)/16 ; count of 16-byte chunks to be copied + ld a, [H_LOADEDROMBANK] + ld b, a + jp CopyVideoData + +JumpMoveEffect: ; 3f132 (f:7132) + call _JumpMoveEffect + ld b, $1 + ret + +_JumpMoveEffect: ; 3f138 (f:7138) + ld a, [$fff3] ;whose turn? + and a + ld a, [W_PLAYERMOVEEFFECT] + jr z, .next1 + ld a, [W_ENEMYMOVEEFFECT] +.next1 + dec a ;subtract 1, there is no special effect for 00 + add a ;x2, 16bit pointers + ld hl, MoveEffectPointerTable + ld b, 0 + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp [hl] ;jump to special effect handler + +MoveEffectPointerTable: ; 3f150 (f:7150) + dw SleepEffect ; unused effect + dw PoisonEffect ; POISON_SIDE_EFFECT1 + dw DrainHPEffect ; DRAIN_HP_EFFECT + dw FreezeBurnParalyzeEffect ; BURN_SIDE_EFFECT1 + dw FreezeBurnParalyzeEffect ; FREEZE_SIDE_EFFECT + dw FreezeBurnParalyzeEffect ; PARALYZE_SIDE_EFFECT1 + dw ExplodeEffect ; EXPLODE_EFFECT + dw DrainHPEffect ; DREAM_EATER_EFFECT + dw $0000 ; MIRROR_MOVE_EFFECT + dw StatModifierUpEffect ; ATTACK_UP1_EFFECT + dw StatModifierUpEffect ; DEFENSE_UP1_EFFECT + dw StatModifierUpEffect ; SPEED_UP1_EFFECT + dw StatModifierUpEffect ; SPECIAL_UP1_EFFECT + dw StatModifierUpEffect ; ACCURACY_UP1_EFFECT + dw StatModifierUpEffect ; EVASION_UP1_EFFECT + dw PayDayEffect ; PAY_DAY_EFFECT + dw $0000 ; SWIFT_EFFECT + dw StatModifierDownEffect ; ATTACK_DOWN1_EFFECT + dw StatModifierDownEffect ; DEFENSE_DOWN1_EFFECT + dw StatModifierDownEffect ; SPEED_DOWN1_EFFECT + dw StatModifierDownEffect ; SPECIAL_DOWN1_EFFECT + dw StatModifierDownEffect ; ACCURACY_DOWN1_EFFECT + dw StatModifierDownEffect ; EVASION_DOWN1_EFFECT + dw ConversionEffect ; CONVERSION_EFFECT + dw HazeEffect ; HAZE_EFFECT + dw BideEffect ; BIDE_EFFECT + dw ThrashPetalDanceEffect ; THRASH_PETAL_DANCE_EFFECT + dw SwitchAndTeleportEffect ; SWITCH_AND_TELEPORT_EFFECT + dw TwoToFiveAttacksEffect ; TWO_TO_FIVE_ATTACKS_EFFECT + dw TwoToFiveAttacksEffect ; unused effect + dw FlichSideEffect ; FLINCH_SIDE_EFFECT1 + dw SleepEffect ; SLEEP_EFFECT + dw PoisonEffect ; POISON_SIDE_EFFECT2 + dw FreezeBurnParalyzeEffect ; BURN_SIDE_EFFECT2 + dw FreezeBurnParalyzeEffect ; unused effect + dw FreezeBurnParalyzeEffect ; PARALYZE_SIDE_EFFECT2 + dw FlichSideEffect ; FLINCH_SIDE_EFFECT2 + dw OneHitKOEffect ; OHKO_EFFECT + dw ChargeEffect ; CHARGE_EFFECT + dw $0000 ; SUPER_FANG_EFFECT + dw $0000 ; SPECIAL_DAMAGE_EFFECT + dw TrappingEffect ; TRAPPING_EFFECT + dw ChargeEffect ; FLY_EFFECT + dw TwoToFiveAttacksEffect ; ATTACK_TWICE_EFFECT + dw $0000 ; JUMP_KICK_EFFECT + dw MistEffect ; MIST_EFFECT + dw FocusEnergyEffect ; FOCUS_ENERGY_EFFECT + dw RecoilEffect ; RECOIL_EFFECT + dw ConfusionEffect ; CONFUSION_EFFECT + dw StatModifierUpEffect ; ATTACK_UP2_EFFECT + dw StatModifierUpEffect ; DEFENSE_UP2_EFFECT + dw StatModifierUpEffect ; SPEED_UP2_EFFECT + dw StatModifierUpEffect ; SPECIAL_UP2_EFFECT + dw StatModifierUpEffect ; ACCURACY_UP2_EFFECT + dw StatModifierUpEffect ; EVASION_UP2_EFFECT + dw HealEffect ; HEAL_EFFECT + dw TransformEffect ; TRANSFORM_EFFECT + dw StatModifierDownEffect ; ATTACK_DOWN2_EFFECT + dw StatModifierDownEffect ; DEFENSE_DOWN2_EFFECT + dw StatModifierDownEffect ; SPEED_DOWN2_EFFECT + dw StatModifierDownEffect ; SPECIAL_DOWN2_EFFECT + dw StatModifierDownEffect ; ACCURACY_DOWN2_EFFECT + dw StatModifierDownEffect ; EVASION_DOWN2_EFFECT + dw ReflectLightScreenEffect ; LIGHT_SCREEN_EFFECT + dw ReflectLightScreenEffect ; REFLECT_EFFECT + dw PoisonEffect ; POISON_EFFECT + dw ParalyzeEffect ; PARALYZE_EFFECT + dw StatModifierDownEffect ; ATTACK_DOWN_SIDE_EFFECT + dw StatModifierDownEffect ; DEFENSE_DOWN_SIDE_EFFECT + dw StatModifierDownEffect ; SPEED_DOWN_SIDE_EFFECT + dw StatModifierDownEffect ; SPECIAL_DOWN_SIDE_EFFECT + dw StatModifierDownEffect ; unused effect + dw StatModifierDownEffect ; unused effect + dw StatModifierDownEffect ; unused effect + dw StatModifierDownEffect ; unused effect + dw ConfusionSideEffect ; CONFUSION_SIDE_EFFECT + dw TwoToFiveAttacksEffect ; TWINEEDLE_EFFECT + dw $0000 ; unused effect + dw SubstituteEffect ; SUBSTITUTE_EFFECT + dw HyperBeamEffect ; HYPER_BEAM_EFFECT + dw RageEffect ; RAGE_EFFECT + dw MimicEffect ; MIMIC_EFFECT + dw $0000 ; METRONOME_EFFECT + dw LeechSeedEffect ; LEECH_SEED_EFFECT + dw SplashEffect ; SPLASH_EFFECT + dw DisableEffect ; DISABLE_EFFECT + +SleepEffect: ; 3f1fc (f:71fc) + ld de, wEnemyMonStatus + ld bc, W_ENEMYBATTSTATUS2 + ld a, [H_WHOSETURN] + and a + jp z, .asm_3f20e + ld de, wBattleMonStatus + ld bc, W_PLAYERBATTSTATUS2 + +.asm_3f20e + ld a, [bc] + bit 5, a ; does the mon need to recharge? (hyper beam) + res 5, a ; mon no longer needs to recharge + ld [bc], a + jr nz, .asm_3f231 + ld a, [de] + ld b, a + and $7 + jr z, .asm_3f222 + ld hl, AlreadyAsleepText + jp PrintText +.asm_3f222 + ld a, b + and a + jr nz, .asm_3f242 + push de + call MoveHitTest + pop de + ld a, [W_MOVEMISSED] + and a + jr nz, .asm_3f242 +.asm_3f231 + call BattleRandom + and $7 + jr z, .asm_3f231 + ld [de], a + call Func_3fb89 + ld hl, FellAsleepText + jp PrintText +.asm_3f242 + jp PrintDidntAffectText + +FellAsleepText: ; 3f245 (f:7245) + TX_FAR _FellAsleepText + db "@" + +AlreadyAsleepText: ; 3f24a (f:724a) + TX_FAR _AlreadyAsleepText + db "@" + +PoisonEffect: ; 3f24f (f:724f) + ld hl, wEnemyMonStatus + ld de, W_PLAYERMOVEEFFECT + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f260 + ld hl, wBattleMonStatus + ld de, W_ENEMYMOVEEFFECT +.asm_3f260 + call CheckTargetSubstitute + jr nz, .asm_3f2d3 + ld a, [hli] + ld b, a + and a + jr nz, .asm_3f2d3 + ld a, [hli] + cp $3 + jr z, .asm_3f2d3 + ld a, [hld] + cp $3 + jr z, .asm_3f2d3 + ld a, [de] + cp POISON_SIDE_EFFECT1 + ld b, $34 ; ~20% chance of poisoning + jr z, .asm_3f290 + cp POISON_SIDE_EFFECT2 + ld b, $67 ; ~40% chance of poisoning + jr z, .asm_3f290 + push hl + push de + call MoveHitTest + pop de + pop hl + ld a, [W_MOVEMISSED] + and a + jr nz, .asm_3f2d7 + jr .asm_3f295 +.asm_3f290 + call BattleRandom + cp b + ret nc +.asm_3f295 + dec hl + set 3, [hl] + push de + dec de + ld a, [H_WHOSETURN] + and a +<<<<<<< HEAD + ld b, ANIM_C7 + ld hl, W_PLAYERBATTSTATUS3 ; W_PLAYERBATTSTATUS3 +======= + ld b, $c7 + ld hl, W_PLAYERBATTSTATUS3 +>>>>>>> yama/master + ld a, [de] + ld de, W_PLAYERTOXICCOUNTER + jr nz, .asm_3f2b0 +<<<<<<< HEAD + ld b, ANIM_A9 + ld hl, W_ENEMYBATTSTATUS3 ; W_ENEMYBATTSTATUS3 + ld de, W_ENEMYTOXICCOUNTER ; wd071 +======= + ld b, $a9 + ld hl, W_ENEMYBATTSTATUS3 + ld de, W_ENEMYTOXICCOUNTER +>>>>>>> yama/master +.asm_3f2b0 + cp TOXIC + jr nz, .asm_3f2bd + set 0, [hl] + xor a + ld [de], a + ld hl, BadlyPoisonedText + jr .asm_3f2c0 +.asm_3f2bd + ld hl, PoisonedText +.asm_3f2c0 + pop de + ld a, [de] + cp POISON_EFFECT + jr z, .asm_3f2cd + ld a, b + call Func_3fb96 + jp PrintText +.asm_3f2cd + call Func_3fb89 + jp PrintText +.asm_3f2d3 + ld a, [de] + cp POISON_EFFECT + ret nz +.asm_3f2d7 + ld c, $32 + call DelayFrames + jp PrintDidntAffectText + +PoisonedText: ; 3f2df (f:72df) + TX_FAR _PoisonedText + db "@" + +BadlyPoisonedText: ; 3f2e4 (f:72e4) + TX_FAR _BadlyPoisonedText + db "@" + +DrainHPEffect: ; 3f2e9 (f:72e9) + ld hl, DrainHPEffect_ + ld b, BANK(DrainHPEffect_) + jp Bankswitch + +ExplodeEffect: ; 3f2f1 (f:72f1) + ld hl, wBattleMonHP + ld de, W_PLAYERBATTSTATUS2 + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f302 + ld hl, wEnemyMonHP + ld de, W_ENEMYBATTSTATUS2 +.asm_3f302 + xor a + ld [hli], a ; set the mon's HP to 0 + ld [hli], a + inc hl + ld [hl], a ; set mon's status to 0 + ld a, [de] + res 7, a ; clear mon's leech seed status + ld [de], a + ret + +FreezeBurnParalyzeEffect: ; 3f30c (f:730c) + xor a + ld [wcc5b], a + call CheckTargetSubstitute ;test bit 4 of d063/d068 flags [target has substitute flag] + ret nz ;return if they have a substitute, can't effect them + ld a, [$fff3] ;whose turn? + and a + jp nz, opponentAttacker + ld a, [wEnemyMonStatus] + and a + jp nz, CheckDefrost + ;opponent has no existing status + ld a, [W_PLAYERMOVETYPE] + ld b, a + ld a, [wEnemyMonType1] + cp b + ret z ;return if they match [can't freeze an ice type etc.] + ld a, [wEnemyMonType2] + cp b + ret z ;return.. + ld a, [W_PLAYERMOVEEFFECT] + cp a, 7 ;10% status effects are 04, 05, 06 so 07 will set carry for those + ld b, $1a ;[1A-1]/100 or [26-1]/256 = 9.8%~ chance + jr c, .next1 ;branch ahead if this is a 10% chance effect.. + ld b, $4d ;..or use [4D-1]/100 or [76-1]/256 = 29.7%~ chance + sub a, $1e ;subtract $1E to map to equivalent 10% chance effects +.next1 + push af ;push effect... + call BattleRandom ;get random 8bit value for probability test + cp b ;success? + pop bc ;...pop effect into C + ret nc ;do nothing if random value is >= 1A or 4D [no status applied] + ;the test passed + ld a, b ;what type of effect is this? + cp a, BURN_SIDE_EFFECT1 + jr z, .burn + cp a, FREEZE_SIDE_EFFECT + jr z, .freeze + ld a, 1 << PAR + ld [wEnemyMonStatus], a +<<<<<<< HEAD + call Func_3ed27 ;quarter speed of affected monster + ld a, ANIM_A9 +======= + call QuarterSpeedDueToParalysis ;quarter speed of affected monster + ld a, $a9 +>>>>>>> yama/master + call Func_3fbb9 ;animation + jp PrintMayNotAttackText ;print paralysis text +.burn + ld a, 1 << BRN + ld [wEnemyMonStatus], a +<<<<<<< HEAD + call Func_3ed64 + ld a, ANIM_A9 +======= + call HalveAttackDueToBurn + ld a, $a9 +>>>>>>> yama/master + call Func_3fbb9 ;animation + ld hl, BurnedText + jp PrintText +.freeze + call Func_3f9cf ;resets bit 5 of the D063/D068 flags + ld a, 1 << FRZ + ld [wEnemyMonStatus], a + ld a, ANIM_A9 + call Func_3fbb9 ;animation + ld hl, FrozenText + jp PrintText +opponentAttacker: ; 3f382 (f:7382) + ld a, [wBattleMonStatus] ;this appears to the same as above with addresses swapped for opponent + and a + jp nz, CheckDefrost + ld a, [W_ENEMYMOVETYPE] + ld b, a + ld a, [wBattleMonType1] + cp b + ret z + ld a, [wBattleMonType2] + cp b + ret z + ld a, [W_ENEMYMOVEEFFECT] + cp a, 7 + ld b, $1a + jr c, .next1 + ld b, $4d + sub a, $1e +.next1 + push af + call BattleRandom + cp b + pop bc + ret nc + ld a, b + cp a, BURN_SIDE_EFFECT1 + jr z, .burn + cp a, FREEZE_SIDE_EFFECT + jr z, .freeze + ld a, 1 << PAR + ld [wBattleMonStatus], a + call QuarterSpeedDueToParalysis + jp PrintMayNotAttackText +.burn + ld a, 1 << BRN + ld [wBattleMonStatus], a + call HalveAttackDueToBurn + ld hl, BurnedText + jp PrintText +.freeze + ld a, 1 << FRZ + ld [wBattleMonStatus], a + ld hl, FrozenText + jp PrintText + +BurnedText: ; 3f3d8 (f:73d8) + TX_FAR _BurnedText + db "@" + +FrozenText: ; 3f3dd (f:73dd) + TX_FAR _FrozenText + db "@" + +CheckDefrost: ; 3f3e2 (f:73e2) + and a, 1 << FRZ ;are they frozen? + ret z ;return if so + ;not frozen + ld a, [$fff3] ;whose turn? + and a + jr nz, .opponent + ;player [attacker] + ld a, [W_PLAYERMOVETYPE] + sub a, FIRE + ret nz ;return if it isn't fire + ;type is fire + ld [wEnemyMonStatus], a ;set opponent status to 00 ["defrost" a frozen monster] + ld hl, wEnemyMon1Status + ld a, [wEnemyMonPartyPos] + ld bc, wEnemyMon2 - wEnemyMon1 + call AddNTimes + xor a + ld [hl], a ;clear status in roster + ld hl, FireDefrostedText + jr .common +.opponent + ld a, [W_ENEMYMOVETYPE] ;same as above with addresses swapped + sub a, FIRE + ret nz + ld [wBattleMonStatus], a + ld hl, wPartyMon1Status + ld a, [wPlayerMonNumber] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + xor a + ld [hl], a + ld hl, FireDefrostedText +.common + jp PrintText + +FireDefrostedText: ; 3f423 (f:7423) + TX_FAR _FireDefrostedText + db "@" + +StatModifierUpEffect: ; 3f428 (f:7428) + ld hl, wPlayerMonStatMods + ld de, W_PLAYERMOVEEFFECT + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f439 + ld hl, wEnemyMonStatMods + ld de, W_ENEMYMOVEEFFECT +.asm_3f439 + ld a, [de] + sub $a + cp $8 + jr c, .asm_3f442 + sub $28 +.asm_3f442 + ld c, a + ld b, $0 + add hl, bc + ld b, [hl] + inc b + ld a, $d + cp b + jp c, Func_3f522 + ld a, [de] + cp $12 + jr c, .asm_3f45a + inc b + ld a, $d + cp b + jr nc, .asm_3f45a + ld b, a +.asm_3f45a + ld [hl], b + ld a, c + cp $4 + jr nc, asm_3f4ca + push hl + ld hl, wBattleMonAttack + 1 + ld de, wcd12 + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f472 + ld hl, wEnemyMonAttack + 1 + ld de, wEnemyMonUnmodifiedAttack +.asm_3f472 + push bc + sla c + ld b, $0 + add hl, bc + ld a, c + add e + ld e, a + jr nc, .asm_3f47e + inc d +.asm_3f47e + pop bc + ld a, [hld] + sub $e7 + jr nz, .asm_3f48a + ld a, [hl] + sbc $3 + jp z, Func_3f520 +.asm_3f48a + push hl + push bc + ld hl, StatModifierRatios + dec b + sla b + ld c, b + ld b, $0 + add hl, bc + pop bc + xor a + ld [H_NUMTOPRINT], a ; $ff96 (aliases: H_MULTIPLICAND) + ld a, [de] + ld [$ff97], a + inc de + ld a, [de] + ld [$ff98], a + ld a, [hli] + ld [H_REMAINDER], a ; $ff99 (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) + call Multiply + ld a, [hl] + ld [H_REMAINDER], a ; $ff99 (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) + ld b, $4 + call Divide + pop hl + ld a, [$ff98] + sub $e7 + ld a, [$ff97] + sbc $3 + jp c, Func_3f4c3 + ld a, 999 / $100 + ld [$ff97], a + ld a, 999 % $100 + ld [$ff98], a + +Func_3f4c3: ; 3f4c3 (f:74c3) + ld a, [$ff97] + ld [hli], a + ld a, [$ff98] + ld [hl], a + pop hl +asm_3f4ca: ; 3f4ca (f:74ca) + ld b, c + inc b + call Func_3f688 + ld hl, W_PLAYERBATTSTATUS2 + ld de, W_PLAYERMOVENUM + ld bc, wccf7 + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f4e6 + ld hl, W_ENEMYBATTSTATUS2 + ld de, W_ENEMYMOVENUM + ld bc, wccf3 +.asm_3f4e6 + ld a, [de] + cp MINIMIZE + jr nz, .asm_3f4f9 + bit 4, [hl] + push af + push bc + ld hl, Func_79747 + ld b, BANK(Func_79747) + push de + call nz, Bankswitch + pop de +.asm_3f4f9 + call Func_3fba8 + ld a, [de] + cp MINIMIZE + jr nz, .asm_3f50e + pop bc + ld a, $1 + ld [bc], a + ld hl, Func_79771 + ld b, BANK(Func_79771) + pop af + call nz, Bankswitch +.asm_3f50e + ld a, [H_WHOSETURN] + and a + call z, ApplyBadgeStatBoosts + ld hl, MonsStatsRoseText + call PrintText + call QuarterSpeedDueToParalysis + jp HalveAttackDueToBurn + +Func_3f520: ; 3f520 (f:7520) + pop hl + dec [hl] + +Func_3f522: ; 3f522 (f:7522) + ld hl, NothingHappenedText + jp PrintText + +MonsStatsRoseText: ; 3f528 (f:7528) + TX_FAR _MonsStatsRoseText + db $08 ; asm + ld hl, GreatlyRoseText + ld a, [H_WHOSETURN] + and a + ld a, [W_PLAYERMOVEEFFECT] + jr z, .asm_3f53b + ld a, [W_ENEMYMOVEEFFECT] +.asm_3f53b + cp ATTACK_DOWN1_EFFECT + ret nc + ld hl, RoseText + ret + +GreatlyRoseText: ; 3f542 (f:7542) + db $0a + TX_FAR _GreatlyRoseText + +RoseText: ; 3f547 (f:7547) + TX_FAR _RoseText + db "@" + +StatModifierDownEffect: ; 3f54c (f:754c) + ld hl, wEnemyMonStatMods + ld de, W_PLAYERMOVEEFFECT + ld bc, W_ENEMYBATTSTATUS1 + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f572 + ld hl, wPlayerMonStatMods + ld de, W_ENEMYMOVEEFFECT + ld bc, W_PLAYERBATTSTATUS1 + ld a, [W_ISLINKBATTLE] + cp $4 + jr z, .asm_3f572 + call BattleRandom + cp $40 + jp c, Func_3f65a +.asm_3f572 + call CheckTargetSubstitute + jp nz, Func_3f65a + ld a, [de] + cp ATTACK_DOWN_SIDE_EFFECT + jr c, .asm_3f58a + call BattleRandom + cp SPLASH_EFFECT + jp nc, Func_3f650 + ld a, [de] + sub ATTACK_DOWN_SIDE_EFFECT + jr .asm_3f5a9 +.asm_3f58a + push hl + push de + push bc + call MoveHitTest + pop bc + pop de + pop hl + ld a, [W_MOVEMISSED] + and a + jp nz, Func_3f65a + ld a, [bc] + bit 6, a + jp nz, Func_3f65a + ld a, [de] + sub $12 + cp $8 + jr c, .asm_3f5a9 + sub $28 +.asm_3f5a9 + ld c, a + ld b, $0 + add hl, bc + ld b, [hl] + dec b + jp z, Func_3f650 + ld a, [de] + cp $24 + jr c, .asm_3f5bf + cp $44 + jr nc, .asm_3f5bf + dec b + jr nz, .asm_3f5bf + inc b +.asm_3f5bf + ld [hl], b + ld a, c + cp $4 + jr nc, asm_3f62c + push hl + push de + ld hl, wEnemyMonAttack + 1 + ld de, wEnemyMonUnmodifiedAttack + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f5d8 + ld hl, wBattleMonAttack + 1 + ld de, wcd12 +.asm_3f5d8 + push bc + sla c + ld b, $0 + add hl, bc + ld a, c + add e + ld e, a + jr nc, .asm_3f5e4 + inc d +.asm_3f5e4 + pop bc + ld a, [hld] + sub $1 + jr nz, .asm_3f5ef + ld a, [hl] + and a + jp z, Func_3f64d +.asm_3f5ef + push hl + push bc + ld hl, StatModifierRatios + dec b + sla b + ld c, b + ld b, $0 + add hl, bc + pop bc + xor a + ld [H_NUMTOPRINT], a ; $ff96 (aliases: H_MULTIPLICAND) + ld a, [de] + ld [$ff97], a + inc de + ld a, [de] + ld [$ff98], a + ld a, [hli] + ld [H_REMAINDER], a ; $ff99 (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) + call Multiply + ld a, [hl] + ld [H_REMAINDER], a ; $ff99 (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) + ld b, $4 + call Divide + pop hl + ld a, [$ff98] + ld b, a + ld a, [$ff97] + or b + jp nz, Func_3f624 + ld [$ff97], a + ld a, $1 + ld [$ff98], a + +Func_3f624: ; 3f624 (f:7624) + ld a, [$ff97] + ld [hli], a + ld a, [$ff98] + ld [hl], a + pop de + pop hl +asm_3f62c: ; 3f62c (f:762c) + ld b, c + inc b + push de + call Func_3f688 + pop de + ld a, [de] + cp $44 + jr nc, .asm_3f63b + call Func_3fb89 +.asm_3f63b + ld a, [H_WHOSETURN] + and a + call nz, ApplyBadgeStatBoosts + ld hl, MonsStatsFellText + call PrintText + call QuarterSpeedDueToParalysis + jp HalveAttackDueToBurn + +Func_3f64d: ; 3f64d (f:764d) + pop de + pop hl + inc [hl] + +Func_3f650: ; 3f650 (f:7650) + ld a, [de] + cp ATTACK_DOWN_SIDE_EFFECT + ret nc + ld hl, NothingHappenedText + jp PrintText + +Func_3f65a: ; 3f65a (f:765a) + ld a, [de] + cp $44 + ret nc + jp Func_3fb4e + +MonsStatsFellText: ; 3f661 (f:7661) + TX_FAR _MonsStatsFellText + db $08 ; asm + ld hl, FellText + ld a, [H_WHOSETURN] + and a + ld a, [W_PLAYERMOVEEFFECT] + jr z, .asm_3f674 + ld a, [W_ENEMYMOVEEFFECT] +.asm_3f674 + cp $1a + ret c + cp $44 + ret nc + ld hl, GreatlyFellText + ret + +GreatlyFellText: ; 3f67e (f:767e) + db $0a + TX_FAR _GreatlyFellText + +FellText: ; 3f683 (f:7683) + TX_FAR _FellText + db "@" + +Func_3f688: ; 3f688 (f:7688) + ld hl, StatsTextStrings + ld c, $50 +.asm_3f68d + dec b + jr z, .asm_3f696 +.asm_3f690 + ld a, [hli] + cp c + jr z, .asm_3f68d + jr .asm_3f690 +.asm_3f696 + ld de, wcf4b + ld bc, $a + jp CopyData + +StatsTextStrings: ; 3f69f (f:769f) + db "ATTACK@" + db "DEFENSE@" + db "SPEED@" + db "SPECIAL@" + db "ACCURACY@" + db "EVADE@" + +StatModifierRatios: ; 3f6cb (f:76cb) +; first byte is numerator, second byte is denominator + db 25, 100 ; 0.25 + db 28, 100 ; 0.28 + db 33, 100 ; 0.33 + db 40, 100 ; 0.40 + db 50, 100 ; 0.50 + db 66, 100 ; 0.66 + db 1, 1 ; 1.00 + db 15, 10 ; 1.50 + db 2, 1 ; 2.00 + db 25, 10 ; 2.50 + db 3, 1 ; 3.00 + db 35, 10 ; 3.50 + db 4, 1 ; 4.00 + +BideEffect: ; 3f6e5 (f:76e5) + ld hl, W_PLAYERBATTSTATUS1 + ld de, W_NUMHITS + ld bc, wPlayerNumAttacksLeft + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f6fc + ld hl, W_ENEMYBATTSTATUS1 + ld de, wcd05 + ld bc, wEnemyNumAttacksLeft +.asm_3f6fc + set 0, [hl] ; mon is now using bide + xor a + ld [de], a + inc de + ld [de], a + ld [W_PLAYERMOVEEFFECT], a + ld [W_ENEMYMOVEEFFECT], a + call BattleRandom + and $1 + inc a + inc a + ld [bc], a + ld a, [H_WHOSETURN] + add XSTATITEM_ANIM + jp Func_3fb96 + +ThrashPetalDanceEffect: ; 3f717 (f:7717) + ld hl, W_PLAYERBATTSTATUS1 + ld de, wPlayerNumAttacksLeft + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f728 + ld hl, W_ENEMYBATTSTATUS1 + ld de, wEnemyNumAttacksLeft +.asm_3f728 + set 1, [hl] ; mon is now using thrash/petal dance + call BattleRandom + and $1 + inc a + inc a + ld [de], a +<<<<<<< HEAD + ld a, [H_WHOSETURN] ; $fff3 + add ANIM_B0 +======= + ld a, [H_WHOSETURN] + add $b0 +>>>>>>> yama/master + jp Func_3fb96 + +SwitchAndTeleportEffect: ; 3f739 (f:7739) + ld a, [H_WHOSETURN] + and a + jr nz, .asm_3f791 + ld a, [W_ISINBATTLE] + dec a + jr nz, .asm_3f77e + ld a, [W_CURENEMYLVL] + ld b, a + ld a, [wBattleMonLevel] + cp b + jr nc, .asm_3f76e + add b + ld c, a + inc c +.asm_3f751 + call BattleRandom + cp c + jr nc, .asm_3f751 + srl b + srl b + cp b + jr nc, .asm_3f76e + ld c, $32 + call DelayFrames + ld a, [W_PLAYERMOVENUM] + cp TELEPORT + jp nz, PrintDidntAffectText + jp PrintButItFailedText_ +.asm_3f76e + call ReadPlayerMonCurHPAndStatus + xor a + ld [wcc5b], a + inc a + ld [wEscapedFromBattle], a + ld a, [W_PLAYERMOVENUM] + jr .asm_3f7e4 +.asm_3f77e + ld c, $32 + call DelayFrames + ld hl, IsUnaffectedText + ld a, [W_PLAYERMOVENUM] + cp TELEPORT + jp nz, PrintText + jp PrintButItFailedText_ +.asm_3f791 + ld a, [W_ISINBATTLE] + dec a + jr nz, .asm_3f7d1 + ld a, [wBattleMonLevel] + ld b, a + ld a, [W_CURENEMYLVL] + cp b + jr nc, .asm_3f7c1 + add b + ld c, a + inc c +.asm_3f7a4 + call BattleRandom + cp c + jr nc, .asm_3f7a4 + srl b + srl b + cp b + jr nc, .asm_3f7c1 + ld c, $32 + call DelayFrames + ld a, [W_ENEMYMOVENUM] + cp TELEPORT + jp nz, PrintDidntAffectText + jp PrintButItFailedText_ +.asm_3f7c1 + call ReadPlayerMonCurHPAndStatus + xor a + ld [wcc5b], a + inc a + ld [wEscapedFromBattle], a + ld a, [W_ENEMYMOVENUM] + jr .asm_3f7e4 +.asm_3f7d1 + ld c, $32 + call DelayFrames + ld hl, IsUnaffectedText + ld a, [W_ENEMYMOVENUM] + cp TELEPORT + jp nz, PrintText + jp Func_3fb4e +.asm_3f7e4 + push af + call Func_3fbb9 + ld c, $14 + call DelayFrames + pop af + ld hl, RanFromBattleText + cp TELEPORT + jr z, .asm_3f7ff + ld hl, RanAwayScaredText + cp ROAR + jr z, .asm_3f7ff + ld hl, WasBlownAwayText +.asm_3f7ff + jp PrintText + +RanFromBattleText: ; 3f802 (f:7802) + TX_FAR _RanFromBattleText + db "@" + +RanAwayScaredText: ; 3f807 (f:7807) + TX_FAR _RanAwayScaredText + db "@" + +WasBlownAwayText: ; 3f80c (f:780c) + TX_FAR _WasBlownAwayText + db "@" + +TwoToFiveAttacksEffect: ; 3f811 (f:7811) + ld hl, W_PLAYERBATTSTATUS1 + ld de, wPlayerNumAttacksLeft + ld bc, W_NUMHITS + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f828 + ld hl, W_ENEMYBATTSTATUS1 + ld de, wEnemyNumAttacksLeft + ld bc, wcd05 +.asm_3f828 + bit 2, [hl] ; is mon attacking multiple times? + ret nz + set 2, [hl] ; mon is now attacking multiple times + ld hl, W_PLAYERMOVEEFFECT + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f838 + ld hl, W_ENEMYMOVEEFFECT +.asm_3f838 + ld a, [hl] + cp TWINEEDLE_EFFECT + jr z, .asm_3f856 + cp ATTACK_TWICE_EFFECT + ld a, $2 + jr z, .asm_3f853 + call BattleRandom + and $3 + cp $2 + jr c, .asm_3f851 + call BattleRandom + and $3 +.asm_3f851 + inc a + inc a +.asm_3f853 + ld [de], a + ld [bc], a + ret +.asm_3f856 + ld a, $2 + ld [hl], a + jr .asm_3f853 + +FlichSideEffect: ; 3f85b (f:785b) + call CheckTargetSubstitute + ret nz + ld hl, W_ENEMYBATTSTATUS1 + ld de, W_PLAYERMOVEEFFECT + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f870 + ld hl, W_PLAYERBATTSTATUS1 + ld de, W_ENEMYMOVEEFFECT +.asm_3f870 + ld a, [de] + cp FLINCH_SIDE_EFFECT1 + ld b, $1a ; ~10% chance of flinch + jr z, .asm_3f879 + ld b, $4d ; ~30% chance of flinch +.asm_3f879 + call BattleRandom + cp b + ret nc + set 3, [hl] ; set mon's status to flinching + call Func_3f9cf + ret + +OneHitKOEffect: ; 3f884 (f:7884) + ld hl, OneHitKOEffect_ + ld b, BANK(OneHitKOEffect_) + jp Bankswitch + +ChargeEffect: ; 3f88c (f:788c) + ld hl, W_PLAYERBATTSTATUS1 + ld de, W_PLAYERMOVEEFFECT + ld a, [H_WHOSETURN] + and a + ld b, XSTATITEM_ANIM + jr z, .asm_3f8a1 +<<<<<<< HEAD + ld hl, W_ENEMYBATTSTATUS1 ; W_ENEMYBATTSTATUS1 + ld de, W_ENEMYMOVEEFFECT ; W_ENEMYMOVEEFFECT + ld b, ANIM_AF +======= + ld hl, W_ENEMYBATTSTATUS1 + ld de, W_ENEMYMOVEEFFECT + ld b, $af +>>>>>>> yama/master +.asm_3f8a1 + set 4, [hl] + ld a, [de] + dec de ; de contains enemy or player MOVENUM + cp FLY_EFFECT + jr nz, .asm_3f8ad + set 6, [hl] ; mon is now invulnerable to typical attacks (fly/dig) + ld b, TELEPORT +.asm_3f8ad + ld a, [de] + cp DIG + jr nz, .asm_3f8b6 + set 6, [hl] ; mon is now invulnerable to typical attacks (fly/dig) + ld b, ANIM_C0 +.asm_3f8b6 + xor a + ld [wcc5b], a + ld a, b + call Func_3fbb9 + ld a, [de] + ld [wWhichTrade], a + ld hl, ChargeMoveEffectText + jp PrintText + +ChargeMoveEffectText: ; 3f8c8 (f:78c8) + TX_FAR _ChargeMoveEffectText + db $08 ; asm + ld a, [wWhichTrade] + cp RAZOR_WIND + ld hl, MadeWhirlwindText + jr z, .asm_3f8f8 + cp SOLARBEAM + ld hl, TookInSunlightText + jr z, .asm_3f8f8 + cp SKULL_BASH + ld hl, LoweredItsHeadText + jr z, .asm_3f8f8 + cp SKY_ATTACK + ld hl, SkyAttackGlowingText + jr z, .asm_3f8f8 + cp FLY + ld hl, FlewUpHighText + jr z, .asm_3f8f8 + cp DIG + ld hl, DugAHoleText +.asm_3f8f8 + ret + +MadeWhirlwindText: ; 3f8f9 (f:78f9) + TX_FAR _MadeWhirlwindText + db "@" + +TookInSunlightText: ; 3f8fe (f:78fe) + TX_FAR _TookInSunlightText + db "@" + +LoweredItsHeadText: ; 3f903 (f:7903) + TX_FAR _LoweredItsHeadText + db "@" + +SkyAttackGlowingText: ; 3f908 (f:7908) + TX_FAR _SkyAttackGlowingText + db "@" + +FlewUpHighText: ; 3f90d (f:790d) + TX_FAR _FlewUpHighText + db "@" + +DugAHoleText: ; 3f912 (f:7912) + TX_FAR _DugAHoleText + db "@" + +TrappingEffect: ; 3f917 (f:7917) + ld hl, W_PLAYERBATTSTATUS1 + ld de, wPlayerNumAttacksLeft + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f928 + ld hl, W_ENEMYBATTSTATUS1 + ld de, wEnemyNumAttacksLeft +.asm_3f928 + bit 5, [hl] + ret nz + call Func_3f9cf + set 5, [hl] + call BattleRandom + and $3 + cp $2 + jr c, .asm_3f93e + call BattleRandom + and $3 +.asm_3f93e + inc a + ld [de], a + ret + +MistEffect: ; 3f941 (f:7941) + ld hl, MistEffect_ + ld b, BANK(MistEffect_) + jp Bankswitch + +FocusEnergyEffect: ; 3f949 (f:7949) + ld hl, FocusEnergyEffect_ + ld b, BANK(FocusEnergyEffect_) + jp Bankswitch + +RecoilEffect: ; 3f951 (f:7951) + ld hl, RecoilEffect_ + ld b, BANK(RecoilEffect_) + jp Bankswitch + +ConfusionSideEffect: ; 3f959 (f:7959) + call BattleRandom + cp $19 + ret nc + jr Func_3f96f + +ConfusionEffect: ; 3f961 (f:7961) + call CheckTargetSubstitute + jr nz, Func_3f9a6 + call MoveHitTest + ld a, [W_MOVEMISSED] + and a + jr nz, Func_3f9a6 + +Func_3f96f: ; 3f96f (f:796f) + ld a, [H_WHOSETURN] + and a + ld hl, W_ENEMYBATTSTATUS1 + ld bc, wd070 + ld a, [W_PLAYERMOVEEFFECT] + jr z, .asm_3f986 + ld hl, W_PLAYERBATTSTATUS1 + ld bc, wd06b + ld a, [W_ENEMYMOVEEFFECT] +.asm_3f986 + bit 7, [hl] ; is mon confused? + jr nz, Func_3f9a6 + set 7, [hl] ; mon is now confused + push af + call BattleRandom + and $3 + inc a + inc a + ld [bc], a + pop af + cp CONFUSION_SIDE_EFFECT + call nz, Func_3fb89 + ld hl, BecameConfusedText + jp PrintText + +BecameConfusedText: ; 3f9a1 (f:79a1) + TX_FAR _BecameConfusedText + db "@" + +Func_3f9a6: ; 3f9a6 (f:79a6) + cp CONFUSION_SIDE_EFFECT + ret z + ld c, $32 + call DelayFrames + jp Func_3fb4e + +ParalyzeEffect: ; 3f9b1 (f:79b1) + ld hl, ParalyzeEffect_ + ld b, BANK(ParalyzeEffect_) + jp Bankswitch + +SubstituteEffect: ; 3f9b9 (f:79b9) + ld hl, SubstituteEffectHandler + ld b, BANK(SubstituteEffectHandler) + jp Bankswitch + +HyperBeamEffect: ; 3f9c1 (f:79c1) + ld hl, W_PLAYERBATTSTATUS2 + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f9cc + ld hl, W_ENEMYBATTSTATUS2 +.asm_3f9cc + set 5, [hl] ; mon now needs to recharge + ret + +Func_3f9cf: ; 3f9cf (f:79cf) + push hl + ld hl, W_ENEMYBATTSTATUS2 + ld a, [H_WHOSETURN] + and a + jr z, .asm_3f9db + ld hl, W_PLAYERBATTSTATUS2 +.asm_3f9db + res 5, [hl] ; mon no longer needs to recharge + pop hl + ret + +RageEffect: ; 3f9df (f:79df) + ld hl, W_PLAYERBATTSTATUS2 + ld a, [H_WHOSETURN] + and a + jr z, .player + ld hl, W_ENEMYBATTSTATUS2 +.player + set 6, [hl] ; mon is now in "rage" mode + ret + +MimicEffect: ; 3f9ed (f:79ed) + ld c, $32 + call DelayFrames + call MoveHitTest + ld a, [W_MOVEMISSED] + and a + jr nz, .asm_3fa74 + ld a, [H_WHOSETURN] + and a + ld hl, wBattleMonMoves + ld a, [W_PLAYERBATTSTATUS1] + jr nz, .asm_3fa13 + ld a, [W_ISLINKBATTLE] + cp $4 + jr nz, .asm_3fa3a + ld hl, wEnemyMonMoves + ld a, [W_ENEMYBATTSTATUS1] +.asm_3fa13 + bit 6, a + jr nz, .asm_3fa74 +.asm_3fa17 + push hl + call BattleRandom + and $3 + ld c, a + ld b, $0 + add hl, bc + ld a, [hl] + pop hl + and a + jr z, .asm_3fa17 + ld d, a + ld a, [H_WHOSETURN] + and a + ld hl, wBattleMonMoves + ld a, [wPlayerMoveListIndex] + jr z, .asm_3fa5f + ld hl, wEnemyMonMoves + ld a, [wEnemyMoveListIndex] + jr .asm_3fa5f +.asm_3fa3a + ld a, [W_ENEMYBATTSTATUS1] + bit 6, a + jr nz, .asm_3fa74 + ld a, [wCurrentMenuItem] + push af + ld a, $1 + ld [wMoveMenuType], a + call MoveSelectionMenu + call LoadScreenTilesFromBuffer1 + ld hl, wEnemyMonMoves + ld a, [wCurrentMenuItem] + ld c, a + ld b, $0 + add hl, bc + ld d, [hl] + pop af + ld hl, wBattleMonMoves +.asm_3fa5f + ld c, a + ld b, $0 + add hl, bc + ld a, d + ld [hl], a + ld [wd11e], a + call GetMoveName + call Func_3fba8 + ld hl, MimicLearnedMoveText + jp PrintText +.asm_3fa74 + jp PrintButItFailedText_ + +MimicLearnedMoveText: ; 3fa77 (f:7a77) + TX_FAR _MimicLearnedMoveText + db "@" + +LeechSeedEffect: ; 3fa7c (f:7a7c) + ld hl, LeechSeedEffect_ + ld b, BANK(LeechSeedEffect_) + jp Bankswitch + +SplashEffect: ; 3fa84 (f:7a84) + call Func_3fba8 + jp PrintNoEffectText + +DisableEffect: ; 3fa8a (f:7a8a) + call MoveHitTest + ld a, [W_MOVEMISSED] + and a + jr nz, .asm_3fb06 + ld de, W_ENEMYDISABLEDMOVE + ld hl, wEnemyMonMoves + ld a, [H_WHOSETURN] + and a + jr z, .asm_3faa4 + ld de, W_PLAYERDISABLEDMOVE + ld hl, wBattleMonMoves +.asm_3faa4 + ld a, [de] + and a + jr nz, .asm_3fb06 +.asm_3faa8 + push hl + call BattleRandom + and $3 + ld c, a + ld b, $0 + add hl, bc + ld a, [hl] + pop hl + and a + jr z, .asm_3faa8 + ld [wd11e], a + push hl + ld a, [H_WHOSETURN] + and a + ld hl, wBattleMonPP + jr nz, .asm_3facf + ld a, [W_ISLINKBATTLE] + cp $4 + pop hl + jr nz, .asm_3fae1 + push hl + ld hl, wEnemyMonPP +.asm_3facf + push hl + ld a, [hli] + or [hl] + inc hl + or [hl] + inc hl + or [hl] + and $3f + pop hl + jr z, .asm_3fb05 + add hl, bc + ld a, [hl] + pop hl + and a + jr z, .asm_3faa8 +.asm_3fae1 + call BattleRandom + and $7 + inc a + inc c + swap c + add c + ld [de], a + call Func_3fb89 + ld hl, wccee + ld a, [H_WHOSETURN] + and a + jr nz, .asm_3faf8 + inc hl +.asm_3faf8 + ld a, [wd11e] + ld [hl], a + call GetMoveName + ld hl, MoveWasDisabledText + jp PrintText +.asm_3fb05 + pop hl +.asm_3fb06 + jp PrintButItFailedText_ + +MoveWasDisabledText: ; 3fb09 (f:7b09) + TX_FAR _MoveWasDisabledText + db "@" + +PayDayEffect: ; 3fb0e (f:7b0e) + ld hl, PayDayEffect_ + ld b, BANK(PayDayEffect_) + jp Bankswitch + +ConversionEffect: ; 3fb16 (f:7b16) + ld hl, ConversionEffect_ + ld b, BANK(ConversionEffect_) + jp Bankswitch + +HazeEffect: ; 3fb1e (f:7b1e) + ld hl, HazeEffect_ + ld b, BANK(HazeEffect_) + jp Bankswitch + +HealEffect: ; 3fb26 (f:7b26) + ld hl, HealEffect_ + ld b, BANK(HealEffect_) + jp Bankswitch + +TransformEffect: ; 3fb2e (f:7b2e) + ld hl, TransformEffect_ + ld b, BANK(TransformEffect_) + jp Bankswitch + +ReflectLightScreenEffect: ; 3fb36 (f:7b36) + ld hl, ReflectLightScreenEffect_ + ld b, BANK(ReflectLightScreenEffect_) + jp Bankswitch + +NothingHappenedText: ; 3fb3e (f:7b3e) + TX_FAR _NothingHappenedText + db "@" + +PrintNoEffectText: ; 3fb43 (f:7b43) + ld hl, NoEffectText + jp PrintText + +NoEffectText: ; 3fb49 (f:7b49) + TX_FAR _NoEffectText + db "@" + +Func_3fb4e: ; 3fb4e (f:7b4e) + ld a, [wccf4] + and a + ret nz + +PrintButItFailedText_: ; 3fb53 (f:7b53) + ld hl, ButItFailedText + jp PrintText + +ButItFailedText: ; 3fb59 (f:7b59) + TX_FAR _ButItFailedText + db "@" + +PrintDidntAffectText: ; 3fb5e (f:7b5e) + ld hl, DidntAffectText + jp PrintText + +DidntAffectText: ; 3fb64 (f:7b64) + TX_FAR _DidntAffectText + db "@" + +IsUnaffectedText: ; 3fb69 (f:7b69) + TX_FAR _IsUnaffectedText + db "@" + +PrintMayNotAttackText: ; 3fb6e (f:7b6e) + ld hl, ParalyzedMayNotAttackText + jp PrintText + +ParalyzedMayNotAttackText: ; 3fb74 (f:7b74) + TX_FAR _ParalyzedMayNotAttackText + db "@" + +CheckTargetSubstitute: ; 3fb79 (f:7b79) + push hl + ld hl, W_ENEMYBATTSTATUS2 + ld a, [$fff3] ;whose turn? + and a + jr z, .next1 + ld hl, W_PLAYERBATTSTATUS2 +.next1 + bit 4, [hl] ;test bit 4 in d063/d068 flags + pop hl + ret + +Func_3fb89: ; 3fb89 (f:7b89) + ld a, [H_WHOSETURN] + and a + ld a, [W_PLAYERMOVENUM] + jr z, .asm_3fb94 + ld a, [W_ENEMYMOVENUM] +.asm_3fb94 + and a + ret z + +Func_3fb96: ; 3fb96 (f:7b96) + ld [W_ANIMATIONID], a + ld a, [H_WHOSETURN] + and a + ld a, $6 + jr z, .asm_3fba2 + ld a, $3 +.asm_3fba2 + ld [wcc5b], a + jp Func_3fbbc + +Func_3fba8: ; 3fba8 (f:7ba8) + xor a + ld [wcc5b], a + ld a, [H_WHOSETURN] + and a + ld a, [W_PLAYERMOVENUM] + jr z, .asm_3fbb7 + ld a, [W_ENEMYMOVENUM] +.asm_3fbb7 + and a + ret z + +Func_3fbb9: ; 3fbb9 (f:7bb9) + ld [W_ANIMATIONID], a + +Func_3fbbc: ; 3fbbc (f:7bbc) + push hl + push de + push bc + predef MoveAnimation + pop bc + pop de + pop hl + ret diff --git a/engine/battle/e.asm b/engine/battle/e.asm index 1112f39b..072aca49 100755 --- a/engine/battle/e.asm +++ b/engine/battle/e.asm @@ -587,7 +587,7 @@ Func_39b87: ; 39b87 (e:5b87) jr z, .asm_39bc1 push hl ld [wd0b5], a - ld a, $2c + ld a, BANK(MoveNames) ld [wPredefBank], a ld a, MOVE_NAME ld [W_LISTTYPE], a @@ -1407,14 +1407,14 @@ SetupEnemyPartyPokeballs: ; 3a887 (e:6887) ld [hl], $20 ld a, $f8 ld [wTrainerEngageDistance], a - ld hl, wOAMBuffer + $18 + ld hl, wOAMBuffer + PARTY_LENGTH * 4 jp Func_3a8e1 SetupPokeballs: ; 0x3a8a6 ld a, [de] push af ld de, wBuffer - ld c, $6 ; max num of partymons + ld c, PARTY_LENGTH ld a, $34 ; empty pokeball .emptyloop ld [de], a @@ -1462,7 +1462,7 @@ PickPokeball: ; 3a8c2 (e:68c2) Func_3a8e1: ; 3a8e1 (e:68e1) ld de, wHPBarMaxHP - ld c, $6 + ld c, PARTY_LENGTH .asm_3a8e6 ld a, [W_BASECOORDY] ; wd082 ld [hli], a diff --git a/engine/cable_club.asm b/engine/cable_club.asm index 34a9d0a1..a8a1f90f 100755 --- a/engine/cable_club.asm +++ b/engine/cable_club.asm @@ -537,7 +537,7 @@ TradeCenter_SelectMon: ld [wTileMap + $141], a .asm_574a call JoypadLowSensitivity - ld a, [$ffb5] + ld a, [hJoy5] and a jr z, .asm_574a ; 0x5750 $f8 bit 0, a @@ -896,7 +896,7 @@ Func_5a5f: ; 5a5f (1:5a5f) ld [W_GRASSRATE], a ; W_GRASSRATE inc a ld [W_ISLINKBATTLE], a ; W_ISLINKBATTLE - ld [$ffb5], a + ld [hJoy5], a ld a, $a ld [wMusicHeaderPointer], a ld a, BANK(Music_Celadon) diff --git a/engine/evolution.asm b/engine/evolution.asm index 106107d2..5842f1a2 100755 --- a/engine/evolution.asm +++ b/engine/evolution.asm @@ -140,7 +140,7 @@ asm_7befa: ; 7befa (1e:7efa) call DelayFrame push bc call JoypadLowSensitivity - ld a, [$ffb5] + ld a, [hJoy5] pop bc and $2 jr nz, .asm_7bf0d diff --git a/engine/evos_moves.asm b/engine/evos_moves.asm index bda4c9ff..3a7dda43 100755 --- a/engine/evos_moves.asm +++ b/engine/evos_moves.asm @@ -140,7 +140,7 @@ Evolution_PartyMonLoop: ; loop over party mons ld [wHPBarMaxHP + 1], a ld a, MONSTER_NAME ld [W_LISTTYPE], a - ld a, $e + ld a, BANK(TrainerNames) ; bank is not used for monster names ld [wPredefBank], a call GetName push hl diff --git a/engine/give_pokemon.asm b/engine/give_pokemon.asm index d4d45bfb..d4d58d33 100755 --- a/engine/give_pokemon.asm +++ b/engine/give_pokemon.asm @@ -3,10 +3,10 @@ _GivePokemon: ; 4fda5 (13:7da5) xor a ld [wccd3], a ld a, [wPartyCount] ; wPartyCount - cp $6 + cp PARTY_LENGTH jr c, .asm_4fe01 ld a, [W_NUMINBOX] ; wda80 - cp $14 + cp MONS_PER_BOX jr nc, .asm_4fdf9 xor a ld [W_ENEMYBATTSTATUS3], a ; W_ENEMYBATTSTATUS3 @@ -18,18 +18,18 @@ _GivePokemon: ; 4fda5 (13:7da5) ld hl, wcf4b ld a, [wd5a0] and $7f - cp $9 + cp 9 jr c, .asm_4fdec - sub $9 - ld [hl], $f7 + sub 9 + ld [hl], "1" inc hl - add $f6 + add "0" jr .asm_4fdee .asm_4fdec - add $f7 + add "1" .asm_4fdee ld [hli], a - ld [hl], $50 + ld [hl], "@" ld hl, SetToBoxText call PrintText scf diff --git a/engine/items/items.asm b/engine/items/items.asm index b2bff822..af6c9552 100755 --- a/engine/items/items.asm +++ b/engine/items/items.asm @@ -110,10 +110,10 @@ ItemUseBall: ; d687 (3:5687) dec a jr z,.UseBall ld a,[wPartyCount] ;is Party full? - cp a,6 + cp a,PARTY_LENGTH jr nz,.UseBall ld a,[W_NUMINBOX] ;is Box full? - cp a,20 + cp a,MONS_PER_BOX jp z,BoxFullCannotThrowBall .UseBall ;$56a7 ;ok, you can use a ball @@ -421,7 +421,7 @@ ItemUseBall: ; d687 (3:5687) predef ShowPokedexData .checkParty ;$58f4 ld a,[wPartyCount] - cp a,6 ;is party full? + cp a,PARTY_LENGTH ;is party full? jr z,.sendToBox xor a ld [wcc49],a diff --git a/engine/menu/bills_pc.asm b/engine/menu/bills_pc.asm index 65b70bb1..f1a0e798 100644 --- a/engine/menu/bills_pc.asm +++ b/engine/menu/bills_pc.asm @@ -88,25 +88,13 @@ Func_213c8:: ; 213c8 (8:53c8) ld [H_AUTOBGTRANSFERENABLED], a ; $ffba ret -SomeonesPCText: ; 2148b (8:548b) - db "SOMEONE's PC@" +SomeonesPCText: db "SOMEONE's PC@" +BillsPCText: db "BILL's PC@" +PlayersPCText: db "'s PC@" +OaksPCText: db "PROF.OAK's PC@" +PKMNLeaguePCText: db $4a, "LEAGUE@" +LogOffPCText: db "LOG OFF@" -BillsPCText: ; 21497 (8:5497) - db "BILL's PC@" - -PlayersPCText: ; 214a0 (8:54a0) - db "'s PC@" - -OaksPCText: ; 214a5 (8:54a5) - db "PROF.OAK's PC@" - -PKMNLeaguePCText: ; 214b2 (8:54b2) - db $4a,"LEAGUE@" - -LogOffPCText: ; 214ba (8:54ba) - db "LOG OFF@" - -Func_214c2:: ; 214c2 (8:54c2) BillsPC_:: ; 0x214c2 ld hl, wd730 set 6, [hl] @@ -167,15 +155,15 @@ BillsPCMenu: call TextBoxBorder ld a, [wd5a0] and $7f - cp $9 + cp 9 jr c, .asm_2154f - sub $9 + sub 9 hlCoord 17, 16 - ld [hl], $f7 - add $f6 + ld [hl], "1" + add "0" jr .asm_21551 .asm_2154f - add $f7 + add "1" .asm_21551 Coorda 18, 16 hlCoord 10, 16 @@ -227,7 +215,7 @@ BillsPCDeposit: jp BillsPCMenu .asm_215bb ld a, [W_NUMINBOX] ; wda80 - cp $14 + cp MONS_PER_BOX jr nz, .asm_215cb ld hl, BoxFullText ; $5802 call PrintText @@ -251,15 +239,15 @@ BillsPCDeposit: ld hl, wWhichTrade ; wWhichTrade ld a, [wd5a0] and $7f - cp $9 + cp 9 jr c, .asm_2160a - sub $9 - ld [hl], $f7 + sub 9 + ld [hl], "1" inc hl - add $f6 + add "0" jr .asm_2160c .asm_2160a - add $f7 + add "1" .asm_2160c ld [hli], a ld [hl], $50 @@ -276,7 +264,7 @@ Func_21618: ; 21618 (8:5618) jp Func_214e8 .asm_21627 ld a, [wPartyCount] ; wPartyCount - cp $6 + cp PARTY_LENGTH jr nz, .asm_21637 ld hl, CantTakeMonText ; $5811 call PrintText @@ -353,7 +341,12 @@ Func_216be: ; 216be (8:56be) ret BillsPCMenuText: ; 216e1 (8:56e1) - db "WITHDRAW ",$4a,$4e,"DEPOSIT ",$4a,$4e,"RELEASE ",$4a,$4e,"CHANGE BOX",$4e,"SEE YA!@" + db "WITHDRAW ", $4a + next "DEPOSIT ", $4a + next "RELEASE ", $4a + next "CHANGE BOX" + next "SEE YA!" + db "@" BoxNoPCText: ; 21713 (8:5713) db "BOX No.@" @@ -389,7 +382,7 @@ HMMoveArray: ; 21745 (8:5745) db SURF db STRENGTH db FLASH - db $ff + db -1 Func_2174b: ; 2174b (8:574b) hlCoord 9, 10 @@ -458,14 +451,11 @@ Func_2174b: ; 2174b (8:574b) call LoadGBPal jr .asm_2178f -DepositPCText: ; 217cb (8:57cb) - db "DEPOSIT@" - -WithdrawPCText: ; 217d3 (8:57d3) - db "WITHDRAW@" - -StatsCancelPCText: ; 217dc (8:57dc) - db "STATS",$4e,"CANCEL@" +DepositPCText: db "DEPOSIT@" +WithdrawPCText: db "WITHDRAW@" +StatsCancelPCText: + db "STATS" + next "CANCEL@" SwitchOnText: ; 0x217e9 TX_FAR _SwitchOnText diff --git a/engine/menu/main_menu.asm b/engine/menu/main_menu.asm index 6ffc6249..c6052f03 100755 --- a/engine/menu/main_menu.asm +++ b/engine/menu/main_menu.asm @@ -308,7 +308,7 @@ SpecialEnterMap: ; 5d5f (1:5d5f) xor a ld [hJoyPressed], a ld [hJoyHeld], a - ld [$ffb5], a + ld [hJoy5], a ld [wd72d], a ld hl, wd732 set 0, [hl] ; count play time @@ -462,7 +462,7 @@ DisplayOptionMenu: ; 5e8a (1:5e8a) call SetOptionsFromCursorPositions .getJoypadStateLoop call JoypadLowSensitivity - ld a,[$ffb5] + ld a,[hJoy5] ld b,a and a,%11111011 ; any key besides select pressed? jr z,.getJoypadStateLoop diff --git a/engine/menu/pokedex.asm b/engine/menu/pokedex.asm index 152b8129..227728a0 100755 --- a/engine/menu/pokedex.asm +++ b/engine/menu/pokedex.asm @@ -10,7 +10,7 @@ ShowPokedexMenu: ; 40000 (10:4000) ld [wLastMenuItem],a inc a ld [wd11e],a - ld [$ffb7],a + ld [hJoy7],a .setUpGraphics ld b,$08 call GoPAL_SET @@ -35,7 +35,7 @@ ShowPokedexMenu: ; 40000 (10:4000) ld [wcc37],a ld [wCurrentMenuItem],a ld [wLastMenuItem],a - ld [$ffb7],a + ld [hJoy7],a ld [wWastedByteCD3A],a ld [wOverrideSimulatedJoypadStatesMask],a pop af @@ -550,7 +550,7 @@ ShowPokedexDataInternal: ; 402e2 (10:42e2) ld [$fff4],a .waitForButtonPress call JoypadLowSensitivity - ld a,[$ffb5] + ld a,[hJoy5] and a,%00000011 ; A button and B button jr z,.waitForButtonPress pop af diff --git a/engine/menu/pokedex.asm.orig b/engine/menu/pokedex.asm.orig new file mode 100755 index 00000000..7d7d2b38 --- /dev/null +++ b/engine/menu/pokedex.asm.orig @@ -0,0 +1,647 @@ +ShowPokedexMenu: ; 40000 (10:4000) + call GBPalWhiteOut + call ClearScreen + call UpdateSprites ; move sprites + ld a,[wListScrollOffset] + push af + xor a + ld [wCurrentMenuItem],a + ld [wListScrollOffset],a + ld [wLastMenuItem],a + inc a + ld [wd11e],a + ld [hJoy7],a +.setUpGraphics + ld b,$08 + call GoPAL_SET + callab LoadPokedexTilePatterns +.doPokemonListMenu + ld hl,wTopMenuItemY + ld a,3 + ld [hli],a ; top menu item Y + xor a + ld [hli],a ; top menu item X + inc a + ld [wcc37],a + inc hl + inc hl + ld a,6 + ld [hli],a ; max menu item ID + ld [hl],%00110011 ; menu watched keys (Left, Right, B button, A button) + call HandlePokedexListMenu + jr c,.goToSideMenu ; if the player chose a pokemon from the list +.exitPokedex + xor a + ld [wcc37],a + ld [wCurrentMenuItem],a + ld [wLastMenuItem],a +<<<<<<< HEAD + ld [hJoy7],a + ld [wcd3a],a + ld [wcd3b],a +======= + ld [$ffb7],a + ld [wWastedByteCD3A],a + ld [wOverrideSimulatedJoypadStatesMask],a +>>>>>>> yama/master + pop af + ld [wListScrollOffset],a + call GBPalWhiteOutWithDelay3 + call GoPAL_SET_CF1C + jp ReloadMapData +.goToSideMenu + call HandlePokedexSideMenu + dec b + jr z,.exitPokedex ; if the player chose Quit + dec b + jr z,.doPokemonListMenu ; if pokemon not seen or player pressed B button + jp .setUpGraphics ; if pokemon data or area was shown + +; handles the menu on the lower right in the pokedex screen +; OUTPUT: +; b = reason for exiting menu +; 00: showed pokemon data or area +; 01: the player chose Quit +; 02: the pokemon has not been seen yet or the player pressed the B button +HandlePokedexSideMenu: ; 4006d (10:406d) + call PlaceUnfilledArrowMenuCursor + ld a,[wCurrentMenuItem] + push af + ld b,a + ld a,[wLastMenuItem] + push af + ld a,[wListScrollOffset] + push af + add b + inc a + ld [wd11e],a + ld a,[wd11e] + push af + ld a,[wWhichTrade] + push af + ld hl,wPokedexSeen + call IsPokemonBitSet + ld b,2 + jr z,.exitSideMenu + call PokedexToIndex + ld hl,wTopMenuItemY + ld a,10 + ld [hli],a ; top menu item Y + ld a,15 + ld [hli],a ; top menu item X + xor a + ld [hli],a ; current menu item ID + inc hl + ld a,3 + ld [hli],a ; max menu item ID + ld [hli],a ; menu watched keys (A button and B button) + xor a + ld [hli],a ; old menu item ID + ld [wcc37],a +.handleMenuInput + call HandleMenuInput + bit 1,a ; was the B button pressed? + ld b,2 + jr nz,.buttonBPressed + ld a,[wCurrentMenuItem] + and a + jr z,.choseData + dec a + jr z,.choseCry + dec a + jr z,.choseArea +.choseQuit + ld b,1 +.exitSideMenu + pop af + ld [wWhichTrade],a + pop af + ld [wd11e],a + pop af + ld [wListScrollOffset],a + pop af + ld [wLastMenuItem],a + pop af + ld [wCurrentMenuItem],a + push bc + hlCoord 0, 3 + ld de,20 + ld bc,$7f0d ; 13 blank tiles + call DrawTileLine ; cover up the menu cursor in the pokemon list + pop bc + ret +.buttonBPressed + push bc + hlCoord 15, 10 + ld de,20 + ld bc,$7f07 ; 7 blank tiles + call DrawTileLine ; cover up the menu cursor in the side menu + pop bc + jr .exitSideMenu +.choseData + call ShowPokedexDataInternal + ld b,0 + jr .exitSideMenu +; play pokemon cry +.choseCry + ld a,[wd11e] + call GetCryData ; get cry data + call PlaySound ; play sound + jr .handleMenuInput +.choseArea + predef LoadTownMap_Nest ; display pokemon areas + ld b,0 + jr .exitSideMenu + +; handles the list of pokemon on the left of the pokedex screen +; sets carry flag if player presses A, unsets carry flag if player presses B +HandlePokedexListMenu: ; 40111 (10:4111) + xor a + ld [H_AUTOBGTRANSFERENABLED],a +; draw the horizontal line separating the seen and owned amounts from the menu + hlCoord 15, 8 + ld a,$7a ; horizontal line tile + ld [hli],a + ld [hli],a + ld [hli],a + ld [hli],a + ld [hli],a + hlCoord 14, 0 + ld [hl],$71 ; vertical line tile + hlCoord 14, 1 + call DrawPokedexVerticalLine + hlCoord 14, 9 + call DrawPokedexVerticalLine + ld hl,wPokedexSeen + ld b,wPokedexSeenEnd - wPokedexSeen + call CountSetBits + ld de,wd11e + hlCoord 16, 3 + ld bc,$0103 + call PrintNumber ; print number of seen pokemon + ld hl,wPokedexOwned + ld b,wPokedexOwnedEnd - wPokedexOwned + call CountSetBits + ld de,wd11e + hlCoord 16, 6 + ld bc,$0103 + call PrintNumber ; print number of owned pokemon + hlCoord 16, 2 + ld de,PokedexSeenText + call PlaceString + hlCoord 16, 5 + ld de,PokedexOwnText + call PlaceString + hlCoord 1, 1 + ld de,PokedexContentsText + call PlaceString + hlCoord 16, 10 + ld de,PokedexMenuItemsText + call PlaceString +; find the highest pokedex number among the pokemon the player has seen + ld hl,wPokedexSeenEnd - 1 + ld b,153 +.maxSeenPokemonLoop + ld a,[hld] + ld c,8 +.maxSeenPokemonInnerLoop + dec b + sla a + jr c,.storeMaxSeenPokemon + dec c + jr nz,.maxSeenPokemonInnerLoop + jr .maxSeenPokemonLoop +.storeMaxSeenPokemon + ld a,b + ld [wWhichTrade],a ; max seen pokemon +.loop + xor a + ld [H_AUTOBGTRANSFERENABLED],a + hlCoord 4, 2 + ld bc,$0e0a + call ClearScreenArea + hlCoord 1, 3 + ld a,[wListScrollOffset] + ld [wd11e],a + ld d,7 + ld a,[wWhichTrade] + cp a,7 + jr nc,.printPokemonLoop + ld d,a + dec a + ld [wMaxMenuItem],a +; loop to print pokemon pokedex numbers and names +; if the player has owned the pokemon, it puts a pokeball beside the name +.printPokemonLoop + ld a,[wd11e] + inc a + ld [wd11e],a + push af + push de + push hl + ld de,-20 + add hl,de + ld de,wd11e + ld bc,$8103 + call PrintNumber ; print the pokedex number + ld de,20 + add hl,de + dec hl + push hl + ld hl,wPokedexOwned + call IsPokemonBitSet + pop hl + ld a," " + jr z,.writeTile + ld a,$72 ; pokeball tile +.writeTile + ld [hl],a ; put a pokeball next to pokemon that the player has owned + push hl + ld hl,wPokedexSeen + call IsPokemonBitSet + jr nz,.getPokemonName ; if the player has seen the pokemon + ld de,.dashedLine ; print a dashed line in place of the name if the player hasn't seen the pokemon + jr .skipGettingName +.dashedLine ; for unseen pokemon in the list + db "----------@" +.getPokemonName + call PokedexToIndex + call GetMonName +.skipGettingName + pop hl + inc hl + call PlaceString + pop hl + ld bc,2 * 20 + add hl,bc + pop de + pop af + ld [wd11e],a + dec d + jr nz,.printPokemonLoop + ld a,01 + ld [H_AUTOBGTRANSFERENABLED],a + call Delay3 + call GBPalNormal + call HandleMenuInput + bit 1,a ; was the B button pressed? + jp nz,.buttonBPressed +.checkIfUpPressed + bit 6,a ; was Up pressed? + jr z,.checkIfDownPressed +.upPressed ; scroll up one row + ld a,[wListScrollOffset] + and a + jp z,.loop + dec a + ld [wListScrollOffset],a + jp .loop +.checkIfDownPressed + bit 7,a ; was Down pressed? + jr z,.checkIfRightPressed +.downPressed ; scroll down one row + ld a,[wWhichTrade] + cp a,7 + jp c,.loop + sub a,7 + ld b,a + ld a,[wListScrollOffset] + cp b + jp z,.loop + inc a + ld [wListScrollOffset],a + jp .loop +.checkIfRightPressed + bit 4,a ; was Right pressed? + jr z,.checkIfLeftPressed +.rightPressed ; scroll down 7 rows + ld a,[wWhichTrade] + cp a,7 + jp c,.loop + sub a,6 + ld b,a + ld a,[wListScrollOffset] + add a,7 + ld [wListScrollOffset],a + cp b + jp c,.loop + dec b + ld a,b + ld [wListScrollOffset],a + jp .loop +.checkIfLeftPressed ; scroll up 7 rows + bit 5,a ; was Left pressed? + jr z,.buttonAPressed +.leftPressed + ld a,[wListScrollOffset] + sub a,7 + ld [wListScrollOffset],a + jp nc,.loop + xor a + ld [wListScrollOffset],a + jp .loop +.buttonAPressed + scf + ret +.buttonBPressed + and a + ret + +DrawPokedexVerticalLine: ; 4028e (10:428e) + ld c,9 ; height of line + ld de,20 ; width of screen + ld a,$71 ; vertical line tile +.loop + ld [hl],a + add hl,de + xor a,1 ; toggle between vertical line tile and box tile + dec c + jr nz,.loop + ret + +PokedexSeenText: ; 4029d (10:429d) + db "SEEN@" + +PokedexOwnText: ; 402a2 (10:42a2) + db "OWN@" + +PokedexContentsText: ; 402a6 (10:42a6) + db "CONTENTS@" + +PokedexMenuItemsText: ; 402af (10:42af) + db "DATA" + next "CRY" + next "AREA" + next "QUIT@" + +; tests if a pokemon's bit is set in the seen or owned pokemon bit fields +; INPUT: +; [wd11e] = pokedex number +; hl = address of bit field +IsPokemonBitSet: ; 402c2 (10:42c2) + ld a,[wd11e] + dec a + ld c,a + ld b,2 + predef FlagActionPredef + ld a,c + and a + ret + +; function to display pokedex data from outside the pokedex +ShowPokedexData: ; 402d1 (10:42d1) + call GBPalWhiteOutWithDelay3 + call ClearScreen + call UpdateSprites + callab LoadPokedexTilePatterns ; load pokedex tiles + +; function to display pokedex data from inside the pokedex +ShowPokedexDataInternal: ; 402e2 (10:42e2) + ld hl,wd72c + set 1,[hl] + ld a,$33 ; 3/7 volume + ld [$ff24],a + call GBPalWhiteOut ; zero all palettes + call ClearScreen + ld a,[wd11e] ; pokemon ID + ld [wcf91],a + push af + ld b,04 + call GoPAL_SET + pop af + ld [wd11e],a + ld a,[hTilesetType] + push af + xor a + ld [hTilesetType],a + hlCoord 0, 0 + ld de,1 + ld bc,$6414 + call DrawTileLine ; draw top border + hlCoord 0, 17 + ld b,$6f + call DrawTileLine ; draw bottom border + hlCoord 0, 1 + ld de,20 + ld bc,$6610 + call DrawTileLine ; draw left border + hlCoord 19, 1 + ld b,$67 + call DrawTileLine ; draw right border + ld a,$63 ; upper left corner tile + Coorda 0, 0 + ld a,$65 ; upper right corner tile + Coorda 19, 0 + ld a,$6c ; lower left corner tile + Coorda 0, 17 + ld a,$6e ; lower right corner tile + Coorda 19, 17 + hlCoord 0, 9 + ld de,PokedexDataDividerLine + call PlaceString ; draw horizontal divider line + hlCoord 9, 6 + ld de,HeightWeightText + call PlaceString + call GetMonName + hlCoord 9, 2 + call PlaceString + ld hl,PokedexEntryPointers + ld a,[wd11e] + dec a + ld e,a + ld d,0 + add hl,de + add hl,de + ld a,[hli] + ld e,a + ld d,[hl] ; de = address of pokedex entry + hlCoord 9, 4 + call PlaceString ; print species name + ld h,b + ld l,c + push de + ld a,[wd11e] + push af + call IndexToPokedex + hlCoord 2, 8 + ld a, "№" + ld [hli],a + ld a,$f2 + ld [hli],a + ld de,wd11e + ld bc,$8103 + call PrintNumber ; print pokedex number + ld hl,wPokedexOwned + call IsPokemonBitSet + pop af + ld [wd11e],a + ld a,[wcf91] + ld [wd0b5],a + pop de + push af + push bc + push de + push hl + call Delay3 + call GBPalNormal + call GetMonHeader ; load pokemon picture location + hlCoord 1, 1 + call LoadFlippedFrontSpriteByMonIndex ; draw pokemon picture + ld a,[wcf91] + call PlayCry ; play pokemon cry + pop hl + pop de + pop bc + pop af + ld a,c + and a + jp z,.waitForButtonPress ; if the pokemon has not been owned, don't print the height, weight, or description + inc de ; de = address of feet (height) + ld a,[de] ; reads feet, but a is overwritten without being used + hlCoord 12, 6 + ld bc,$0102 + call PrintNumber ; print feet (height) + ld a,$60 ; feet symbol tile (one tick) + ld [hl],a + inc de + inc de ; de = address of inches (height) + hlCoord 15, 6 + ld bc,$8102 + call PrintNumber ; print inches (height) + ld a,$61 ; inches symbol tile (two ticks) + ld [hl],a +; now print the weight (note that weight is stored in tenths of pounds internally) + inc de + inc de + inc de ; de = address of upper byte of weight + push de +; put weight in big-endian order at $ff8b + ld hl,$ff8b + ld a,[hl] ; save existing value of [$ff8b] + push af + ld a,[de] ; a = upper byte of weight + ld [hli],a ; store upper byte of weight in [$ff8b] + ld a,[hl] ; save existing value of [$ff8c] + push af + dec de + ld a,[de] ; a = lower byte of weight + ld [hl],a ; store lower byte of weight in [$ff8c] + ld de,$ff8b + hlCoord 11, 8 + ld bc,$0205 ; no leading zeroes, right-aligned, 2 bytes, 5 digits + call PrintNumber ; print weight + hlCoord 14, 8 + ld a,[$ff8c] + sub a,10 + ld a,[$ff8b] + sbc a,0 + jr nc,.next + ld [hl],"0" ; if the weight is less than 10, put a 0 before the decimal point +.next + inc hl + ld a,[hli] + ld [hld],a ; make space for the decimal point by moving the last digit forward one tile + ld [hl],$f2 ; decimal point tile + pop af + ld [$ff8c],a ; restore original value of [$ff8c] + pop af + ld [$ff8b],a ; restore original value of [$ff8b] + pop hl + inc hl ; hl = address of pokedex description text + bcCoord 1, 11 + ld a,2 + ld [$fff4],a + call TextCommandProcessor ; print pokedex description text + xor a + ld [$fff4],a +.waitForButtonPress + call JoypadLowSensitivity + ld a,[hJoy5] + and a,%00000011 ; A button and B button + jr z,.waitForButtonPress + pop af + ld [hTilesetType],a + call GBPalWhiteOut + call ClearScreen + call GoPAL_SET_CF1C + call LoadTextBoxTilePatterns + call GBPalNormal + ld hl,wd72c + res 1,[hl] + ld a,$77 ; max volume + ld [$ff24],a + ret + +HeightWeightText: ; 40448 (10:4448) + db "HT ?",$60,"??",$61,$4E,"WT ???lb@" + +; XXX does anything point to this? +Unknown_4045D: ; 4045d (10:445d) + db $54,$50 + +; horizontal line that divides the pokedex text description from the rest of the data +PokedexDataDividerLine: ; 4045f (10:445f) + db $68,$69,$6B,$69,$6B + db $69,$6B,$69,$6B,$6B + db $6B,$6B,$69,$6B,$69 + db $6B,$69,$6B,$69,$6A + db $50 + +; draws a line of tiles +; INPUT: +; b = tile ID +; c = number of tile ID's to write +; de = amount to destination address after each tile (1 for horizontal, 20 for vertical) +; hl = destination address +DrawTileLine: ; 40474 (10:4474) + push bc + push de +.loop + ld [hl],b + add hl,de + dec c + jr nz,.loop + pop de + pop bc + ret + +INCLUDE "data/pokedex_entries.asm" + +PokedexToIndex: ; 40ff9 (10:4ff9) + ; converts the Pokédex number at wd11e to an index + push bc + push hl + ld a,[wd11e] + ld b,a + ld c,0 + ld hl,PokedexOrder + +.loop ; go through the list until we find an entry with a matching dex number + inc c + ld a,[hli] + cp b + jr nz,.loop + + ld a,c + ld [wd11e],a + pop hl + pop bc + ret + +IndexToPokedex: ; 41010 (10:5010) + ; converts the indexédex number at wd11e to a Pokédex number + push bc + push hl + ld a,[wd11e] + dec a + ld hl,PokedexOrder + ld b,0 + ld c,a + add hl,bc + ld a,[hl] + ld [wd11e],a + pop hl + pop bc + ret + +INCLUDE "data/pokedex_order.asm" diff --git a/engine/save.asm b/engine/save.asm index f4057577..e6b1bd94 100755 --- a/engine/save.asm +++ b/engine/save.asm @@ -445,15 +445,15 @@ Func_7393f: ; 7393f (1c:793f) res 2, [hl] ld a, [wd5a0] and $7f - cp $9 + cp 9 jr c, .asm_739a6 - sub $9 + sub 9 hlCoord 8, 2 - ld [hl], $f7 - add $f6 + ld [hl], "1" + add "0" jr .asm_739a8 .asm_739a6 - add $f7 + add "1" .asm_739a8 Coorda 9, 2 hlCoord 1, 2 diff --git a/engine/slot_machine.asm b/engine/slot_machine.asm index 6964b94e..b24b2d25 100755 --- a/engine/slot_machine.asm +++ b/engine/slot_machine.asm @@ -797,7 +797,7 @@ SlotMachine_3784e: ; 3784e (d:784e) SlotMachine_37882: ; 37882 (d:7882) call DelayFrame call JoypadLowSensitivity - ld a, [$ffb5] + ld a, [hJoy5] and $1 ret z ld hl, wTrainerSpriteOffset diff --git a/engine/town_map.asm b/engine/town_map.asm index 3b7506d5..dece8d1f 100755 --- a/engine/town_map.asm +++ b/engine/town_map.asm @@ -6,7 +6,7 @@ DisplayTownMap: ; 70e3e (1c:4e3e) ld [hl], $ff push hl ld a, $1 - ld [$ffb7], a + ld [hJoy7], a ld a, [W_CURMAP] ; W_CURMAP push af ld b, $0 @@ -66,7 +66,7 @@ Func_70e92: ; 70e92 (1c:4e92) .asm_70ec8 call TownMapSpriteBlinkingAnimation call JoypadLowSensitivity - ld a, [$ffb5] + ld a, [hJoy5] ld b, a and $c3 jr z, .asm_70ec8 @@ -78,7 +78,7 @@ Func_70e92: ; 70e92 (1c:4e92) jr nz, .asm_70f01 xor a ld [wTownMapSpriteBlinkingEnabled], a - ld [$ffb7], a + ld [hJoy7], a ld [wTownMapSpriteBlinkingCounter], a call Func_711ab pop hl @@ -188,7 +188,7 @@ LoadTownMap_Fly: ; 70f90 (1c:4f90) push hl call DelayFrame call JoypadLowSensitivity - ld a, [$ffb5] + ld a, [hJoy5] ld b, a pop hl and $c3 diff --git a/engine/town_map.asm.orig b/engine/town_map.asm.orig new file mode 100755 index 00000000..9ccc03c0 --- /dev/null +++ b/engine/town_map.asm.orig @@ -0,0 +1,605 @@ +DisplayTownMap: ; 70e3e (1c:4e3e) + call LoadTownMap + ld hl, wUpdateSpritesEnabled + ld a, [hl] + push af + ld [hl], $ff + push hl + ld a, $1 + ld [hJoy7], a + ld a, [W_CURMAP] ; W_CURMAP + push af + ld b, $0 + call Func_711c4 + hlCoord 1, 0 + ld de, wcd6d + call PlaceString + ld hl, wOAMBuffer + ld de, wTileMapBackup + ld bc, $10 + call CopyData + ld hl, vSprites + $40 + ld de, TownMapCursor ; $4f40 + ld bc, (BANK(TownMapCursor) << 8) + $04 + call CopyVideoDataDouble + xor a + ld [wWhichTrade], a ; wWhichTrade + pop af + jr Func_70e92 + +Func_70e7e: ; 70e7e (1c:4e7e) + ld hl, wTileMap + ld bc, $114 + call ClearScreenArea + ld hl, TownMapOrder ; $4f11 + ld a, [wWhichTrade] ; wWhichTrade + ld c, a + ld b, $0 + add hl, bc + ld a, [hl] + +Func_70e92: ; 70e92 (1c:4e92) + ld de, wHPBarMaxHP + call Func_712f1 + ld a, [de] + push hl + call Func_71258 + ld a, $4 + ld [wcd5b], a + ld hl, wOAMBuffer + $10 + call Func_71279 + pop hl + ld de, wcd6d +.asm_70eac + ld a, [hli] + ld [de], a + inc de + cp $50 + jr nz, .asm_70eac + hlCoord 1, 0 + ld de, wcd6d + call PlaceString + ld hl, wOAMBuffer + $10 + ld de, wTileMapBackup + 16 + ld bc, $10 + call CopyData +.asm_70ec8 + call TownMapSpriteBlinkingAnimation + call JoypadLowSensitivity + ld a, [hJoy5] + ld b, a + and $c3 + jr z, .asm_70ec8 + ld a, (SFX_02_3c - SFX_Headers_02) / 3 + call PlaySound + bit 6, b + jr nz, .asm_70ef2 + bit 7, b + jr nz, .asm_70f01 + xor a +<<<<<<< HEAD + ld [wd09b], a + ld [hJoy7], a + ld [W_SUBANIMTRANSFORM], a ; W_SUBANIMTRANSFORM +======= + ld [wTownMapSpriteBlinkingEnabled], a + ld [$ffb7], a + ld [wTownMapSpriteBlinkingCounter], a +>>>>>>> yama/master + call Func_711ab + pop hl + pop af + ld [hl], a + ret +.asm_70ef2 + ld a, [wWhichTrade] ; wWhichTrade + inc a + cp $2f + jr nz, .asm_70efb + xor a +.asm_70efb + ld [wWhichTrade], a ; wWhichTrade + jp Func_70e7e +.asm_70f01 + ld a, [wWhichTrade] ; wWhichTrade + dec a + cp $ff + jr nz, .asm_70f0b + ld a, $2e +.asm_70f0b + ld [wWhichTrade], a ; wWhichTrade + jp Func_70e7e + +INCLUDE "data/town_map_order.asm" + +TownMapCursor: ; 70f40 (1c:4f40) + INCBIN "gfx/town_map_cursor.1bpp" + +LoadTownMap_Nest: ; 70f60 (1c:4f60) + call LoadTownMap + ld hl, wUpdateSpritesEnabled + ld a, [hl] + push af + ld [hl], $ff + push hl + call Func_711ef + call GetMonName + hlCoord 1, 0 + call PlaceString + ld h, b + ld l, c + ld de, MonsNestText + call PlaceString + call WaitForTextScrollButtonPress + call Func_711ab + pop hl + pop af + ld [hl], a + ret + +MonsNestText: ; 70f89 (1c:4f89) + db "'s NEST@" + +LoadTownMap_Fly: ; 70f90 (1c:4f90) + call ClearSprites + call LoadTownMap + call LoadPlayerSpriteGraphics + call LoadFontTilePatterns + ld de, BirdSprite ; $4d80 + ld hl, vSprites + $40 + ld bc, (BANK(BirdSprite) << 8) + $0c + call CopyVideoData + ld de, TownMapUpArrow ; $5093 + ld hl, vChars1 + $6d0 + ld bc, (BANK(TownMapUpArrow) << 8) + $01 + call CopyVideoDataDouble + call Func_71070 + ld hl, wUpdateSpritesEnabled + ld a, [hl] + push af + ld [hl], $ff + push hl + ld hl, wTileMap + ld de, ToText + call PlaceString + ld a, [W_CURMAP] ; W_CURMAP + ld b, $0 + call Func_711c4 + ld hl, wTrainerEngageDistance + deCoord 18, 0 + +.townMapFlyLoop + ld a, $7f + ld [de], a + push hl + push hl + hlCoord 3, 0 + ld bc, $10f + call ClearScreenArea + pop hl + ld a, [hl] + ld b, $4 + call Func_711c4 + hlCoord 3, 0 + ld de, wcd6d + call PlaceString + ld c, $f + call DelayFrames + hlCoord 18, 0 + ld [hl], $ed + hlCoord 19, 0 + ld [hl], $ee + pop hl +.asm_71004 + push hl + call DelayFrame + call JoypadLowSensitivity + ld a, [hJoy5] + ld b, a + pop hl + and $c3 + jr z, .asm_71004 + bit 0, b + jr nz, .asm_71026 + ld a, (SFX_02_3c - SFX_Headers_02) / 3 + call PlaySound + bit 6, b + jr nz, .asm_71042 + bit 7, b + jr nz, .asm_71058 + jr .asm_71037 +.asm_71026 + ld a, (SFX_02_3e - SFX_Headers_02) / 3 + call PlaySound + ld a, [hl] + ld [wDestinationMap], a + ld hl, wd732 + set 3, [hl] + inc hl + set 7, [hl] +.asm_71037 + xor a + ld [wTownMapSpriteBlinkingEnabled], a + call GBPalWhiteOutWithDelay3 + pop hl + pop af + ld [hl], a + ret +.asm_71042 + deCoord 18, 0 + inc hl + ld a, [hl] + cp $ff + jr z, .asm_71052 + cp $fe + jr z, .asm_71042 + jp .townMapFlyLoop +.asm_71052 + ld hl, wTrainerEngageDistance + jp .townMapFlyLoop +.asm_71058 + deCoord 19, 0 + dec hl + ld a, [hl] + cp $ff + jr z, .asm_71068 + cp $fe + jr z, .asm_71058 + jp .townMapFlyLoop +.asm_71068 + ld hl, wcd49 + jr .asm_71058 + +ToText: ; 7106d (1c:506d) + db "To@" + +Func_71070: ; 71070 (1c:5070) + ld hl, wWhichTrade ; wWhichTrade + ld [hl], $ff + inc hl + ld a, [W_TOWNVISITEDFLAG] + ld e, a + ld a, [W_TOWNVISITEDFLAG + 1] + ld d, a + ld bc, $b +.asm_71081 + srl d + rr e + ld a, $fe + jr nc, .asm_7108a + ld a, b +.asm_7108a + ld [hl], a + inc hl + inc b + dec c + jr nz, .asm_71081 + ld [hl], $ff + ret + +TownMapUpArrow: ; 71093 (1c:5093) + INCBIN "gfx/up_arrow.1bpp" + +LoadTownMap: ; 7109b (1c:509b) + call GBPalWhiteOutWithDelay3 + call ClearScreen + call UpdateSprites + ld hl, wTileMap + ld b, $12 + ld c, $12 + call TextBoxBorder + call DisableLCD + ld hl, WorldMapTileGraphics ; $65a8 + ld de, vChars2 + $600 + ld bc, $100 + ld a, BANK(WorldMapTileGraphics) + call FarCopyData2 + ld hl, MonNestIcon ; $56be + ld de, vSprites + $40 + ld bc, $8 + ld a, BANK(MonNestIcon) + call FarCopyDataDouble + ld hl, wTileMap + ld de, CompressedMap ; $5100 +.asm_710d3 + ld a, [de] + and a + jr z, .asm_710e9 + ld b, a + and $f + ld c, a + ld a, b + swap a + and $f + add $60 +.asm_710e2 + ld [hli], a + dec c + jr nz, .asm_710e2 + inc de + jr .asm_710d3 +.asm_710e9 + call EnableLCD + ld b, $2 + call GoPAL_SET + call Delay3 + call GBPalNormal + xor a + ld [wTownMapSpriteBlinkingCounter], a + inc a + ld [wTownMapSpriteBlinkingEnabled], a + ret + +CompressedMap: ; 71100 (1c:5100) +; you can decompress this file with the redrle program in the extras/ dir + INCBIN "gfx/town_map.rle" + +Func_711ab: ; 711ab (1c:51ab) + xor a + ld [wTownMapSpriteBlinkingEnabled], a + call GBPalWhiteOut + call ClearScreen + call ClearSprites + call LoadPlayerSpriteGraphics + call LoadFontTilePatterns + call UpdateSprites + jp GoPAL_SET_CF1C + +Func_711c4: ; 711c4 (1c:51c4) + push af + ld a, b + ld [wcd5b], a + pop af + ld de, wHPBarMaxHP + call Func_712f1 + ld a, [de] + push hl + call Func_71258 + call Func_7126d + pop hl + ld de, wcd6d +.asm_711dc + ld a, [hli] + ld [de], a + inc de + cp $50 + jr nz, .asm_711dc + ld hl, wOAMBuffer + ld de, wTileMapBackup + ld bc, $a0 + jp CopyData + +Func_711ef: ; 711ef (1c:51ef) + callba Func_e9cb + call Func_712d9 + ld hl, wOAMBuffer + ld de, wHPBarMaxHP +.asm_71200 + ld a, [de] + cp $ff + jr z, .asm_7121d + and a + jr z, .asm_7121a + push hl + call Func_712f1 + pop hl + ld a, [de] + cp $19 + jr z, .asm_7121a + call Func_71258 + ld a, $4 + ld [hli], a + xor a + ld [hli], a +.asm_7121a + inc de + jr .asm_71200 +.asm_7121d + ld a, l + and a + jr nz, .asm_71236 + hlCoord 1, 7 + ld b, $2 + ld c, $f + call TextBoxBorder + hlCoord 2, 9 + ld de, AreaUnknownText + call PlaceString + jr .asm_7123e +.asm_71236 + ld a, [W_CURMAP] ; W_CURMAP + ld b, $0 + call Func_711c4 +.asm_7123e + ld hl, wOAMBuffer + ld de, wTileMapBackup + ld bc, $a0 + jp CopyData + +AreaUnknownText: ; 7124a (1c:524a) + db " AREA UNKNOWN@" + +Func_71258: ; 71258 (1c:5258) + push af + and $f0 + srl a + add $18 + ld b, a + ld [hli], a + pop af + and $f + swap a + srl a + add $18 + ld c, a + ld [hli], a + ret + +Func_7126d: ; 7126d (1c:526d) + ld a, [wcd5b] + and a + ld hl, wOAMBuffer + $90 + jr z, Func_71279 + ld hl, wOAMBuffer + $80 + +Func_71279: ; 71279 (1c:5279) + push hl + ld hl, $fcfc + add hl, bc + ld b, h + ld c, l + pop hl + +Func_71281: ; 71281 (1c:5281) + ld de, $202 +.asm_71284 + push de + push bc +.asm_71286 + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld a, [wcd5b] + ld [hli], a + inc a + ld [wcd5b], a + xor a + ld [hli], a + inc d + ld a, $8 + add c + ld c, a + dec e + jr nz, .asm_71286 + pop bc + pop de + ld a, $8 + add b + ld b, a + dec d + jr nz, .asm_71284 + ret + +Func_712a6: ; 712a6 (1c:52a6) + xor a + ld [wcd5c], a + ld de, $202 +.asm_712ad + push de + push bc +.asm_712af + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld a, [wcd5b] + ld [hli], a + ld a, [wcd5c] + ld [hli], a + xor $20 + ld [wcd5c], a + inc d + ld a, $8 + add c + ld c, a + dec e + jr nz, .asm_712af + pop bc + pop de + push hl + ld hl, wcd5b + inc [hl] + inc [hl] + pop hl + ld a, $8 + add b + ld b, a + dec d + jr nz, .asm_712ad + ret + +Func_712d9: ; 712d9 (1c:52d9) + ld de, wHPBarMaxHP +.asm_712dc + ld a, [de] + inc de + cp $ff + ret z + ld c, a + ld l, e + ld h, d +.asm_712e4 + ld a, [hl] + cp $ff + jr z, .asm_712dc + cp c + jr nz, .asm_712ee + xor a + ld [hl], a +.asm_712ee + inc hl + jr .asm_712e4 + +Func_712f1: ; 712f1 (1c:52f1) + cp REDS_HOUSE_1F + jr c, .asm_71304 + ld bc, $4 + ld hl, InternalMapEntries ; $5382 +.asm_712fb + cp [hl] + jr c, .asm_71301 + add hl, bc + jr .asm_712fb +.asm_71301 + inc hl + jr .asm_7130d +.asm_71304 + ld hl, ExternalMapEntries ; $5313 + ld c, a + ld b, $0 + add hl, bc + add hl, bc + add hl, bc +.asm_7130d + ld a, [hli] + ld [de], a + ld a, [hli] + ld h, [hl] + ld l, a + ret + +INCLUDE "data/town_map_entries.asm" + +INCLUDE "text/map_names.asm" + +MonNestIcon: ; 716be (1c:56be) + INCBIN "gfx/mon_nest_icon.1bpp" + +TownMapSpriteBlinkingAnimation: ; 716c6 (1c:56c6) + ld a, [wTownMapSpriteBlinkingCounter] + inc a + cp 25 + jr z, .hideSprites + cp 50 + jr nz, .done +; show sprites when the counter reaches 50 + ld hl, wTileMapBackup + ld de, wOAMBuffer + ld bc, $90 + call CopyData + xor a + jr .done +.hideSprites + ld hl, wOAMBuffer + ld b, $24 + ld de, $4 +.hideSpritesLoop + ld [hl], $a0 + add hl, de + dec b + jr nz, .hideSpritesLoop + ld a, 25 +.done + ld [wTownMapSpriteBlinkingCounter], a + jp DelayFrame diff --git a/engine/trade.asm b/engine/trade.asm index d134e15a..4d6c044c 100755 --- a/engine/trade.asm +++ b/engine/trade.asm @@ -203,9 +203,9 @@ Func_41245: ; 41245 (10:5245) and a jr nz, .asm_41273 call Delay50 - ld a, $ad + ld a, ANIM_AD call Func_41676 - ld a, $aa + ld a, ANIM_AA call Func_41676 ld a, [wWhichTrade] ; wWhichTrade call PlayCry @@ -242,9 +242,9 @@ Func_41298: ; 41298 (10:5298) ret Func_412d2: ; 412d2 (10:52d2) - ld a, $ab + ld a, ANIM_AB call Func_41676 - ld c, $a + ld c, 10 call DelayFrames ld a, $e4 ld [rOBP0], a ; $ff48 @@ -295,7 +295,7 @@ UnknownOAM_4132e: ; 4132e (10:532e) db $7E,$40,$7E,$60 Func_41336: ; 41336 (10:5336) - ld a, $ac + ld a, ANIM_AC call Func_41676 call Func_415c8 hlCoord 4, 10 @@ -308,7 +308,7 @@ Func_41336: ; 41336 (10:5336) ld [H_AUTOBGTRANSFERENABLED], a ; $ffba ld a, [wTrainerEngageDistance] call Func_415a4 - ld a, $ad + ld a, ANIM_AD call Func_41676 ld a, $1 ld [H_AUTOBGTRANSFERENABLED], a ; $ffba @@ -1,35 +1,36 @@ + ; The rst vectors are unused. -SECTION "rst00", ROM0[$00] +SECTION "rst 00", ROM0 [$00] rst $38 -SECTION "rst08", ROM0[$08] +SECTION "rst 08", ROM0 [$08] rst $38 -SECTION "rst10", ROM0[$10] +SECTION "rst 10", ROM0 [$10] rst $38 -SECTION "rst18", ROM0[$18] +SECTION "rst 18", ROM0 [$18] rst $38 -SECTION "rst20", ROM0[$20] +SECTION "rst 20", ROM0 [$20] rst $38 -SECTION "rst28", ROM0[$28] +SECTION "rst 28", ROM0 [$28] rst $38 -SECTION "rst30", ROM0[$30] +SECTION "rst 30", ROM0 [$30] rst $38 -SECTION "rst38", ROM0[$38] +SECTION "rst 38", ROM0 [$38] rst $38 -; interrupts -SECTION "vblank", ROM0[$40] +; Hardware interrupts +SECTION "vblank", ROM0 [$40] jp VBlank -SECTION "lcdc", ROM0[$48] +SECTION "hblank", ROM0 [$48] rst $38 -SECTION "timer", ROM0[$50] +SECTION "timer", ROM0 [$50] jp Timer -SECTION "serial", ROM0[$58] +SECTION "serial", ROM0 [$58] jp Serial -SECTION "joypad", ROM0[$60] +SECTION "joypad", ROM0 [$60] reti -SECTION "bank0",ROM0[$61] +SECTION "Home", ROM0 DisableLCD:: xor a @@ -79,38 +80,26 @@ HideSprites:: jr nz, .loop ret -FarCopyData:: -; Copy bc bytes from a:hl to de. - ld [wBuffer], a - ld a, [H_LOADEDROMBANK] - push af - ld a, [wBuffer] - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - call CopyData - pop af - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - ret +INCLUDE "home/copy.asm" -CopyData:: -; Copy bc bytes from hl to de. - ld a, [hli] - ld [de], a - inc de - dec bc - ld a, c - or b - jr nz, CopyData - ret -SECTION "Entry", ROM0[$100] +SECTION "Entry", ROM0 [$100] + nop jp Start -SECTION "Start", ROM0[$150] +SECTION "Header", ROM0 [$104] + + ; The header is generated by rgbfix. + ; The space here is allocated to prevent code from being overwritten. + + ds $150 - $104 + + + +SECTION "Main", ROM0 Start:: cp GBC @@ -125,34 +114,34 @@ Start:: INCLUDE "home/joypad.asm" - INCLUDE "data/map_header_pointers.asm" - INCLUDE "home/overworld.asm" -; this is used to check if the player wants to interrupt the opening sequence at several points -; XXX is this used anywhere else? -; INPUT: -; c = number of frames to wait -; sets carry if Up+Select+B, Start, or A is pressed within c frames -; unsets carry otherwise + CheckForUserInterruption:: ; 12f8 (0:12f8) +; Return carry if Up+Select+B, Start or A are pressed in c frames. +; Used only in the intro and title screen. call DelayFrame + push bc call JoypadLowSensitivity pop bc - ld a,[hJoyHeld] ; currently pressed buttons - cp a,%01000110 ; Up, Select button, B button - jr z,.setCarry ; if all three keys are pressed - ld a,[$ffb5] ; either newly pressed buttons or currently pressed buttons at low sampling rate - and a,%00001001 ; Start button, A button - jr nz,.setCarry ; if either key is pressed + + ld a, [hJoyHeld] + cp D_UP + SELECT + B_BUTTON + jr z, .input + + ld a, [hJoy5] + and START | A_BUTTON + jr nz, .input + dec c - jr nz,CheckForUserInterruption -.unsetCarry + jr nz, CheckForUserInterruption + and a ret -.setCarry + +.input scf ret @@ -180,63 +169,76 @@ LoadDestinationWarpPosition:: ; 1313 (0:1313) ld [$2000],a ret -; INPUT: -; c: if nonzero, show at least a sliver of health -; d = number of HP bar sections (normally 6) -; e = health (in eighths of bar sections) (normally out of 48) + DrawHPBar:: ; 1336 (0:1336) +; Draw an HP bar d tiles long, and fill it to e pixels. +; If c is nonzero, show at least a sliver regardless. +; The right end of the bar changes with [wListMenuID]. + push hl push de push bc - ld a,$71 ; left of HP bar tile 1 - ld [hli],a - ld a,$62 ; left of HP bar tile 2 - ld [hli],a + + ; Left + ld a, $71 ; "HP:" + ld [hli], a + ld a, $62 + ld [hli], a + push hl - ld a,$63 ; empty bar section tile -.drawEmptyBarLoop + + ; Middle + ld a, $63 ; empty +.draw ld [hli],a dec d - jr nz,.drawEmptyBarLoop + jr nz, .draw + + ; Right ld a,[wListMenuID] - dec a ; what should the right of HP bar tile be? - ld a,$6d ; right of HP bar tile, in status screen and battles - jr z,.writeTile - dec a ; right of HP bar tile, in pokemon menu -.writeTile + dec a + ld a, $6d ; status screen and battle + jr z, .ok + dec a ; pokemon menu +.ok ld [hl],a + pop hl - ld a,e - and a ; is there enough health to show up on the HP bar? - jr nz,.loop ; if so, draw the HP bar - ld a,c - and a ; should a sliver of health be shown no matter what? - jr z,.done - ld e,1 ; if so, fill one eighth of a bar section -; loop to draw every full bar section -.loop - ld a,e - sub a,8 - jr c,.drawPartialBarSection - ld e,a - ld a,$6b ; filled bar section tile - ld [hli],a - ld a,e + + ld a, e and a - jr z,.done - jr .loop -; draws a partial bar section at the end (if necessary) -; there are 7 possible partial bar sections from 1/8 to 7/8 full -.drawPartialBarSection - ld a,$63 ; empty bar section tile - add e ; add e to get the appropriate partial bar section tile - ld [hl],a ; write the tile + jr nz, .fill + + ; If c iz nonzero, draw a pixel anyway. + ld a, c + and a + jr z, .done + ld e, 1 + +.fill + ld a, e + sub 8 + jr c, .partial + ld e, a + ld a, $6b ; full + ld [hli], a + ld a, e + and a + jr z, .done + jr .fill + +.partial + ; Fill remaining pixels at the end if necessary. + ld a, $63 ; empty + add e + ld [hl], a .done pop bc pop de pop hl ret + ; loads pokemon data from one of multiple sources to wcf98 ; loads base stats to W_MONHDEXNUM ; INPUT: @@ -251,23 +253,23 @@ DrawHPBar:: ; 1336 (0:1336) ; wcf98 = base address of pokemon data ; W_MONHDEXNUM = base address of base stats LoadMonData:: ; 1372 (0:1372) - ld hl,LoadMonData_ - ld b,BANK(LoadMonData_) + ld hl, LoadMonData_ + ld b, BANK(LoadMonData_) jp Bankswitch -; writes c to wd0dc+b -; XXX unused? + Func_137a:: ; 137a (0:137a) +; Write c to [wd0dc + b]. Unused. ld hl, wd0dc ld e, b - ld d, $0 + ld d, 0 add hl, de ld a, c ld [hl], a ret LoadFlippedFrontSpriteByMonIndex:: ; 1384 (0:1384) - ld a, $1 + ld a, 1 ld [W_SPRITEFLIPPED], a LoadFrontSpriteByMonIndex:: ; 1389 (0:1389) @@ -283,9 +285,9 @@ LoadFrontSpriteByMonIndex:: ; 1389 (0:1389) ld [hl], b and a pop hl - jr z, .invalidDexNumber ; dex #0 invalid + jr z, .invalidDexNumber ; dex #0 invalid cp NUM_POKEMON + 1 - jr c, .validDexNumber ; dex >#151 invalid + jr c, .validDexNumber ; dex >#151 invalid .invalidDexNumber ld a, RHYDON ; $1 ld [wcf91], a @@ -310,41 +312,44 @@ LoadFrontSpriteByMonIndex:: ; 1389 (0:1389) ld [$2000], a ret -; plays the cry of a pokemon -; INPUT: -; a = pokemon ID + PlayCry:: ; 13d0 (0:13d0) +; Play monster a's cry. call GetCryData - call PlaySound ; play cry - jp WaitForSoundToFinish ; wait for sound to be done playing + call PlaySound + jp WaitForSoundToFinish -; gets a pokemon's cry data -; INPUT: -; a = pokemon ID GetCryData:: ; 13d9 (0:13d9) +; Load cry data for monster a. dec a - ld c,a - ld b,0 - ld hl,CryData - add hl,bc - add hl,bc - add hl,bc - ld a,Bank(CryData) + ld c, a + ld b, 0 + ld hl, CryData + add hl, bc + add hl, bc + add hl, bc + + ld a, Bank(CryData) call BankswitchHome - ld a,[hli] - ld b,a - ld a,[hli] - ld [wc0f1],a - ld a,[hl] - ld [wc0f2],a + ld a, [hli] + ld b, a ; cry id + ld a, [hli] + ld [wc0f1], a + ld a, [hl] + ld [wc0f2], a call BankswitchBack - ld a,b ; a = cryID - ld c,$14 ; base sound ID for pokemon cries - rlca - add b ; a = cryID * 3 - add c ; a = $14 + cryID * 3 + + ; Cry headers have 3 channels, + ; and start from index $14, + ; so add 3 times the cry id. + ld a, b + ld c, $14 + rlca ; * 2 + add b + add c ret + DisplayPartyMenu:: ; 13fc (0:13fc) ld a,[hTilesetType] push af @@ -366,42 +371,42 @@ GoBackToPartyMenu:: ; 1411 (0:1411) jp HandlePartyMenuInput PartyMenuInit:: ; 1420 (0:1420) - ld a,$01 + ld a, 1 ; hardcoded bank call BankswitchHome call LoadHpBarAndStatusTilePatterns - ld hl,wd730 - set 6,[hl] ; turn off letter printing delay + ld hl, wd730 + set 6, [hl] ; turn off letter printing delay xor a - ld [wcc49],a - ld [wcc37],a - ld hl,wTopMenuItemY + ld [wcc49], a + ld [wcc37], a + ld hl, wTopMenuItemY inc a - ld [hli],a ; top menu item Y + ld [hli], a ; top menu item Y xor a - ld [hli],a ; top menu item X - ld a,[wcc2b] + ld [hli], a ; top menu item X + ld a, [wcc2b] push af - ld [hli],a ; current menu item ID + ld [hli], a ; current menu item ID inc hl - ld a,[wPartyCount] + ld a, [wPartyCount] and a ; are there more than 0 pokemon in the party? - jr z,.storeMaxMenuItemID + jr z, .storeMaxMenuItemID dec a ; if party is not empty, the max menu item ID is ([wPartyCount] - 1) ; otherwise, it is 0 .storeMaxMenuItemID - ld [hli],a ; max menu item ID - ld a,[wd11f] + ld [hli], a ; max menu item ID + ld a, [wd11f] and a - ld a,%00000011 ; A button and B button - jr z,.next + ld a, A_BUTTON + B_BUTTON + jr z, .next xor a - ld [wd11f],a + ld [wd11f], a inc a .next - ld [hli],a ; menu watched keys + ld [hli], a ; menu watched keys pop af - ld [hl],a ; old menu item ID + ld [hl], a ; old menu item ID ret HandlePartyMenuInput:: ; 145a (0:145a) @@ -539,8 +544,8 @@ PrintLevelCommon:: ; 1523 (0:1523) ld b,$41 ; no leading zeroes, left-aligned, one byte jp PrintNumber -; XXX unused? Func_152e:: ; 152e (0:152e) +; Unused. ld hl,wd0dc ld c,a ld b,0 @@ -685,7 +690,7 @@ PrintBCDNumber:: ; 15cd (0:15cd) ret PrintBCDDigit:: ; 1604 (0:1604) - and a,%00001111 + and $f and a jr z,.zeroDigit .nonzeroDigit @@ -910,556 +915,14 @@ InterlaceMergeSpriteBuffers:: ; 16ea (0:16ea) INCLUDE "data/collision.asm" - - -FarCopyData2:: -; Identical to FarCopyData, but uses $ff8b -; as temp space instead of wBuffer. - ld [$ff8b],a - ld a,[H_LOADEDROMBANK] - push af - ld a,[$ff8b] - ld [H_LOADEDROMBANK],a - ld [MBC1RomBank],a - call CopyData - pop af - ld [H_LOADEDROMBANK],a - ld [MBC1RomBank],a - ret - -FarCopyData3:: -; Copy bc bytes from a:de to hl. - ld [$ff8b],a - ld a,[H_LOADEDROMBANK] - push af - ld a,[$ff8b] - ld [H_LOADEDROMBANK],a - ld [MBC1RomBank],a - push hl - push de - push de - ld d,h - ld e,l - pop hl - call CopyData - pop de - pop hl - pop af - ld [H_LOADEDROMBANK],a - ld [MBC1RomBank],a - ret - -FarCopyDataDouble:: -; Expand bc bytes of 1bpp image data -; from a:hl to 2bpp data at de. - ld [$ff8b],a - ld a,[H_LOADEDROMBANK] - push af - ld a,[$ff8b] - ld [H_LOADEDROMBANK],a - ld [MBC1RomBank],a -.loop - ld a,[hli] - ld [de],a - inc de - ld [de],a - inc de - dec bc - ld a,c - or b - jr nz,.loop - pop af - ld [H_LOADEDROMBANK],a - ld [MBC1RomBank],a - ret - -CopyVideoData:: -; Wait for the next VBlank, then copy c 2bpp -; tiles from b:de to hl, 8 tiles at a time. -; This takes c/8 frames. - - ld a, [H_AUTOBGTRANSFERENABLED] - push af - xor a ; disable auto-transfer while copying - ld [H_AUTOBGTRANSFERENABLED], a - - ld a, [H_LOADEDROMBANK] - ld [$ff8b], a - - ld a, b - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - - ld a, e - ld [H_VBCOPYSRC], a - ld a, d - ld [H_VBCOPYSRC + 1], a - - ld a, l - ld [H_VBCOPYDEST], a - ld a, h - ld [H_VBCOPYDEST + 1], a - -.loop - ld a, c - cp 8 - jr nc, .keepgoing - -.done - ld [H_VBCOPYSIZE], a - call DelayFrame - ld a, [$ff8b] - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - pop af - ld [H_AUTOBGTRANSFERENABLED], a - ret - -.keepgoing - ld a, 8 - ld [H_VBCOPYSIZE], a - call DelayFrame - ld a, c - sub 8 - ld c, a - jr .loop - -CopyVideoDataDouble:: -; Wait for the next VBlank, then copy c 1bpp -; tiles from b:de to hl, 8 tiles at a time. -; This takes c/8 frames. - ld a, [H_AUTOBGTRANSFERENABLED] - push af - xor a ; disable auto-transfer while copying - ld [H_AUTOBGTRANSFERENABLED], a - ld a, [H_LOADEDROMBANK] - ld [$ff8b], a - - ld a, b - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - - ld a, e - ld [H_VBCOPYDOUBLESRC], a - ld a, d - ld [H_VBCOPYDOUBLESRC + 1], a - - ld a, l - ld [H_VBCOPYDOUBLEDEST], a - ld a, h - ld [H_VBCOPYDOUBLEDEST + 1], a - -.loop - ld a, c - cp 8 - jr nc, .keepgoing - -.done - ld [H_VBCOPYDOUBLESIZE], a - call DelayFrame - ld a, [$ff8b] - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - pop af - ld [H_AUTOBGTRANSFERENABLED], a - ret - -.keepgoing - ld a, 8 - ld [H_VBCOPYDOUBLESIZE], a - call DelayFrame - ld a, c - sub 8 - ld c, a - jr .loop - -ClearScreenArea:: -; Clear tilemap area cxb at hl. - ld a, $7f ; blank tile - ld de, 20 ; screen width -.y - push hl - push bc -.x - ld [hli], a - dec c - jr nz, .x - pop bc - pop hl - add hl, de - dec b - jr nz, .y - ret - -CopyScreenTileBufferToVRAM:: -; Copy wTileMap to the BG Map starting at b * $100. -; This is done in thirds of 6 rows, so it takes 3 frames. - - ld c, 6 - - ld hl, $600 * 0 - ld de, wTileMap + 20 * 6 * 0 - call .setup - call DelayFrame - - ld hl, $600 * 1 - ld de, wTileMap + 20 * 6 * 1 - call .setup - call DelayFrame - - ld hl, $600 * 2 - ld de, wTileMap + 20 * 6 * 2 - call .setup - jp DelayFrame - -.setup - ld a, d - ld [H_VBCOPYBGSRC+1], a - call GetRowColAddressBgMap - ld a, l - ld [H_VBCOPYBGDEST], a - ld a, h - ld [H_VBCOPYBGDEST+1], a - ld a, c - ld [H_VBCOPYBGNUMROWS], a - ld a, e - ld [H_VBCOPYBGSRC], a - ret - -ClearScreen:: -; Clear wTileMap, then wait -; for the bg map to update. - ld bc, 20 * 18 - inc b - ld hl, wTileMap - ld a, $7f -.loop - ld [hli], a - dec c - jr nz, .loop - dec b - jr nz, .loop - jp Delay3 - - +INCLUDE "home/copy2.asm" INCLUDE "home/text.asm" INCLUDE "home/vcopy.asm" INCLUDE "home/init.asm" INCLUDE "home/vblank.asm" INCLUDE "home/fade.asm" - - -Serial:: ; 2125 (0:2125) - push af - push bc - push de - push hl - ld a, [$ffaa] - inc a - jr z, .asm_2142 - ld a, [rSB] - ld [$ffad], a - ld a, [$ffac] - ld [rSB], a - ld a, [$ffaa] - cp $2 - jr z, .asm_2162 - ld a, $80 - ld [$ff02], a - jr .asm_2162 -.asm_2142 - ld a, [rSB] - ld [$ffad], a - ld [$ffaa], a - cp $2 - jr z, .asm_215f - xor a - ld [rSB], a - ld a, $3 - ld [rDIV], a ; $ff04 -.asm_2153 - ld a, [rDIV] ; $ff04 - bit 7, a - jr nz, .asm_2153 - ld a, $80 - ld [$ff02], a - jr .asm_2162 -.asm_215f - xor a - ld [rSB], a -.asm_2162 - ld a, $1 - ld [$ffa9], a - ld a, $fe - ld [$ffac], a - pop hl - pop de - pop bc - pop af - reti - -Func_216f:: ; 216f (0:216f) - ld a, $1 - ld [$ffab], a -.asm_2173 - ld a, [hl] - ld [$ffac], a - call Func_219a - push bc - ld b, a - inc hl - ld a, $30 -.asm_217e - dec a - jr nz, .asm_217e - ld a, [$ffab] - and a - ld a, b - pop bc - jr z, .asm_2192 - dec hl - cp $fd - jr nz, .asm_2173 - xor a - ld [$ffab], a - jr .asm_2173 -.asm_2192 - ld [de], a - inc de - dec bc - ld a, b - or c - jr nz, .asm_2173 - ret - -Func_219a:: ; 219a (0:219a) - xor a - ld [$ffa9], a - ld a, [$ffaa] - cp $2 - jr nz, .asm_21a7 - ld a, $81 - ld [$ff02], a -.asm_21a7 - ld a, [$ffa9] - and a - jr nz, .asm_21f1 - ld a, [$ffaa] - cp $1 - jr nz, .asm_21cc - call Func_2237 - jr z, .asm_21cc - call Func_2231 - push hl - ld hl, wcc48 - inc [hl] - jr nz, .asm_21c3 - dec hl - inc [hl] -.asm_21c3 - pop hl - call Func_2237 - jr nz, .asm_21a7 - jp Func_223f -.asm_21cc - ld a, [rIE] ; $ffff - and $f - cp $8 - jr nz, .asm_21a7 - ld a, [W_NUMHITS] ; wd074 - dec a - ld [W_NUMHITS], a ; wd074 - jr nz, .asm_21a7 - ld a, [wd075] - dec a - ld [wd075], a - jr nz, .asm_21a7 - ld a, [$ffaa] - cp $1 - jr z, .asm_21f1 - ld a, $ff -.asm_21ee - dec a - jr nz, .asm_21ee -.asm_21f1 - xor a - ld [$ffa9], a - ld a, [rIE] ; $ffff - and $f - sub $8 - jr nz, .asm_2204 - ld [W_NUMHITS], a ; wd074 - ld a, $50 - ld [wd075], a -.asm_2204 - ld a, [$ffad] - cp $fe - ret nz - call Func_2237 - jr z, .asm_221f - push hl - ld hl, wcc48 - ld a, [hl] - dec a - ld [hld], a - inc a - jr nz, .asm_2219 - dec [hl] -.asm_2219 - pop hl - call Func_2237 - jr z, Func_223f -.asm_221f - ld a, [rIE] ; $ffff - and $f - cp $8 - ld a, $fe - ret z - ld a, [hl] - ld [$ffac], a - call DelayFrame - jp Func_219a - -Func_2231:: ; 2231 (0:2231) - ld a, $f -.asm_2233 - dec a - jr nz, .asm_2233 - ret - -Func_2237:: ; 2237 (0:2237) - push hl - ld hl, wcc47 - ld a, [hli] - or [hl] - pop hl - ret - -Func_223f:: ; 223f (0:223f) - dec a - ld [wcc47], a - ld [wcc48], a - ret - -Func_2247:: ; 2247 (0:2247) - ld hl, wcc42 - ld de, wcc3d - ld c, $2 - ld a, $1 - ld [$ffab], a -.asm_2253 - call DelayFrame - ld a, [hl] - ld [$ffac], a - call Func_219a - ld b, a - inc hl - ld a, [$ffab] - and a - ld a, $0 - ld [$ffab], a - jr nz, .asm_2253 - ld a, b - ld [de], a - inc de - dec c - jr nz, .asm_2253 - ret - -Func_226e:: ; 226e (0:226e) - call SaveScreenTilesToBuffer1 - callab PrintWaitingText - call Func_227f - jp LoadScreenTilesFromBuffer1 - -Func_227f:: ; 227f (0:227f) - ld a, $ff - ld [wcc3e], a -.asm_2284 - call Func_22c3 - call DelayFrame - call Func_2237 - jr z, .asm_22a0 - push hl - ld hl, wcc48 - dec [hl] - jr nz, .asm_229f - dec hl - dec [hl] - jr nz, .asm_229f - pop hl - xor a - jp Func_223f -.asm_229f - pop hl -.asm_22a0 - ld a, [wcc3e] - inc a - jr z, .asm_2284 - ld b, $a -.asm_22a8 - call DelayFrame - call Func_22c3 - dec b - jr nz, .asm_22a8 - ld b, $a -.asm_22b3 - call DelayFrame - call Func_22ed - dec b - jr nz, .asm_22b3 - ld a, [wcc3e] - ld [wcc3d], a - ret - -Func_22c3:: ; 22c3 (0:22c3) - call asm_22d7 - ld a, [wcc42] - add $60 - ld [$ffac], a - ld a, [$ffaa] - cp $2 - jr nz, asm_22d7 - ld a, $81 - ld [$ff02], a -asm_22d7:: ; 22d7 (0:22d7) - ld a, [$ffad] - ld [wcc3d], a - and $f0 - cp $60 - ret nz - xor a - ld [$ffad], a - ld a, [wcc3d] - and $f - ld [wcc3e], a - ret - -Func_22ed:: ; 22ed (0:22ed) - xor a - ld [$ffac], a - ld a, [$ffaa] - cp $2 - ret nz - ld a, $81 - ld [$ff02], a - ret - -Func_22fa:: ; 22fa (0:22fa) - ld a, $2 - ld [rSB], a - xor a - ld [$ffad], a - ld a, $80 - ld [$ff02], a - ret - - -; timer interrupt is apparently not invoked anyway -Timer:: ; 2306 (0:2306) - reti - - +INCLUDE "home/serial.asm" +INCLUDE "home/timer.asm" INCLUDE "home/audio.asm" @@ -1914,7 +1377,7 @@ DisplayListMenuID:: ; 2be6 (0:2be6) xor a ld [H_AUTOBGTRANSFERENABLED],a ; disable auto-transfer ld a,1 - ld [$ffb7],a ; joypad state update flag + ld [hJoy7],a ; joypad state update flag ld a,[W_BATTLETYPE] and a ; is it the Old Man battle? jr nz,.specialBattleType @@ -1959,7 +1422,7 @@ DisplayListMenuID:: ; 2be6 (0:2be6) ld [wTopMenuItemY],a ld a,5 ld [wTopMenuItemX],a - ld a,%00000111 ; A button, B button, Select button + ld a,A_BUTTON | B_BUTTON | SELECT ld [wMenuWatchedKeys],a ld c,10 call DelayFrames @@ -2047,7 +1510,7 @@ DisplayListMenuIDLoop:: ; 2c53 (0:2c53) .skipGettingQuantity ld a,[wcf91] ld [wd0b5],a - ld a,$01 + ld a,BANK(ItemNames) ld [wPredefBank],a call GetName jr .storeChosenEntry @@ -2069,7 +1532,7 @@ DisplayListMenuIDLoop:: ; 2c53 (0:2c53) ld a,[wCurrentMenuItem] ld [wd12d],a xor a - ld [$ffb7],a ; joypad state update flag + ld [hJoy7],a ; joypad state update flag ld hl,wd730 res 6,[hl] ; turn on letter printing delay jp BankswitchBack @@ -2230,7 +1693,7 @@ ExitListMenu:: ; 2e3b (0:2e3b) ld [wd12e],a ld [wcc37],a xor a - ld [$ffb7],a + ld [hJoy7],a ld hl,wd730 res 6,[hl] call BankswitchBack @@ -2383,7 +1846,7 @@ PrintListMenuEntries:: ; 2e5a (0:2e5a) ld bc,20 + 8 ; 1 row down and 8 columns right add hl,bc ld a,"×" - ldi [hl],a + ld [hli],a ld a,[wd11e] push af ld a,[de] @@ -3218,8 +2681,8 @@ FuncTX_ItemStoragePC:: ; 3460 (0:3460) FuncTX_BillsPC:: ; 346a (0:346a) call SaveScreenTilesToBuffer2 - ld b, BANK(Func_214c2) - ld hl, Func_214c2 + ld b, BANK(BillsPC_) + ld hl, BillsPC_ jr bankswitchAndContinue FuncTX_SlotMachine:: ; 3474 (0:3474) @@ -3631,65 +3094,63 @@ DivideBytes:: ; 366b (0:366b) pop hl ret -; copies the tile patterns for letters and numbers into VRAM -LoadFontTilePatterns:: ; 3680 (0:3680) - ld a,[rLCDC] - bit 7,a ; is the LCD enabled? - jr nz,.lcdEnabled -.lcdDisabled - ld hl,FontGraphics - ld de,vFont - ld bc,$400 - ld a,BANK(FontGraphics) + +LoadFontTilePatterns:: + ld a, [rLCDC] + bit 7, a ; is the LCD enabled? + jr nz, .on +.off + ld hl, FontGraphics + ld de, vFont + ld bc, $400 + ld a, BANK(FontGraphics) jp FarCopyDataDouble ; if LCD is off, transfer all at once -.lcdEnabled - ld de,FontGraphics - ld hl,vFont - ld bc,(BANK(FontGraphics) << 8 | $80) +.on + ld de, FontGraphics + ld hl, vFont + ld bc, BANK(FontGraphics) << 8 | $80 jp CopyVideoDataDouble ; if LCD is on, transfer during V-blank -; copies the text box tile patterns into VRAM -LoadTextBoxTilePatterns:: ; 36a0 (0:36a0) - ld a,[rLCDC] - bit 7,a ; is the LCD enabled? - jr nz,.lcdEnabled -.lcdDisabled - ld hl,TextBoxGraphics - ld de,vChars2 + $600 - ld bc,$200 - ld a,BANK(TextBoxGraphics) +LoadTextBoxTilePatterns:: + ld a, [rLCDC] + bit 7, a ; is the LCD enabled? + jr nz, .on +.off + ld hl, TextBoxGraphics + ld de, vChars2 + $600 + ld bc, $200 + ld a, BANK(TextBoxGraphics) jp FarCopyData2 ; if LCD is off, transfer all at once -.lcdEnabled - ld de,TextBoxGraphics - ld hl,vChars2 + $600 - ld bc,(BANK(TextBoxGraphics) << 8 | $20) +.on + ld de, TextBoxGraphics + ld hl, vChars2 + $600 + ld bc, BANK(TextBoxGraphics) << 8 | $20 jp CopyVideoData ; if LCD is on, transfer during V-blank -; copies HP bar and status display tile patterns into VRAM -LoadHpBarAndStatusTilePatterns:: ; 36c0 (0:36c0) - ld a,[rLCDC] - bit 7,a ; is the LCD enabled? - jr nz,.lcdEnabled -.lcdDisabled - ld hl,HpBarAndStatusGraphics - ld de,vChars2 + $620 - ld bc,$1e0 - ld a,BANK(HpBarAndStatusGraphics) +LoadHpBarAndStatusTilePatterns:: + ld a, [rLCDC] + bit 7, a ; is the LCD enabled? + jr nz, .on +.off + ld hl, HpBarAndStatusGraphics + ld de, vChars2 + $620 + ld bc, $1e0 + ld a, BANK(HpBarAndStatusGraphics) jp FarCopyData2 ; if LCD is off, transfer all at once -.lcdEnabled - ld de,HpBarAndStatusGraphics - ld hl,vChars2 + $620 - ld bc,(BANK(HpBarAndStatusGraphics) << 8 | $1e) +.on + ld de, HpBarAndStatusGraphics + ld hl, vChars2 + $620 + ld bc, BANK(HpBarAndStatusGraphics) << 8 | $1e jp CopyVideoData ; if LCD is on, transfer during V-blank -;Fills memory range with the specified byte. -;input registers a = fill_byte, bc = length, hl = address -FillMemory:: ; 36e0 (0:36e0) + +FillMemory:: +; Fill bc bytes at hl with a. push de ld d, a .loop ld a, d - ldi [hl], a + ld [hli], a dec bc ld a, b or c @@ -3697,15 +3158,16 @@ FillMemory:: ; 36e0 (0:36e0) pop de ret -; loads sprite that de points to -; bank of sprite is given in a + UncompressSpriteFromDE:: ; 36eb (0:36eb) +; Decompress pic at a:de. ld hl, W_SPRITEINPUTPTR ld [hl], e inc hl ld [hl], d jp UncompressSpriteData + SaveScreenTilesToBuffer2:: ; 36f4 (0:36f4) ld hl, wTileMap ld de, wTileMapBackup2 @@ -3796,8 +3258,12 @@ GetName:: ; 376b (0:376b) ; returns pointer to name in de ld a,[wd0b5] ld [wd11e],a - cp a,$C4 ;it's TM/HM - jp nc,GetMachineName + + ; TM names are separate from item names. + ; BUG: This applies to all names instead of just items. + cp HM_01 + jp nc, GetMachineName + ld a,[H_LOADEDROMBANK] push af push hl @@ -3872,8 +3338,8 @@ GetItemPrice:: ; 37df (0:37df) ld a, [H_LOADEDROMBANK] push af ld a, [wListMenuID] ; wListMenuID - cp $1 - ld a, $1 ; hardcoded Bank + cp MOVESLISTMENU + ld a, BANK(ItemPrices) jr nz, .asm_37ed ld a, $f ; hardcoded Bank .asm_37ed @@ -3926,29 +3392,29 @@ CopyString:: ; 3829 (0:3829) ret ; this function is used when lower button sensitivity is wanted (e.g. menus) -; OUTPUT: [$ffb5] = pressed buttons in usual format -; there are two flags that control its functionality, [$ffb6] and [$ffb7] +; OUTPUT: [hJoy5] = pressed buttons in usual format +; there are two flags that control its functionality, [hJoy6] and [hJoy7] ; there are esentially three modes of operation ; 1. Get newly pressed buttons only -; ([$ffb7] == 0, [$ffb6] == any) -; Just copies [hJoyPressed] to [$ffb5]. +; ([hJoy7] == 0, [hJoy6] == any) +; Just copies [hJoyPressed] to [hJoy5]. ; 2. Get currently pressed buttons at low sample rate with delay -; ([$ffb7] == 1, [$ffb6] != 0) +; ([hJoy7] == 1, [hJoy6] != 0) ; If the user holds down buttons for more than half a second, ; report buttons as being pressed up to 12 times per second thereafter. ; If the user holds down buttons for less than half a second, ; report only one button press. ; 3. Same as 2, but report no buttons as pressed if A or B is held down. -; ([$ffb7] == 1, [$ffb6] == 0) +; ([hJoy7] == 1, [hJoy6] == 0) JoypadLowSensitivity:: ; 3831 (0:3831) call Joypad - ld a,[$ffb7] ; flag + ld a,[hJoy7] ; flag and a ; get all currently pressed buttons or only newly pressed buttons? ld a,[hJoyPressed] ; newly pressed buttons jr z,.storeButtonState ld a,[hJoyHeld] ; all currently pressed buttons .storeButtonState - ld [$ffb5],a + ld [hJoy5],a ld a,[hJoyPressed] ; newly pressed buttons and a ; have any buttons been newly pressed since last check? jr z,.noNewlyPressedButtons @@ -3962,18 +3428,18 @@ JoypadLowSensitivity:: ; 3831 (0:3831) jr z,.delayOver .delayNotOver xor a - ld [$ffb5],a ; report no buttons as pressed + ld [hJoy5],a ; report no buttons as pressed ret .delayOver -; if [$ffb6] = 0 and A or B is pressed, report no buttons as pressed +; if [hJoy6] = 0 and A or B is pressed, report no buttons as pressed ld a,[hJoyHeld] - and a,%00000011 ; A and B buttons + and A_BUTTON | B_BUTTON jr z,.setShortDelay - ld a,[$ffb6] ; flag + ld a,[hJoy6] ; flag and a jr nz,.setShortDelay xor a - ld [$ffb5],a + ld [hJoy5],a .setShortDelay ld a,5 ; 1/12 of a second delay ld [H_FRAMECOUNTER],a @@ -4000,7 +3466,7 @@ WaitForTextScrollButtonPress:: ; 3865 (0:3865) pop hl call JoypadLowSensitivity predef Func_5a5f - ld a, [$ffb5] + ld a, [hJoy5] and A_BUTTON | B_BUTTON jr z, .loop pop af @@ -4080,7 +3546,7 @@ PrintLetterDelay:: ; 38d3 (0:38d3) bit 0,a jr z,.waitOneFrame ld a,[W_OPTIONS] - and a,$0f + and $f ld [H_FRAMECOUNTER],a jr .checkButtons .waitOneFrame @@ -4467,7 +3933,7 @@ HandleMenuInputPokemonSelection:: ; 3ac2 (0:3ac2) .getJoypadState pop hl call JoypadLowSensitivity - ld a,[$ffb5] + ld a,[hJoy5] and a ; was a key pressed? jr nz,.keyPressed push hl @@ -4490,7 +3956,7 @@ HandleMenuInputPokemonSelection:: ; 3ac2 (0:3ac2) .keyPressed xor a ld [wcc4b],a - ld a,[$ffb5] + ld a,[hJoy5] ld b,a bit 6,a ; pressed Up key? jr z,.checkIfDownPressed @@ -4532,8 +3998,8 @@ HandleMenuInputPokemonSelection:: ; 3ac2 (0:3ac2) and b ; does the menu care about any of the pressed keys? jp z,.loop1 .checkIfAButtonOrBButtonPressed - ld a,[$ffb5] - and a,%00000011 ; pressed A button or B button? + ld a,[hJoy5] + and A_BUTTON | B_BUTTON jr z,.skipPlayingSound .AButtonOrBButtonPressed push hl @@ -4550,7 +4016,7 @@ HandleMenuInputPokemonSelection:: ; 3ac2 (0:3ac2) ld [H_DOWNARROWBLINKCNT1],a ; restore previous values xor a ld [wMenuWrappingEnabled],a ; disable menu wrapping - ld a,[$ffb5] + ld a,[hJoy5] ret .noWrappingAround ld a,[wcc37] @@ -4563,14 +4029,14 @@ PlaceMenuCursor:: ; 3b7c (0:3b7c) and a ; is the y coordinate 0? jr z,.adjustForXCoord ld hl,wTileMap - ld bc,20 ; screen width + ld bc,SCREEN_WIDTH .topMenuItemLoop add hl,bc dec a jr nz,.topMenuItemLoop .adjustForXCoord ld a,[wTopMenuItemX] - ld b,$00 + ld b,0 ld c,a add hl,bc push hl @@ -4723,7 +4189,7 @@ AutoTextBoxDrawingCommon:: ; 3c41 (0:3c41) ret PrintText:: ; 3c49 (0:3c49) -; given a pointer in hl, print the text there +; Print text hl at (1, 14). push hl ld a,1 ld [wd125],a @@ -4735,256 +4201,244 @@ Func_3c59:: ; 3c59 (0:3c59) bcCoord 1, 14 jp TextCommandProcessor -; converts a big-endian binary number into decimal and prints it -; INPUT: -; b = flags and number of bytes -; bit 7: if set, print leading zeroes -; if unset, do not print leading zeroes -; bit 6: if set, left-align the string (do not pad empty digits with spaces) -; if unset, right-align the string -; bits 4-5: unused -; bits 0-3: number of bytes (only 1 - 3 bytes supported) -; c = number of decimal digits -; de = address of the number (big-endian) -PrintNumber:: ; 3c5f (0:3c5f) + +PrintNumber:: ; 3c5f +; Print the c-digit, b-byte value at de. +; Allows 2 to 7 digits. For 1-digit numbers, add +; the value to char "0" instead of calling PrintNumber. +; Flags LEADING_ZEROES and LEFT_ALIGN can be given +; in bits 7 and 6 of b respectively. +LEADING_ZEROES EQU 7 +LEFT_ALIGN EQU 6 + push bc xor a - ld [H_PASTLEADINGZEROES],a - ld [H_NUMTOPRINT],a - ld [H_NUMTOPRINT + 1],a - ld a,b - and a,%00001111 - cp a,1 - jr z,.oneByte - cp a,2 - jr z,.twoBytes -.threeBytes - ld a,[de] - ld [H_NUMTOPRINT],a + ld [H_PASTLEADINGZEROES], a + ld [H_NUMTOPRINT], a + ld [H_NUMTOPRINT + 1], a + ld a, b + and $f + cp 1 + jr z, .byte + cp 2 + jr z, .word +.long + ld a, [de] + ld [H_NUMTOPRINT], a inc de - ld a,[de] - ld [H_NUMTOPRINT + 1],a + ld a, [de] + ld [H_NUMTOPRINT + 1], a inc de - ld a,[de] - ld [H_NUMTOPRINT + 2],a - jr .checkNumDigits -.twoBytes - ld a,[de] - ld [H_NUMTOPRINT + 1],a + ld a, [de] + ld [H_NUMTOPRINT + 2], a + jr .start + +.word + ld a, [de] + ld [H_NUMTOPRINT + 1], a inc de - ld a,[de] - ld [H_NUMTOPRINT + 2],a - jr .checkNumDigits -.oneByte - ld a,[de] - ld [H_NUMTOPRINT + 2],a -.checkNumDigits + ld a, [de] + ld [H_NUMTOPRINT + 2], a + jr .start + +.byte + ld a, [de] + ld [H_NUMTOPRINT + 2], a + +.start push de - ld d,b - ld a,c - ld b,a - xor a - ld c,a - ld a,b ; a = number of decimal digits - cp a,2 - jr z,.tensPlace - cp a,3 - jr z,.hundredsPlace - cp a,4 - jr z,.thousandsPlace - cp a,5 - jr z,.tenThousandsPlace - cp a,6 - jr z,.hundredThousandsPlace -.millionsPlace - ld a,1000000 >> 16 - ld [H_POWEROFTEN],a - ld a,(1000000 >> 8) & $FF - ld [H_POWEROFTEN + 1],a - ld a,1000000 & $FF - ld [H_POWEROFTEN + 2],a - call PrintNumber_PrintDigit - call PrintNumber_AdvancePointer -.hundredThousandsPlace - ld a,100000 >> 16 - ld [H_POWEROFTEN],a - ld a,(100000 >> 8) & $FF - ld [H_POWEROFTEN + 1],a - ld a,100000 & $FF - ld [H_POWEROFTEN + 2],a - call PrintNumber_PrintDigit - call PrintNumber_AdvancePointer -.tenThousandsPlace - xor a - ld [H_POWEROFTEN],a - ld a,10000 >> 8 - ld [H_POWEROFTEN + 1],a - ld a,10000 & $FF - ld [H_POWEROFTEN + 2],a - call PrintNumber_PrintDigit - call PrintNumber_AdvancePointer -.thousandsPlace - xor a - ld [H_POWEROFTEN],a - ld a,1000 >> 8 - ld [H_POWEROFTEN + 1],a - ld a,1000 & $FF - ld [H_POWEROFTEN + 2],a - call PrintNumber_PrintDigit - call PrintNumber_AdvancePointer -.hundredsPlace - xor a - ld [H_POWEROFTEN],a + + ld d, b + ld a, c + ld b, a xor a - ld [H_POWEROFTEN + 1],a - ld a,100 - ld [H_POWEROFTEN + 2],a - call PrintNumber_PrintDigit - call PrintNumber_AdvancePointer -.tensPlace - ld c,00 - ld a,[H_NUMTOPRINT + 2] -.loop - cp a,10 - jr c,.underflow - sub a,10 + ld c, a + ld a, b + + cp 2 + jr z, .tens + cp 3 + jr z, .hundreds + cp 4 + jr z, .thousands + cp 5 + jr z, .ten_thousands + cp 6 + jr z, .hundred_thousands + +print_digit: macro + +if (\1) / $10000 + ld a, \1 / $10000 % $100 +else xor a +endc + ld [H_POWEROFTEN + 0], a + +if (\1) / $100 + ld a, \1 / $100 % $100 +else xor a +endc + ld [H_POWEROFTEN + 1], a + + ld a, \1 / $1 % $100 + ld [H_POWEROFTEN + 2], a + + call .PrintDigit + call .NextDigit +endm + +.millions print_digit 1000000 +.hundred_thousands print_digit 100000 +.ten_thousands print_digit 10000 +.thousands print_digit 1000 +.hundreds print_digit 100 + +.tens + ld c, 0 + ld a, [H_NUMTOPRINT + 2] +.mod + cp 10 + jr c, .ok + sub 10 inc c - jr .loop -.underflow - ld b,a - ld a,[H_PASTLEADINGZEROES] + jr .mod +.ok + + ld b, a + ld a, [H_PASTLEADINGZEROES] or c - ld [H_PASTLEADINGZEROES],a - jr nz,.pastLeadingZeroes - call PrintNumber_PrintLeadingZero - jr .advancePointer -.pastLeadingZeroes - ld a,"0" + ld [H_PASTLEADINGZEROES], a + jr nz, .past + call .PrintLeadingZero + jr .next +.past + ld a, "0" add c - ld [hl],a -.advancePointer - call PrintNumber_AdvancePointer -.onesPlace - ld a,"0" + ld [hl], a +.next + + call .NextDigit +.ones + ld a, "0" add b - ld [hli],a + ld [hli], a pop de dec de pop bc ret -; prints a decimal digit -; This works by repeatedely subtracting a power of ten until the number becomes negative. -; The number of subtractions it took in order to make the number negative is the digit for the current number place. -; The last value that the number had before becoming negative is kept as the new value of the number. -; A more succinct description is that the number is divided by a power of ten -; and the quotient becomes the digit while the remainder is stored as the new value of the number. -PrintNumber_PrintDigit:: ; 3d25 (0:3d25) - ld c,0 ; counts number of loop iterations to determine the decimal digit +.PrintDigit: +; Divide by the current decimal place. +; Print the quotient, and keep the modulus. + ld c, 0 .loop - ld a,[H_POWEROFTEN] - ld b,a - ld a,[H_NUMTOPRINT] - ld [H_SAVEDNUMTOPRINT],a + ld a, [H_POWEROFTEN] + ld b, a + ld a, [H_NUMTOPRINT] + ld [H_SAVEDNUMTOPRINT], a cp b - jr c,.underflow0 + jr c, .underflow0 sub b - ld [H_NUMTOPRINT],a - ld a,[H_POWEROFTEN + 1] - ld b,a - ld a,[H_NUMTOPRINT + 1] - ld [H_SAVEDNUMTOPRINT + 1],a + ld [H_NUMTOPRINT], a + ld a, [H_POWEROFTEN + 1] + ld b, a + ld a, [H_NUMTOPRINT + 1] + ld [H_SAVEDNUMTOPRINT + 1], a cp b - jr nc,.noBorrowForByte1 -.byte1BorrowFromByte0 - ld a,[H_NUMTOPRINT] - or a,0 - jr z,.underflow1 + jr nc, .noborrow1 + + ld a, [H_NUMTOPRINT] + or 0 + jr z, .underflow1 dec a - ld [H_NUMTOPRINT],a - ld a,[H_NUMTOPRINT + 1] -.noBorrowForByte1 + ld [H_NUMTOPRINT], a + ld a, [H_NUMTOPRINT + 1] +.noborrow1 + sub b - ld [H_NUMTOPRINT + 1],a - ld a,[H_POWEROFTEN + 2] - ld b,a - ld a,[H_NUMTOPRINT + 2] - ld [H_SAVEDNUMTOPRINT + 2],a + ld [H_NUMTOPRINT + 1], a + ld a, [H_POWEROFTEN + 2] + ld b, a + ld a, [H_NUMTOPRINT + 2] + ld [H_SAVEDNUMTOPRINT + 2], a cp b - jr nc,.noBorrowForByte2 -.byte2BorrowFromByte1 - ld a,[H_NUMTOPRINT + 1] + jr nc, .noborrow2 + + ld a, [H_NUMTOPRINT + 1] and a - jr nz,.finishByte2BorrowFromByte1 -.byte2BorrowFromByte0 - ld a,[H_NUMTOPRINT] + jr nz, .borrowed + + ld a, [H_NUMTOPRINT] and a - jr z,.underflow2 + jr z, .underflow2 dec a - ld [H_NUMTOPRINT],a + ld [H_NUMTOPRINT], a xor a -.finishByte2BorrowFromByte1 +.borrowed + dec a - ld [H_NUMTOPRINT + 1],a - ld a,[H_NUMTOPRINT + 2] -.noBorrowForByte2 + ld [H_NUMTOPRINT + 1], a + ld a, [H_NUMTOPRINT + 2] +.noborrow2 sub b - ld [H_NUMTOPRINT + 2],a + ld [H_NUMTOPRINT + 2], a inc c jr .loop + .underflow2 - ld a,[H_SAVEDNUMTOPRINT + 1] - ld [H_NUMTOPRINT + 1],a + ld a, [H_SAVEDNUMTOPRINT + 1] + ld [H_NUMTOPRINT + 1], a .underflow1 - ld a,[H_SAVEDNUMTOPRINT] - ld [H_NUMTOPRINT],a + ld a, [H_SAVEDNUMTOPRINT] + ld [H_NUMTOPRINT], a .underflow0 - ld a,[H_PASTLEADINGZEROES] + ld a, [H_PASTLEADINGZEROES] or c - jr z,PrintNumber_PrintLeadingZero - ld a,"0" + jr z, .PrintLeadingZero + + ld a, "0" add c - ld [hl],a - ld [H_PASTLEADINGZEROES],a + ld [hl], a + ld [H_PASTLEADINGZEROES], a ret -; prints a leading zero unless they are turned off in the flags -PrintNumber_PrintLeadingZero:: ; 3d83 (0:3d83) - bit 7,d ; print leading zeroes? +.PrintLeadingZero: + bit LEADING_ZEROES, d ret z - ld [hl],"0" - ret - -; increments the pointer unless leading zeroes are not being printed, -; the number is left-aligned, and no nonzero digits have been printed yet -PrintNumber_AdvancePointer:: ; 3d89 (0:3d89) - bit 7,d ; print leading zeroes? - jr nz,.incrementPointer - bit 6,d ; left alignment or right alignment? - jr z,.incrementPointer - ld a,[H_PASTLEADINGZEROES] + ld [hl], "0" + ret + +.NextDigit: +; Increment unless the number is left-aligned, +; leading zeroes are not printed, and no digits +; have been printed yet. + bit LEADING_ZEROES, d + jr nz, .inc + bit LEFT_ALIGN, d + jr z, .inc + ld a, [H_PASTLEADINGZEROES] and a ret z -.incrementPointer +.inc inc hl ret -; calls a function from a table of function pointers -; INPUT: -; a = index within table -; hl = address of function pointer table -CallFunctionInTable:: ; 3d97 (0:3d97) + +CallFunctionInTable:: +JumpTable:: +; Call function a in jumptable hl. +; de is not preserved. push hl push de push bc add a - ld d,0 - ld e,a - add hl,de - ld a,[hli] - ld h,[hl] - ld l,a - ld de,.returnAddress + ld d, 0 + ld e, a + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .returnAddress push de jp [hl] .returnAddress @@ -5139,7 +4593,7 @@ Random:: push de push bc callba Random_ - ld a,[hRandomAdd] + ld a, [hRandomAdd] pop bc pop de pop hl @@ -5193,18 +4647,17 @@ CheckForHiddenObjectOrBookshelfOrCardKeyDoor:: ; 3eb5 (0:3eb5) PrintPredefTextID:: ; 3ef5 (0:3ef5) ld [H_DOWNARROWBLINKCNT2], a ; $ff8c - ld hl, PredefTextIDPointerTable + ld hl, TextPredefs call SetMapTextPointer ld hl, wcf11 set 0, [hl] call DisplayTextID - ; fall through RestoreMapTextPointer:: ; 3f05 (0:3f05) ld hl, W_MAPTEXTPTR ld a, [$ffec] ld [hli], a - ld a, [$ffed] + ld a, [$ffec + 1] ld [hl], a ret @@ -5212,77 +4665,77 @@ SetMapTextPointer:: ; 3f0f (0:3f0f) ld a, [W_MAPTEXTPTR] ld [$ffec], a ld a, [W_MAPTEXTPTR + 1] - ld [$ffed], a + ld [$ffec + 1], a ld a, l ld [W_MAPTEXTPTR], a ld a, h ld [W_MAPTEXTPTR + 1], a ret -PredefTextIDPointerTable:: ; 3f22 (0:3f22) - dw CardKeySuccessText ; id = 01 - dw CardKeyFailText ; id = 02 - dw RedBedroomPC ; id = 03 - dw RedBedroomSNESText ; id = 04 - dw PushStartText ; id = 05 - dw SaveOptionText ; id = 06 - dw StrengthsAndWeaknessesText ; id = 07 - dw OakLabEmailText ; id = 08 - dw AerodactylFossilText ; id = 09 - dw Route15UpstairsBinocularsText ; id = 0A - dw KabutopsFossilText ; id = 0B - dw GymStatueText1 ; id = 0C - dw GymStatueText2 ; id = 0D - dw BookcaseText ; id = 0E - dw ViridianCityPokecenterBenchGuyText ; id = 0F - dw PewterCityPokecenterBenchGuyText ; id = 10 - dw CeruleanCityPokecenterBenchGuyText ; id = 11 - dw LavenderCityPokecenterBenchGuyText ; id = 12 - dw VermilionCityPokecenterBenchGuyText ; id = 13 - dw CeladonCityPokecenterBenchGuyText ; id = 14 - dw CeladonCityHotelText ; id = 15 - dw FuchsiaCityPokecenterBenchGuyText ; id = 16 - dw CinnabarIslandPokecenterBenchGuyText ; id = 17 - dw SaffronCityPokecenterBenchGuyText ; id = 18 - dw MtMoonPokecenterBenchGuyText ; id = 19 - dw RockTunnelPokecenterBenchGuyText ; id = 1A - dw UnusedBenchGuyText1 ; id = 1B - dw UnusedBenchGuyText2 ; id = 1C - dw UnusedBenchGuyText3 ; id = 1D - dw TerminatorText_62508 ; id = 1E - dw PredefText1f ; id = 1F - dw ViridianSchoolNotebook ; id = 20 - dw ViridianSchoolBlackboard ; id = 21 - dw JustAMomentText ; id = 22 - dw PredefText23 ; id = 23 - dw FoundHiddenItemText ; id = 24 - dw HiddenItemBagFullText ; id = 25 - dw VermilionGymTrashText ; id = 26 - dw IndigoPlateauHQText ; id = 27 - dw GameCornerOutOfOrderText ; id = 28 - dw GameCornerOutToLunchText ; id = 29 - dw GameCornerSomeonesKeysText ; id = 2A - dw FoundHiddenCoinsText ; id = 2B - dw DroppedHiddenCoinsText ; id = 2C - dw BillsHouseMonitorText ; id = 2D - dw BillsHouseInitiatedText ; id = 2E - dw BillsHousePokemonList ; id = 2F - dw MagazinesText ; id = 30 - dw CinnabarGymQuiz ; id = 31 - dw GameCornerNoCoinsText ; id = 32 - dw GameCornerCoinCaseText ; id = 33 - dw LinkCableHelp ; id = 34 - dw TMNotebook ; id = 35 - dw FightingDojoText ; id = 36 - dw FightingDojoText_52a10 ; id = 37 - dw FightingDojoText_52a1d ; id = 38 - dw NewBicycleText ; id = 39 - dw IndigoPlateauStatues ; id = 3A - dw VermilionGymTrashSuccesText1 ; id = 3B - dw VermilionGymTrashSuccesText2 ; id = 3C - dw VermilionGymTrashSuccesText3 ; id = 3D - dw VermilionGymTrashFailText ; id = 3E - dw TownMapText ; id = 3F - dw BookOrSculptureText ; id = 40 - dw ElevatorText ; id = 41 - dw PokemonStuffText ; id = 42 +TextPredefs:: + add_tx_pre CardKeySuccessText ; 01 + add_tx_pre CardKeyFailText ; 02 + add_tx_pre RedBedroomPC ; 03 + add_tx_pre RedBedroomSNESText ; 04 + add_tx_pre PushStartText ; 05 + add_tx_pre SaveOptionText ; 06 + add_tx_pre StrengthsAndWeaknessesText ; 07 + add_tx_pre OakLabEmailText ; 08 + add_tx_pre AerodactylFossilText ; 09 + add_tx_pre Route15UpstairsBinocularsText ; 0A + add_tx_pre KabutopsFossilText ; 0B + add_tx_pre GymStatueText1 ; 0C + add_tx_pre GymStatueText2 ; 0D + add_tx_pre BookcaseText ; 0E + add_tx_pre ViridianCityPokecenterBenchGuyText ; 0F + add_tx_pre PewterCityPokecenterBenchGuyText ; 10 + add_tx_pre CeruleanCityPokecenterBenchGuyText ; 11 + add_tx_pre LavenderCityPokecenterBenchGuyText ; 12 + add_tx_pre VermilionCityPokecenterBenchGuyText ; 13 + add_tx_pre CeladonCityPokecenterBenchGuyText ; 14 + add_tx_pre CeladonCityHotelText ; 15 + add_tx_pre FuchsiaCityPokecenterBenchGuyText ; 16 + add_tx_pre CinnabarIslandPokecenterBenchGuyText ; 17 + add_tx_pre SaffronCityPokecenterBenchGuyText ; 18 + add_tx_pre MtMoonPokecenterBenchGuyText ; 19 + add_tx_pre RockTunnelPokecenterBenchGuyText ; 1A + add_tx_pre UnusedBenchGuyText1 ; 1B + add_tx_pre UnusedBenchGuyText2 ; 1C + add_tx_pre UnusedBenchGuyText3 ; 1D + add_tx_pre TerminatorText_62508 ; 1E + add_tx_pre PredefText1f ; 1F + add_tx_pre ViridianSchoolNotebook ; 20 + add_tx_pre ViridianSchoolBlackboard ; 21 + add_tx_pre JustAMomentText ; 22 + add_tx_pre PredefText23 ; 23 + add_tx_pre FoundHiddenItemText ; 24 + add_tx_pre HiddenItemBagFullText ; 25 + add_tx_pre VermilionGymTrashText ; 26 + add_tx_pre IndigoPlateauHQText ; 27 + add_tx_pre GameCornerOutOfOrderText ; 28 + add_tx_pre GameCornerOutToLunchText ; 29 + add_tx_pre GameCornerSomeonesKeysText ; 2A + add_tx_pre FoundHiddenCoinsText ; 2B + add_tx_pre DroppedHiddenCoinsText ; 2C + add_tx_pre BillsHouseMonitorText ; 2D + add_tx_pre BillsHouseInitiatedText ; 2E + add_tx_pre BillsHousePokemonList ; 2F + add_tx_pre MagazinesText ; 30 + add_tx_pre CinnabarGymQuiz ; 31 + add_tx_pre GameCornerNoCoinsText ; 32 + add_tx_pre GameCornerCoinCaseText ; 33 + add_tx_pre LinkCableHelp ; 34 + add_tx_pre TMNotebook ; 35 + add_tx_pre FightingDojoText ; 36 + add_tx_pre FightingDojoText_52a10 ; 37 + add_tx_pre FightingDojoText_52a1d ; 38 + add_tx_pre NewBicycleText ; 39 + add_tx_pre IndigoPlateauStatues ; 3A + add_tx_pre VermilionGymTrashSuccesText1 ; 3B + add_tx_pre VermilionGymTrashSuccesText2 ; 3C + add_tx_pre VermilionGymTrashSuccesText3 ; 3D + add_tx_pre VermilionGymTrashFailText ; 3E + add_tx_pre TownMapText ; 3F + add_tx_pre BookOrSculptureText ; 40 + add_tx_pre ElevatorText ; 41 + add_tx_pre PokemonStuffText ; 42 diff --git a/home/copy.asm b/home/copy.asm new file mode 100644 index 00000000..be9c8c0c --- /dev/null +++ b/home/copy.asm @@ -0,0 +1,24 @@ +FarCopyData:: +; Copy bc bytes from a:hl to de. + ld [wBuffer], a + ld a, [H_LOADEDROMBANK] + push af + ld a, [wBuffer] + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + call CopyData + pop af + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + ret + +CopyData:: +; Copy bc bytes from hl to de. + ld a, [hli] + ld [de], a + inc de + dec bc + ld a, c + or b + jr nz, CopyData + ret diff --git a/home/copy2.asm b/home/copy2.asm new file mode 100644 index 00000000..7b407cdc --- /dev/null +++ b/home/copy2.asm @@ -0,0 +1,228 @@ +FarCopyData2:: +; Identical to FarCopyData, but uses $ff8b +; as temp space instead of wBuffer. + ld [$ff8b],a + ld a,[H_LOADEDROMBANK] + push af + ld a,[$ff8b] + ld [H_LOADEDROMBANK],a + ld [MBC1RomBank],a + call CopyData + pop af + ld [H_LOADEDROMBANK],a + ld [MBC1RomBank],a + ret + +FarCopyData3:: +; Copy bc bytes from a:de to hl. + ld [$ff8b],a + ld a,[H_LOADEDROMBANK] + push af + ld a,[$ff8b] + ld [H_LOADEDROMBANK],a + ld [MBC1RomBank],a + push hl + push de + push de + ld d,h + ld e,l + pop hl + call CopyData + pop de + pop hl + pop af + ld [H_LOADEDROMBANK],a + ld [MBC1RomBank],a + ret + +FarCopyDataDouble:: +; Expand bc bytes of 1bpp image data +; from a:hl to 2bpp data at de. + ld [$ff8b],a + ld a,[H_LOADEDROMBANK] + push af + ld a,[$ff8b] + ld [H_LOADEDROMBANK],a + ld [MBC1RomBank],a +.loop + ld a,[hli] + ld [de],a + inc de + ld [de],a + inc de + dec bc + ld a,c + or b + jr nz,.loop + pop af + ld [H_LOADEDROMBANK],a + ld [MBC1RomBank],a + ret + +CopyVideoData:: +; Wait for the next VBlank, then copy c 2bpp +; tiles from b:de to hl, 8 tiles at a time. +; This takes c/8 frames. + + ld a, [H_AUTOBGTRANSFERENABLED] + push af + xor a ; disable auto-transfer while copying + ld [H_AUTOBGTRANSFERENABLED], a + + ld a, [H_LOADEDROMBANK] + ld [$ff8b], a + + ld a, b + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + + ld a, e + ld [H_VBCOPYSRC], a + ld a, d + ld [H_VBCOPYSRC + 1], a + + ld a, l + ld [H_VBCOPYDEST], a + ld a, h + ld [H_VBCOPYDEST + 1], a + +.loop + ld a, c + cp 8 + jr nc, .keepgoing + +.done + ld [H_VBCOPYSIZE], a + call DelayFrame + ld a, [$ff8b] + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + pop af + ld [H_AUTOBGTRANSFERENABLED], a + ret + +.keepgoing + ld a, 8 + ld [H_VBCOPYSIZE], a + call DelayFrame + ld a, c + sub 8 + ld c, a + jr .loop + +CopyVideoDataDouble:: +; Wait for the next VBlank, then copy c 1bpp +; tiles from b:de to hl, 8 tiles at a time. +; This takes c/8 frames. + ld a, [H_AUTOBGTRANSFERENABLED] + push af + xor a ; disable auto-transfer while copying + ld [H_AUTOBGTRANSFERENABLED], a + ld a, [H_LOADEDROMBANK] + ld [$ff8b], a + + ld a, b + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + + ld a, e + ld [H_VBCOPYDOUBLESRC], a + ld a, d + ld [H_VBCOPYDOUBLESRC + 1], a + + ld a, l + ld [H_VBCOPYDOUBLEDEST], a + ld a, h + ld [H_VBCOPYDOUBLEDEST + 1], a + +.loop + ld a, c + cp 8 + jr nc, .keepgoing + +.done + ld [H_VBCOPYDOUBLESIZE], a + call DelayFrame + ld a, [$ff8b] + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + pop af + ld [H_AUTOBGTRANSFERENABLED], a + ret + +.keepgoing + ld a, 8 + ld [H_VBCOPYDOUBLESIZE], a + call DelayFrame + ld a, c + sub 8 + ld c, a + jr .loop + +ClearScreenArea:: +; Clear tilemap area cxb at hl. + ld a, $7f ; blank tile + ld de, 20 ; screen width +.y + push hl + push bc +.x + ld [hli], a + dec c + jr nz, .x + pop bc + pop hl + add hl, de + dec b + jr nz, .y + ret + +CopyScreenTileBufferToVRAM:: +; Copy wTileMap to the BG Map starting at b * $100. +; This is done in thirds of 6 rows, so it takes 3 frames. + + ld c, 6 + + ld hl, $600 * 0 + ld de, wTileMap + 20 * 6 * 0 + call .setup + call DelayFrame + + ld hl, $600 * 1 + ld de, wTileMap + 20 * 6 * 1 + call .setup + call DelayFrame + + ld hl, $600 * 2 + ld de, wTileMap + 20 * 6 * 2 + call .setup + jp DelayFrame + +.setup + ld a, d + ld [H_VBCOPYBGSRC+1], a + call GetRowColAddressBgMap + ld a, l + ld [H_VBCOPYBGDEST], a + ld a, h + ld [H_VBCOPYBGDEST+1], a + ld a, c + ld [H_VBCOPYBGNUMROWS], a + ld a, e + ld [H_VBCOPYBGSRC], a + ret + +ClearScreen:: +; Clear wTileMap, then wait +; for the bg map to update. + ld bc, 20 * 18 + inc b + ld hl, wTileMap + ld a, $7f +.loop + ld [hli], a + dec c + jr nz, .loop + dec b + jr nz, .loop + jp Delay3 diff --git a/home/serial.asm b/home/serial.asm new file mode 100644 index 00000000..02eb3534 --- /dev/null +++ b/home/serial.asm @@ -0,0 +1,304 @@ +Serial:: ; 2125 (0:2125) + push af + push bc + push de + push hl + ld a, [$ffaa] + inc a + jr z, .asm_2142 + ld a, [$ff01] + ld [$ffad], a + ld a, [$ffac] + ld [$ff01], a + ld a, [$ffaa] + cp $2 + jr z, .asm_2162 + ld a, $80 + ld [$ff02], a + jr .asm_2162 +.asm_2142 + ld a, [$ff01] + ld [$ffad], a + ld [$ffaa], a + cp $2 + jr z, .asm_215f + xor a + ld [$ff01], a + ld a, $3 + ld [rDIV], a ; $ff04 +.asm_2153 + ld a, [rDIV] ; $ff04 + bit 7, a + jr nz, .asm_2153 + ld a, $80 + ld [$ff02], a + jr .asm_2162 +.asm_215f + xor a + ld [$ff01], a +.asm_2162 + ld a, $1 + ld [$ffa9], a + ld a, $fe + ld [$ffac], a + pop hl + pop de + pop bc + pop af + reti + +Func_216f:: ; 216f (0:216f) + ld a, $1 + ld [$ffab], a +.asm_2173 + ld a, [hl] + ld [$ffac], a + call Func_219a + push bc + ld b, a + inc hl + ld a, $30 +.asm_217e + dec a + jr nz, .asm_217e + ld a, [$ffab] + and a + ld a, b + pop bc + jr z, .asm_2192 + dec hl + cp $fd + jr nz, .asm_2173 + xor a + ld [$ffab], a + jr .asm_2173 +.asm_2192 + ld [de], a + inc de + dec bc + ld a, b + or c + jr nz, .asm_2173 + ret + +Func_219a:: ; 219a (0:219a) + xor a + ld [$ffa9], a + ld a, [$ffaa] + cp $2 + jr nz, .asm_21a7 + ld a, $81 + ld [$ff02], a +.asm_21a7 + ld a, [$ffa9] + and a + jr nz, .asm_21f1 + ld a, [$ffaa] + cp $1 + jr nz, .asm_21cc + call Func_2237 + jr z, .asm_21cc + call Func_2231 + push hl + ld hl, wcc48 + inc [hl] + jr nz, .asm_21c3 + dec hl + inc [hl] +.asm_21c3 + pop hl + call Func_2237 + jr nz, .asm_21a7 + jp Func_223f +.asm_21cc + ld a, [rIE] ; $ffff + and $f + cp $8 + jr nz, .asm_21a7 + ld a, [W_NUMHITS] ; wd074 + dec a + ld [W_NUMHITS], a ; wd074 + jr nz, .asm_21a7 + ld a, [wd075] + dec a + ld [wd075], a + jr nz, .asm_21a7 + ld a, [$ffaa] + cp $1 + jr z, .asm_21f1 + ld a, $ff +.asm_21ee + dec a + jr nz, .asm_21ee +.asm_21f1 + xor a + ld [$ffa9], a + ld a, [rIE] ; $ffff + and $f + sub $8 + jr nz, .asm_2204 + ld [W_NUMHITS], a ; wd074 + ld a, $50 + ld [wd075], a +.asm_2204 + ld a, [$ffad] + cp $fe + ret nz + call Func_2237 + jr z, .asm_221f + push hl + ld hl, wcc48 + ld a, [hl] + dec a + ld [hld], a + inc a + jr nz, .asm_2219 + dec [hl] +.asm_2219 + pop hl + call Func_2237 + jr z, Func_223f +.asm_221f + ld a, [rIE] ; $ffff + and $f + cp $8 + ld a, $fe + ret z + ld a, [hl] + ld [$ffac], a + call DelayFrame + jp Func_219a + +Func_2231:: ; 2231 (0:2231) + ld a, $f +.asm_2233 + dec a + jr nz, .asm_2233 + ret + +Func_2237:: ; 2237 (0:2237) + push hl + ld hl, wcc47 + ld a, [hli] + or [hl] + pop hl + ret + +Func_223f:: ; 223f (0:223f) + dec a + ld [wcc47], a + ld [wcc48], a + ret + +Func_2247:: ; 2247 (0:2247) + ld hl, wcc42 + ld de, wcc3d + ld c, $2 + ld a, $1 + ld [$ffab], a +.asm_2253 + call DelayFrame + ld a, [hl] + ld [$ffac], a + call Func_219a + ld b, a + inc hl + ld a, [$ffab] + and a + ld a, $0 + ld [$ffab], a + jr nz, .asm_2253 + ld a, b + ld [de], a + inc de + dec c + jr nz, .asm_2253 + ret + +Func_226e:: ; 226e (0:226e) + call SaveScreenTilesToBuffer1 + callab PrintWaitingText + call Func_227f + jp LoadScreenTilesFromBuffer1 + +Func_227f:: ; 227f (0:227f) + ld a, $ff + ld [wcc3e], a +.asm_2284 + call Func_22c3 + call DelayFrame + call Func_2237 + jr z, .asm_22a0 + push hl + ld hl, wcc48 + dec [hl] + jr nz, .asm_229f + dec hl + dec [hl] + jr nz, .asm_229f + pop hl + xor a + jp Func_223f +.asm_229f + pop hl +.asm_22a0 + ld a, [wcc3e] + inc a + jr z, .asm_2284 + ld b, $a +.asm_22a8 + call DelayFrame + call Func_22c3 + dec b + jr nz, .asm_22a8 + ld b, $a +.asm_22b3 + call DelayFrame + call Func_22ed + dec b + jr nz, .asm_22b3 + ld a, [wcc3e] + ld [wcc3d], a + ret + +Func_22c3:: ; 22c3 (0:22c3) + call asm_22d7 + ld a, [wcc42] + add $60 + ld [$ffac], a + ld a, [$ffaa] + cp $2 + jr nz, asm_22d7 + ld a, $81 + ld [$ff02], a +asm_22d7:: ; 22d7 (0:22d7) + ld a, [$ffad] + ld [wcc3d], a + and $f0 + cp $60 + ret nz + xor a + ld [$ffad], a + ld a, [wcc3d] + and $f + ld [wcc3e], a + ret + +Func_22ed:: ; 22ed (0:22ed) + xor a + ld [$ffac], a + ld a, [$ffaa] + cp $2 + ret nz + ld a, $81 + ld [$ff02], a + ret + +Func_22fa:: ; 22fa (0:22fa) + ld a, $2 + ld [$ff01], a + xor a + ld [$ffad], a + ld a, $80 + ld [$ff02], a + ret diff --git a/home/timer.asm b/home/timer.asm new file mode 100644 index 00000000..8578df1a --- /dev/null +++ b/home/timer.asm @@ -0,0 +1,3 @@ +; timer interrupt is apparently not invoked anyway +Timer:: ; 2306 (0:2306) + reti @@ -1,8 +1,8 @@ -H_SPRITEWIDTH EQU $FF8B ; in bytes +H_SPRITEWIDTH EQU $FF8B ; in tiles H_SPRITEINTERLACECOUNTER EQU $FF8B -H_SPRITEHEIGHT EQU $FF8C ; in bytes -H_SPRITEOFFSET EQU $FF8D +H_SPRITEHEIGHT EQU $FF8C ; in tiles +H_SPRITEOFFSET EQU $FF8D hSoftReset EQU $FF8A ; Initialized to 16. @@ -20,33 +20,36 @@ H_SPRITEINDEX EQU $FF8C ; DisplayTextID's argument hSpriteIndexOrTextID EQU $FF8C -; Note: the following multiplication and division addresses are used for multiple purposes -; and so they overlap with each other +; Multiplcation and division variables are meant +; to overlap for back-to-back usage. Big endian. -H_MULTIPLICAND EQU $FF96 ; 3 bytes, big endian order +H_MULTIPLICAND EQU $FF96 ; 3 bytes H_MULTIPLIER EQU $FF99 ; 1 byte -H_PRODUCT EQU $FF95 ; 4 bytes, big endian order +H_PRODUCT EQU $FF95 ; 4 bytes -H_DIVIDEND EQU $FF95 ; 4 bytes, big endian order +H_DIVIDEND EQU $FF95 ; 4 bytes H_DIVISOR EQU $FF99 ; 1 byte -H_QUOTIENT EQU $FF95 ; 4 bytes, big endian order +H_QUOTIENT EQU $FF95 ; 4 bytes H_REMAINDER EQU $FF99 ; 1 byte -; used to convert numbers to decimal -H_PASTLEADINGZEROES EQU $FF95 ; flag to indicate that a nonzero digit has been printed -H_NUMTOPRINT EQU $FF96 ; 3 bytes, big endian order -H_POWEROFTEN EQU $FF99 ; 3 bytes, big endian order -H_SAVEDNUMTOPRINT EQU $FF9C ; 3 bytes, big endian order (to back out of a subtraction) +; PrintNumber (big endian). +H_PASTLEADINGZEROES EQU $FF95 ; last char printed +H_NUMTOPRINT EQU $FF96 ; 3 bytes +H_POWEROFTEN EQU $FF99 ; 3 bytes +H_SAVEDNUMTOPRINT EQU $FF9C ; 3 bytes ; these values are copied to SCX, SCY, and WY during V-blank hVBlankSCX EQU $FFAE hVBlankSCY EQU $FFAF hVBlankWY EQU $FFB0 -hJoyHeldLast EQU $FFB1 -hJoyReleased EQU $FFB2 -hJoyPressed EQU $FFB3 -hJoyHeld EQU $FFB4 +hJoyHeldLast EQU $FFB1 +hJoyReleased EQU $FFB2 +hJoyPressed EQU $FFB3 +hJoyHeld EQU $FFB4 +hJoy5 EQU $FFB5 +hJoy6 EQU $FFB6 +hJoy7 EQU $FFB7 H_LOADEDROMBANK EQU $FFB8 @@ -11,6 +11,20 @@ page EQUS "db $49," ; Start a new Pokedex page. dex EQUS "db $5f, $50" ; End a Pokedex entry. +percent EQUS "* $ff / 100" + + +; Constant enumeration is useful for monsters, items, moves, etc. +const_def: MACRO +const_value = 0 +ENDM + +const: MACRO +\1 EQU const_value +const_value = const_value + 1 +ENDM + + homecall: MACRO ld a, [H_LOADEDROMBANK] push af @@ -189,6 +203,24 @@ predef_jump: MACRO ENDM +add_tx_pre: MACRO +\1_id:: dw \1 +ENDM + +tx_pre_id: MACRO + ld a, (\1_id - TextPredefs) / 2 +ENDM + +tx_pre: MACRO + tx_pre_id \1 + call PrintPredefTextID +ENDM + +tx_pre_jump: MACRO + tx_pre_id \1 + jp PrintPredefTextID +ENDM + ;1_channel EQU $00 ;2_channels EQU $40 @@ -3528,7 +3528,7 @@ _AddPartyMon: ; f2e5 (3:72e5) .asm_f2f2 ld a, [de] inc a - cp $7 + cp PARTY_LENGTH + 1 ret nc ld [de], a ld a, [de] @@ -3790,7 +3790,7 @@ AddPartyMon_WriteMovePP: ; f476 (3:7476) _AddEnemyMonToPlayerParty: ; f49d (3:749d) ld hl, wPartyCount ld a, [hl] - cp $6 + cp PARTY_LENGTH scf ret z ; party full, return failure inc a @@ -3859,13 +3859,13 @@ Func_f51e: ; f51e (3:751e) jr z, .asm_f575 ld hl, W_NUMINBOX ; wda80 ld a, [hl] - cp $14 + cp MONS_PER_BOX jr nz, .partyOrBoxNotFull jr .boxFull .checkPartyMonSlots ld hl, wPartyCount ; wPartyCount ld a, [hl] - cp $6 + cp PARTY_LENGTH jr nz, .partyOrBoxNotFull .boxFull scf @@ -4008,7 +4008,7 @@ Func_f51e: ; f51e (3:751e) ld a, d ld [W_CURENEMYLVL], a ; W_CURENEMYLVL pop hl - ld bc, $21 + ld bc, wBoxMon2 - wBoxMon1 add hl, bc ld [hli], a ld d, h diff --git a/scripts/daycarem.asm b/scripts/daycarem.asm index f2bf3188..3190ba0a 100755 --- a/scripts/daycarem.asm +++ b/scripts/daycarem.asm @@ -67,9 +67,9 @@ DayCareMScript_562e1: ; 562e1 (15:62e1) call LoadMonData callab CalcLevelFromExperience ld a, d - cp $64 + cp MAX_LEVEL jr c, .asm_56315 - ld d, $64 + ld d, MAX_LEVEL callab CalcExperience ld hl, wDayCareMonExp ld a, [H_NUMTOPRINT] @@ -78,7 +78,7 @@ DayCareMScript_562e1: ; 562e1 (15:62e1) ld [hli], a ld a, [$ff98] ld [hl], a - ld d, $64 + ld d, MAX_LEVEL .asm_56315 xor a @@ -100,7 +100,7 @@ DayCareMScript_562e1: ; 562e1 (15:62e1) .asm_56333 call PrintText ld a, [wPartyCount] - cp $6 + cp PARTY_LENGTH ld hl, DayCareMText_56440 jp z, .asm_56403 ld de, wTrainerFacingDirection diff --git a/scripts/route5gate.asm b/scripts/route5gate.asm index 87acd01a..bee70e77 100755 --- a/scripts/route5gate.asm +++ b/scripts/route5gate.asm @@ -27,11 +27,11 @@ Route5GateScript0: ; 1df50 (7:5f50) xor a ld [hJoyHeld], a callba RemoveGuardDrink - ld a, [$ff00+$db] + ld a, [$ffdb] and a jr nz, .asm_1df82 ; 0x1df70 $10 ld a, $2 - ld [$ff00+$8c], a + ld [$ff8c], a call DisplayTextID call Route5GateScript_1df43 ld a, $1 @@ -39,7 +39,7 @@ Route5GateScript0: ; 1df50 (7:5f50) ret .asm_1df82 ld a, $3 - ld [$ff00+$8c], a + ld [$ff8c], a call DisplayTextID ld hl, wd728 set 6, [hl] @@ -74,7 +74,7 @@ Route5GateText1: ; 1dfaa (7:5faa) bit 6, a jr nz, .asm_88856 ; 0x1dfb0 $2c callba RemoveGuardDrink - ld a, [$ff00+$db] + ld a, [$ffdb] and a jr nz, .asm_768a2 ; 0x1dfbd $11 ld hl, Route5GateText2 diff --git a/version.asm b/version.asm index 6f80aa1c..7d9fa036 100644 --- a/version.asm +++ b/version.asm @@ -1,20 +1,11 @@ -if !def(_RED) -_RED EQU 0 -endc - -if !def(_BLUE) -_BLUE EQU 0 -endc - -if !def(_JAPAN) -_JAPAN EQU 0 -endc - -if !def(_GREEN) -_GREEN EQU 0 -endc - -if !def(_YELLOW) -_YELLOW EQU 0 +check_ver: MACRO +if !def(\1) +\1 EQU 0 endc +ENDM + check_ver _RED + check_ver _BLUE + check_ver _JAPAN + check_ver _GREEN + check_ver _YELLOW |