shithub: pokered

Download patch

ref: bf67f7174d8e3f1348c786618ee5a3a076d1eff8
parent: 10289bf7ddac46d0188da06f2714dbce0dece59c
author: YamaArashi <shadow962@live.com>
date: Sat Dec 31 12:23:54 EST 2016

split code out of main.asm

--- /dev/null
+++ b/engine/add_mon.asm
@@ -1,0 +1,512 @@
+_AddPartyMon:
+; Adds a new mon to the player's or enemy's party.
+; [wMonDataLocation] is used in an unusual way in this function.
+; If the lower nybble is 0, the mon is added to the player's party, else the enemy's.
+; If the entire value is 0, then the player is allowed to name the mon.
+	ld de, wPartyCount
+	ld a, [wMonDataLocation]
+	and $f
+	jr z, .next
+	ld de, wEnemyPartyCount
+.next
+	ld a, [de]
+	inc a
+	cp PARTY_LENGTH + 1
+	ret nc ; return if the party is already full
+	ld [de], a
+	ld a, [de]
+	ld [hNewPartyLength], a
+	add e
+	ld e, a
+	jr nc, .noCarry
+	inc d
+.noCarry
+	ld a, [wcf91]
+	ld [de], a ; write species of new mon in party list
+	inc de
+	ld a, $ff ; terminator
+	ld [de], a
+	ld hl, wPartyMonOT
+	ld a, [wMonDataLocation]
+	and $f
+	jr z, .next2
+	ld hl, wEnemyMonOT
+.next2
+	ld a, [hNewPartyLength]
+	dec a
+	call SkipFixedLengthTextEntries
+	ld d, h
+	ld e, l
+	ld hl, wPlayerName
+	ld bc, NAME_LENGTH
+	call CopyData
+	ld a, [wMonDataLocation]
+	and a
+	jr nz, .skipNaming
+	ld hl, wPartyMonNicks
+	ld a, [hNewPartyLength]
+	dec a
+	call SkipFixedLengthTextEntries
+	ld a, NAME_MON_SCREEN
+	ld [wNamingScreenType], a
+	predef AskName
+.skipNaming
+	ld hl, wPartyMons
+	ld a, [wMonDataLocation]
+	and $f
+	jr z, .next3
+	ld hl, wEnemyMons
+.next3
+	ld a, [hNewPartyLength]
+	dec a
+	ld bc, wPartyMon2 - wPartyMon1
+	call AddNTimes
+	ld e, l
+	ld d, h
+	push hl
+	ld a, [wcf91]
+	ld [wd0b5], a
+	call GetMonHeader
+	ld hl, wMonHeader
+	ld a, [hli]
+	ld [de], a ; species
+	inc de
+	pop hl
+	push hl
+	ld a, [wMonDataLocation]
+	and $f
+	ld a, $98     ; set enemy trainer mon IVs to fixed average values
+	ld b, $88
+	jr nz, .next4
+
+; If the mon is being added to the player's party, update the pokedex.
+	ld a, [wcf91]
+	ld [wd11e], a
+	push de
+	predef IndexToPokedex
+	pop de
+	ld a, [wd11e]
+	dec a
+	ld c, a
+	ld b, FLAG_TEST
+	ld hl, wPokedexOwned
+	call FlagAction
+	ld a, c ; whether the mon was already flagged as owned
+	ld [wUnusedD153], a ; not read
+	ld a, [wd11e]
+	dec a
+	ld c, a
+	ld b, FLAG_SET
+	push bc
+	call FlagAction
+	pop bc
+	ld hl, wPokedexSeen
+	call FlagAction
+
+	pop hl
+	push hl
+
+	ld a, [wIsInBattle]
+	and a ; is this a wild mon caught in battle?
+	jr nz, .copyEnemyMonData
+
+; Not wild.
+	call Random ; generate random IVs
+	ld b, a
+	call Random
+
+.next4
+	push bc
+	ld bc, wPartyMon1DVs - wPartyMon1
+	add hl, bc
+	pop bc
+	ld [hli], a
+	ld [hl], b         ; write IVs
+	ld bc, (wPartyMon1HPExp - 1) - (wPartyMon1DVs + 1)
+	add hl, bc
+	ld a, 1
+	ld c, a
+	xor a
+	ld b, a
+	call CalcStat      ; calc HP stat (set cur Hp to max HP)
+	ld a, [H_MULTIPLICAND+1]
+	ld [de], a
+	inc de
+	ld a, [H_MULTIPLICAND+2]
+	ld [de], a
+	inc de
+	xor a
+	ld [de], a         ; box level
+	inc de
+	ld [de], a         ; status ailments
+	inc de
+	jr .copyMonTypesAndMoves
+.copyEnemyMonData
+	ld bc, wEnemyMon1DVs - wEnemyMon1
+	add hl, bc
+	ld a, [wEnemyMonDVs] ; copy IVs from cur enemy mon
+	ld [hli], a
+	ld a, [wEnemyMonDVs + 1]
+	ld [hl], a
+	ld a, [wEnemyMonHP]    ; copy HP from cur enemy mon
+	ld [de], a
+	inc de
+	ld a, [wEnemyMonHP+1]
+	ld [de], a
+	inc de
+	xor a
+	ld [de], a                ; box level
+	inc de
+	ld a, [wEnemyMonStatus]   ; copy status ailments from cur enemy mon
+	ld [de], a
+	inc de
+.copyMonTypesAndMoves
+	ld hl, wMonHTypes
+	ld a, [hli]       ; type 1
+	ld [de], a
+	inc de
+	ld a, [hli]       ; type 2
+	ld [de], a
+	inc de
+	ld a, [hli]       ; catch rate (held item in gen 2)
+	ld [de], a
+	ld hl, wMonHMoves
+	ld a, [hli]
+	inc de
+	push de
+	ld [de], a
+	ld a, [hli]
+	inc de
+	ld [de], a
+	ld a, [hli]
+	inc de
+	ld [de], a
+	ld a, [hli]
+	inc de
+	ld [de], a
+	push de
+	dec de
+	dec de
+	dec de
+	xor a
+	ld [wLearningMovesFromDayCare], a
+	predef WriteMonMoves
+	pop de
+	ld a, [wPlayerID]  ; set trainer ID to player ID
+	inc de
+	ld [de], a
+	ld a, [wPlayerID + 1]
+	inc de
+	ld [de], a
+	push de
+	ld a, [wCurEnemyLVL]
+	ld d, a
+	callab CalcExperience
+	pop de
+	inc de
+	ld a, [hExperience] ; write experience
+	ld [de], a
+	inc de
+	ld a, [hExperience + 1]
+	ld [de], a
+	inc de
+	ld a, [hExperience + 2]
+	ld [de], a
+	xor a
+	ld b, NUM_STATS * 2
+.writeEVsLoop              ; set all EVs to 0
+	inc de
+	ld [de], a
+	dec b
+	jr nz, .writeEVsLoop
+	inc de
+	inc de
+	pop hl
+	call AddPartyMon_WriteMovePP
+	inc de
+	ld a, [wCurEnemyLVL]
+	ld [de], a
+	inc de
+	ld a, [wIsInBattle]
+	dec a
+	jr nz, .calcFreshStats
+	ld hl, wEnemyMonMaxHP
+	ld bc, $a
+	call CopyData          ; copy stats of cur enemy mon
+	pop hl
+	jr .done
+.calcFreshStats
+	pop hl
+	ld bc, wPartyMon1HPExp - 1 - wPartyMon1
+	add hl, bc
+	ld b, $0
+	call CalcStats         ; calculate fresh set of stats
+.done
+	scf
+	ret
+
+LoadMovePPs:
+	call GetPredefRegisters
+	; fallthrough
+AddPartyMon_WriteMovePP:
+	ld b, NUM_MOVES
+.pploop
+	ld a, [hli]     ; read move ID
+	and a
+	jr z, .empty
+	dec a
+	push hl
+	push de
+	push bc
+	ld hl, Moves
+	ld bc, MoveEnd - Moves
+	call AddNTimes
+	ld de, wcd6d
+	ld a, BANK(Moves)
+	call FarCopyData
+	pop bc
+	pop de
+	pop hl
+	ld a, [wcd6d + 5] ; PP is byte 5 of move data
+.empty
+	inc de
+	ld [de], a
+	dec b
+	jr nz, .pploop ; there are still moves to read
+	ret
+
+; adds enemy mon [wcf91] (at position [wWhichPokemon] in enemy list) to own party
+; used in the cable club trade center
+_AddEnemyMonToPlayerParty:
+	ld hl, wPartyCount
+	ld a, [hl]
+	cp PARTY_LENGTH
+	scf
+	ret z            ; party full, return failure
+	inc a
+	ld [hl], a       ; add 1 to party members
+	ld c, a
+	ld b, $0
+	add hl, bc
+	ld a, [wcf91]
+	ld [hli], a      ; add mon as last list entry
+	ld [hl], $ff     ; write new sentinel
+	ld hl, wPartyMons
+	ld a, [wPartyCount]
+	dec a
+	ld bc, wPartyMon2 - wPartyMon1
+	call AddNTimes
+	ld e, l
+	ld d, h
+	ld hl, wLoadedMon
+	call CopyData    ; write new mon's data (from wLoadedMon)
+	ld hl, wPartyMonOT
+	ld a, [wPartyCount]
+	dec a
+	call SkipFixedLengthTextEntries
+	ld d, h
+	ld e, l
+	ld hl, wEnemyMonOT
+	ld a, [wWhichPokemon]
+	call SkipFixedLengthTextEntries
+	ld bc, NAME_LENGTH
+	call CopyData    ; write new mon's OT name (from an enemy mon)
+	ld hl, wPartyMonNicks
+	ld a, [wPartyCount]
+	dec a
+	call SkipFixedLengthTextEntries
+	ld d, h
+	ld e, l
+	ld hl, wEnemyMonNicks
+	ld a, [wWhichPokemon]
+	call SkipFixedLengthTextEntries
+	ld bc, NAME_LENGTH
+	call CopyData    ; write new mon's nickname (from an enemy mon)
+	ld a, [wcf91]
+	ld [wd11e], a
+	predef IndexToPokedex
+	ld a, [wd11e]
+	dec a
+	ld c, a
+	ld b, FLAG_SET
+	ld hl, wPokedexOwned
+	push bc
+	call FlagAction ; add to owned pokemon
+	pop bc
+	ld hl, wPokedexSeen
+	call FlagAction ; add to seen pokemon
+	and a
+	ret                  ; return success
+
+_MoveMon:
+	ld a, [wMoveMonType]
+	and a
+	jr z, .checkPartyMonSlots
+	cp DAYCARE_TO_PARTY
+	jr z, .checkPartyMonSlots
+	cp PARTY_TO_DAYCARE
+	ld hl, wDayCareMon
+	jr z, .asm_f575
+	ld hl, wNumInBox
+	ld a, [hl]
+	cp MONS_PER_BOX
+	jr nz, .partyOrBoxNotFull
+	jr .boxFull
+.checkPartyMonSlots
+	ld hl, wPartyCount
+	ld a, [hl]
+	cp PARTY_LENGTH
+	jr nz, .partyOrBoxNotFull
+.boxFull
+	scf
+	ret
+.partyOrBoxNotFull
+	inc a
+	ld [hl], a           ; increment number of mons in party/box
+	ld c, a
+	ld b, 0
+	add hl, bc
+	ld a, [wMoveMonType]
+	cp DAYCARE_TO_PARTY
+	ld a, [wDayCareMon]
+	jr z, .asm_f556
+	ld a, [wcf91]
+.asm_f556
+	ld [hli], a          ; write new mon ID
+	ld [hl], $ff         ; write new sentinel
+	ld a, [wMoveMonType]
+	dec a
+	ld hl, wPartyMons
+	ld bc, wPartyMon2 - wPartyMon1 ; $2c
+	ld a, [wPartyCount]
+	jr nz, .skipToNewMonEntry
+	ld hl, wBoxMons
+	ld bc, wBoxMon2 - wBoxMon1 ; $21
+	ld a, [wNumInBox]
+.skipToNewMonEntry
+	dec a
+	call AddNTimes
+.asm_f575
+	push hl
+	ld e, l
+	ld d, h
+	ld a, [wMoveMonType]
+	and a
+	ld hl, wBoxMons
+	ld bc, wBoxMon2 - wBoxMon1 ; $21
+	jr z, .asm_f591
+	cp DAYCARE_TO_PARTY
+	ld hl, wDayCareMon
+	jr z, .asm_f597
+	ld hl, wPartyMons
+	ld bc, wPartyMon2 - wPartyMon1 ; $2c
+.asm_f591
+	ld a, [wWhichPokemon]
+	call AddNTimes
+.asm_f597
+	push hl
+	push de
+	ld bc, wBoxMon2 - wBoxMon1
+	call CopyData
+	pop de
+	pop hl
+	ld a, [wMoveMonType]
+	and a
+	jr z, .asm_f5b4
+	cp DAYCARE_TO_PARTY
+	jr z, .asm_f5b4
+	ld bc, wBoxMon2 - wBoxMon1
+	add hl, bc
+	ld a, [hl]
+	inc de
+	inc de
+	inc de
+	ld [de], a
+.asm_f5b4
+	ld a, [wMoveMonType]
+	cp PARTY_TO_DAYCARE
+	ld de, wDayCareMonOT
+	jr z, .asm_f5d3
+	dec a
+	ld hl, wPartyMonOT
+	ld a, [wPartyCount]
+	jr nz, .asm_f5cd
+	ld hl, wBoxMonOT
+	ld a, [wNumInBox]
+.asm_f5cd
+	dec a
+	call SkipFixedLengthTextEntries
+	ld d, h
+	ld e, l
+.asm_f5d3
+	ld hl, wBoxMonOT
+	ld a, [wMoveMonType]
+	and a
+	jr z, .asm_f5e6
+	ld hl, wDayCareMonOT
+	cp DAYCARE_TO_PARTY
+	jr z, .asm_f5ec
+	ld hl, wPartyMonOT
+.asm_f5e6
+	ld a, [wWhichPokemon]
+	call SkipFixedLengthTextEntries
+.asm_f5ec
+	ld bc, NAME_LENGTH
+	call CopyData
+	ld a, [wMoveMonType]
+	cp PARTY_TO_DAYCARE
+	ld de, wDayCareMonName
+	jr z, .asm_f611
+	dec a
+	ld hl, wPartyMonNicks
+	ld a, [wPartyCount]
+	jr nz, .asm_f60b
+	ld hl, wBoxMonNicks
+	ld a, [wNumInBox]
+.asm_f60b
+	dec a
+	call SkipFixedLengthTextEntries
+	ld d, h
+	ld e, l
+.asm_f611
+	ld hl, wBoxMonNicks
+	ld a, [wMoveMonType]
+	and a
+	jr z, .asm_f624
+	ld hl, wDayCareMonName
+	cp DAYCARE_TO_PARTY
+	jr z, .asm_f62a
+	ld hl, wPartyMonNicks
+.asm_f624
+	ld a, [wWhichPokemon]
+	call SkipFixedLengthTextEntries
+.asm_f62a
+	ld bc, NAME_LENGTH
+	call CopyData
+	pop hl
+	ld a, [wMoveMonType]
+	cp PARTY_TO_BOX
+	jr z, .asm_f664
+	cp PARTY_TO_DAYCARE
+	jr z, .asm_f664
+	push hl
+	srl a
+	add $2
+	ld [wMonDataLocation], a
+	call LoadMonData
+	callba CalcLevelFromExperience
+	ld a, d
+	ld [wCurEnemyLVL], a
+	pop hl
+	ld bc, wBoxMon2 - wBoxMon1
+	add hl, bc
+	ld [hli], a
+	ld d, h
+	ld e, l
+	ld bc, -18
+	add hl, bc
+	ld b, $1
+	call CalcStats
+.asm_f664
+	and a
+	ret
--- /dev/null
+++ b/engine/bcd.asm
@@ -1,0 +1,212 @@
+DivideBCDPredef::
+DivideBCDPredef2::
+DivideBCDPredef3::
+DivideBCDPredef4::
+	call GetPredefRegisters
+
+DivideBCD::
+	xor a
+	ld [$ffa5], a
+	ld [$ffa6], a
+	ld [$ffa7], a
+	ld d, $1
+.asm_f72a
+	ld a, [$ffa2]
+	and $f0
+	jr nz, .asm_f75b
+	inc d
+	ld a, [$ffa2]
+	swap a
+	and $f0
+	ld b, a
+	ld a, [$ffa3]
+	swap a
+	ld [$ffa3], a
+	and $f
+	or b
+	ld [$ffa2], a
+	ld a, [$ffa3]
+	and $f0
+	ld b, a
+	ld a, [$ffa4]
+	swap a
+	ld [$ffa4], a
+	and $f
+	or b
+	ld [$ffa3], a
+	ld a, [$ffa4]
+	and $f0
+	ld [$ffa4], a
+	jr .asm_f72a
+.asm_f75b
+	push de
+	push de
+	call DivideBCD_f800
+	pop de
+	ld a, b
+	swap a
+	and $f0
+	ld [$ffa5], a
+	dec d
+	jr z, .asm_f7bc
+	push de
+	call DivideBCD_f7d7
+	call DivideBCD_f800
+	pop de
+	ld a, [$ffa5]
+	or b
+	ld [$ffa5], a
+	dec d
+	jr z, .asm_f7bc
+	push de
+	call DivideBCD_f7d7
+	call DivideBCD_f800
+	pop de
+	ld a, b
+	swap a
+	and $f0
+	ld [$ffa6], a
+	dec d
+	jr z, .asm_f7bc
+	push de
+	call DivideBCD_f7d7
+	call DivideBCD_f800
+	pop de
+	ld a, [$ffa6]
+	or b
+	ld [$ffa6], a
+	dec d
+	jr z, .asm_f7bc
+	push de
+	call DivideBCD_f7d7
+	call DivideBCD_f800
+	pop de
+	ld a, b
+	swap a
+	and $f0
+	ld [$ffa7], a
+	dec d
+	jr z, .asm_f7bc
+	push de
+	call DivideBCD_f7d7
+	call DivideBCD_f800
+	pop de
+	ld a, [$ffa7]
+	or b
+	ld [$ffa7], a
+.asm_f7bc
+	ld a, [$ffa5]
+	ld [$ffa2], a
+	ld a, [$ffa6]
+	ld [$ffa3], a
+	ld a, [$ffa7]
+	ld [$ffa4], a
+	pop de
+	ld a, $6
+	sub d
+	and a
+	ret z
+.asm_f7ce
+	push af
+	call DivideBCD_f7d7
+	pop af
+	dec a
+	jr nz, .asm_f7ce
+	ret
+
+DivideBCD_f7d7:
+	ld a, [$ffa4]
+	swap a
+	and $f
+	ld b, a
+	ld a, [$ffa3]
+	swap a
+	ld [$ffa3], a
+	and $f0
+	or b
+	ld [$ffa4], a
+	ld a, [$ffa3]
+	and $f
+	ld b, a
+	ld a, [$ffa2]
+	swap a
+	ld [$ffa2], a
+	and $f0
+	or b
+	ld [$ffa3], a
+	ld a, [$ffa2]
+	and $f
+	ld [$ffa2], a
+	ret
+
+DivideBCD_f800:
+	ld bc, $3
+.asm_f803
+	ld de, $ff9f
+	ld hl, $ffa2
+	push bc
+	call StringCmp
+	pop bc
+	ret c
+	inc b
+	ld de, $ffa1
+	ld hl, $ffa4
+	push bc
+	call SubBCD
+	pop bc
+	jr .asm_f803
+
+
+AddBCDPredef::
+	call GetPredefRegisters
+
+AddBCD::
+	and a
+	ld b, c
+.add
+	ld a, [de]
+	adc [hl]
+	daa
+	ld [de], a
+	dec de
+	dec hl
+	dec c
+	jr nz, .add
+	jr nc, .done
+	ld a, $99
+	inc de
+.fill
+	ld [de], a
+	inc de
+	dec b
+	jr nz, .fill
+.done
+	ret
+
+
+SubBCDPredef::
+	call GetPredefRegisters
+
+SubBCD::
+	and a
+	ld b, c
+.sub
+	ld a, [de]
+	sbc [hl]
+	daa
+	ld [de], a
+	dec de
+	dec hl
+	dec c
+	jr nz, .sub
+	jr nc, .done
+	ld a, $00
+	inc de
+.fill
+	ld [de], a
+	inc de
+	dec b
+	jr nz, .fill
+	scf
+.done
+	ret
--- a/engine/cable_club.asm
+++ b/engine/cable_club.asm
@@ -588,7 +588,7 @@
 	dec a
 	ld [wDestinationWarpID], a
 	call LoadMapData
-	callba ClearVariablesAfterLoadingMapData
+	callba ClearVariablesOnEnterMap
 	pop hl
 	pop af
 	ld [hl], a
--- /dev/null
+++ b/engine/flag_action.asm
@@ -1,0 +1,73 @@
+FlagActionPredef:
+	call GetPredefRegisters
+
+FlagAction:
+; Perform action b on bit c
+; in the bitfield at hl.
+;  0: reset
+;  1: set
+;  2: read
+; Return the result in c.
+
+	push hl
+	push de
+	push bc
+
+	; bit
+	ld a, c
+	ld d, a
+	and 7
+	ld e, a
+
+	; byte
+	ld a, d
+	srl a
+	srl a
+	srl a
+	add l
+	ld l, a
+	jr nc, .ok
+	inc h
+.ok
+
+	; d = 1 << e (bitmask)
+	inc e
+	ld d, 1
+.shift
+	dec e
+	jr z, .shifted
+	sla d
+	jr .shift
+.shifted
+
+	ld a, b
+	and a
+	jr z, .reset
+	cp 2
+	jr z, .read
+
+.set
+	ld b, [hl]
+	ld a, d
+	or b
+	ld [hl], a
+	jr .done
+
+.reset
+	ld b, [hl]
+	ld a, d
+	xor $ff
+	and b
+	ld [hl], a
+	jr .done
+
+.read
+	ld b, [hl]
+	ld a, d
+	and b
+.done
+	pop bc
+	pop de
+	pop hl
+	ld c, a
+	ret
--- /dev/null
+++ b/engine/get_bag_item_quantity.asm
@@ -1,0 +1,18 @@
+GetQuantityOfItemInBag:
+; In: b = item ID
+; Out: b = how many of that item are in the bag
+	call GetPredefRegisters
+	ld hl, wNumBagItems
+.loop
+	inc hl
+	ld a, [hli]
+	cp $ff
+	jr z, .notInBag
+	cp b
+	jr nz, .loop
+	ld a, [hl]
+	ld b, a
+	ret
+.notInBag
+	ld b, 0
+	ret
--- /dev/null
+++ b/engine/heal_party.asm
@@ -1,0 +1,99 @@
+HealParty:
+; Restore HP and PP.
+
+	ld hl, wPartySpecies
+	ld de, wPartyMon1HP
+.healmon
+	ld a, [hli]
+	cp $ff
+	jr z, .done
+
+	push hl
+	push de
+
+	ld hl, wPartyMon1Status - wPartyMon1HP
+	add hl, de
+	xor a
+	ld [hl], a
+
+	push de
+	ld b, NUM_MOVES ; A Pokémon has 4 moves
+.pp
+	ld hl, wPartyMon1Moves - wPartyMon1HP
+	add hl, de
+
+	ld a, [hl]
+	and a
+	jr z, .nextmove
+
+	dec a
+	ld hl, wPartyMon1PP - wPartyMon1HP
+	add hl, de
+
+	push hl
+	push de
+	push bc
+
+	ld hl, Moves
+	ld bc, MoveEnd - Moves
+	call AddNTimes
+	ld de, wcd6d
+	ld a, BANK(Moves)
+	call FarCopyData
+	ld a, [wcd6d + 5] ; PP is byte 5 of move data
+
+	pop bc
+	pop de
+	pop hl
+
+	inc de
+	push bc
+	ld b, a
+	ld a, [hl]
+	and $c0
+	add b
+	ld [hl], a
+	pop bc
+
+.nextmove
+	dec b
+	jr nz, .pp
+	pop de
+
+	ld hl, wPartyMon1MaxHP - wPartyMon1HP
+	add hl, de
+	ld a, [hli]
+	ld [de], a
+	inc de
+	ld a, [hl]
+	ld [de], a
+
+	pop de
+	pop hl
+
+	push hl
+	ld bc, wPartyMon2 - wPartyMon1
+	ld h, d
+	ld l, e
+	add hl, bc
+	ld d, h
+	ld e, l
+	pop hl
+	jr .healmon
+
+.done
+	xor a
+	ld [wWhichPokemon], a
+	ld [wd11e], a
+
+	ld a, [wPartyCount]
+	ld b, a
+.ppup
+	push bc
+	call RestoreBonusPP
+	pop bc
+	ld hl, wWhichPokemon
+	inc [hl]
+	dec b
+	jr nz, .ppup
+	ret
--- /dev/null
+++ b/engine/init_player_data.asm
@@ -1,0 +1,55 @@
+InitPlayerData:
+InitPlayerData2:
+
+	call Random
+	ld a, [hRandomSub]
+	ld [wPlayerID], a
+
+	call Random
+	ld a, [hRandomAdd]
+	ld [wPlayerID + 1], a
+
+	ld a, $ff
+	ld [wUnusedD71B], a
+
+	ld hl, wPartyCount
+	call InitializeEmptyList
+	ld hl, wNumInBox
+	call InitializeEmptyList
+	ld hl, wNumBagItems
+	call InitializeEmptyList
+	ld hl, wNumBoxItems
+	call InitializeEmptyList
+
+START_MONEY EQU $3000
+	ld hl, wPlayerMoney + 1
+	ld a, START_MONEY / $100
+	ld [hld], a
+	xor a
+	ld [hli], a
+	inc hl
+	ld [hl], a
+
+	ld [wMonDataLocation], a
+
+	ld hl, wObtainedBadges
+	ld [hli], a
+
+	ld [hl], a
+
+	ld hl, wPlayerCoins
+	ld [hli], a
+	ld [hl], a
+
+	ld hl, wGameProgressFlags
+	ld bc, wGameProgressFlagsEnd - wGameProgressFlags
+	call FillMemory ; clear all game progress flags
+
+	jp InitializeMissableObjectsFlags
+
+InitializeEmptyList:
+	xor a ; count
+	ld [hli], a
+	dec a ; terminator
+	ld [hl], a
+	ret
--- /dev/null
+++ b/engine/items/inventory.asm
@@ -1,0 +1,150 @@
+; function to add an item (in varying quantities) to the player's bag or PC box
+; INPUT:
+; hl = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wcf91] = item ID
+; [wItemQuantity] = item quantity
+; sets carry flag if successful, unsets carry flag if unsuccessful
+AddItemToInventory_:
+	ld a,[wItemQuantity] ; a = item quantity
+	push af
+	push bc
+	push de
+	push hl
+	push hl
+	ld d,PC_ITEM_CAPACITY ; how many items the PC can hold
+	ld a,wNumBagItems & $FF
+	cp l
+	jr nz,.checkIfInventoryFull
+	ld a,wNumBagItems >> 8
+	cp h
+	jr nz,.checkIfInventoryFull
+; if the destination is the bag
+	ld d,BAG_ITEM_CAPACITY ; how many items the bag can hold
+.checkIfInventoryFull
+	ld a,[hl]
+	sub d
+	ld d,a
+	ld a,[hli]
+	and a
+	jr z,.addNewItem
+.loop
+	ld a,[hli]
+	ld b,a ; b = ID of current item in table
+	ld a,[wcf91] ; a = ID of item being added
+	cp b ; does the current item in the table match the item being added?
+	jp z,.increaseItemQuantity ; if so, increase the item's quantity
+	inc hl
+	ld a,[hl]
+	cp a,$ff ; is it the end of the table?
+	jr nz,.loop
+.addNewItem ; add an item not yet in the inventory
+	pop hl
+	ld a,d
+	and a ; is there room for a new item slot?
+	jr z,.done
+; if there is room
+	inc [hl] ; increment the number of items in the inventory
+	ld a,[hl] ; the number of items will be the index of the new item
+	add a
+	dec a
+	ld c,a
+	ld b,0
+	add hl,bc ; hl = address to store the item
+	ld a,[wcf91]
+	ld [hli],a ; store item ID
+	ld a,[wItemQuantity]
+	ld [hli],a ; store item quantity
+	ld [hl],$ff ; store terminator
+	jp .success
+.increaseItemQuantity ; increase the quantity of an item already in the inventory
+	ld a,[wItemQuantity]
+	ld b,a ; b = quantity to add
+	ld a,[hl] ; a = existing item quantity
+	add b ; a = new item quantity
+	cp a,100
+	jp c,.storeNewQuantity ; if the new quantity is less than 100, store it
+; if the new quantity is greater than or equal to 100,
+; try to max out the current slot and add the rest in a new slot
+	sub a,99
+	ld [wItemQuantity],a ; a = amount left over (to put in the new slot)
+	ld a,d
+	and a ; is there room for a new item slot?
+	jr z,.increaseItemQuantityFailed
+; if so, store 99 in the current slot and store the rest in a new slot
+	ld a,99
+	ld [hli],a
+	jp .loop
+.increaseItemQuantityFailed
+	pop hl
+	and a
+	jr .done
+.storeNewQuantity
+	ld [hl],a
+	pop hl
+.success
+	scf
+.done
+	pop hl
+	pop de
+	pop bc
+	pop bc
+	ld a,b
+	ld [wItemQuantity],a ; restore the initial value from when the function was called
+	ret
+
+; function to remove an item (in varying quantities) from the player's bag or PC box
+; INPUT:
+; hl = address of inventory (either wNumBagItems or wNumBoxItems)
+; [wWhichPokemon] = index (within the inventory) of the item to remove
+; [wItemQuantity] = quantity to remove
+RemoveItemFromInventory_:
+	push hl
+	inc hl
+	ld a,[wWhichPokemon] ; index (within the inventory) of the item being removed
+	sla a
+	add l
+	ld l,a
+	jr nc,.noCarry
+	inc h
+.noCarry
+	inc hl
+	ld a,[wItemQuantity] ; quantity being removed
+	ld e,a
+	ld a,[hl] ; a = current quantity
+	sub e
+	ld [hld],a ; store new quantity
+	ld [wMaxItemQuantity],a
+	and a
+	jr nz,.skipMovingUpSlots
+; if the remaining quantity is 0,
+; remove the emptied item slot and move up all the following item slots
+.moveSlotsUp
+	ld e,l
+	ld d,h
+	inc de
+	inc de ; de = address of the slot following the emptied one
+.loop ; loop to move up the following slots
+	ld a,[de]
+	inc de
+	ld [hli],a
+	cp a,$ff
+	jr nz,.loop
+; update menu info
+	xor a
+	ld [wListScrollOffset],a
+	ld [wCurrentMenuItem],a
+	ld [wBagSavedMenuItem],a
+	ld [wSavedListScrollOffset],a
+	pop hl
+	ld a,[hl] ; a = number of items in inventory
+	dec a ; decrement the number of items
+	ld [hl],a ; store new number of items
+	ld [wListCount],a
+	cp a,2
+	jr c,.done
+	ld [wMaxMenuItem],a
+	jr .done
+.skipMovingUpSlots
+	pop hl
+.done
+	ret
--- /dev/null
+++ b/engine/menu/draw_badges.asm
@@ -1,0 +1,120 @@
+DrawBadges:
+; Draw 4x2 gym leader faces, with the faces replaced by
+; badges if they are owned. Used in the player status screen.
+
+; In Japanese versions, names are displayed above faces.
+; Instead of removing relevant code, the name graphics were erased.
+
+; Tile ids for face/badge graphics.
+	ld de, wBadgeOrFaceTiles
+	ld hl, .FaceBadgeTiles
+	ld bc, 8
+	call CopyData
+
+; Booleans for each badge.
+	ld hl, wTempObtainedBadgesBooleans
+	ld bc, 8
+	xor a
+	call FillMemory
+
+; Alter these based on owned badges.
+	ld de, wTempObtainedBadgesBooleans
+	ld hl, wBadgeOrFaceTiles
+	ld a, [wObtainedBadges]
+	ld b, a
+	ld c, 8
+.CheckBadge
+	srl b
+	jr nc, .NextBadge
+	ld a, [hl]
+	add 4 ; Badge graphics are after each face
+	ld [hl], a
+	ld a, 1
+	ld [de], a
+.NextBadge
+	inc hl
+	inc de
+	dec c
+	jr nz, .CheckBadge
+
+; Draw two rows of badges.
+	ld hl, wBadgeNumberTile
+	ld a, $d8 ; [1]
+	ld [hli], a
+	ld [hl], $60 ; First name
+
+	coord hl, 2, 11
+	ld de, wTempObtainedBadgesBooleans
+	call .DrawBadgeRow
+
+	coord hl, 2, 14
+	ld de, wTempObtainedBadgesBooleans + 4
+;	call .DrawBadgeRow
+;	ret
+
+.DrawBadgeRow
+; Draw 4 badges.
+
+	ld c, 4
+.DrawBadge
+	push de
+	push hl
+
+; Badge no.
+	ld a, [wBadgeNumberTile]
+	ld [hli], a
+	inc a
+	ld [wBadgeNumberTile], a
+
+; Names aren't printed if the badge is owned.
+	ld a, [de]
+	and a
+	ld a, [wBadgeNameTile]
+	jr nz, .SkipName
+	call .PlaceTiles
+	jr .PlaceBadge
+
+.SkipName
+	inc a
+	inc a
+	inc hl
+
+.PlaceBadge
+	ld [wBadgeNameTile], a
+	ld de, SCREEN_WIDTH - 1
+	add hl, de
+	ld a, [wBadgeOrFaceTiles]
+	call .PlaceTiles
+	add hl, de
+	call .PlaceTiles
+
+; Shift badge array back one byte.
+	push bc
+	ld hl, wBadgeOrFaceTiles + 1
+	ld de, wBadgeOrFaceTiles
+	ld bc, 8
+	call CopyData
+	pop bc
+
+	pop hl
+	ld de, 4
+	add hl, de
+
+	pop de
+	inc de
+	dec c
+	jr nz, .DrawBadge
+	ret
+
+.PlaceTiles
+	ld [hli], a
+	inc a
+	ld [hl], a
+	inc a
+	ret
+
+.FaceBadgeTiles
+	db $20, $28, $30, $38, $40, $48, $50, $58
+
+GymLeaderFaceAndBadgeTileGraphics:
+	INCBIN "gfx/badges.2bpp"
--- /dev/null
+++ b/engine/overworld/clear_variables.asm
@@ -1,0 +1,20 @@
+ClearVariablesOnEnterMap:
+	ld a, SCREEN_HEIGHT_PIXELS
+	ld [hWY], a
+	ld [rWY], a
+	xor a
+	ld [H_AUTOBGTRANSFERENABLED], a
+	ld [wStepCounter], a
+	ld [wLoneAttackNo], a
+	ld [hJoyPressed], a
+	ld [hJoyReleased], a
+	ld [hJoyHeld], a
+	ld [wActionResultOrTookBattleTurn], a
+	ld [wUnusedD5A3], a
+	ld hl, wCardKeyDoorY
+	ld [hli], a
+	ld [hl], a
+	ld hl, wWhichTrade
+	ld bc, wStandingOnWarpPadOrHole - wWhichTrade
+	call FillMemory
+	ret
--- /dev/null
+++ b/engine/overworld/daycare_exp.asm
@@ -1,0 +1,18 @@
+IncrementDayCareMonExp:
+	ld a, [wDayCareInUse]
+	and a
+	ret z
+	ld hl, wDayCareMonExp + 2
+	inc [hl]
+	ret nz
+	dec hl
+	inc [hl]
+	ret nz
+	dec hl
+	inc [hl]
+	ld a, [hl]
+	cp $50
+	ret c
+	ld a, $50
+	ld [hl], a
+	ret
--- /dev/null
+++ b/engine/overworld/field_move_messages.asm
@@ -1,0 +1,57 @@
+PrintStrengthTxt:
+	ld hl, wd728
+	set 0, [hl]
+	ld hl, UsedStrengthText
+	call PrintText
+	ld hl, CanMoveBouldersText
+	jp PrintText
+
+UsedStrengthText:
+	TX_FAR _UsedStrengthText
+	TX_ASM
+	ld a, [wcf91]
+	call PlayCry
+	call Delay3
+	jp TextScriptEnd
+
+CanMoveBouldersText:
+	TX_FAR _CanMoveBouldersText
+	db "@"
+
+IsSurfingAllowed:
+; Returns whether surfing is allowed in bit 1 of wd728.
+; Surfing isn't allowed on the Cycling Road or in the lowest level of the
+; Seafoam Islands before the current has been slowed with boulders.
+	ld hl, wd728
+	set 1, [hl]
+	ld a, [wd732]
+	bit 5, a
+	jr nz, .forcedToRideBike
+	ld a, [wCurMap]
+	cp SEAFOAM_ISLANDS_5
+	ret nz
+	CheckBothEventsSet EVENT_SEAFOAM4_BOULDER1_DOWN_HOLE, EVENT_SEAFOAM4_BOULDER2_DOWN_HOLE
+	ret z
+	ld hl, CoordsData_cdf7
+	call ArePlayerCoordsInArray
+	ret nc
+	ld hl, wd728
+	res 1, [hl]
+	ld hl, CurrentTooFastText
+	jp PrintText
+.forcedToRideBike
+	ld hl, wd728
+	res 1, [hl]
+	ld hl, CyclingIsFunText
+	jp PrintText
+
+CoordsData_cdf7:
+	db $0B,$07,$FF
+
+CurrentTooFastText:
+	TX_FAR _CurrentTooFastText
+	db "@"
+
+CyclingIsFunText:
+	TX_FAR _CyclingIsFunText
+	db "@"
--- /dev/null
+++ b/engine/overworld/missable_objects.asm
@@ -1,0 +1,215 @@
+MarkTownVisitedAndLoadMissableObjects:
+	ld a, [wCurMap]
+	cp ROUTE_1
+	jr nc, .notInTown
+	ld c, a
+	ld b, FLAG_SET
+	ld hl, wTownVisitedFlag   ; mark town as visited (for flying)
+	predef FlagActionPredef
+.notInTown
+	ld hl, MapHSPointers
+	ld a, [wCurMap]
+	ld b, $0
+	ld c, a
+	add hl, bc
+	add hl, bc
+	ld a, [hli]                ; load missable objects pointer in hl
+	ld h, [hl]
+	; fall through
+
+LoadMissableObjects:
+	ld l, a
+	push hl
+	ld de, MapHS00             ; calculate difference between out pointer and the base pointer
+	ld a, l
+	sub e
+	jr nc, .asm_f13c
+	dec h
+.asm_f13c
+	ld l, a
+	ld a, h
+	sub d
+	ld h, a
+	ld a, h
+	ld [H_DIVIDEND], a
+	ld a, l
+	ld [H_DIVIDEND+1], a
+	xor a
+	ld [H_DIVIDEND+2], a
+	ld [H_DIVIDEND+3], a
+	ld a, $3
+	ld [H_DIVISOR], a
+	ld b, $2
+	call Divide                ; divide difference by 3, resulting in the global offset (number of missable items before ours)
+	ld a, [wCurMap]
+	ld b, a
+	ld a, [H_DIVIDEND+3]
+	ld c, a                    ; store global offset in c
+	ld de, wMissableObjectList
+	pop hl
+.writeMissableObjectsListLoop
+	ld a, [hli]
+	cp $ff
+	jr z, .done     ; end of list
+	cp b
+	jr nz, .done    ; not for current map anymore
+	ld a, [hli]
+	inc hl
+	ld [de], a                 ; write (map-local) sprite ID
+	inc de
+	ld a, c
+	inc c
+	ld [de], a                 ; write (global) missable object index
+	inc de
+	jr .writeMissableObjectsListLoop
+.done
+	ld a, $ff
+	ld [de], a                 ; write sentinel
+	ret
+
+InitializeMissableObjectsFlags:
+	ld hl, wMissableObjectFlags
+	ld bc, wMissableObjectFlagsEnd - wMissableObjectFlags
+	xor a
+	call FillMemory ; clear missable objects flags
+	ld hl, MapHS00
+	xor a
+	ld [wMissableObjectCounter], a
+.missableObjectsLoop
+	ld a, [hli]
+	cp $ff          ; end of list
+	ret z
+	push hl
+	inc hl
+	ld a, [hl]
+	cp Hide
+	jr nz, .skip
+	ld hl, wMissableObjectFlags
+	ld a, [wMissableObjectCounter]
+	ld c, a
+	ld b, FLAG_SET
+	call MissableObjectFlagAction ; set flag if Item is hidden
+.skip
+	ld hl, wMissableObjectCounter
+	inc [hl]
+	pop hl
+	inc hl
+	inc hl
+	jr .missableObjectsLoop
+
+; tests if current sprite is a missable object that is hidden/has been removed
+IsObjectHidden:
+	ld a, [H_CURRENTSPRITEOFFSET]
+	swap a
+	ld b, a
+	ld hl, wMissableObjectList
+.loop
+	ld a, [hli]
+	cp $ff
+	jr z, .notHidden ; not missable -> not hidden
+	cp b
+	ld a, [hli]
+	jr nz, .loop
+	ld c, a
+	ld b, FLAG_TEST
+	ld hl, wMissableObjectFlags
+	call MissableObjectFlagAction
+	ld a, c
+	and a
+	jr nz, .hidden
+.notHidden
+	xor a
+.hidden
+	ld [$ffe5], a
+	ret
+
+; adds missable object (items, leg. pokemon, etc.) to the map
+; [wMissableObjectIndex]: index of the missable object to be added (global index)
+ShowObject:
+ShowObject2:
+	ld hl, wMissableObjectFlags
+	ld a, [wMissableObjectIndex]
+	ld c, a
+	ld b, FLAG_RESET
+	call MissableObjectFlagAction   ; reset "removed" flag
+	jp UpdateSprites
+
+; removes missable object (items, leg. pokemon, etc.) from the map
+; [wMissableObjectIndex]: index of the missable object to be removed (global index)
+HideObject:
+	ld hl, wMissableObjectFlags
+	ld a, [wMissableObjectIndex]
+	ld c, a
+	ld b, FLAG_SET
+	call MissableObjectFlagAction   ; set "removed" flag
+	jp UpdateSprites
+
+MissableObjectFlagAction:
+; identical to FlagAction
+
+	push hl
+	push de
+	push bc
+
+	; bit
+	ld a, c
+	ld d, a
+	and 7
+	ld e, a
+
+	; byte
+	ld a, d
+	srl a
+	srl a
+	srl a
+	add l
+	ld l, a
+	jr nc, .ok
+	inc h
+.ok
+
+	; d = 1 << e (bitmask)
+	inc e
+	ld d, 1
+.shift
+	dec e
+	jr z, .shifted
+	sla d
+	jr .shift
+.shifted
+
+	ld a, b
+	and a
+	jr z, .reset
+	cp 2
+	jr z, .read
+
+.set
+	ld a, [hl]
+	ld b, a
+	ld a, d
+	or b
+	ld [hl], a
+	jr .done
+
+.reset
+	ld a, [hl]
+	ld b, a
+	ld a, d
+	xor $ff
+	and b
+	ld [hl], a
+	jr .done
+
+.read
+	ld a, [hl]
+	ld b, a
+	ld a, d
+	and b
+
+.done
+	pop bc
+	pop de
+	pop hl
+	ld c, a
+	ret
--- /dev/null
+++ b/engine/overworld/player_state.asm
@@ -1,0 +1,463 @@
+; only used for setting bit 2 of wd736 upon entering a new map
+IsPlayerStandingOnWarp:
+	ld a, [wNumberOfWarps]
+	and a
+	ret z
+	ld c, a
+	ld hl, wWarpEntries
+.loop
+	ld a, [wYCoord]
+	cp [hl]
+	jr nz, .nextWarp1
+	inc hl
+	ld a, [wXCoord]
+	cp [hl]
+	jr nz, .nextWarp2
+	inc hl
+	ld a, [hli] ; target warp
+	ld [wDestinationWarpID], a
+	ld a, [hl] ; target map
+	ld [hWarpDestinationMap], a
+	ld hl, wd736
+	set 2, [hl] ; standing on warp flag
+	ret
+.nextWarp1
+	inc hl
+.nextWarp2
+	inc hl
+	inc hl
+	inc hl
+	dec c
+	jr nz, .loop
+	ret
+
+CheckForceBikeOrSurf:
+	ld hl, wd732
+	bit 5, [hl]
+	ret nz
+	ld hl, ForcedBikeOrSurfMaps
+	ld a, [wYCoord]
+	ld b, a
+	ld a, [wXCoord]
+	ld c, a
+	ld a, [wCurMap]
+	ld d, a
+.loop
+	ld a, [hli]
+	cp $ff
+	ret z ;if we reach FF then it's not part of the list
+	cp d ;compare to current map
+	jr nz, .incorrectMap
+	ld a, [hli]
+	cp b ;compare y-coord
+	jr nz, .incorrectY
+	ld a, [hli]
+	cp c ;compare x-coord
+	jr nz, .loop ; incorrect x-coord, check next item
+	ld a, [wCurMap]
+	cp SEAFOAM_ISLANDS_4
+	ld a, $2
+	ld [wSeafoamIslands4CurScript], a
+	jr z, .forceSurfing
+	ld a, [wCurMap]
+	cp SEAFOAM_ISLANDS_5
+	ld a, $2
+	ld [wSeafoamIslands5CurScript], a
+	jr z, .forceSurfing
+	;force bike riding
+	ld hl, wd732
+	set 5, [hl]
+	ld a, $1
+	ld [wWalkBikeSurfState], a
+	ld [wWalkBikeSurfStateCopy], a
+	jp ForceBikeOrSurf
+.incorrectMap
+	inc hl
+.incorrectY
+	inc hl
+	jr .loop
+.forceSurfing
+	ld a, $2
+	ld [wWalkBikeSurfState], a
+	ld [wWalkBikeSurfStateCopy], a
+	jp ForceBikeOrSurf
+
+INCLUDE "data/force_bike_surf.asm"
+
+IsPlayerFacingEdgeOfMap:
+	push hl
+	push de
+	push bc
+	ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction
+	srl a
+	ld c, a
+	ld b, $0
+	ld hl, .functionPointerTable
+	add hl, bc
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+	ld a, [wYCoord]
+	ld b, a
+	ld a, [wXCoord]
+	ld c, a
+	ld de, .asm_c41e
+	push de
+	jp [hl]
+.asm_c41e
+	pop bc
+	pop de
+	pop hl
+	ret
+
+.functionPointerTable
+	dw .facingDown
+	dw .facingUp
+	dw .facingLeft
+	dw .facingRight
+
+.facingDown
+	ld a, [wCurMapHeight]
+	add a
+	dec a
+	cp b
+	jr z, .setCarry
+	jr .resetCarry
+
+.facingUp
+	ld a, b
+	and a
+	jr z, .setCarry
+	jr .resetCarry
+
+.facingLeft
+	ld a, c
+	and a
+	jr z, .setCarry
+	jr .resetCarry
+
+.facingRight
+	ld a, [wCurMapWidth]
+	add a
+	dec a
+	cp c
+	jr z, .setCarry
+	jr .resetCarry
+.resetCarry
+	and a
+	ret
+.setCarry
+	scf
+	ret
+
+IsWarpTileInFrontOfPlayer:
+	push hl
+	push de
+	push bc
+	call _GetTileAndCoordsInFrontOfPlayer
+	ld a, [wCurMap]
+	cp SS_ANNE_5
+	jr z, .ssAnne5
+	ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction
+	srl a
+	ld c, a
+	ld b, 0
+	ld hl, .warpTileListPointers
+	add hl, bc
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+	ld a, [wTileInFrontOfPlayer]
+	ld de, $1
+	call IsInArray
+.done
+	pop bc
+	pop de
+	pop hl
+	ret
+
+.warpTileListPointers:
+	dw .facingDownWarpTiles
+	dw .facingUpWarpTiles
+	dw .facingLeftWarpTiles
+	dw .facingRightWarpTiles
+
+.facingDownWarpTiles
+	db $01,$12,$17,$3D,$04,$18,$33,$FF
+
+.facingUpWarpTiles
+	db $01,$5C,$FF
+
+.facingLeftWarpTiles
+	db $1A,$4B,$FF
+
+.facingRightWarpTiles
+	db $0F,$4E,$FF
+
+.ssAnne5
+	ld a, [wTileInFrontOfPlayer]
+	cp $15
+	jr nz, .notSSAnne5Warp
+	scf
+	jr .done
+.notSSAnne5Warp
+	and a
+	jr .done
+
+IsPlayerStandingOnDoorTileOrWarpTile:
+	push hl
+	push de
+	push bc
+	callba IsPlayerStandingOnDoorTile
+	jr c, .done
+	ld a, [wCurMapTileset]
+	add a
+	ld c, a
+	ld b, $0
+	ld hl, WarpTileIDPointers
+	add hl, bc
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+	ld de, $1
+	aCoord 8, 9
+	call IsInArray
+	jr nc, .done
+	ld hl, wd736
+	res 2, [hl]
+.done
+	pop bc
+	pop de
+	pop hl
+	ret
+
+INCLUDE "data/warp_tile_ids.asm"
+
+PrintSafariZoneSteps:
+	ld a, [wCurMap]
+	cp SAFARI_ZONE_EAST
+	ret c
+	cp UNKNOWN_DUNGEON_2
+	ret nc
+	coord hl, 0, 0
+	ld b, 3
+	ld c, 7
+	call TextBoxBorder
+	coord hl, 1, 1
+	ld de, wSafariSteps
+	lb bc, 2, 3
+	call PrintNumber
+	coord hl, 4, 1
+	ld de, SafariSteps
+	call PlaceString
+	coord hl, 1, 3
+	ld de, SafariBallText
+	call PlaceString
+	ld a, [wNumSafariBalls]
+	cp 10
+	jr nc, .asm_c56d
+	coord hl, 5, 3
+	ld a, " "
+	ld [hl], a
+.asm_c56d
+	coord hl, 6, 3
+	ld de, wNumSafariBalls
+	lb bc, 1, 2
+	jp PrintNumber
+
+SafariSteps:
+	db "/500@"
+
+SafariBallText:
+	db "BALL×× @"
+
+GetTileAndCoordsInFrontOfPlayer:
+	call GetPredefRegisters
+
+_GetTileAndCoordsInFrontOfPlayer:
+	ld a, [wYCoord]
+	ld d, a
+	ld a, [wXCoord]
+	ld e, a
+	ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+	and a ; cp SPRITE_FACING_DOWN
+	jr nz, .notFacingDown
+; facing down
+	aCoord 8, 11
+	inc d
+	jr .storeTile
+.notFacingDown
+	cp SPRITE_FACING_UP
+	jr nz, .notFacingUp
+; facing up
+	aCoord 8, 7
+	dec d
+	jr .storeTile
+.notFacingUp
+	cp SPRITE_FACING_LEFT
+	jr nz, .notFacingLeft
+; facing left
+	aCoord 6, 9
+	dec e
+	jr .storeTile
+.notFacingLeft
+	cp SPRITE_FACING_RIGHT
+	jr nz, .storeTile
+; facing right
+	aCoord 10, 9
+	inc e
+.storeTile
+	ld c, a
+	ld [wTileInFrontOfPlayer], a
+	ret
+
+GetTileTwoStepsInFrontOfPlayer:
+	xor a
+	ld [$ffdb], a
+	ld hl, wYCoord
+	ld a, [hli]
+	ld d, a
+	ld e, [hl]
+	ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+	and a ; cp SPRITE_FACING_DOWN
+	jr nz, .notFacingDown
+; facing down
+	ld hl, $ffdb
+	set 0, [hl]
+	aCoord 8, 13
+	inc d
+	jr .storeTile
+.notFacingDown
+	cp SPRITE_FACING_UP
+	jr nz, .notFacingUp
+; facing up
+	ld hl, $ffdb
+	set 1, [hl]
+	aCoord 8, 5
+	dec d
+	jr .storeTile
+.notFacingUp
+	cp SPRITE_FACING_LEFT
+	jr nz, .notFacingLeft
+; facing left
+	ld hl, $ffdb
+	set 2, [hl]
+	aCoord 4, 9
+	dec e
+	jr .storeTile
+.notFacingLeft
+	cp SPRITE_FACING_RIGHT
+	jr nz, .storeTile
+; facing right
+	ld hl, $ffdb
+	set 3, [hl]
+	aCoord 12, 9
+	inc e
+.storeTile
+	ld c, a
+	ld [wTileInFrontOfBoulderAndBoulderCollisionResult], a
+	ld [wTileInFrontOfPlayer], a
+	ret
+
+CheckForCollisionWhenPushingBoulder:
+	call GetTileTwoStepsInFrontOfPlayer
+	ld hl, wTilesetCollisionPtr
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+.loop
+	ld a, [hli]
+	cp $ff
+	jr z, .done ; if the tile two steps ahead is not passable
+	cp c
+	jr nz, .loop
+	ld hl, TilePairCollisionsLand
+	call CheckForTilePairCollisions2
+	ld a, $ff
+	jr c, .done ; if there is an elevation difference between the current tile and the one two steps ahead
+	ld a, [wTileInFrontOfBoulderAndBoulderCollisionResult]
+	cp $15 ; stairs tile
+	ld a, $ff
+	jr z, .done ; if the tile two steps ahead is stairs
+	call CheckForBoulderCollisionWithSprites
+.done
+	ld [wTileInFrontOfBoulderAndBoulderCollisionResult], a
+	ret
+
+; sets a to $ff if there is a collision and $00 if there is no collision
+CheckForBoulderCollisionWithSprites:
+	ld a, [wBoulderSpriteIndex]
+	dec a
+	swap a
+	ld d, 0
+	ld e, a
+	ld hl, wSpriteStateData2 + $14
+	add hl, de
+	ld a, [hli] ; map Y position
+	ld [$ffdc], a
+	ld a, [hl] ; map X position
+	ld [$ffdd], a
+	ld a, [wNumSprites]
+	ld c, a
+	ld de, $f
+	ld hl, wSpriteStateData2 + $14
+	ld a, [$ffdb]
+	and $3 ; facing up or down?
+	jr z, .pushingHorizontallyLoop
+.pushingVerticallyLoop
+	inc hl
+	ld a, [$ffdd]
+	cp [hl]
+	jr nz, .nextSprite1 ; if X coordinates don't match
+	dec hl
+	ld a, [hli]
+	ld b, a
+	ld a, [$ffdb]
+	rrca
+	jr c, .pushingDown
+; pushing up
+	ld a, [$ffdc]
+	dec a
+	jr .compareYCoords
+.pushingDown
+	ld a, [$ffdc]
+	inc a
+.compareYCoords
+	cp b
+	jr z, .failure
+.nextSprite1
+	dec c
+	jr z, .success
+	add hl, de
+	jr .pushingVerticallyLoop
+.pushingHorizontallyLoop
+	ld a, [hli]
+	ld b, a
+	ld a, [$ffdc]
+	cp b
+	jr nz, .nextSprite2
+	ld b, [hl]
+	ld a, [$ffdb]
+	bit 2, a
+	jr nz, .pushingLeft
+; pushing right
+	ld a, [$ffdd]
+	inc a
+	jr .compareXCoords
+.pushingLeft
+	ld a, [$ffdd]
+	dec a
+.compareXCoords
+	cp b
+	jr z, .failure
+.nextSprite2
+	dec c
+	jr z, .success
+	add hl, de
+	jr .pushingHorizontallyLoop
+.failure
+	ld a, $ff
+	ret
+.success
+	xor a
+	ret
--- /dev/null
+++ b/engine/overworld/poison.asm
@@ -1,0 +1,112 @@
+ApplyOutOfBattlePoisonDamage:
+	ld a, [wd730]
+	add a
+	jp c, .noBlackOut ; no black out if joypad states are being simulated
+	ld a, [wPartyCount]
+	and a
+	jp z, .noBlackOut
+	call IncrementDayCareMonExp
+	ld a, [wStepCounter]
+	and $3 ; is the counter a multiple of 4?
+	jp nz, .noBlackOut ; only apply poison damage every fourth step
+	ld [wWhichPokemon], a
+	ld hl, wPartyMon1Status
+	ld de, wPartySpecies
+.applyDamageLoop
+	ld a, [hl]
+	and (1 << PSN)
+	jr z, .nextMon2 ; not poisoned
+	dec hl
+	dec hl
+	ld a, [hld]
+	ld b, a
+	ld a, [hli]
+	or b
+	jr z, .nextMon ; already fainted
+; subtract 1 from HP
+	ld a, [hl]
+	dec a
+	ld [hld], a
+	inc a
+	jr nz, .noBorrow
+; borrow 1 from upper byte of HP
+	dec [hl]
+	inc hl
+	jr .nextMon
+.noBorrow
+	ld a, [hli]
+	or [hl]
+	jr nz, .nextMon ; didn't faint from damage
+; the mon fainted from the damage
+	push hl
+	inc hl
+	inc hl
+	ld [hl], a
+	ld a, [de]
+	ld [wd11e], a
+	push de
+	ld a, [wWhichPokemon]
+	ld hl, wPartyMonNicks
+	call GetPartyMonName
+	xor a
+	ld [wJoyIgnore], a
+	call EnableAutoTextBoxDrawing
+	ld a, $d0
+	ld [hSpriteIndexOrTextID], a
+	call DisplayTextID
+	pop de
+	pop hl
+.nextMon
+	inc hl
+	inc hl
+.nextMon2
+	inc de
+	ld a, [de]
+	inc a
+	jr z, .applyDamageLoopDone
+	ld bc, wPartyMon2 - wPartyMon1
+	add hl, bc
+	push hl
+	ld hl, wWhichPokemon
+	inc [hl]
+	pop hl
+	jr .applyDamageLoop
+.applyDamageLoopDone
+	ld hl, wPartyMon1Status
+	ld a, [wPartyCount]
+	ld d, a
+	ld e, 0
+.countPoisonedLoop
+	ld a, [hl]
+	and (1 << PSN)
+	or e
+	ld e, a
+	ld bc, wPartyMon2 - wPartyMon1
+	add hl, bc
+	dec d
+	jr nz, .countPoisonedLoop
+	ld a, e
+	and a ; are any party members poisoned?
+	jr z, .skipPoisonEffectAndSound
+	ld b, $2
+	predef ChangeBGPalColor0_4Frames ; change BG white to dark grey for 4 frames
+	ld a, SFX_POISONED
+	call PlaySound
+.skipPoisonEffectAndSound
+	predef AnyPartyAlive
+	ld a, d
+	and a
+	jr nz, .noBlackOut
+	call EnableAutoTextBoxDrawing
+	ld a, $d1
+	ld [hSpriteIndexOrTextID], a
+	call DisplayTextID
+	ld hl, wd72e
+	set 5, [hl]
+	ld a, $ff
+	jr .done
+.noBlackOut
+	xor a
+.done
+	ld [wOutOfBattleBlackout], a
+	ret
--- /dev/null
+++ b/engine/overworld/push_boulder.asm
@@ -1,0 +1,105 @@
+TryPushingBoulder:
+	ld a, [wd728]
+	bit 0, a ; using Strength?
+	ret z
+	ld a, [wFlags_0xcd60]
+	bit 1, a ; has boulder dust animation from previous push played yet?
+	ret nz
+	xor a
+	ld [hSpriteIndexOrTextID], a
+	call IsSpriteInFrontOfPlayer
+	ld a, [hSpriteIndexOrTextID]
+	ld [wBoulderSpriteIndex], a
+	and a
+	jp z, ResetBoulderPushFlags
+	ld hl, wSpriteStateData1 + 1
+	ld d, $0
+	ld a, [hSpriteIndexOrTextID]
+	swap a
+	ld e, a
+	add hl, de
+	res 7, [hl]
+	call GetSpriteMovementByte2Pointer
+	ld a, [hl]
+	cp BOULDER_MOVEMENT_BYTE_2
+	jp nz, ResetBoulderPushFlags
+	ld hl, wFlags_0xcd60
+	bit 6, [hl]
+	set 6, [hl] ; indicate that the player has tried pushing
+	ret z ; the player must try pushing twice before the boulder will move
+	ld a, [hJoyHeld]
+	and D_RIGHT | D_LEFT | D_UP | D_DOWN
+	ret z
+	predef CheckForCollisionWhenPushingBoulder
+	ld a, [wTileInFrontOfBoulderAndBoulderCollisionResult]
+	and a ; was there a collision?
+	jp nz, ResetBoulderPushFlags
+	ld a, [hJoyHeld]
+	ld b, a
+	ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+	cp SPRITE_FACING_UP
+	jr z, .pushBoulderUp
+	cp SPRITE_FACING_LEFT
+	jr z, .pushBoulderLeft
+	cp SPRITE_FACING_RIGHT
+	jr z, .pushBoulderRight
+.pushBoulderDown
+	bit 7, b
+	ret z
+	ld de, PushBoulderDownMovementData
+	jr .done
+.pushBoulderUp
+	bit 6, b
+	ret z
+	ld de, PushBoulderUpMovementData
+	jr .done
+.pushBoulderLeft
+	bit 5, b
+	ret z
+	ld de, PushBoulderLeftMovementData
+	jr .done
+.pushBoulderRight
+	bit 4, b
+	ret z
+	ld de, PushBoulderRightMovementData
+.done
+	call MoveSprite
+	ld a, SFX_PUSH_BOULDER
+	call PlaySound
+	ld hl, wFlags_0xcd60
+	set 1, [hl]
+	ret
+
+PushBoulderUpMovementData:
+	db NPC_MOVEMENT_UP,$FF
+
+PushBoulderDownMovementData:
+	db NPC_MOVEMENT_DOWN,$FF
+
+PushBoulderLeftMovementData:
+	db NPC_MOVEMENT_LEFT,$FF
+
+PushBoulderRightMovementData:
+	db NPC_MOVEMENT_RIGHT,$FF
+
+DoBoulderDustAnimation:
+	ld a, [wd730]
+	bit 0, a
+	ret nz
+	callab AnimateBoulderDust
+	call DiscardButtonPresses
+	ld [wJoyIgnore], a
+	call ResetBoulderPushFlags
+	set 7, [hl]
+	ld a, [wBoulderSpriteIndex]
+	ld [H_SPRITEINDEX], a
+	call GetSpriteMovementByte2Pointer
+	ld [hl], $10
+	ld a, SFX_CUT
+	jp PlaySound
+
+ResetBoulderPushFlags:
+	ld hl, wFlags_0xcd60
+	res 1, [hl]
+	res 6, [hl]
+	ret
--- /dev/null
+++ b/engine/overworld/tileset_header.asm
@@ -1,0 +1,60 @@
+LoadTilesetHeader:
+	call GetPredefRegisters
+	push hl
+	ld d, 0
+	ld a, [wCurMapTileset]
+	add a
+	add a
+	ld b, a
+	add a
+	add b ; a = tileset * 12
+	jr nc, .noCarry
+	inc d
+.noCarry
+	ld e, a
+	ld hl, Tilesets
+	add hl, de
+	ld de, wTilesetBank
+	ld c, $b
+.copyTilesetHeaderLoop
+	ld a, [hli]
+	ld [de], a
+	inc de
+	dec c
+	jr nz, .copyTilesetHeaderLoop
+	ld a, [hl]
+	ld [hTilesetType], a
+	xor a
+	ld [$ffd8], a
+	pop hl
+	ld a, [wCurMapTileset]
+	push hl
+	push de
+	ld hl, DungeonTilesets
+	ld de, $1
+	call IsInArray
+	pop de
+	pop hl
+	jr c, .asm_c797
+	ld a, [wCurMapTileset]
+	ld b, a
+	ld a, [hPreviousTileset]
+	cp b
+	jr z, .done
+.asm_c797
+	ld a, [wDestinationWarpID]
+	cp $ff
+	jr z, .done
+	call LoadDestinationWarpPosition
+	ld a, [wYCoord]
+	and $1
+	ld [wYBlockCoord], a
+	ld a, [wXCoord]
+	and $1
+	ld [wXBlockCoord], a
+.done
+	ret
+
+INCLUDE "data/dungeon_tilesets.asm"
+
+INCLUDE "data/tileset_headers.asm"
--- /dev/null
+++ b/engine/overworld/update_map.asm
@@ -1,0 +1,126 @@
+; replaces a tile block with the one specified in [wNewTileBlockID]
+; and redraws the map view if necessary
+; b = Y
+; c = X
+ReplaceTileBlock:
+	call GetPredefRegisters
+	ld hl, wOverworldMap
+	ld a, [wCurMapWidth]
+	add $6
+	ld e, a
+	ld d, $0
+	add hl, de
+	add hl, de
+	add hl, de
+	ld e, $3
+	add hl, de
+	ld e, a
+	ld a, b
+	and a
+	jr z, .addX
+; add width * Y
+.addWidthYTimesLoop
+	add hl, de
+	dec b
+	jr nz, .addWidthYTimesLoop
+.addX
+	add hl, bc ; add X
+	ld a, [wNewTileBlockID]
+	ld [hl], a
+	ld a, [wCurrentTileBlockMapViewPointer]
+	ld c, a
+	ld a, [wCurrentTileBlockMapViewPointer + 1]
+	ld b, a
+	call CompareHLWithBC
+	ret c ; return if the replaced tile block is below the map view in memory
+	push hl
+	ld l, e
+	ld h, $0
+	ld e, $6
+	ld d, h
+	add hl, hl
+	add hl, hl
+	add hl, de
+	add hl, bc
+	pop bc
+	call CompareHLWithBC
+	ret c ; return if the replaced tile block is above the map view in memory
+
+RedrawMapView:
+	ld a, [wIsInBattle]
+	inc a
+	ret z
+	ld a, [H_AUTOBGTRANSFERENABLED]
+	push af
+	ld a, [hTilesetType]
+	push af
+	xor a
+	ld [H_AUTOBGTRANSFERENABLED], a
+	ld [hTilesetType], a ; no flower/water BG tile animations
+	call LoadCurrentMapView
+	call RunDefaultPaletteCommand
+	ld hl, wMapViewVRAMPointer
+	ld a, [hli]
+	ld h, [hl]
+	ld l, a
+	ld de, -2 * 32
+	add hl, de
+	ld a, h
+	and $3
+	or $98
+	ld a, l
+	ld [wBuffer], a
+	ld a, h
+	ld [wBuffer + 1], a ; this copy of the address is not used
+	ld a, 2
+	ld [$ffbe], a
+	ld c, 9 ; number of rows of 2x2 tiles (this covers the whole screen)
+.redrawRowLoop
+	push bc
+	push hl
+	push hl
+	ld hl, wTileMap - 2 * SCREEN_WIDTH
+	ld de, SCREEN_WIDTH
+	ld a, [$ffbe]
+.calcWRAMAddrLoop
+	add hl, de
+	dec a
+	jr nz, .calcWRAMAddrLoop
+	call CopyToRedrawRowOrColumnSrcTiles
+	pop hl
+	ld de, $20
+	ld a, [$ffbe]
+	ld c, a
+.calcVRAMAddrLoop
+	add hl, de
+	ld a, h
+	and $3
+	or $98
+	dec c
+	jr nz, .calcVRAMAddrLoop
+	ld [hRedrawRowOrColumnDest + 1], a
+	ld a, l
+	ld [hRedrawRowOrColumnDest], a
+	ld a, REDRAW_ROW
+	ld [hRedrawRowOrColumnMode], a
+	call DelayFrame
+	ld hl, $ffbe
+	inc [hl]
+	inc [hl]
+	pop hl
+	pop bc
+	dec c
+	jr nz, .redrawRowLoop
+	pop af
+	ld [hTilesetType], a
+	pop af
+	ld [H_AUTOBGTRANSFERENABLED], a
+	ret
+
+CompareHLWithBC:
+	ld a, h
+	sub b
+	ret nz
+	ld a, l
+	sub c
+	ret
--- /dev/null
+++ b/engine/overworld/wild_mons.asm
@@ -1,0 +1,33 @@
+LoadWildData:
+	ld hl,WildDataPointers
+	ld a,[wCurMap]
+
+	; get wild data for current map
+	ld c,a
+	ld b,0
+	add hl,bc
+	add hl,bc
+	ld a,[hli]
+	ld h,[hl]
+	ld l,a       ; hl now points to wild data for current map
+	ld a,[hli]
+	ld [wGrassRate],a
+	and a
+	jr z,.NoGrassData ; if no grass data, skip to surfing data
+	push hl
+	ld de,wGrassMons ; otherwise, load grass data
+	ld bc,$0014
+	call CopyData
+	pop hl
+	ld bc,$0014
+	add hl,bc
+.NoGrassData
+	ld a,[hli]
+	ld [wWaterRate],a
+	and a
+	ret z        ; if no water data, we're done
+	ld de,wWaterMons  ; otherwise, load surfing data
+	ld bc,$0014
+	jp CopyData
+
+INCLUDE "data/wild_mons.asm"
--- /dev/null
+++ b/engine/pathfinding.asm
@@ -1,0 +1,201 @@
+FindPathToPlayer:
+	xor a
+	ld hl, hFindPathNumSteps
+	ld [hli], a ; hFindPathNumSteps
+	ld [hli], a ; hFindPathFlags
+	ld [hli], a ; hFindPathYProgress
+	ld [hl], a  ; hFindPathXProgress
+	ld hl, wNPCMovementDirections2
+	ld de, $0
+.loop
+	ld a, [hFindPathYProgress]
+	ld b, a
+	ld a, [hNPCPlayerYDistance] ; Y distance in steps
+	call CalcDifference
+	ld d, a
+	and a
+	jr nz, .asm_f8da
+	ld a, [hFindPathFlags]
+	set 0, a ; current end of path matches the player's Y coordinate
+	ld [hFindPathFlags], a
+.asm_f8da
+	ld a, [hFindPathXProgress]
+	ld b, a
+	ld a, [hNPCPlayerXDistance] ; X distance in steps
+	call CalcDifference
+	ld e, a
+	and a
+	jr nz, .asm_f8ec
+	ld a, [hFindPathFlags]
+	set 1, a ; current end of path matches the player's X coordinate
+	ld [hFindPathFlags], a
+.asm_f8ec
+	ld a, [hFindPathFlags]
+	cp $3 ; has the end of the path reached the player's position?
+	jr z, .done
+; Compare whether the X distance between the player and the current of the path
+; is greater or if the Y distance is. Then, try to reduce whichever is greater.
+	ld a, e
+	cp d
+	jr c, .yDistanceGreater
+; x distance is greater
+	ld a, [hNPCPlayerRelativePosFlags]
+	bit 1, a
+	jr nz, .playerIsLeftOfNPC
+	ld d, NPC_MOVEMENT_RIGHT
+	jr .next1
+.playerIsLeftOfNPC
+	ld d, NPC_MOVEMENT_LEFT
+.next1
+	ld a, [hFindPathXProgress]
+	add 1
+	ld [hFindPathXProgress], a
+	jr .storeDirection
+.yDistanceGreater
+	ld a, [hNPCPlayerRelativePosFlags]
+	bit 0, a
+	jr nz, .playerIsAboveNPC
+	ld d, NPC_MOVEMENT_DOWN
+	jr .next2
+.playerIsAboveNPC
+	ld d, NPC_MOVEMENT_UP
+.next2
+	ld a, [hFindPathYProgress]
+	add 1
+	ld [hFindPathYProgress], a
+.storeDirection
+	ld a, d
+	ld [hli], a
+	ld a, [hFindPathNumSteps]
+	inc a
+	ld [hFindPathNumSteps], a
+	jp .loop
+.done
+	ld [hl], $ff
+	ret
+
+CalcPositionOfPlayerRelativeToNPC:
+	xor a
+	ld [hNPCPlayerRelativePosFlags], a
+	ld a, [wSpriteStateData1 + 4] ; player's sprite screen Y position in pixels
+	ld d, a
+	ld a, [wSpriteStateData1 + 6] ; player's sprite screen X position in pixels
+	ld e, a
+	ld hl, wSpriteStateData1
+	ld a, [hNPCSpriteOffset]
+	add l
+	add $4
+	ld l, a
+	jr nc, .noCarry
+	inc h
+.noCarry
+	ld a, d
+	ld b, a
+	ld a, [hli] ; NPC sprite screen Y position in pixels
+	call CalcDifference
+	jr nc, .NPCSouthOfOrAlignedWithPlayer
+.NPCNorthOfPlayer
+	push hl
+	ld hl, hNPCPlayerRelativePosFlags
+	bit 0, [hl]
+	set 0, [hl]
+	pop hl
+	jr .divideYDistance
+.NPCSouthOfOrAlignedWithPlayer
+	push hl
+	ld hl, hNPCPlayerRelativePosFlags
+	bit 0, [hl]
+	res 0, [hl]
+	pop hl
+.divideYDistance
+	push hl
+	ld hl, hDividend2
+	ld [hli], a
+	ld a, 16
+	ld [hli], a
+	call DivideBytes ; divide Y absolute distance by 16
+	ld a, [hl] ; quotient
+	ld [hNPCPlayerYDistance], a
+	pop hl
+	inc hl
+	ld b, e
+	ld a, [hl] ; NPC sprite screen X position in pixels
+	call CalcDifference
+	jr nc, .NPCEastOfOrAlignedWithPlayer
+.NPCWestOfPlayer
+	push hl
+	ld hl, hNPCPlayerRelativePosFlags
+	bit 1, [hl]
+	set 1, [hl]
+	pop hl
+	jr .divideXDistance
+.NPCEastOfOrAlignedWithPlayer
+	push hl
+	ld hl, hNPCPlayerRelativePosFlags
+	bit 1, [hl]
+	res 1, [hl]
+	pop hl
+.divideXDistance
+	ld [hDividend2], a
+	ld a, 16
+	ld [hDivisor2], a
+	call DivideBytes ; divide X absolute distance by 16
+	ld a, [hQuotient2]
+	ld [hNPCPlayerXDistance], a
+	ld a, [hNPCPlayerRelativePosPerspective]
+	and a
+	ret z
+	ld a, [hNPCPlayerRelativePosFlags]
+	cpl
+	and $3
+	ld [hNPCPlayerRelativePosFlags], a
+	ret
+
+ConvertNPCMovementDirectionsToJoypadMasks:
+	ld a, [hNPCMovementDirections2Index]
+	ld [wNPCMovementDirections2Index], a
+	dec a
+	ld de, wSimulatedJoypadStatesEnd
+	ld hl, wNPCMovementDirections2
+	add l
+	ld l, a
+	jr nc, .loop
+	inc h
+.loop
+	ld a, [hld]
+	call ConvertNPCMovementDirectionToJoypadMask
+	ld [de], a
+	inc de
+	ld a, [hNPCMovementDirections2Index]
+	dec a
+	ld [hNPCMovementDirections2Index], a
+	jr nz, .loop
+	ret
+
+ConvertNPCMovementDirectionToJoypadMask:
+	push hl
+	ld b, a
+	ld hl, NPCMovementDirectionsToJoypadMasksTable
+.loop
+	ld a, [hli]
+	cp $ff
+	jr z, .done
+	cp b
+	jr z, .loadJoypadMask
+	inc hl
+	jr .loop
+.loadJoypadMask
+	ld a, [hl]
+.done
+	pop hl
+	ret
+
+NPCMovementDirectionsToJoypadMasksTable:
+	db NPC_MOVEMENT_UP, D_UP
+	db NPC_MOVEMENT_DOWN, D_DOWN
+	db NPC_MOVEMENT_LEFT, D_LEFT
+	db NPC_MOVEMENT_RIGHT, D_RIGHT
+	db $ff
+
+; unreferenced
+	ret
--- a/home/overworld.asm
+++ b/home/overworld.asm
@@ -8,7 +8,7 @@
 	ld a, $ff
 	ld [wJoyIgnore], a
 	call LoadMapData
-	callba ClearVariablesAfterLoadingMapData
+	callba ClearVariablesOnEnterMap
 	ld hl, wd72c
 	bit 0, [hl] ; has the player already made 3 steps since the last battle?
 	jr z, .skipGivingThreeStepsOfNoRandomBattles
--- a/main.asm
+++ b/main.asm
@@ -94,2691 +94,38 @@
 
 INCLUDE "data/map_header_banks.asm"
 
-ClearVariablesAfterLoadingMapData:
-	ld a, SCREEN_HEIGHT_PIXELS
-	ld [hWY], a
-	ld [rWY], a
-	xor a
-	ld [H_AUTOBGTRANSFERENABLED], a
-	ld [wStepCounter], a
-	ld [wLoneAttackNo], a
-	ld [hJoyPressed], a
-	ld [hJoyReleased], a
-	ld [hJoyHeld], a
-	ld [wActionResultOrTookBattleTurn], a
-	ld [wUnusedD5A3], a
-	ld hl, wCardKeyDoorY
-	ld [hli], a
-	ld [hl], a
-	ld hl, wWhichTrade
-	ld bc, wStandingOnWarpPadOrHole - wWhichTrade
-	call FillMemory
-	ret
+INCLUDE "engine/overworld/clear_variables.asm"
+INCLUDE "engine/overworld/player_state.asm"
+INCLUDE "engine/overworld/poison.asm"
+INCLUDE "engine/overworld/tileset_header.asm"
+INCLUDE "engine/overworld/daycare_exp.asm"
 
-; only used for setting bit 2 of wd736 upon entering a new map
-IsPlayerStandingOnWarp:
-	ld a, [wNumberOfWarps]
-	and a
-	ret z
-	ld c, a
-	ld hl, wWarpEntries
-.loop
-	ld a, [wYCoord]
-	cp [hl]
-	jr nz, .nextWarp1
-	inc hl
-	ld a, [wXCoord]
-	cp [hl]
-	jr nz, .nextWarp2
-	inc hl
-	ld a, [hli] ; target warp
-	ld [wDestinationWarpID], a
-	ld a, [hl] ; target map
-	ld [hWarpDestinationMap], a
-	ld hl, wd736
-	set 2, [hl] ; standing on warp flag
-	ret
-.nextWarp1
-	inc hl
-.nextWarp2
-	inc hl
-	inc hl
-	inc hl
-	dec c
-	jr nz, .loop
-	ret
-
-CheckForceBikeOrSurf:
-	ld hl, wd732
-	bit 5, [hl]
-	ret nz
-	ld hl, ForcedBikeOrSurfMaps
-	ld a, [wYCoord]
-	ld b, a
-	ld a, [wXCoord]
-	ld c, a
-	ld a, [wCurMap]
-	ld d, a
-.loop
-	ld a, [hli]
-	cp $ff
-	ret z ;if we reach FF then it's not part of the list
-	cp d ;compare to current map
-	jr nz, .incorrectMap
-	ld a, [hli]
-	cp b ;compare y-coord
-	jr nz, .incorrectY
-	ld a, [hli]
-	cp c ;compare x-coord
-	jr nz, .loop ; incorrect x-coord, check next item
-	ld a, [wCurMap]
-	cp SEAFOAM_ISLANDS_4
-	ld a, $2
-	ld [wSeafoamIslands4CurScript], a
-	jr z, .forceSurfing
-	ld a, [wCurMap]
-	cp SEAFOAM_ISLANDS_5
-	ld a, $2
-	ld [wSeafoamIslands5CurScript], a
-	jr z, .forceSurfing
-	;force bike riding
-	ld hl, wd732
-	set 5, [hl]
-	ld a, $1
-	ld [wWalkBikeSurfState], a
-	ld [wWalkBikeSurfStateCopy], a
-	jp ForceBikeOrSurf
-.incorrectMap
-	inc hl
-.incorrectY
-	inc hl
-	jr .loop
-.forceSurfing
-	ld a, $2
-	ld [wWalkBikeSurfState], a
-	ld [wWalkBikeSurfStateCopy], a
-	jp ForceBikeOrSurf
-
-INCLUDE "data/force_bike_surf.asm"
-
-IsPlayerFacingEdgeOfMap:
-	push hl
-	push de
-	push bc
-	ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction
-	srl a
-	ld c, a
-	ld b, $0
-	ld hl, .functionPointerTable
-	add hl, bc
-	ld a, [hli]
-	ld h, [hl]
-	ld l, a
-	ld a, [wYCoord]
-	ld b, a
-	ld a, [wXCoord]
-	ld c, a
-	ld de, .asm_c41e
-	push de
-	jp [hl]
-.asm_c41e
-	pop bc
-	pop de
-	pop hl
-	ret
-
-.functionPointerTable
-	dw .facingDown
-	dw .facingUp
-	dw .facingLeft
-	dw .facingRight
-
-.facingDown
-	ld a, [wCurMapHeight]
-	add a
-	dec a
-	cp b
-	jr z, .setCarry
-	jr .resetCarry
-
-.facingUp
-	ld a, b
-	and a
-	jr z, .setCarry
-	jr .resetCarry
-
-.facingLeft
-	ld a, c
-	and a
-	jr z, .setCarry
-	jr .resetCarry
-
-.facingRight
-	ld a, [wCurMapWidth]
-	add a
-	dec a
-	cp c
-	jr z, .setCarry
-	jr .resetCarry
-.resetCarry
-	and a
-	ret
-.setCarry
-	scf
-	ret
-
-IsWarpTileInFrontOfPlayer:
-	push hl
-	push de
-	push bc
-	call _GetTileAndCoordsInFrontOfPlayer
-	ld a, [wCurMap]
-	cp SS_ANNE_5
-	jr z, .ssAnne5
-	ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction
-	srl a
-	ld c, a
-	ld b, 0
-	ld hl, .warpTileListPointers
-	add hl, bc
-	ld a, [hli]
-	ld h, [hl]
-	ld l, a
-	ld a, [wTileInFrontOfPlayer]
-	ld de, $1
-	call IsInArray
-.done
-	pop bc
-	pop de
-	pop hl
-	ret
-
-.warpTileListPointers:
-	dw .facingDownWarpTiles
-	dw .facingUpWarpTiles
-	dw .facingLeftWarpTiles
-	dw .facingRightWarpTiles
-
-.facingDownWarpTiles
-	db $01,$12,$17,$3D,$04,$18,$33,$FF
-
-.facingUpWarpTiles
-	db $01,$5C,$FF
-
-.facingLeftWarpTiles
-	db $1A,$4B,$FF
-
-.facingRightWarpTiles
-	db $0F,$4E,$FF
-
-.ssAnne5
-	ld a, [wTileInFrontOfPlayer]
-	cp $15
-	jr nz, .notSSAnne5Warp
-	scf
-	jr .done
-.notSSAnne5Warp
-	and a
-	jr .done
-
-IsPlayerStandingOnDoorTileOrWarpTile:
-	push hl
-	push de
-	push bc
-	callba IsPlayerStandingOnDoorTile
-	jr c, .done
-	ld a, [wCurMapTileset]
-	add a
-	ld c, a
-	ld b, $0
-	ld hl, WarpTileIDPointers
-	add hl, bc
-	ld a, [hli]
-	ld h, [hl]
-	ld l, a
-	ld de, $1
-	aCoord 8, 9
-	call IsInArray
-	jr nc, .done
-	ld hl, wd736
-	res 2, [hl]
-.done
-	pop bc
-	pop de
-	pop hl
-	ret
-
-INCLUDE "data/warp_tile_ids.asm"
-
-PrintSafariZoneSteps:
-	ld a, [wCurMap]
-	cp SAFARI_ZONE_EAST
-	ret c
-	cp UNKNOWN_DUNGEON_2
-	ret nc
-	coord hl, 0, 0
-	ld b, 3
-	ld c, 7
-	call TextBoxBorder
-	coord hl, 1, 1
-	ld de, wSafariSteps
-	lb bc, 2, 3
-	call PrintNumber
-	coord hl, 4, 1
-	ld de, SafariSteps
-	call PlaceString
-	coord hl, 1, 3
-	ld de, SafariBallText
-	call PlaceString
-	ld a, [wNumSafariBalls]
-	cp 10
-	jr nc, .asm_c56d
-	coord hl, 5, 3
-	ld a, " "
-	ld [hl], a
-.asm_c56d
-	coord hl, 6, 3
-	ld de, wNumSafariBalls
-	lb bc, 1, 2
-	jp PrintNumber
-
-SafariSteps:
-	db "/500@"
-
-SafariBallText:
-	db "BALL×× @"
-
-GetTileAndCoordsInFrontOfPlayer:
-	call GetPredefRegisters
-
-_GetTileAndCoordsInFrontOfPlayer:
-	ld a, [wYCoord]
-	ld d, a
-	ld a, [wXCoord]
-	ld e, a
-	ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
-	and a ; cp SPRITE_FACING_DOWN
-	jr nz, .notFacingDown
-; facing down
-	aCoord 8, 11
-	inc d
-	jr .storeTile
-.notFacingDown
-	cp SPRITE_FACING_UP
-	jr nz, .notFacingUp
-; facing up
-	aCoord 8, 7
-	dec d
-	jr .storeTile
-.notFacingUp
-	cp SPRITE_FACING_LEFT
-	jr nz, .notFacingLeft
-; facing left
-	aCoord 6, 9
-	dec e
-	jr .storeTile
-.notFacingLeft
-	cp SPRITE_FACING_RIGHT
-	jr nz, .storeTile
-; facing right
-	aCoord 10, 9
-	inc e
-.storeTile
-	ld c, a
-	ld [wTileInFrontOfPlayer], a
-	ret
-
-GetTileTwoStepsInFrontOfPlayer:
-	xor a
-	ld [$ffdb], a
-	ld hl, wYCoord
-	ld a, [hli]
-	ld d, a
-	ld e, [hl]
-	ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
-	and a ; cp SPRITE_FACING_DOWN
-	jr nz, .notFacingDown
-; facing down
-	ld hl, $ffdb
-	set 0, [hl]
-	aCoord 8, 13
-	inc d
-	jr .storeTile
-.notFacingDown
-	cp SPRITE_FACING_UP
-	jr nz, .notFacingUp
-; facing up
-	ld hl, $ffdb
-	set 1, [hl]
-	aCoord 8, 5
-	dec d
-	jr .storeTile
-.notFacingUp
-	cp SPRITE_FACING_LEFT
-	jr nz, .notFacingLeft
-; facing left
-	ld hl, $ffdb
-	set 2, [hl]
-	aCoord 4, 9
-	dec e
-	jr .storeTile
-.notFacingLeft
-	cp SPRITE_FACING_RIGHT
-	jr nz, .storeTile
-; facing right
-	ld hl, $ffdb
-	set 3, [hl]
-	aCoord 12, 9
-	inc e
-.storeTile
-	ld c, a
-	ld [wTileInFrontOfBoulderAndBoulderCollisionResult], a
-	ld [wTileInFrontOfPlayer], a
-	ret
-
-CheckForCollisionWhenPushingBoulder:
-	call GetTileTwoStepsInFrontOfPlayer
-	ld hl, wTilesetCollisionPtr
-	ld a, [hli]
-	ld h, [hl]
-	ld l, a
-.loop
-	ld a, [hli]
-	cp $ff
-	jr z, .done ; if the tile two steps ahead is not passable
-	cp c
-	jr nz, .loop
-	ld hl, TilePairCollisionsLand
-	call CheckForTilePairCollisions2
-	ld a, $ff
-	jr c, .done ; if there is an elevation difference between the current tile and the one two steps ahead
-	ld a, [wTileInFrontOfBoulderAndBoulderCollisionResult]
-	cp $15 ; stairs tile
-	ld a, $ff
-	jr z, .done ; if the tile two steps ahead is stairs
-	call CheckForBoulderCollisionWithSprites
-.done
-	ld [wTileInFrontOfBoulderAndBoulderCollisionResult], a
-	ret
-
-; sets a to $ff if there is a collision and $00 if there is no collision
-CheckForBoulderCollisionWithSprites:
-	ld a, [wBoulderSpriteIndex]
-	dec a
-	swap a
-	ld d, 0
-	ld e, a
-	ld hl, wSpriteStateData2 + $14
-	add hl, de
-	ld a, [hli] ; map Y position
-	ld [$ffdc], a
-	ld a, [hl] ; map X position
-	ld [$ffdd], a
-	ld a, [wNumSprites]
-	ld c, a
-	ld de, $f
-	ld hl, wSpriteStateData2 + $14
-	ld a, [$ffdb]
-	and $3 ; facing up or down?
-	jr z, .pushingHorizontallyLoop
-.pushingVerticallyLoop
-	inc hl
-	ld a, [$ffdd]
-	cp [hl]
-	jr nz, .nextSprite1 ; if X coordinates don't match
-	dec hl
-	ld a, [hli]
-	ld b, a
-	ld a, [$ffdb]
-	rrca
-	jr c, .pushingDown
-; pushing up
-	ld a, [$ffdc]
-	dec a
-	jr .compareYCoords
-.pushingDown
-	ld a, [$ffdc]
-	inc a
-.compareYCoords
-	cp b
-	jr z, .failure
-.nextSprite1
-	dec c
-	jr z, .success
-	add hl, de
-	jr .pushingVerticallyLoop
-.pushingHorizontallyLoop
-	ld a, [hli]
-	ld b, a
-	ld a, [$ffdc]
-	cp b
-	jr nz, .nextSprite2
-	ld b, [hl]
-	ld a, [$ffdb]
-	bit 2, a
-	jr nz, .pushingLeft
-; pushing right
-	ld a, [$ffdd]
-	inc a
-	jr .compareXCoords
-.pushingLeft
-	ld a, [$ffdd]
-	dec a
-.compareXCoords
-	cp b
-	jr z, .failure
-.nextSprite2
-	dec c
-	jr z, .success
-	add hl, de
-	jr .pushingHorizontallyLoop
-.failure
-	ld a, $ff
-	ret
-.success
-	xor a
-	ret
-
-ApplyOutOfBattlePoisonDamage:
-	ld a, [wd730]
-	add a
-	jp c, .noBlackOut ; no black out if joypad states are being simulated
-	ld a, [wPartyCount]
-	and a
-	jp z, .noBlackOut
-	call IncrementDayCareMonExp
-	ld a, [wStepCounter]
-	and $3 ; is the counter a multiple of 4?
-	jp nz, .noBlackOut ; only apply poison damage every fourth step
-	ld [wWhichPokemon], a
-	ld hl, wPartyMon1Status
-	ld de, wPartySpecies
-.applyDamageLoop
-	ld a, [hl]
-	and (1 << PSN)
-	jr z, .nextMon2 ; not poisoned
-	dec hl
-	dec hl
-	ld a, [hld]
-	ld b, a
-	ld a, [hli]
-	or b
-	jr z, .nextMon ; already fainted
-; subtract 1 from HP
-	ld a, [hl]
-	dec a
-	ld [hld], a
-	inc a
-	jr nz, .noBorrow
-; borrow 1 from upper byte of HP
-	dec [hl]
-	inc hl
-	jr .nextMon
-.noBorrow
-	ld a, [hli]
-	or [hl]
-	jr nz, .nextMon ; didn't faint from damage
-; the mon fainted from the damage
-	push hl
-	inc hl
-	inc hl
-	ld [hl], a
-	ld a, [de]
-	ld [wd11e], a
-	push de
-	ld a, [wWhichPokemon]
-	ld hl, wPartyMonNicks
-	call GetPartyMonName
-	xor a
-	ld [wJoyIgnore], a
-	call EnableAutoTextBoxDrawing
-	ld a, $d0
-	ld [hSpriteIndexOrTextID], a
-	call DisplayTextID
-	pop de
-	pop hl
-.nextMon
-	inc hl
-	inc hl
-.nextMon2
-	inc de
-	ld a, [de]
-	inc a
-	jr z, .applyDamageLoopDone
-	ld bc, wPartyMon2 - wPartyMon1
-	add hl, bc
-	push hl
-	ld hl, wWhichPokemon
-	inc [hl]
-	pop hl
-	jr .applyDamageLoop
-.applyDamageLoopDone
-	ld hl, wPartyMon1Status
-	ld a, [wPartyCount]
-	ld d, a
-	ld e, 0
-.countPoisonedLoop
-	ld a, [hl]
-	and (1 << PSN)
-	or e
-	ld e, a
-	ld bc, wPartyMon2 - wPartyMon1
-	add hl, bc
-	dec d
-	jr nz, .countPoisonedLoop
-	ld a, e
-	and a ; are any party members poisoned?
-	jr z, .skipPoisonEffectAndSound
-	ld b, $2
-	predef ChangeBGPalColor0_4Frames ; change BG white to dark grey for 4 frames
-	ld a, SFX_POISONED
-	call PlaySound
-.skipPoisonEffectAndSound
-	predef AnyPartyAlive
-	ld a, d
-	and a
-	jr nz, .noBlackOut
-	call EnableAutoTextBoxDrawing
-	ld a, $d1
-	ld [hSpriteIndexOrTextID], a
-	call DisplayTextID
-	ld hl, wd72e
-	set 5, [hl]
-	ld a, $ff
-	jr .done
-.noBlackOut
-	xor a
-.done
-	ld [wOutOfBattleBlackout], a
-	ret
-
-LoadTilesetHeader:
-	call GetPredefRegisters
-	push hl
-	ld d, 0
-	ld a, [wCurMapTileset]
-	add a
-	add a
-	ld b, a
-	add a
-	add b ; a = tileset * 12
-	jr nc, .noCarry
-	inc d
-.noCarry
-	ld e, a
-	ld hl, Tilesets
-	add hl, de
-	ld de, wTilesetBank
-	ld c, $b
-.copyTilesetHeaderLoop
-	ld a, [hli]
-	ld [de], a
-	inc de
-	dec c
-	jr nz, .copyTilesetHeaderLoop
-	ld a, [hl]
-	ld [hTilesetType], a
-	xor a
-	ld [$ffd8], a
-	pop hl
-	ld a, [wCurMapTileset]
-	push hl
-	push de
-	ld hl, DungeonTilesets
-	ld de, $1
-	call IsInArray
-	pop de
-	pop hl
-	jr c, .asm_c797
-	ld a, [wCurMapTileset]
-	ld b, a
-	ld a, [hPreviousTileset]
-	cp b
-	jr z, .done
-.asm_c797
-	ld a, [wDestinationWarpID]
-	cp $ff
-	jr z, .done
-	call LoadDestinationWarpPosition
-	ld a, [wYCoord]
-	and $1
-	ld [wYBlockCoord], a
-	ld a, [wXCoord]
-	and $1
-	ld [wXBlockCoord], a
-.done
-	ret
-
-INCLUDE "data/dungeon_tilesets.asm"
-
-INCLUDE "data/tileset_headers.asm"
-
-IncrementDayCareMonExp:
-	ld a, [wDayCareInUse]
-	and a
-	ret z
-	ld hl, wDayCareMonExp + 2
-	inc [hl]
-	ret nz
-	dec hl
-	inc [hl]
-	ret nz
-	dec hl
-	inc [hl]
-	ld a, [hl]
-	cp $50
-	ret c
-	ld a, $50
-	ld [hl], a
-	ret
-
 INCLUDE "data/hide_show_data.asm"
 
-PrintStrengthTxt:
-	ld hl, wd728
-	set 0, [hl]
-	ld hl, UsedStrengthText
-	call PrintText
-	ld hl, CanMoveBouldersText
-	jp PrintText
+INCLUDE "engine/overworld/field_move_messages.asm"
 
-UsedStrengthText:
-	TX_FAR _UsedStrengthText
-	TX_ASM
-	ld a, [wcf91]
-	call PlayCry
-	call Delay3
-	jp TextScriptEnd
+INCLUDE "engine/items/inventory.asm"
 
-CanMoveBouldersText:
-	TX_FAR _CanMoveBouldersText
-	db "@"
+INCLUDE "engine/overworld/wild_mons.asm"
 
-IsSurfingAllowed:
-; Returns whether surfing is allowed in bit 1 of wd728.
-; Surfing isn't allowed on the Cycling Road or in the lowest level of the
-; Seafoam Islands before the current has been slowed with boulders.
-	ld hl, wd728
-	set 1, [hl]
-	ld a, [wd732]
-	bit 5, a
-	jr nz, .forcedToRideBike
-	ld a, [wCurMap]
-	cp SEAFOAM_ISLANDS_5
-	ret nz
-	CheckBothEventsSet EVENT_SEAFOAM4_BOULDER1_DOWN_HOLE, EVENT_SEAFOAM4_BOULDER2_DOWN_HOLE
-	ret z
-	ld hl, CoordsData_cdf7
-	call ArePlayerCoordsInArray
-	ret nc
-	ld hl, wd728
-	res 1, [hl]
-	ld hl, CurrentTooFastText
-	jp PrintText
-.forcedToRideBike
-	ld hl, wd728
-	res 1, [hl]
-	ld hl, CyclingIsFunText
-	jp PrintText
-
-CoordsData_cdf7:
-	db $0B,$07,$FF
-
-CurrentTooFastText:
-	TX_FAR _CurrentTooFastText
-	db "@"
-
-CyclingIsFunText:
-	TX_FAR _CyclingIsFunText
-	db "@"
-
-; function to add an item (in varying quantities) to the player's bag or PC box
-; INPUT:
-; hl = address of inventory (either wNumBagItems or wNumBoxItems)
-; [wcf91] = item ID
-; [wItemQuantity] = item quantity
-; sets carry flag if successful, unsets carry flag if unsuccessful
-AddItemToInventory_:
-	ld a,[wItemQuantity] ; a = item quantity
-	push af
-	push bc
-	push de
-	push hl
-	push hl
-	ld d,PC_ITEM_CAPACITY ; how many items the PC can hold
-	ld a,wNumBagItems & $FF
-	cp l
-	jr nz,.checkIfInventoryFull
-	ld a,wNumBagItems >> 8
-	cp h
-	jr nz,.checkIfInventoryFull
-; if the destination is the bag
-	ld d,BAG_ITEM_CAPACITY ; how many items the bag can hold
-.checkIfInventoryFull
-	ld a,[hl]
-	sub d
-	ld d,a
-	ld a,[hli]
-	and a
-	jr z,.addNewItem
-.loop
-	ld a,[hli]
-	ld b,a ; b = ID of current item in table
-	ld a,[wcf91] ; a = ID of item being added
-	cp b ; does the current item in the table match the item being added?
-	jp z,.increaseItemQuantity ; if so, increase the item's quantity
-	inc hl
-	ld a,[hl]
-	cp a,$ff ; is it the end of the table?
-	jr nz,.loop
-.addNewItem ; add an item not yet in the inventory
-	pop hl
-	ld a,d
-	and a ; is there room for a new item slot?
-	jr z,.done
-; if there is room
-	inc [hl] ; increment the number of items in the inventory
-	ld a,[hl] ; the number of items will be the index of the new item
-	add a
-	dec a
-	ld c,a
-	ld b,0
-	add hl,bc ; hl = address to store the item
-	ld a,[wcf91]
-	ld [hli],a ; store item ID
-	ld a,[wItemQuantity]
-	ld [hli],a ; store item quantity
-	ld [hl],$ff ; store terminator
-	jp .success
-.increaseItemQuantity ; increase the quantity of an item already in the inventory
-	ld a,[wItemQuantity]
-	ld b,a ; b = quantity to add
-	ld a,[hl] ; a = existing item quantity
-	add b ; a = new item quantity
-	cp a,100
-	jp c,.storeNewQuantity ; if the new quantity is less than 100, store it
-; if the new quantity is greater than or equal to 100,
-; try to max out the current slot and add the rest in a new slot
-	sub a,99
-	ld [wItemQuantity],a ; a = amount left over (to put in the new slot)
-	ld a,d
-	and a ; is there room for a new item slot?
-	jr z,.increaseItemQuantityFailed
-; if so, store 99 in the current slot and store the rest in a new slot
-	ld a,99
-	ld [hli],a
-	jp .loop
-.increaseItemQuantityFailed
-	pop hl
-	and a
-	jr .done
-.storeNewQuantity
-	ld [hl],a
-	pop hl
-.success
-	scf
-.done
-	pop hl
-	pop de
-	pop bc
-	pop bc
-	ld a,b
-	ld [wItemQuantity],a ; restore the initial value from when the function was called
-	ret
-
-; function to remove an item (in varying quantities) from the player's bag or PC box
-; INPUT:
-; hl = address of inventory (either wNumBagItems or wNumBoxItems)
-; [wWhichPokemon] = index (within the inventory) of the item to remove
-; [wItemQuantity] = quantity to remove
-RemoveItemFromInventory_:
-	push hl
-	inc hl
-	ld a,[wWhichPokemon] ; index (within the inventory) of the item being removed
-	sla a
-	add l
-	ld l,a
-	jr nc,.noCarry
-	inc h
-.noCarry
-	inc hl
-	ld a,[wItemQuantity] ; quantity being removed
-	ld e,a
-	ld a,[hl] ; a = current quantity
-	sub e
-	ld [hld],a ; store new quantity
-	ld [wMaxItemQuantity],a
-	and a
-	jr nz,.skipMovingUpSlots
-; if the remaining quantity is 0,
-; remove the emptied item slot and move up all the following item slots
-.moveSlotsUp
-	ld e,l
-	ld d,h
-	inc de
-	inc de ; de = address of the slot following the emptied one
-.loop ; loop to move up the following slots
-	ld a,[de]
-	inc de
-	ld [hli],a
-	cp a,$ff
-	jr nz,.loop
-; update menu info
-	xor a
-	ld [wListScrollOffset],a
-	ld [wCurrentMenuItem],a
-	ld [wBagSavedMenuItem],a
-	ld [wSavedListScrollOffset],a
-	pop hl
-	ld a,[hl] ; a = number of items in inventory
-	dec a ; decrement the number of items
-	ld [hl],a ; store new number of items
-	ld [wListCount],a
-	cp a,2
-	jr c,.done
-	ld [wMaxMenuItem],a
-	jr .done
-.skipMovingUpSlots
-	pop hl
-.done
-	ret
-
-; wild pokemon data: from 4EB8 to 55C7
-
-LoadWildData:
-	ld hl,WildDataPointers
-	ld a,[wCurMap]
-
-	; get wild data for current map
-	ld c,a
-	ld b,0
-	add hl,bc
-	add hl,bc
-	ld a,[hli]
-	ld h,[hl]
-	ld l,a       ; hl now points to wild data for current map
-	ld a,[hli]
-	ld [wGrassRate],a
-	and a
-	jr z,.NoGrassData ; if no grass data, skip to surfing data
-	push hl
-	ld de,wGrassMons ; otherwise, load grass data
-	ld bc,$0014
-	call CopyData
-	pop hl
-	ld bc,$0014
-	add hl,bc
-.NoGrassData
-	ld a,[hli]
-	ld [wWaterRate],a
-	and a
-	ret z        ; if no water data, we're done
-	ld de,wWaterMons  ; otherwise, load surfing data
-	ld bc,$0014
-	jp CopyData
-
-INCLUDE "data/wild_mons.asm"
-
 INCLUDE "engine/items/items.asm"
 
-DrawBadges:
-; Draw 4x2 gym leader faces, with the faces replaced by
-; badges if they are owned. Used in the player status screen.
+INCLUDE "engine/menu/draw_badges.asm"
 
-; In Japanese versions, names are displayed above faces.
-; Instead of removing relevant code, the name graphics were erased.
-
-; Tile ids for face/badge graphics.
-	ld de, wBadgeOrFaceTiles
-	ld hl, .FaceBadgeTiles
-	ld bc, 8
-	call CopyData
-
-; Booleans for each badge.
-	ld hl, wTempObtainedBadgesBooleans
-	ld bc, 8
-	xor a
-	call FillMemory
-
-; Alter these based on owned badges.
-	ld de, wTempObtainedBadgesBooleans
-	ld hl, wBadgeOrFaceTiles
-	ld a, [wObtainedBadges]
-	ld b, a
-	ld c, 8
-.CheckBadge
-	srl b
-	jr nc, .NextBadge
-	ld a, [hl]
-	add 4 ; Badge graphics are after each face
-	ld [hl], a
-	ld a, 1
-	ld [de], a
-.NextBadge
-	inc hl
-	inc de
-	dec c
-	jr nz, .CheckBadge
-
-; Draw two rows of badges.
-	ld hl, wBadgeNumberTile
-	ld a, $d8 ; [1]
-	ld [hli], a
-	ld [hl], $60 ; First name
-
-	coord hl, 2, 11
-	ld de, wTempObtainedBadgesBooleans
-	call .DrawBadgeRow
-
-	coord hl, 2, 14
-	ld de, wTempObtainedBadgesBooleans + 4
-;	call .DrawBadgeRow
-;	ret
-
-.DrawBadgeRow
-; Draw 4 badges.
-
-	ld c, 4
-.DrawBadge
-	push de
-	push hl
-
-; Badge no.
-	ld a, [wBadgeNumberTile]
-	ld [hli], a
-	inc a
-	ld [wBadgeNumberTile], a
-
-; Names aren't printed if the badge is owned.
-	ld a, [de]
-	and a
-	ld a, [wBadgeNameTile]
-	jr nz, .SkipName
-	call .PlaceTiles
-	jr .PlaceBadge
-
-.SkipName
-	inc a
-	inc a
-	inc hl
-
-.PlaceBadge
-	ld [wBadgeNameTile], a
-	ld de, SCREEN_WIDTH - 1
-	add hl, de
-	ld a, [wBadgeOrFaceTiles]
-	call .PlaceTiles
-	add hl, de
-	call .PlaceTiles
-
-; Shift badge array back one byte.
-	push bc
-	ld hl, wBadgeOrFaceTiles + 1
-	ld de, wBadgeOrFaceTiles
-	ld bc, 8
-	call CopyData
-	pop bc
-
-	pop hl
-	ld de, 4
-	add hl, de
-
-	pop de
-	inc de
-	dec c
-	jr nz, .DrawBadge
-	ret
-
-.PlaceTiles
-	ld [hli], a
-	inc a
-	ld [hl], a
-	inc a
-	ret
-
-.FaceBadgeTiles
-	db $20, $28, $30, $38, $40, $48, $50, $58
-
-GymLeaderFaceAndBadgeTileGraphics:
-	INCBIN "gfx/badges.2bpp"
-
-; replaces a tile block with the one specified in [wNewTileBlockID]
-; and redraws the map view if necessary
-; b = Y
-; c = X
-ReplaceTileBlock:
-	call GetPredefRegisters
-	ld hl, wOverworldMap
-	ld a, [wCurMapWidth]
-	add $6
-	ld e, a
-	ld d, $0
-	add hl, de
-	add hl, de
-	add hl, de
-	ld e, $3
-	add hl, de
-	ld e, a
-	ld a, b
-	and a
-	jr z, .addX
-; add width * Y
-.addWidthYTimesLoop
-	add hl, de
-	dec b
-	jr nz, .addWidthYTimesLoop
-.addX
-	add hl, bc ; add X
-	ld a, [wNewTileBlockID]
-	ld [hl], a
-	ld a, [wCurrentTileBlockMapViewPointer]
-	ld c, a
-	ld a, [wCurrentTileBlockMapViewPointer + 1]
-	ld b, a
-	call CompareHLWithBC
-	ret c ; return if the replaced tile block is below the map view in memory
-	push hl
-	ld l, e
-	ld h, $0
-	ld e, $6
-	ld d, h
-	add hl, hl
-	add hl, hl
-	add hl, de
-	add hl, bc
-	pop bc
-	call CompareHLWithBC
-	ret c ; return if the replaced tile block is above the map view in memory
-
-RedrawMapView:
-	ld a, [wIsInBattle]
-	inc a
-	ret z
-	ld a, [H_AUTOBGTRANSFERENABLED]
-	push af
-	ld a, [hTilesetType]
-	push af
-	xor a
-	ld [H_AUTOBGTRANSFERENABLED], a
-	ld [hTilesetType], a ; no flower/water BG tile animations
-	call LoadCurrentMapView
-	call RunDefaultPaletteCommand
-	ld hl, wMapViewVRAMPointer
-	ld a, [hli]
-	ld h, [hl]
-	ld l, a
-	ld de, -2 * 32
-	add hl, de
-	ld a, h
-	and $3
-	or $98
-	ld a, l
-	ld [wBuffer], a
-	ld a, h
-	ld [wBuffer + 1], a ; this copy of the address is not used
-	ld a, 2
-	ld [$ffbe], a
-	ld c, 9 ; number of rows of 2x2 tiles (this covers the whole screen)
-.redrawRowLoop
-	push bc
-	push hl
-	push hl
-	ld hl, wTileMap - 2 * SCREEN_WIDTH
-	ld de, SCREEN_WIDTH
-	ld a, [$ffbe]
-.calcWRAMAddrLoop
-	add hl, de
-	dec a
-	jr nz, .calcWRAMAddrLoop
-	call CopyToRedrawRowOrColumnSrcTiles
-	pop hl
-	ld de, $20
-	ld a, [$ffbe]
-	ld c, a
-.calcVRAMAddrLoop
-	add hl, de
-	ld a, h
-	and $3
-	or $98
-	dec c
-	jr nz, .calcVRAMAddrLoop
-	ld [hRedrawRowOrColumnDest + 1], a
-	ld a, l
-	ld [hRedrawRowOrColumnDest], a
-	ld a, REDRAW_ROW
-	ld [hRedrawRowOrColumnMode], a
-	call DelayFrame
-	ld hl, $ffbe
-	inc [hl]
-	inc [hl]
-	pop hl
-	pop bc
-	dec c
-	jr nz, .redrawRowLoop
-	pop af
-	ld [hTilesetType], a
-	pop af
-	ld [H_AUTOBGTRANSFERENABLED], a
-	ret
-
-CompareHLWithBC:
-	ld a, h
-	sub b
-	ret nz
-	ld a, l
-	sub c
-	ret
-
+INCLUDE "engine/overworld/update_map.asm"
 INCLUDE "engine/overworld/cut.asm"
+INCLUDE "engine/overworld/missable_objects.asm"
+INCLUDE "engine/overworld/push_boulder.asm"
 
-MarkTownVisitedAndLoadMissableObjects:
-	ld a, [wCurMap]
-	cp ROUTE_1
-	jr nc, .notInTown
-	ld c, a
-	ld b, FLAG_SET
-	ld hl, wTownVisitedFlag   ; mark town as visited (for flying)
-	predef FlagActionPredef
-.notInTown
-	ld hl, MapHSPointers
-	ld a, [wCurMap]
-	ld b, $0
-	ld c, a
-	add hl, bc
-	add hl, bc
-	ld a, [hli]                ; load missable objects pointer in hl
-	ld h, [hl]
-	; fall through
-
-LoadMissableObjects:
-	ld l, a
-	push hl
-	ld de, MapHS00             ; calculate difference between out pointer and the base pointer
-	ld a, l
-	sub e
-	jr nc, .asm_f13c
-	dec h
-.asm_f13c
-	ld l, a
-	ld a, h
-	sub d
-	ld h, a
-	ld a, h
-	ld [H_DIVIDEND], a
-	ld a, l
-	ld [H_DIVIDEND+1], a
-	xor a
-	ld [H_DIVIDEND+2], a
-	ld [H_DIVIDEND+3], a
-	ld a, $3
-	ld [H_DIVISOR], a
-	ld b, $2
-	call Divide                ; divide difference by 3, resulting in the global offset (number of missable items before ours)
-	ld a, [wCurMap]
-	ld b, a
-	ld a, [H_DIVIDEND+3]
-	ld c, a                    ; store global offset in c
-	ld de, wMissableObjectList
-	pop hl
-.writeMissableObjectsListLoop
-	ld a, [hli]
-	cp $ff
-	jr z, .done     ; end of list
-	cp b
-	jr nz, .done    ; not for current map anymore
-	ld a, [hli]
-	inc hl
-	ld [de], a                 ; write (map-local) sprite ID
-	inc de
-	ld a, c
-	inc c
-	ld [de], a                 ; write (global) missable object index
-	inc de
-	jr .writeMissableObjectsListLoop
-.done
-	ld a, $ff
-	ld [de], a                 ; write sentinel
-	ret
-
-InitializeMissableObjectsFlags:
-	ld hl, wMissableObjectFlags
-	ld bc, wMissableObjectFlagsEnd - wMissableObjectFlags
-	xor a
-	call FillMemory ; clear missable objects flags
-	ld hl, MapHS00
-	xor a
-	ld [wMissableObjectCounter], a
-.missableObjectsLoop
-	ld a, [hli]
-	cp $ff          ; end of list
-	ret z
-	push hl
-	inc hl
-	ld a, [hl]
-	cp Hide
-	jr nz, .skip
-	ld hl, wMissableObjectFlags
-	ld a, [wMissableObjectCounter]
-	ld c, a
-	ld b, FLAG_SET
-	call MissableObjectFlagAction ; set flag if Item is hidden
-.skip
-	ld hl, wMissableObjectCounter
-	inc [hl]
-	pop hl
-	inc hl
-	inc hl
-	jr .missableObjectsLoop
-
-; tests if current sprite is a missable object that is hidden/has been removed
-IsObjectHidden:
-	ld a, [H_CURRENTSPRITEOFFSET]
-	swap a
-	ld b, a
-	ld hl, wMissableObjectList
-.loop
-	ld a, [hli]
-	cp $ff
-	jr z, .notHidden ; not missable -> not hidden
-	cp b
-	ld a, [hli]
-	jr nz, .loop
-	ld c, a
-	ld b, FLAG_TEST
-	ld hl, wMissableObjectFlags
-	call MissableObjectFlagAction
-	ld a, c
-	and a
-	jr nz, .hidden
-.notHidden
-	xor a
-.hidden
-	ld [$ffe5], a
-	ret
-
-; adds missable object (items, leg. pokemon, etc.) to the map
-; [wMissableObjectIndex]: index of the missable object to be added (global index)
-ShowObject:
-ShowObject2:
-	ld hl, wMissableObjectFlags
-	ld a, [wMissableObjectIndex]
-	ld c, a
-	ld b, FLAG_RESET
-	call MissableObjectFlagAction   ; reset "removed" flag
-	jp UpdateSprites
-
-; removes missable object (items, leg. pokemon, etc.) from the map
-; [wMissableObjectIndex]: index of the missable object to be removed (global index)
-HideObject:
-	ld hl, wMissableObjectFlags
-	ld a, [wMissableObjectIndex]
-	ld c, a
-	ld b, FLAG_SET
-	call MissableObjectFlagAction   ; set "removed" flag
-	jp UpdateSprites
-
-MissableObjectFlagAction:
-; identical to FlagAction
-
-	push hl
-	push de
-	push bc
-
-	; bit
-	ld a, c
-	ld d, a
-	and 7
-	ld e, a
-
-	; byte
-	ld a, d
-	srl a
-	srl a
-	srl a
-	add l
-	ld l, a
-	jr nc, .ok
-	inc h
-.ok
-
-	; d = 1 << e (bitmask)
-	inc e
-	ld d, 1
-.shift
-	dec e
-	jr z, .shifted
-	sla d
-	jr .shift
-.shifted
-
-	ld a, b
-	and a
-	jr z, .reset
-	cp 2
-	jr z, .read
-
-.set
-	ld a, [hl]
-	ld b, a
-	ld a, d
-	or b
-	ld [hl], a
-	jr .done
-
-.reset
-	ld a, [hl]
-	ld b, a
-	ld a, d
-	xor $ff
-	and b
-	ld [hl], a
-	jr .done
-
-.read
-	ld a, [hl]
-	ld b, a
-	ld a, d
-	and b
-
-.done
-	pop bc
-	pop de
-	pop hl
-	ld c, a
-	ret
-
-TryPushingBoulder:
-	ld a, [wd728]
-	bit 0, a ; using Strength?
-	ret z
-	ld a, [wFlags_0xcd60]
-	bit 1, a ; has boulder dust animation from previous push played yet?
-	ret nz
-	xor a
-	ld [hSpriteIndexOrTextID], a
-	call IsSpriteInFrontOfPlayer
-	ld a, [hSpriteIndexOrTextID]
-	ld [wBoulderSpriteIndex], a
-	and a
-	jp z, ResetBoulderPushFlags
-	ld hl, wSpriteStateData1 + 1
-	ld d, $0
-	ld a, [hSpriteIndexOrTextID]
-	swap a
-	ld e, a
-	add hl, de
-	res 7, [hl]
-	call GetSpriteMovementByte2Pointer
-	ld a, [hl]
-	cp BOULDER_MOVEMENT_BYTE_2
-	jp nz, ResetBoulderPushFlags
-	ld hl, wFlags_0xcd60
-	bit 6, [hl]
-	set 6, [hl] ; indicate that the player has tried pushing
-	ret z ; the player must try pushing twice before the boulder will move
-	ld a, [hJoyHeld]
-	and D_RIGHT | D_LEFT | D_UP | D_DOWN
-	ret z
-	predef CheckForCollisionWhenPushingBoulder
-	ld a, [wTileInFrontOfBoulderAndBoulderCollisionResult]
-	and a ; was there a collision?
-	jp nz, ResetBoulderPushFlags
-	ld a, [hJoyHeld]
-	ld b, a
-	ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
-	cp SPRITE_FACING_UP
-	jr z, .pushBoulderUp
-	cp SPRITE_FACING_LEFT
-	jr z, .pushBoulderLeft
-	cp SPRITE_FACING_RIGHT
-	jr z, .pushBoulderRight
-.pushBoulderDown
-	bit 7, b
-	ret z
-	ld de, PushBoulderDownMovementData
-	jr .done
-.pushBoulderUp
-	bit 6, b
-	ret z
-	ld de, PushBoulderUpMovementData
-	jr .done
-.pushBoulderLeft
-	bit 5, b
-	ret z
-	ld de, PushBoulderLeftMovementData
-	jr .done
-.pushBoulderRight
-	bit 4, b
-	ret z
-	ld de, PushBoulderRightMovementData
-.done
-	call MoveSprite
-	ld a, SFX_PUSH_BOULDER
-	call PlaySound
-	ld hl, wFlags_0xcd60
-	set 1, [hl]
-	ret
-
-PushBoulderUpMovementData:
-	db NPC_MOVEMENT_UP,$FF
-
-PushBoulderDownMovementData:
-	db NPC_MOVEMENT_DOWN,$FF
-
-PushBoulderLeftMovementData:
-	db NPC_MOVEMENT_LEFT,$FF
-
-PushBoulderRightMovementData:
-	db NPC_MOVEMENT_RIGHT,$FF
-
-DoBoulderDustAnimation:
-	ld a, [wd730]
-	bit 0, a
-	ret nz
-	callab AnimateBoulderDust
-	call DiscardButtonPresses
-	ld [wJoyIgnore], a
-	call ResetBoulderPushFlags
-	set 7, [hl]
-	ld a, [wBoulderSpriteIndex]
-	ld [H_SPRITEINDEX], a
-	call GetSpriteMovementByte2Pointer
-	ld [hl], $10
-	ld a, SFX_CUT
-	jp PlaySound
-
-ResetBoulderPushFlags:
-	ld hl, wFlags_0xcd60
-	res 1, [hl]
-	res 6, [hl]
-	ret
-
-_AddPartyMon:
-; Adds a new mon to the player's or enemy's party.
-; [wMonDataLocation] is used in an unusual way in this function.
-; If the lower nybble is 0, the mon is added to the player's party, else the enemy's.
-; If the entire value is 0, then the player is allowed to name the mon.
-	ld de, wPartyCount
-	ld a, [wMonDataLocation]
-	and $f
-	jr z, .next
-	ld de, wEnemyPartyCount
-.next
-	ld a, [de]
-	inc a
-	cp PARTY_LENGTH + 1
-	ret nc ; return if the party is already full
-	ld [de], a
-	ld a, [de]
-	ld [hNewPartyLength], a
-	add e
-	ld e, a
-	jr nc, .noCarry
-	inc d
-.noCarry
-	ld a, [wcf91]
-	ld [de], a ; write species of new mon in party list
-	inc de
-	ld a, $ff ; terminator
-	ld [de], a
-	ld hl, wPartyMonOT
-	ld a, [wMonDataLocation]
-	and $f
-	jr z, .next2
-	ld hl, wEnemyMonOT
-.next2
-	ld a, [hNewPartyLength]
-	dec a
-	call SkipFixedLengthTextEntries
-	ld d, h
-	ld e, l
-	ld hl, wPlayerName
-	ld bc, NAME_LENGTH
-	call CopyData
-	ld a, [wMonDataLocation]
-	and a
-	jr nz, .skipNaming
-	ld hl, wPartyMonNicks
-	ld a, [hNewPartyLength]
-	dec a
-	call SkipFixedLengthTextEntries
-	ld a, NAME_MON_SCREEN
-	ld [wNamingScreenType], a
-	predef AskName
-.skipNaming
-	ld hl, wPartyMons
-	ld a, [wMonDataLocation]
-	and $f
-	jr z, .next3
-	ld hl, wEnemyMons
-.next3
-	ld a, [hNewPartyLength]
-	dec a
-	ld bc, wPartyMon2 - wPartyMon1
-	call AddNTimes
-	ld e, l
-	ld d, h
-	push hl
-	ld a, [wcf91]
-	ld [wd0b5], a
-	call GetMonHeader
-	ld hl, wMonHeader
-	ld a, [hli]
-	ld [de], a ; species
-	inc de
-	pop hl
-	push hl
-	ld a, [wMonDataLocation]
-	and $f
-	ld a, $98     ; set enemy trainer mon IVs to fixed average values
-	ld b, $88
-	jr nz, .next4
-
-; If the mon is being added to the player's party, update the pokedex.
-	ld a, [wcf91]
-	ld [wd11e], a
-	push de
-	predef IndexToPokedex
-	pop de
-	ld a, [wd11e]
-	dec a
-	ld c, a
-	ld b, FLAG_TEST
-	ld hl, wPokedexOwned
-	call FlagAction
-	ld a, c ; whether the mon was already flagged as owned
-	ld [wUnusedD153], a ; not read
-	ld a, [wd11e]
-	dec a
-	ld c, a
-	ld b, FLAG_SET
-	push bc
-	call FlagAction
-	pop bc
-	ld hl, wPokedexSeen
-	call FlagAction
-
-	pop hl
-	push hl
-
-	ld a, [wIsInBattle]
-	and a ; is this a wild mon caught in battle?
-	jr nz, .copyEnemyMonData
-
-; Not wild.
-	call Random ; generate random IVs
-	ld b, a
-	call Random
-
-.next4
-	push bc
-	ld bc, wPartyMon1DVs - wPartyMon1
-	add hl, bc
-	pop bc
-	ld [hli], a
-	ld [hl], b         ; write IVs
-	ld bc, (wPartyMon1HPExp - 1) - (wPartyMon1DVs + 1)
-	add hl, bc
-	ld a, 1
-	ld c, a
-	xor a
-	ld b, a
-	call CalcStat      ; calc HP stat (set cur Hp to max HP)
-	ld a, [H_MULTIPLICAND+1]
-	ld [de], a
-	inc de
-	ld a, [H_MULTIPLICAND+2]
-	ld [de], a
-	inc de
-	xor a
-	ld [de], a         ; box level
-	inc de
-	ld [de], a         ; status ailments
-	inc de
-	jr .copyMonTypesAndMoves
-.copyEnemyMonData
-	ld bc, wEnemyMon1DVs - wEnemyMon1
-	add hl, bc
-	ld a, [wEnemyMonDVs] ; copy IVs from cur enemy mon
-	ld [hli], a
-	ld a, [wEnemyMonDVs + 1]
-	ld [hl], a
-	ld a, [wEnemyMonHP]    ; copy HP from cur enemy mon
-	ld [de], a
-	inc de
-	ld a, [wEnemyMonHP+1]
-	ld [de], a
-	inc de
-	xor a
-	ld [de], a                ; box level
-	inc de
-	ld a, [wEnemyMonStatus]   ; copy status ailments from cur enemy mon
-	ld [de], a
-	inc de
-.copyMonTypesAndMoves
-	ld hl, wMonHTypes
-	ld a, [hli]       ; type 1
-	ld [de], a
-	inc de
-	ld a, [hli]       ; type 2
-	ld [de], a
-	inc de
-	ld a, [hli]       ; catch rate (held item in gen 2)
-	ld [de], a
-	ld hl, wMonHMoves
-	ld a, [hli]
-	inc de
-	push de
-	ld [de], a
-	ld a, [hli]
-	inc de
-	ld [de], a
-	ld a, [hli]
-	inc de
-	ld [de], a
-	ld a, [hli]
-	inc de
-	ld [de], a
-	push de
-	dec de
-	dec de
-	dec de
-	xor a
-	ld [wLearningMovesFromDayCare], a
-	predef WriteMonMoves
-	pop de
-	ld a, [wPlayerID]  ; set trainer ID to player ID
-	inc de
-	ld [de], a
-	ld a, [wPlayerID + 1]
-	inc de
-	ld [de], a
-	push de
-	ld a, [wCurEnemyLVL]
-	ld d, a
-	callab CalcExperience
-	pop de
-	inc de
-	ld a, [hExperience] ; write experience
-	ld [de], a
-	inc de
-	ld a, [hExperience + 1]
-	ld [de], a
-	inc de
-	ld a, [hExperience + 2]
-	ld [de], a
-	xor a
-	ld b, NUM_STATS * 2
-.writeEVsLoop              ; set all EVs to 0
-	inc de
-	ld [de], a
-	dec b
-	jr nz, .writeEVsLoop
-	inc de
-	inc de
-	pop hl
-	call AddPartyMon_WriteMovePP
-	inc de
-	ld a, [wCurEnemyLVL]
-	ld [de], a
-	inc de
-	ld a, [wIsInBattle]
-	dec a
-	jr nz, .calcFreshStats
-	ld hl, wEnemyMonMaxHP
-	ld bc, $a
-	call CopyData          ; copy stats of cur enemy mon
-	pop hl
-	jr .done
-.calcFreshStats
-	pop hl
-	ld bc, wPartyMon1HPExp - 1 - wPartyMon1
-	add hl, bc
-	ld b, $0
-	call CalcStats         ; calculate fresh set of stats
-.done
-	scf
-	ret
-
-LoadMovePPs:
-	call GetPredefRegisters
-	; fallthrough
-AddPartyMon_WriteMovePP:
-	ld b, NUM_MOVES
-.pploop
-	ld a, [hli]     ; read move ID
-	and a
-	jr z, .empty
-	dec a
-	push hl
-	push de
-	push bc
-	ld hl, Moves
-	ld bc, MoveEnd - Moves
-	call AddNTimes
-	ld de, wcd6d
-	ld a, BANK(Moves)
-	call FarCopyData
-	pop bc
-	pop de
-	pop hl
-	ld a, [wcd6d + 5] ; PP is byte 5 of move data
-.empty
-	inc de
-	ld [de], a
-	dec b
-	jr nz, .pploop ; there are still moves to read
-	ret
-
-; adds enemy mon [wcf91] (at position [wWhichPokemon] in enemy list) to own party
-; used in the cable club trade center
-_AddEnemyMonToPlayerParty:
-	ld hl, wPartyCount
-	ld a, [hl]
-	cp PARTY_LENGTH
-	scf
-	ret z            ; party full, return failure
-	inc a
-	ld [hl], a       ; add 1 to party members
-	ld c, a
-	ld b, $0
-	add hl, bc
-	ld a, [wcf91]
-	ld [hli], a      ; add mon as last list entry
-	ld [hl], $ff     ; write new sentinel
-	ld hl, wPartyMons
-	ld a, [wPartyCount]
-	dec a
-	ld bc, wPartyMon2 - wPartyMon1
-	call AddNTimes
-	ld e, l
-	ld d, h
-	ld hl, wLoadedMon
-	call CopyData    ; write new mon's data (from wLoadedMon)
-	ld hl, wPartyMonOT
-	ld a, [wPartyCount]
-	dec a
-	call SkipFixedLengthTextEntries
-	ld d, h
-	ld e, l
-	ld hl, wEnemyMonOT
-	ld a, [wWhichPokemon]
-	call SkipFixedLengthTextEntries
-	ld bc, NAME_LENGTH
-	call CopyData    ; write new mon's OT name (from an enemy mon)
-	ld hl, wPartyMonNicks
-	ld a, [wPartyCount]
-	dec a
-	call SkipFixedLengthTextEntries
-	ld d, h
-	ld e, l
-	ld hl, wEnemyMonNicks
-	ld a, [wWhichPokemon]
-	call SkipFixedLengthTextEntries
-	ld bc, NAME_LENGTH
-	call CopyData    ; write new mon's nickname (from an enemy mon)
-	ld a, [wcf91]
-	ld [wd11e], a
-	predef IndexToPokedex
-	ld a, [wd11e]
-	dec a
-	ld c, a
-	ld b, FLAG_SET
-	ld hl, wPokedexOwned
-	push bc
-	call FlagAction ; add to owned pokemon
-	pop bc
-	ld hl, wPokedexSeen
-	call FlagAction ; add to seen pokemon
-	and a
-	ret                  ; return success
-
-_MoveMon:
-	ld a, [wMoveMonType]
-	and a
-	jr z, .checkPartyMonSlots
-	cp DAYCARE_TO_PARTY
-	jr z, .checkPartyMonSlots
-	cp PARTY_TO_DAYCARE
-	ld hl, wDayCareMon
-	jr z, .asm_f575
-	ld hl, wNumInBox
-	ld a, [hl]
-	cp MONS_PER_BOX
-	jr nz, .partyOrBoxNotFull
-	jr .boxFull
-.checkPartyMonSlots
-	ld hl, wPartyCount
-	ld a, [hl]
-	cp PARTY_LENGTH
-	jr nz, .partyOrBoxNotFull
-.boxFull
-	scf
-	ret
-.partyOrBoxNotFull
-	inc a
-	ld [hl], a           ; increment number of mons in party/box
-	ld c, a
-	ld b, 0
-	add hl, bc
-	ld a, [wMoveMonType]
-	cp DAYCARE_TO_PARTY
-	ld a, [wDayCareMon]
-	jr z, .asm_f556
-	ld a, [wcf91]
-.asm_f556
-	ld [hli], a          ; write new mon ID
-	ld [hl], $ff         ; write new sentinel
-	ld a, [wMoveMonType]
-	dec a
-	ld hl, wPartyMons
-	ld bc, wPartyMon2 - wPartyMon1 ; $2c
-	ld a, [wPartyCount]
-	jr nz, .skipToNewMonEntry
-	ld hl, wBoxMons
-	ld bc, wBoxMon2 - wBoxMon1 ; $21
-	ld a, [wNumInBox]
-.skipToNewMonEntry
-	dec a
-	call AddNTimes
-.asm_f575
-	push hl
-	ld e, l
-	ld d, h
-	ld a, [wMoveMonType]
-	and a
-	ld hl, wBoxMons
-	ld bc, wBoxMon2 - wBoxMon1 ; $21
-	jr z, .asm_f591
-	cp DAYCARE_TO_PARTY
-	ld hl, wDayCareMon
-	jr z, .asm_f597
-	ld hl, wPartyMons
-	ld bc, wPartyMon2 - wPartyMon1 ; $2c
-.asm_f591
-	ld a, [wWhichPokemon]
-	call AddNTimes
-.asm_f597
-	push hl
-	push de
-	ld bc, wBoxMon2 - wBoxMon1
-	call CopyData
-	pop de
-	pop hl
-	ld a, [wMoveMonType]
-	and a
-	jr z, .asm_f5b4
-	cp DAYCARE_TO_PARTY
-	jr z, .asm_f5b4
-	ld bc, wBoxMon2 - wBoxMon1
-	add hl, bc
-	ld a, [hl]
-	inc de
-	inc de
-	inc de
-	ld [de], a
-.asm_f5b4
-	ld a, [wMoveMonType]
-	cp PARTY_TO_DAYCARE
-	ld de, wDayCareMonOT
-	jr z, .asm_f5d3
-	dec a
-	ld hl, wPartyMonOT
-	ld a, [wPartyCount]
-	jr nz, .asm_f5cd
-	ld hl, wBoxMonOT
-	ld a, [wNumInBox]
-.asm_f5cd
-	dec a
-	call SkipFixedLengthTextEntries
-	ld d, h
-	ld e, l
-.asm_f5d3
-	ld hl, wBoxMonOT
-	ld a, [wMoveMonType]
-	and a
-	jr z, .asm_f5e6
-	ld hl, wDayCareMonOT
-	cp DAYCARE_TO_PARTY
-	jr z, .asm_f5ec
-	ld hl, wPartyMonOT
-.asm_f5e6
-	ld a, [wWhichPokemon]
-	call SkipFixedLengthTextEntries
-.asm_f5ec
-	ld bc, NAME_LENGTH
-	call CopyData
-	ld a, [wMoveMonType]
-	cp PARTY_TO_DAYCARE
-	ld de, wDayCareMonName
-	jr z, .asm_f611
-	dec a
-	ld hl, wPartyMonNicks
-	ld a, [wPartyCount]
-	jr nz, .asm_f60b
-	ld hl, wBoxMonNicks
-	ld a, [wNumInBox]
-.asm_f60b
-	dec a
-	call SkipFixedLengthTextEntries
-	ld d, h
-	ld e, l
-.asm_f611
-	ld hl, wBoxMonNicks
-	ld a, [wMoveMonType]
-	and a
-	jr z, .asm_f624
-	ld hl, wDayCareMonName
-	cp DAYCARE_TO_PARTY
-	jr z, .asm_f62a
-	ld hl, wPartyMonNicks
-.asm_f624
-	ld a, [wWhichPokemon]
-	call SkipFixedLengthTextEntries
-.asm_f62a
-	ld bc, NAME_LENGTH
-	call CopyData
-	pop hl
-	ld a, [wMoveMonType]
-	cp PARTY_TO_BOX
-	jr z, .asm_f664
-	cp PARTY_TO_DAYCARE
-	jr z, .asm_f664
-	push hl
-	srl a
-	add $2
-	ld [wMonDataLocation], a
-	call LoadMonData
-	callba CalcLevelFromExperience
-	ld a, d
-	ld [wCurEnemyLVL], a
-	pop hl
-	ld bc, wBoxMon2 - wBoxMon1
-	add hl, bc
-	ld [hli], a
-	ld d, h
-	ld e, l
-	ld bc, -18
-	add hl, bc
-	ld b, $1
-	call CalcStats
-.asm_f664
-	and a
-	ret
-
-
-FlagActionPredef:
-	call GetPredefRegisters
-
-FlagAction:
-; Perform action b on bit c
-; in the bitfield at hl.
-;  0: reset
-;  1: set
-;  2: read
-; Return the result in c.
-
-	push hl
-	push de
-	push bc
-
-	; bit
-	ld a, c
-	ld d, a
-	and 7
-	ld e, a
-
-	; byte
-	ld a, d
-	srl a
-	srl a
-	srl a
-	add l
-	ld l, a
-	jr nc, .ok
-	inc h
-.ok
-
-	; d = 1 << e (bitmask)
-	inc e
-	ld d, 1
-.shift
-	dec e
-	jr z, .shifted
-	sla d
-	jr .shift
-.shifted
-
-	ld a, b
-	and a
-	jr z, .reset
-	cp 2
-	jr z, .read
-
-.set
-	ld b, [hl]
-	ld a, d
-	or b
-	ld [hl], a
-	jr .done
-
-.reset
-	ld b, [hl]
-	ld a, d
-	xor $ff
-	and b
-	ld [hl], a
-	jr .done
-
-.read
-	ld b, [hl]
-	ld a, d
-	and b
-.done
-	pop bc
-	pop de
-	pop hl
-	ld c, a
-	ret
-
-
-HealParty:
-; Restore HP and PP.
-
-	ld hl, wPartySpecies
-	ld de, wPartyMon1HP
-.healmon
-	ld a, [hli]
-	cp $ff
-	jr z, .done
-
-	push hl
-	push de
-
-	ld hl, wPartyMon1Status - wPartyMon1HP
-	add hl, de
-	xor a
-	ld [hl], a
-
-	push de
-	ld b, NUM_MOVES ; A Pokémon has 4 moves
-.pp
-	ld hl, wPartyMon1Moves - wPartyMon1HP
-	add hl, de
-
-	ld a, [hl]
-	and a
-	jr z, .nextmove
-
-	dec a
-	ld hl, wPartyMon1PP - wPartyMon1HP
-	add hl, de
-
-	push hl
-	push de
-	push bc
-
-	ld hl, Moves
-	ld bc, MoveEnd - Moves
-	call AddNTimes
-	ld de, wcd6d
-	ld a, BANK(Moves)
-	call FarCopyData
-	ld a, [wcd6d + 5] ; PP is byte 5 of move data
-
-	pop bc
-	pop de
-	pop hl
-
-	inc de
-	push bc
-	ld b, a
-	ld a, [hl]
-	and $c0
-	add b
-	ld [hl], a
-	pop bc
-
-.nextmove
-	dec b
-	jr nz, .pp
-	pop de
-
-	ld hl, wPartyMon1MaxHP - wPartyMon1HP
-	add hl, de
-	ld a, [hli]
-	ld [de], a
-	inc de
-	ld a, [hl]
-	ld [de], a
-
-	pop de
-	pop hl
-
-	push hl
-	ld bc, wPartyMon2 - wPartyMon1
-	ld h, d
-	ld l, e
-	add hl, bc
-	ld d, h
-	ld e, l
-	pop hl
-	jr .healmon
-
-.done
-	xor a
-	ld [wWhichPokemon], a
-	ld [wd11e], a
-
-	ld a, [wPartyCount]
-	ld b, a
-.ppup
-	push bc
-	call RestoreBonusPP
-	pop bc
-	ld hl, wWhichPokemon
-	inc [hl]
-	dec b
-	jr nz, .ppup
-	ret
-
-
-DivideBCDPredef::
-DivideBCDPredef2::
-DivideBCDPredef3::
-DivideBCDPredef4::
-	call GetPredefRegisters
-
-DivideBCD::
-	xor a
-	ld [$ffa5], a
-	ld [$ffa6], a
-	ld [$ffa7], a
-	ld d, $1
-.asm_f72a
-	ld a, [$ffa2]
-	and $f0
-	jr nz, .asm_f75b
-	inc d
-	ld a, [$ffa2]
-	swap a
-	and $f0
-	ld b, a
-	ld a, [$ffa3]
-	swap a
-	ld [$ffa3], a
-	and $f
-	or b
-	ld [$ffa2], a
-	ld a, [$ffa3]
-	and $f0
-	ld b, a
-	ld a, [$ffa4]
-	swap a
-	ld [$ffa4], a
-	and $f
-	or b
-	ld [$ffa3], a
-	ld a, [$ffa4]
-	and $f0
-	ld [$ffa4], a
-	jr .asm_f72a
-.asm_f75b
-	push de
-	push de
-	call DivideBCD_f800
-	pop de
-	ld a, b
-	swap a
-	and $f0
-	ld [$ffa5], a
-	dec d
-	jr z, .asm_f7bc
-	push de
-	call DivideBCD_f7d7
-	call DivideBCD_f800
-	pop de
-	ld a, [$ffa5]
-	or b
-	ld [$ffa5], a
-	dec d
-	jr z, .asm_f7bc
-	push de
-	call DivideBCD_f7d7
-	call DivideBCD_f800
-	pop de
-	ld a, b
-	swap a
-	and $f0
-	ld [$ffa6], a
-	dec d
-	jr z, .asm_f7bc
-	push de
-	call DivideBCD_f7d7
-	call DivideBCD_f800
-	pop de
-	ld a, [$ffa6]
-	or b
-	ld [$ffa6], a
-	dec d
-	jr z, .asm_f7bc
-	push de
-	call DivideBCD_f7d7
-	call DivideBCD_f800
-	pop de
-	ld a, b
-	swap a
-	and $f0
-	ld [$ffa7], a
-	dec d
-	jr z, .asm_f7bc
-	push de
-	call DivideBCD_f7d7
-	call DivideBCD_f800
-	pop de
-	ld a, [$ffa7]
-	or b
-	ld [$ffa7], a
-.asm_f7bc
-	ld a, [$ffa5]
-	ld [$ffa2], a
-	ld a, [$ffa6]
-	ld [$ffa3], a
-	ld a, [$ffa7]
-	ld [$ffa4], a
-	pop de
-	ld a, $6
-	sub d
-	and a
-	ret z
-.asm_f7ce
-	push af
-	call DivideBCD_f7d7
-	pop af
-	dec a
-	jr nz, .asm_f7ce
-	ret
-
-DivideBCD_f7d7:
-	ld a, [$ffa4]
-	swap a
-	and $f
-	ld b, a
-	ld a, [$ffa3]
-	swap a
-	ld [$ffa3], a
-	and $f0
-	or b
-	ld [$ffa4], a
-	ld a, [$ffa3]
-	and $f
-	ld b, a
-	ld a, [$ffa2]
-	swap a
-	ld [$ffa2], a
-	and $f0
-	or b
-	ld [$ffa3], a
-	ld a, [$ffa2]
-	and $f
-	ld [$ffa2], a
-	ret
-
-DivideBCD_f800:
-	ld bc, $3
-.asm_f803
-	ld de, $ff9f
-	ld hl, $ffa2
-	push bc
-	call StringCmp
-	pop bc
-	ret c
-	inc b
-	ld de, $ffa1
-	ld hl, $ffa4
-	push bc
-	call SubBCD
-	pop bc
-	jr .asm_f803
-
-
-AddBCDPredef::
-	call GetPredefRegisters
-
-AddBCD::
-	and a
-	ld b, c
-.add
-	ld a, [de]
-	adc [hl]
-	daa
-	ld [de], a
-	dec de
-	dec hl
-	dec c
-	jr nz, .add
-	jr nc, .done
-	ld a, $99
-	inc de
-.fill
-	ld [de], a
-	inc de
-	dec b
-	jr nz, .fill
-.done
-	ret
-
-
-SubBCDPredef::
-	call GetPredefRegisters
-
-SubBCD::
-	and a
-	ld b, c
-.sub
-	ld a, [de]
-	sbc [hl]
-	daa
-	ld [de], a
-	dec de
-	dec hl
-	dec c
-	jr nz, .sub
-	jr nc, .done
-	ld a, $00
-	inc de
-.fill
-	ld [de], a
-	inc de
-	dec b
-	jr nz, .fill
-	scf
-.done
-	ret
-
-
-InitPlayerData:
-InitPlayerData2:
-
-	call Random
-	ld a, [hRandomSub]
-	ld [wPlayerID], a
-
-	call Random
-	ld a, [hRandomAdd]
-	ld [wPlayerID + 1], a
-
-	ld a, $ff
-	ld [wUnusedD71B], a
-
-	ld hl, wPartyCount
-	call InitializeEmptyList
-	ld hl, wNumInBox
-	call InitializeEmptyList
-	ld hl, wNumBagItems
-	call InitializeEmptyList
-	ld hl, wNumBoxItems
-	call InitializeEmptyList
-
-START_MONEY EQU $3000
-	ld hl, wPlayerMoney + 1
-	ld a, START_MONEY / $100
-	ld [hld], a
-	xor a
-	ld [hli], a
-	inc hl
-	ld [hl], a
-
-	ld [wMonDataLocation], a
-
-	ld hl, wObtainedBadges
-	ld [hli], a
-
-	ld [hl], a
-
-	ld hl, wPlayerCoins
-	ld [hli], a
-	ld [hl], a
-
-	ld hl, wGameProgressFlags
-	ld bc, wGameProgressFlagsEnd - wGameProgressFlags
-	call FillMemory ; clear all game progress flags
-
-	jp InitializeMissableObjectsFlags
-
-InitializeEmptyList:
-	xor a ; count
-	ld [hli], a
-	dec a ; terminator
-	ld [hl], a
-	ret
-
-
-GetQuantityOfItemInBag:
-; In: b = item ID
-; Out: b = how many of that item are in the bag
-	call GetPredefRegisters
-	ld hl, wNumBagItems
-.loop
-	inc hl
-	ld a, [hli]
-	cp $ff
-	jr z, .notInBag
-	cp b
-	jr nz, .loop
-	ld a, [hl]
-	ld b, a
-	ret
-.notInBag
-	ld b, 0
-	ret
-
-FindPathToPlayer:
-	xor a
-	ld hl, hFindPathNumSteps
-	ld [hli], a ; hFindPathNumSteps
-	ld [hli], a ; hFindPathFlags
-	ld [hli], a ; hFindPathYProgress
-	ld [hl], a  ; hFindPathXProgress
-	ld hl, wNPCMovementDirections2
-	ld de, $0
-.loop
-	ld a, [hFindPathYProgress]
-	ld b, a
-	ld a, [hNPCPlayerYDistance] ; Y distance in steps
-	call CalcDifference
-	ld d, a
-	and a
-	jr nz, .asm_f8da
-	ld a, [hFindPathFlags]
-	set 0, a ; current end of path matches the player's Y coordinate
-	ld [hFindPathFlags], a
-.asm_f8da
-	ld a, [hFindPathXProgress]
-	ld b, a
-	ld a, [hNPCPlayerXDistance] ; X distance in steps
-	call CalcDifference
-	ld e, a
-	and a
-	jr nz, .asm_f8ec
-	ld a, [hFindPathFlags]
-	set 1, a ; current end of path matches the player's X coordinate
-	ld [hFindPathFlags], a
-.asm_f8ec
-	ld a, [hFindPathFlags]
-	cp $3 ; has the end of the path reached the player's position?
-	jr z, .done
-; Compare whether the X distance between the player and the current of the path
-; is greater or if the Y distance is. Then, try to reduce whichever is greater.
-	ld a, e
-	cp d
-	jr c, .yDistanceGreater
-; x distance is greater
-	ld a, [hNPCPlayerRelativePosFlags]
-	bit 1, a
-	jr nz, .playerIsLeftOfNPC
-	ld d, NPC_MOVEMENT_RIGHT
-	jr .next1
-.playerIsLeftOfNPC
-	ld d, NPC_MOVEMENT_LEFT
-.next1
-	ld a, [hFindPathXProgress]
-	add 1
-	ld [hFindPathXProgress], a
-	jr .storeDirection
-.yDistanceGreater
-	ld a, [hNPCPlayerRelativePosFlags]
-	bit 0, a
-	jr nz, .playerIsAboveNPC
-	ld d, NPC_MOVEMENT_DOWN
-	jr .next2
-.playerIsAboveNPC
-	ld d, NPC_MOVEMENT_UP
-.next2
-	ld a, [hFindPathYProgress]
-	add 1
-	ld [hFindPathYProgress], a
-.storeDirection
-	ld a, d
-	ld [hli], a
-	ld a, [hFindPathNumSteps]
-	inc a
-	ld [hFindPathNumSteps], a
-	jp .loop
-.done
-	ld [hl], $ff
-	ret
-
-CalcPositionOfPlayerRelativeToNPC:
-	xor a
-	ld [hNPCPlayerRelativePosFlags], a
-	ld a, [wSpriteStateData1 + 4] ; player's sprite screen Y position in pixels
-	ld d, a
-	ld a, [wSpriteStateData1 + 6] ; player's sprite screen X position in pixels
-	ld e, a
-	ld hl, wSpriteStateData1
-	ld a, [hNPCSpriteOffset]
-	add l
-	add $4
-	ld l, a
-	jr nc, .noCarry
-	inc h
-.noCarry
-	ld a, d
-	ld b, a
-	ld a, [hli] ; NPC sprite screen Y position in pixels
-	call CalcDifference
-	jr nc, .NPCSouthOfOrAlignedWithPlayer
-.NPCNorthOfPlayer
-	push hl
-	ld hl, hNPCPlayerRelativePosFlags
-	bit 0, [hl]
-	set 0, [hl]
-	pop hl
-	jr .divideYDistance
-.NPCSouthOfOrAlignedWithPlayer
-	push hl
-	ld hl, hNPCPlayerRelativePosFlags
-	bit 0, [hl]
-	res 0, [hl]
-	pop hl
-.divideYDistance
-	push hl
-	ld hl, hDividend2
-	ld [hli], a
-	ld a, 16
-	ld [hli], a
-	call DivideBytes ; divide Y absolute distance by 16
-	ld a, [hl] ; quotient
-	ld [hNPCPlayerYDistance], a
-	pop hl
-	inc hl
-	ld b, e
-	ld a, [hl] ; NPC sprite screen X position in pixels
-	call CalcDifference
-	jr nc, .NPCEastOfOrAlignedWithPlayer
-.NPCWestOfPlayer
-	push hl
-	ld hl, hNPCPlayerRelativePosFlags
-	bit 1, [hl]
-	set 1, [hl]
-	pop hl
-	jr .divideXDistance
-.NPCEastOfOrAlignedWithPlayer
-	push hl
-	ld hl, hNPCPlayerRelativePosFlags
-	bit 1, [hl]
-	res 1, [hl]
-	pop hl
-.divideXDistance
-	ld [hDividend2], a
-	ld a, 16
-	ld [hDivisor2], a
-	call DivideBytes ; divide X absolute distance by 16
-	ld a, [hQuotient2]
-	ld [hNPCPlayerXDistance], a
-	ld a, [hNPCPlayerRelativePosPerspective]
-	and a
-	ret z
-	ld a, [hNPCPlayerRelativePosFlags]
-	cpl
-	and $3
-	ld [hNPCPlayerRelativePosFlags], a
-	ret
-
-ConvertNPCMovementDirectionsToJoypadMasks:
-	ld a, [hNPCMovementDirections2Index]
-	ld [wNPCMovementDirections2Index], a
-	dec a
-	ld de, wSimulatedJoypadStatesEnd
-	ld hl, wNPCMovementDirections2
-	add l
-	ld l, a
-	jr nc, .loop
-	inc h
-.loop
-	ld a, [hld]
-	call ConvertNPCMovementDirectionToJoypadMask
-	ld [de], a
-	inc de
-	ld a, [hNPCMovementDirections2Index]
-	dec a
-	ld [hNPCMovementDirections2Index], a
-	jr nz, .loop
-	ret
-
-ConvertNPCMovementDirectionToJoypadMask:
-	push hl
-	ld b, a
-	ld hl, NPCMovementDirectionsToJoypadMasksTable
-.loop
-	ld a, [hli]
-	cp $ff
-	jr z, .done
-	cp b
-	jr z, .loadJoypadMask
-	inc hl
-	jr .loop
-.loadJoypadMask
-	ld a, [hl]
-.done
-	pop hl
-	ret
-
-NPCMovementDirectionsToJoypadMasksTable:
-	db NPC_MOVEMENT_UP, D_UP
-	db NPC_MOVEMENT_DOWN, D_DOWN
-	db NPC_MOVEMENT_LEFT, D_LEFT
-	db NPC_MOVEMENT_RIGHT, D_RIGHT
-	db $ff
-
-; unreferenced
-	ret
-
+INCLUDE "engine/add_mon.asm"
+INCLUDE "engine/flag_action.asm"
+INCLUDE "engine/heal_party.asm"
+INCLUDE "engine/bcd.asm"
+INCLUDE "engine/init_player_data.asm"
+INCLUDE "engine/get_bag_item_quantity.asm"
+INCLUDE "engine/pathfinding.asm"
 INCLUDE "engine/hp_bar.asm"
-
 INCLUDE "engine/hidden_object_functions3.asm"
-
 
 SECTION "NPC Sprites 1", ROMX, BANK[NPC_SPRITES_1]