summaryrefslogtreecommitdiff
path: root/engine/pokemon
diff options
context:
space:
mode:
Diffstat (limited to 'engine/pokemon')
-rwxr-xr-xengine/pokemon/experience.asm162
-rwxr-xr-xengine/pokemon/mon_stats.asm475
-rwxr-xr-xengine/pokemon/party_menu.asm783
-rw-r--r--engine/pokemon/stats_screen.asm868
-rwxr-xr-xengine/pokemon/switchpartymons.asm145
-rwxr-xr-xengine/pokemon/tempmon.asm127
-rwxr-xr-xengine/pokemon/types.asm92
7 files changed, 2652 insertions, 0 deletions
diff --git a/engine/pokemon/experience.asm b/engine/pokemon/experience.asm
new file mode 100755
index 00000000..7d026704
--- /dev/null
+++ b/engine/pokemon/experience.asm
@@ -0,0 +1,162 @@
+CalcLevel:
+ ld a, [wTempMonSpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld d, 1
+.next_level
+ inc d
+ ld a, d
+ cp LOW(MAX_LEVEL + 1)
+ jr z, .got_level
+ call CalcExpAtLevel
+ push hl
+ ld hl, wTempMonExp + 2
+ ldh a, [hProduct + 3]
+ ld c, a
+ ld a, [hld]
+ sub c
+ ldh a, [hProduct + 2]
+ ld c, a
+ ld a, [hld]
+ sbc c
+ ldh a, [hProduct + 1]
+ ld c, a
+ ld a, [hl]
+ sbc c
+ pop hl
+ jr nc, .next_level
+
+.got_level
+ dec d
+ ret
+
+CalcExpAtLevel:
+; (a/b)*n**3 + c*n**2 + d*n - e
+ ld a, [wBaseGrowthRate]
+ add a
+ add a
+ ld c, a
+ ld b, 0
+ ld hl, GrowthRates
+ add hl, bc
+; Cube the level
+ call .LevelSquared
+ ld a, d
+ ldh [hMultiplier], a
+ call Multiply
+
+; Multiply by a
+ ld a, [hl]
+ and $f0
+ swap a
+ ldh [hMultiplier], a
+ call Multiply
+; Divide by b
+ ld a, [hli]
+ and $f
+ ldh [hDivisor], a
+ ld b, 4
+ call Divide
+; Push the cubic term to the stack
+ ldh a, [hQuotient + 1]
+ push af
+ ldh a, [hQuotient + 2]
+ push af
+ ldh a, [hQuotient + 3]
+ push af
+; Square the level and multiply by the lower 7 bits of c
+ call .LevelSquared
+ ld a, [hl]
+ and $7f
+ ldh [hMultiplier], a
+ call Multiply
+; Push the absolute value of the quadratic term to the stack
+ ldh a, [hProduct + 1]
+ push af
+ ldh a, [hProduct + 2]
+ push af
+ ldh a, [hProduct + 3]
+ push af
+ ld a, [hli]
+ push af
+; Multiply the level by d
+ xor a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, d
+ ldh [hMultiplicand + 2], a
+ ld a, [hli]
+ ldh [hMultiplier], a
+ call Multiply
+; Subtract e
+ ld b, [hl]
+ ldh a, [hProduct + 3]
+ sub b
+ ldh [hMultiplicand + 2], a
+ ld b, 0
+ ldh a, [hProduct + 2]
+ sbc b
+ ldh [hMultiplicand + 1], a
+ ldh a, [hProduct + 1]
+ sbc b
+ ldh [hMultiplicand], a
+; If bit 7 of c is set, c is negative; otherwise, it's positive
+ pop af
+ and $80
+ jr nz, .subtract
+; Add c*n**2 to (d*n - e)
+ pop bc
+ ldh a, [hProduct + 3]
+ add b
+ ldh [hMultiplicand + 2], a
+ pop bc
+ ldh a, [hProduct + 2]
+ adc b
+ ldh [hMultiplicand + 1], a
+ pop bc
+ ldh a, [hProduct + 1]
+ adc b
+ ldh [hMultiplicand], a
+ jr .done_quadratic
+
+.subtract
+; Subtract c*n**2 from (d*n - e)
+ pop bc
+ ldh a, [hProduct + 3]
+ sub b
+ ldh [hMultiplicand + 2], a
+ pop bc
+ ldh a, [hProduct + 2]
+ sbc b
+ ldh [hMultiplicand + 1], a
+ pop bc
+ ldh a, [hProduct + 1]
+ sbc b
+ ldh [hMultiplicand], a
+
+.done_quadratic
+; Add (a/b)*n**3 to (d*n - e +/- c*n**2)
+ pop bc
+ ldh a, [hProduct + 3]
+ add b
+ ldh [hMultiplicand + 2], a
+ pop bc
+ ldh a, [hProduct + 2]
+ adc b
+ ldh [hMultiplicand + 1], a
+ pop bc
+ ldh a, [hProduct + 1]
+ adc b
+ ldh [hMultiplicand], a
+ ret
+
+.LevelSquared:
+ xor a
+ ldh [hMultiplicand + 0], a
+ ldh [hMultiplicand + 1], a
+ ld a, d
+ ldh [hMultiplicand + 2], a
+ ldh [hMultiplier], a
+ jp Multiply
+
+INCLUDE "data/growth_rates.asm"
diff --git a/engine/pokemon/mon_stats.asm b/engine/pokemon/mon_stats.asm
new file mode 100755
index 00000000..04285f87
--- /dev/null
+++ b/engine/pokemon/mon_stats.asm
@@ -0,0 +1,475 @@
+DrawPlayerHP:
+ ld a, 1
+ jr DrawHP
+
+DrawEnemyHP:
+ ld a, 2
+
+DrawHP:
+ ld [wWhichHPBar], a
+ push hl
+ push bc
+ ; box mons have full HP
+ ld a, [wMonType]
+ cp BOXMON
+ jr z, .at_least_1_hp
+
+ ld a, [wTempMonHP]
+ ld b, a
+ ld a, [wTempMonHP + 1]
+ ld c, a
+
+; Any HP?
+ or b
+ jr nz, .at_least_1_hp
+
+ xor a
+ ld c, a
+ ld e, a
+ ld a, 6
+ ld d, a
+ jp .fainted
+
+.at_least_1_hp
+ ld a, [wTempMonMaxHP]
+ ld d, a
+ ld a, [wTempMonMaxHP + 1]
+ ld e, a
+ ld a, [wMonType]
+ cp BOXMON
+ jr nz, .not_boxmon
+
+ ld b, d
+ ld c, e
+
+.not_boxmon
+ predef ComputeHPBarPixels
+ ld a, 6
+ ld d, a
+ ld c, a
+
+.fainted
+ ld a, c
+ pop bc
+ ld c, a
+ pop hl
+ push de
+ push hl
+ push hl
+ call DrawBattleHPBar
+ pop hl
+
+; Print HP
+ bccoord 1, 1, 0
+ add hl, bc
+ ld de, wTempMonHP
+ ld a, [wMonType]
+ cp BOXMON
+ jr nz, .not_boxmon_2
+ ld de, wTempMonMaxHP
+.not_boxmon_2
+ lb bc, 2, 3
+ call PrintNum
+
+ ld a, "/"
+ ld [hli], a
+
+; Print max HP
+ ld de, wTempMonMaxHP
+ lb bc, 2, 3
+ call PrintNum
+ pop hl
+ pop de
+ ret
+
+INCLUDE "engine/pokemon/stats_screen.asm"
+
+PrintTempMonStats:
+; Print wTempMon's stats at hl, with spacing bc.
+ push bc
+ push hl
+ ld de, .StatNames
+ call PlaceString
+ pop hl
+ pop bc
+ add hl, bc
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ ld de, wTempMonAttack
+ lb bc, 2, 3
+ call .PrintStat
+ ld de, wTempMonDefense
+ call .PrintStat
+ ld de, wTempMonSpclAtk
+ call .PrintStat
+ ld de, wTempMonSpclDef
+ call .PrintStat
+ ld de, wTempMonSpeed
+ jp PrintNum
+
+.PrintStat:
+ push hl
+ call PrintNum
+ pop hl
+ ld de, SCREEN_WIDTH * 2
+ add hl, de
+ ret
+
+.StatNames:
+ db "ATTACK"
+ next "DEFENSE"
+ next "SPCL.ATK"
+ next "SPCL.DEF"
+ next "SPEED"
+ next "@"
+
+GetGender:
+; Return the gender of a given monster (wCurPartyMon/wCurOTMon/wCurWildMon).
+; When calling this function, a should be set to an appropriate wMonType value.
+
+; return values:
+; a = 1: f = nc|nz; male
+; a = 0: f = nc|z; female
+; f = c: genderless
+
+; This is determined by comparing the Attack and Speed DVs
+; with the species' gender ratio.
+
+; Figure out what type of monster struct we're looking at.
+
+; 0: PartyMon
+ ld hl, wPartyMon1DVs
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld a, [wMonType]
+ and a
+ jr z, .PartyMon
+
+; 1: OTPartyMon
+ ld hl, wOTPartyMon1DVs
+ dec a
+ jr z, .PartyMon
+
+; 2: sBoxMon
+ ld hl, sBoxMon1DVs
+ ld bc, BOXMON_STRUCT_LENGTH
+ dec a
+ jr z, .sBoxMon
+
+; 3: Unknown
+ ld hl, wTempMonDVs
+ dec a
+ jr z, .DVs
+
+; else: WildMon
+ ld hl, wEnemyMonDVs
+ jr .DVs
+
+; Get our place in the party/box.
+
+.PartyMon:
+.sBoxMon
+ ld a, [wCurPartyMon]
+ call AddNTimes
+
+.DVs:
+; sBoxMon data is read directly from SRAM.
+ ld a, [wMonType]
+ cp BOXMON
+ ld a, BANK(sBox)
+ call z, OpenSRAM
+
+; Attack DV
+ ld a, [hli]
+ and $f0
+ ld b, a
+; Speed DV
+ ld a, [hl]
+ and $f0
+ swap a
+
+; Put our DVs together.
+ or b
+ ld b, a
+
+; Close SRAM if we were dealing with a sBoxMon.
+ ld a, [wMonType]
+ cp BOXMON
+ call z, CloseSRAM
+
+; We need the gender ratio to do anything with this.
+ push bc
+ ld a, [wCurPartySpecies]
+ dec a
+ ld hl, BaseData + BASE_GENDER
+ ld bc, BASE_DATA_SIZE
+ call AddNTimes
+ pop bc
+
+ ld a, BANK(BaseData)
+ call GetFarByte
+
+; The higher the ratio, the more likely the monster is to be female.
+
+ cp GENDER_UNKNOWN
+ jr z, .Genderless
+
+ and a ; GENDER_F0?
+ jr z, .Male
+
+ cp GENDER_F100
+ jr z, .Female
+
+; Values below the ratio are male, and vice versa.
+ cp b
+ jr c, .Male
+
+.Female:
+ xor a
+ ret
+
+.Male:
+ ld a, 1
+ and a
+ ret
+
+.Genderless:
+ scf
+ ret
+
+ListMovePP:
+ ld a, [wNumMoves]
+ inc a
+ ld c, a
+ ld a, NUM_MOVES
+ sub c
+ ld b, a
+ push hl
+ ld a, [wBuffer1]
+ ld e, a
+ ld d, $0
+ ld a, $3e ; P
+ call .load_loop
+ ld a, b
+ and a
+ jr z, .skip
+ ld c, a
+ ld a, "-"
+ call .load_loop
+
+.skip
+ pop hl
+ inc hl
+ inc hl
+ inc hl
+ ld d, h
+ ld e, l
+ ld hl, wTempMonMoves
+ ld b, 0
+.loop
+ ld a, [hli]
+ and a
+ jr z, .done
+ push bc
+ push hl
+ push de
+ ld hl, wMenuCursorY
+ ld a, [hl]
+ push af
+ ld [hl], b
+ push hl
+ callfar GetMaxPPOfMove
+ pop hl
+ pop af
+ ld [hl], a
+ pop de
+ pop hl
+ push hl
+ ld bc, wTempMonPP - (wTempMonMoves + 1)
+ add hl, bc
+ ld a, [hl]
+ and $3f
+ ld [wStringBuffer1 + 4], a
+ ld h, d
+ ld l, e
+ push hl
+ ld de, wStringBuffer1 + 4
+ lb bc, 1, 2
+ call PrintNum
+ ld a, "/"
+ ld [hli], a
+ ld de, wTempPP
+ lb bc, 1, 2
+ call PrintNum
+ pop hl
+ ld a, [wBuffer1]
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld d, h
+ ld e, l
+ pop hl
+ pop bc
+ inc b
+ ld a, b
+ cp NUM_MOVES
+ jr nz, .loop
+
+.done
+ ret
+
+.load_loop
+ ld [hli], a
+ ld [hld], a
+ add hl, de
+ dec c
+ jr nz, .load_loop
+ ret
+
+Unused_PlaceEnemyHPLevel:
+ push hl
+ push hl
+ ld hl, wPartyMonNicknames
+ ld a, [wCurPartyMon]
+ call GetNick
+ pop hl
+ call PlaceString
+ call CopyMonToTempMon
+ pop hl
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr z, .egg
+ push hl
+ ld bc, -12
+ add hl, bc
+ ld b, $0
+ call DrawEnemyHP
+ pop hl
+ ld bc, 5
+ add hl, bc
+ push de
+ call PrintLevel
+ pop de
+
+.egg
+ ret
+
+PlaceStatusString:
+ push de
+ inc de
+ inc de
+ ld a, [de]
+ ld b, a
+ inc de
+ ld a, [de]
+ or b
+ pop de
+ jr nz, PlaceNonFaintStatus
+ push de
+ ld de, FntString
+ call CopyStatusString
+ pop de
+ ld a, $1
+ and a
+ ret
+
+FntString:
+ db "FNT@"
+
+CopyStatusString:
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ ld [hl], a
+ ret
+
+PlaceNonFaintStatus:
+ push de
+ ld a, [de]
+ ld de, PsnString
+ bit PSN, a
+ jr nz, .place
+ ld de, BrnString
+ bit BRN, a
+ jr nz, .place
+ ld de, FrzString
+ bit FRZ, a
+ jr nz, .place
+ ld de, ParString
+ bit PAR, a
+ jr nz, .place
+ ld de, SlpString
+ and SLP
+ jr z, .no_status
+
+.place
+ call CopyStatusString
+ ld a, $1
+ and a
+
+.no_status
+ pop de
+ ret
+
+SlpString: db "SLP@"
+PsnString: db "PSN@"
+BrnString: db "BRN@"
+FrzString: db "FRZ@"
+ParString: db "PAR@"
+
+ListMoves:
+; List moves at hl, spaced every [wBuffer1] tiles.
+ ld de, wListMoves_MoveIndicesBuffer
+ ld b, $0
+.moves_loop
+ ld a, [de]
+ inc de
+ and a
+ jr z, .no_more_moves
+ push de
+ push hl
+ push hl
+ ld [wCurSpecies], a
+ ld a, MOVE_NAME
+ ld [wNamedObjectTypeBuffer], a
+ call GetName
+ ld de, wStringBuffer1
+ pop hl
+ push bc
+ call PlaceString
+ pop bc
+ ld a, b
+ ld [wNumMoves], a
+ inc b
+ pop hl
+ push bc
+ ld a, [wBuffer1]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ pop bc
+ pop de
+ ld a, b
+ cp NUM_MOVES
+ jr z, .done
+ jr .moves_loop
+
+.no_more_moves
+ ld a, b
+.nonmove_loop
+ push af
+ ld [hl], "-"
+ ld a, [wBuffer1]
+ ld c, a
+ ld b, 0
+ add hl, bc
+ pop af
+ inc a
+ cp NUM_MOVES
+ jr nz, .nonmove_loop
+
+.done
+ ret
diff --git a/engine/pokemon/party_menu.asm b/engine/pokemon/party_menu.asm
new file mode 100755
index 00000000..93f9b93b
--- /dev/null
+++ b/engine/pokemon/party_menu.asm
@@ -0,0 +1,783 @@
+SelectMonFromParty:
+ call DisableSpriteUpdates
+ xor a
+ ld [wPartyMenuActionText], a
+ call ClearBGPalettes
+ call InitPartyMenuLayout
+ call WaitBGMap
+ call SetPalettes
+ call DelayFrame
+ call PartyMenuSelect
+ call ReturnToMapWithSpeechTextbox
+ ret
+
+SelectTradeOrDayCareMon:
+ ld a, b
+ ld [wPartyMenuActionText], a
+ call DisableSpriteUpdates
+ call ClearBGPalettes
+ call InitPartyMenuLayout
+ call WaitBGMap
+ ld b, SCGB_PARTY_MENU
+ call GetSGBLayout
+ call SetPalettes
+ call DelayFrame
+ call PartyMenuSelect
+ call ReturnToMapWithSpeechTextbox
+ ret
+
+InitPartyMenuLayout:
+ call LoadPartyMenuGFX
+ call InitPartyMenuWithCancel
+ call InitPartyMenuGFX
+ call WritePartyMenuTilemap
+ call PrintPartyMenuText
+ ret
+
+LoadPartyMenuGFX:
+ call LoadFontsBattleExtra
+ callfar InitPartyMenuPalettes ; engine/color.asm
+ callfar ClearSpriteAnims2
+ ret
+
+WritePartyMenuTilemap:
+ ld hl, wOptions
+ ld a, [hl]
+ push af
+ set NO_TEXT_SCROLL, [hl]
+ xor a
+ ldh [hBGMapMode], a
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, " "
+ call ByteFill ; blank the tilemap
+ call GetPartyMenuQualityIndexes
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .end
+ push hl
+ ld hl, .Jumptable
+ rst JumpTable
+ pop hl
+ jr .loop
+.end
+ pop af
+ ld [wOptions], a
+ ret
+
+.Jumptable:
+; entries correspond to PARTYMENUQUALITY_* constants
+ dw PlacePartyNicknames
+ dw PlacePartyHPBar
+ dw PlacePartyMenuHPDigits
+ dw PlacePartyMonLevel
+ dw PlacePartyMonStatus
+ dw PlacePartyMonTMHMCompatibility
+ dw PlacePartyMonEvoStoneCompatibility
+ dw PlacePartyMonGender
+
+PlacePartyNicknames:
+ hlcoord 3, 1
+ ld a, [wPartyCount]
+ and a
+ jr z, .end
+ ld c, a
+ ld b, 0
+.loop
+ push bc
+ push hl
+ push hl
+ ld hl, wPartyMonNicknames
+ ld a, b
+ call GetNick
+ pop hl
+ call PlaceString
+ pop hl
+ ld de, 2 * SCREEN_WIDTH
+ add hl, de
+ pop bc
+ inc b
+ dec c
+ jr nz, .loop
+
+.end
+ dec hl
+ dec hl
+ ld de, .CANCEL
+ call PlaceString
+ ret
+
+.CANCEL:
+ db "CANCEL@"
+
+PlacePartyHPBar:
+ xor a
+ ld [wSGBPals], a
+ ld a, [wPartyCount]
+ and a
+ ret z
+ ld c, a
+ ld b, 0
+ hlcoord 11, 2
+.loop
+ push bc
+ push hl
+ call PartyMenuCheckEgg
+ jr z, .skip
+ push hl
+ call PlacePartymonHPBar
+ pop hl
+ ld d, $6
+ ld b, $0
+ call DrawBattleHPBar
+ ld hl, wHPPals
+ ld a, [wSGBPals]
+ ld c, a
+ ld b, $0
+ add hl, bc
+ call SetHPPal
+ ld b, SCGB_PARTY_MENU_HP_PALS
+ call GetSGBLayout
+.skip
+ ld hl, wSGBPals
+ inc [hl]
+ pop hl
+ ld de, 2 * SCREEN_WIDTH
+ add hl, de
+ pop bc
+ inc b
+ dec c
+ jr nz, .loop
+ ld b, SCGB_PARTY_MENU
+ call GetSGBLayout
+ ret
+
+PlacePartymonHPBar:
+ ld a, b
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld hl, wPartyMon1HP
+ call AddNTimes
+ ld a, [hli]
+ or [hl]
+ jr nz, .not_fainted
+ xor a
+ ld e, a
+ ld c, a
+ ret
+
+.not_fainted
+ dec hl
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld c, a
+ ld a, [hli]
+ ld d, a
+ ld a, [hli]
+ ld e, a
+ predef ComputeHPBarPixels
+ ret
+
+PlacePartyMenuHPDigits:
+ ld a, [wPartyCount]
+ and a
+ ret z
+ ld c, a
+ ld b, 0
+ hlcoord 13, 1
+.loop
+ push bc
+ push hl
+ call PartyMenuCheckEgg
+ jr z, .next
+ push hl
+ ld a, b
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld hl, wPartyMon1HP
+ call AddNTimes
+ ld e, l
+ ld d, h
+ pop hl
+ push de
+ lb bc, 2, 3
+ call PrintNum
+ pop de
+ ld a, "/"
+ ld [hli], a
+ inc de
+ inc de
+ lb bc, 2, 3
+ call PrintNum
+
+.next
+ pop hl
+ ld de, 2 * SCREEN_WIDTH
+ add hl, de
+ pop bc
+ inc b
+ dec c
+ jr nz, .loop
+ ret
+
+PlacePartyMonLevel:
+ ld a, [wPartyCount]
+ and a
+ ret z
+ ld c, a
+ ld b, 0
+ hlcoord 8, 2
+.loop
+ push bc
+ push hl
+ call PartyMenuCheckEgg
+ jr z, .next
+ push hl
+ ld a, b
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld hl, wPartyMon1Level
+ call AddNTimes
+ ld e, l
+ ld d, h
+ pop hl
+ ld a, [de]
+ cp 100 ; This is distinct from MAX_LEVEL.
+ jr nc, .ThreeDigits
+ ld a, "<LV>"
+ ld [hli], a
+ lb bc, PRINTNUM_LEFTALIGN | 1, 2
+ ; jr .okay
+.ThreeDigits:
+ lb bc, PRINTNUM_LEFTALIGN | 1, 3
+; .okay
+ call PrintNum
+
+.next
+ pop hl
+ ld de, SCREEN_WIDTH * 2
+ add hl, de
+ pop bc
+ inc b
+ dec c
+ jr nz, .loop
+ ret
+
+PlacePartyMonStatus:
+ ld a, [wPartyCount]
+ and a
+ ret z
+ ld c, a
+ ld b, 0
+ hlcoord 5, 2
+.loop
+ push bc
+ push hl
+ call PartyMenuCheckEgg
+ jr z, .next
+ push hl
+ ld a, b
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld hl, wPartyMon1Status
+ call AddNTimes
+ ld e, l
+ ld d, h
+ pop hl
+ call PlaceStatusString
+
+.next
+ pop hl
+ ld de, SCREEN_WIDTH * 2
+ add hl, de
+ pop bc
+ inc b
+ dec c
+ jr nz, .loop
+ ret
+
+PlacePartyMonTMHMCompatibility:
+ ld a, [wPartyCount]
+ and a
+ ret z
+ ld c, a
+ ld b, 0
+ hlcoord 12, 2
+.loop
+ push bc
+ push hl
+ call PartyMenuCheckEgg
+ jr z, .next
+ push hl
+ ld hl, wPartySpecies
+ ld e, b
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ predef CanLearnTMHMMove
+ pop hl
+ call .PlaceAbleNotAble
+ call PlaceString
+
+.next
+ pop hl
+ ld de, SCREEN_WIDTH * 2
+ add hl, de
+ pop bc
+ inc b
+ dec c
+ jr nz, .loop
+ ret
+
+.PlaceAbleNotAble:
+ ld a, c
+ and a
+ jr nz, .able
+ ld de, .string_not_able
+ ret
+
+.able
+ ld de, .string_able
+ ret
+
+.string_able
+ db "ABLE@"
+
+.string_not_able
+ db "NOT ABLE@"
+
+PlacePartyMonEvoStoneCompatibility:
+ ld a, [wPartyCount]
+ and a
+ ret z
+ ld c, a
+ ld b, 0
+ hlcoord 12, 2
+.loop
+ push bc
+ push hl
+ call PartyMenuCheckEgg
+ jr z, .next
+ push hl
+ ld a, b
+ ld bc, PARTYMON_STRUCT_LENGTH
+ ld hl, wPartyMon1Species
+ call AddNTimes
+ ld a, [hl]
+ dec a
+ ld e, a
+ ld d, 0
+ ld hl, EvosAttacksPointers
+ add hl, de
+ add hl, de
+ call .DetermineCompatibility
+ pop hl
+ call PlaceString
+
+.next
+ pop hl
+ ld de, 2 * SCREEN_WIDTH
+ add hl, de
+ pop bc
+ inc b
+ dec c
+ jr nz, .loop
+ ret
+
+.DetermineCompatibility:
+ ld de, wStringBuffer1
+ ld a, BANK(EvosAttacksPointers)
+ ld bc, 2
+ call FarCopyBytes
+ ld hl, wStringBuffer1
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wStringBuffer1
+ ld a, BANK("Evolutions and Attacks")
+ ld bc, 10
+ call FarCopyBytes
+ ld hl, wStringBuffer1
+.loop2
+ ld a, [hli]
+ and a
+ jr z, .nope
+ inc hl
+ inc hl
+ cp EVOLVE_ITEM
+ jr nz, .loop2
+ dec hl
+ dec hl
+ ld a, [wCurItem]
+ cp [hl]
+ inc hl
+ inc hl
+ jr nz, .loop2
+ ld de, .string_able
+ ret
+
+.nope
+ ld de, .string_not_able
+ ret
+
+.string_able
+ db "ABLE@"
+.string_not_able
+ db "NOT ABLE@"
+
+PlacePartyMonGender:
+ ld a, [wPartyCount]
+ and a
+ ret z
+ ld c, a
+ ld b, 0
+ hlcoord 12, 2
+.loop
+ push bc
+ push hl
+ call PartyMenuCheckEgg
+ jr z, .next
+ ld [wCurPartySpecies], a
+ push hl
+ ld a, b
+ ld [wCurPartyMon], a
+ xor a
+ ld [wMonType], a
+ call GetGender
+ ld de, .unknown
+ jr c, .got_gender
+ ld de, .male
+ jr nz, .got_gender
+ ld de, .female
+
+.got_gender
+ pop hl
+ call PlaceString
+
+.next
+ pop hl
+ ld de, 2 * SCREEN_WIDTH
+ add hl, de
+ pop bc
+ inc b
+ dec c
+ jr nz, .loop
+ ret
+
+.male
+ db "♂…MALE@"
+
+.female
+ db "♀…FEMALE@"
+
+.unknown
+ db "…UNKNOWN@"
+
+PartyMenuCheckEgg:
+ ld a, LOW(wPartySpecies)
+ add b
+ ld e, a
+ ld a, HIGH(wPartySpecies)
+ adc 0
+ ld d, a
+ ld a, [de]
+ cp EGG
+ ret
+
+GetPartyMenuQualityIndexes:
+ ld a, [wPartyMenuActionText]
+ and $f0
+ jr nz, .skip
+ ld a, [wPartyMenuActionText]
+ and $f
+ ld e, a
+ ld d, 0
+ ld hl, PartyMenuQualityPointers
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+
+.skip
+ ld hl, PartyMenuQualityPointers.Default
+ ret
+
+INCLUDE "data/party_menu_qualities.asm"
+
+InitPartyMenuGFX:
+ ld hl, wPartyCount
+ ld a, [hli]
+ and a
+ ret z
+ ld c, a
+ xor a
+ ldh [hObjectStructIndexBuffer], a
+.loop
+ push bc
+ push hl
+ ld hl, LoadMenuMonIcon
+ ld a, BANK(LoadMenuMonIcon)
+ ld e, MONICON_PARTYMENU
+ rst FarCall
+ ldh a, [hObjectStructIndexBuffer]
+ inc a
+ ldh [hObjectStructIndexBuffer], a
+ pop hl
+ pop bc
+ dec c
+ jr nz, .loop
+ callfar PlaySpriteAnimations
+ ret
+
+InitPartyMenuWithCancel:
+; with cancel
+ xor a
+ ld [wSwitchMon], a
+ ld de, PartyMenuAttributes
+ call SetMenuAttributes
+ ld a, [wPartyCount]
+ inc a
+ ld [w2DMenuNumRows], a ; list length
+ dec a
+ ld b, a
+ ld a, [wPartyMenuCursor]
+ and a
+ jr z, .skip
+ inc b
+ cp b
+ jr c, .done
+
+.skip
+ ld a, 1
+
+.done
+ ld [wMenuCursorY], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuJoypadFilter], a
+ ret
+
+InitPartyMenuNoCancel:
+; no cancel
+ ld de, PartyMenuAttributes
+ call SetMenuAttributes
+ ld a, [wPartyCount]
+ ld [w2DMenuNumRows], a ; list length
+ ld b, a
+ ld a, [wPartyMenuCursor]
+ and a
+ jr z, .skip
+ inc b
+ cp b
+ jr c, .done
+.skip
+ ld a, 1
+.done
+ ld [wMenuCursorY], a
+ ld a, A_BUTTON | B_BUTTON
+ ld [wMenuJoypadFilter], a
+ ret
+
+PartyMenuAttributes:
+; cursor y
+; cursor x
+; num rows
+; num cols
+; bit 6: animate sprites bit 5: wrap around
+; ?
+; distance between items (hi: y, lo: x)
+; allowed buttons (mask)
+ db 1, 0
+ db 0, 1
+ db $60, $00
+ dn 2, 0
+ db 0
+
+PartyMenuSelect:
+; sets carry if exitted menu.
+ call StaticMenuJoypad
+ call PlaceHollowCursor
+ ld a, [wPartyCount]
+ inc a
+ ld b, a
+ ld a, [wMenuCursorY] ; menu selection?
+ cp b
+ jr z, .exitmenu ; CANCEL
+ ld [wPartyMenuCursor], a
+ ldh a, [hJoyLast]
+ ld b, a
+ bit B_BUTTON_F, b
+ jr nz, .exitmenu ; B button
+ ld a, [wMenuCursorY]
+ dec a
+ ld [wCurPartyMon], a
+ ld c, a
+ ld b, $0
+ ld hl, wPartySpecies
+ add hl, bc
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ call WaitSFX
+ and a
+ ret
+
+.exitmenu
+ ld de, SFX_READ_TEXT_2
+ call PlaySFX
+ call WaitSFX
+ scf
+ ret
+
+PrintPartyMenuText:
+ hlcoord 0, 14
+ lb bc, 2, 18
+ call Textbox
+ ld a, [wPartyCount]
+ and a
+ jr nz, .haspokemon
+ ld de, YouHaveNoPKMNString
+ jr .gotstring
+.haspokemon
+ ld a, [wPartyMenuActionText]
+ and $f ; drop high nibble
+ ld hl, PartyMenuStrings
+ ld e, a
+ ld d, $0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld d, [hl]
+ ld e, a
+.gotstring
+ ld a, [wOptions]
+ push af
+ set NO_TEXT_SCROLL, a
+ ld [wOptions], a
+ hlcoord 1, 16 ; Coord
+ call PlaceString
+ pop af
+ ld [wOptions], a
+ ret
+
+PartyMenuStrings:
+ dw ChooseAMonString
+ dw UseOnWhichPKMNString
+ dw WhichPKMNString
+ dw TeachWhichPKMNString
+ dw MoveToWhereString
+ dw UseOnWhichPKMNString
+ dw ChooseAMonString ; Probably used to be ChooseAFemalePKMNString
+ dw ChooseAMonString ; Probably used to be ChooseAMalePKMNString
+ dw ToWhichPKMNString
+
+ChooseAMonString:
+ db "Choose a #MON.@"
+
+UseOnWhichPKMNString:
+ db "Use on which <PK><MN>?@"
+
+WhichPKMNString:
+ db "Which <PK><MN>?@"
+
+TeachWhichPKMNString:
+ db "Teach which <PK><MN>?@"
+
+MoveToWhereString:
+ db "Move to where?@"
+
+ChooseAFemalePKMNString:
+; unused
+ db "Choose a ♀<PK><MN>.@"
+
+ChooseAMalePKMNString:
+; unused
+ db "Choose a ♂<PK><MN>.@"
+
+ToWhichPKMNString:
+ db "To which <PK><MN>?@"
+
+YouHaveNoPKMNString:
+ db "You have no <PK><MN>!@"
+
+PrintPartyMenuActionText:
+ ld a, [wCurPartyMon]
+ ld hl, wPartyMonNicknames
+ call GetNick
+ ld a, [wPartyMenuActionText]
+ and $f
+ ld hl, .MenuActionTexts
+ call .PrintText
+ ret
+
+.MenuActionTexts:
+; entries correspond to PARTYMENUTEXT_* constants
+ dw .CuredOfPoisonText
+ dw .BurnWasHealedText
+ dw .WasDefrostedText
+ dw .WokeUpText
+ dw .RidOfParalysisText
+ dw .RecoveredSomeHPText
+ dw .HealthReturnedText
+ dw .RevitalizedText
+ dw .GrewToLevelText
+ dw .CameToItsSensesText
+
+.RecoveredSomeHPText:
+ text_far _RecoveredSomeHPText
+ text_end
+
+.CuredOfPoisonText:
+ text_far _CuredOfPoisonText
+ text_end
+
+.RidOfParalysisText:
+ text_far _RidOfParalysisText
+ text_end
+
+.BurnWasHealedText:
+ text_far _BurnWasHealedText
+ text_end
+
+.WasDefrostedText:
+ text_far _WasDefrostedText
+ text_end
+
+.WokeUpText:
+ text_far _WokeUpText
+ text_end
+
+.HealthReturnedText:
+ text_far _HealthReturnedText
+ text_end
+
+.RevitalizedText:
+ text_far _RevitalizedText
+ text_end
+
+.GrewToLevelText:
+ text_far _GrewToLevelText
+ text_end
+
+.CameToItsSensesText:
+ text_far _CameToItsSensesText
+ text_end
+
+.PrintText:
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wOptions]
+ push af
+ set NO_TEXT_SCROLL, a
+ ld [wOptions], a
+ call PrintText
+ pop af
+ ld [wOptions], a
+ ret
diff --git a/engine/pokemon/stats_screen.asm b/engine/pokemon/stats_screen.asm
new file mode 100644
index 00000000..a2345f37
--- /dev/null
+++ b/engine/pokemon/stats_screen.asm
@@ -0,0 +1,868 @@
+ const_def 1
+ const PINK_PAGE ; 1
+ const GREEN_PAGE ; 2
+ const BLUE_PAGE ; 3
+
+StatsScreenInit:
+ ldh a, [hMapAnims]
+ push af
+ xor a
+ ldh [hMapAnims], a ; disable overworld tile animations
+
+ ld c, 1
+ call StatsScreenMain
+
+ ; restore old values
+ pop af
+ ldh [hMapAnims], a
+ ret
+
+StatsScreenMain:
+ push bc
+ ld a, [wMonType]
+ cp TEMPMON
+ jr nz, .not_tempmon
+ ld a, [wBufferMonSpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+ ld hl, wBufferMon
+ ld de, wTempMon
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call CopyBytes
+ jr .got_stats
+
+.not_tempmon
+ call CopyMonToTempMon
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jp z, .got_stats
+ ld a, [wMonType]
+ cp BOXMON
+ jr c, .got_stats
+ call CalcTempmonStats
+
+.got_stats
+ call ClearBGPalettes
+ call ClearTilemap
+ call UpdateSprites
+ callfar StatsScreen_LoadFont
+
+ pop bc
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jp z, EggStatsInit
+ call StatsScreen_InitUpperHalf
+ ld b, 0
+ jp StatsScreen_JumpToLoadPageFunction
+
+StatsScreen_LoadPage:
+ push bc
+ ld de, .done_loading
+ push de
+; first jump to LoadPage function in jumptable
+ jp hl
+
+; return here after LoadPage function finishes
+.done_loading
+ pop bc
+ ld b, 1
+
+.joypad_loop
+ call GetJoypad
+ ld a, [wMonType]
+ cp TEMPMON
+ jr nz, .not_tempmon
+ push hl
+ push de
+ push bc
+ farcall StatsScreenDPad
+ pop bc
+ pop de
+ pop hl
+ ld a, [wMenuJoypad]
+ and D_DOWN | D_UP
+ jr nz, StatsScreenMain
+ ld a, [wMenuJoypad]
+ jr .joypad_action
+
+.not_tempmon
+ ldh a, [hJoyPressed]
+
+.joypad_action
+ and D_DOWN | D_UP | D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON
+ jr z, .joypad_loop
+ bit B_BUTTON_F, a
+ jp nz, StatsScreen_Exit
+ bit D_LEFT_F, a
+ jr nz, .d_left
+ bit D_RIGHT_F, a
+ jr nz, .d_right
+ bit A_BUTTON_F, a
+ jr nz, .a_button
+ bit D_UP_F, a
+ jr nz, .d_up
+
+; .d_down
+ ld a, [wMonType]
+ cp BOXMON
+ jr nc, .joypad_loop
+ and a
+ ld a, [wPartyCount]
+ jr z, .next_mon
+ ld a, [wOTPartyCount]
+.next_mon
+ ld b, a
+ ld a, [wCurPartyMon]
+ inc a
+ cp b
+ jr z, .joypad_loop
+ ld [wCurPartyMon], a
+ ld b, a
+ ld a, [wMonType]
+ and a
+ jr nz, .load_mon
+ ld a, b
+ inc a
+ ld [wPartyMenuCursor], a
+ jr .load_mon
+
+.d_up
+ ld a, [wCurPartyMon]
+ and a
+ jr z, .joypad_loop
+ dec a
+ ld [wCurPartyMon], a
+ ld b, a
+ ld a, [wMonType]
+ and a
+ jr nz, .load_mon
+ ld a, b
+ inc a
+ ld [wPartyMenuCursor], a
+; fall through
+.load_mon
+ jp StatsScreenMain
+
+.a_button
+ ld a, c
+ cp BLUE_PAGE ; last page
+ jr z, StatsScreen_Exit
+
+.d_right
+ inc c
+ ld a, BLUE_PAGE ; last page
+ cp c
+ jr nc, StatsScreen_JumpToLoadPageFunction
+ ld c, PINK_PAGE ; first page
+ jr StatsScreen_JumpToLoadPageFunction
+
+.d_left
+ dec c
+ jr nz, StatsScreen_JumpToLoadPageFunction
+ ld c, BLUE_PAGE ; last page
+; fall through
+
+StatsScreen_JumpToLoadPageFunction:
+ ld hl, StatsScreen_LoadPageJumptable
+ push bc
+ dec c
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop bc
+ jp StatsScreen_LoadPage
+
+EggStatsInit:
+ push bc
+ call EggStatsScreen
+ pop bc
+; fall through
+
+EggStats_JoypadLoop:
+ call GetJoypad
+ ld a, [wMonType]
+ cp TEMPMON
+ jr nz, .not_tempmon
+; .tempmon
+ push hl
+ push de
+ push bc
+ farcall StatsScreenDPad
+ pop bc
+ pop de
+ pop hl
+ ld a, [wMenuJoypad]
+ and D_DOWN | D_UP
+ jp nz, StatsScreenMain
+ ld a, [wMenuJoypad]
+ jr .joypad_action
+
+.not_tempmon
+ ldh a, [hJoyPressed]
+.joypad_action
+ and D_DOWN | D_UP | A_BUTTON | B_BUTTON
+ jr z, EggStats_JoypadLoop
+ bit A_BUTTON_F, a
+ jr nz, StatsScreen_Exit
+ bit B_BUTTON_F, a
+ jr nz, StatsScreen_Exit
+ bit D_UP_F, a
+ jr nz, EggStats_UpAction
+ bit D_DOWN_F, a
+ jp EggStats_DownAction
+
+StatsScreen_Exit:
+ call ClearBGPalettes
+ call ClearTilemap
+ ret
+
+EggStats_DownAction:
+ ld a, [wMonType]
+ cp BOXMON
+ jr nc, EggStats_JoypadLoop
+ and a
+ ld a, [wPartyCount]
+ jr z, .next_mon
+ ld a, [wOTPartyCount]
+.next_mon
+ ld b, a
+ ld a, [wCurPartyMon]
+ inc a
+ cp b
+ jr z, EggStats_JoypadLoop
+ ld [wCurPartyMon], a
+ ld b, a
+ ld a, [wMonType]
+ and a
+ jr nz, EggStats_ScrollToLoadMon
+ ld a, b
+ inc a
+ ld [wPartyMenuCursor], a
+ jr EggStats_ScrollToLoadMon
+
+EggStats_UpAction:
+ ld a, [wCurPartyMon]
+ and a
+ jr z, EggStats_JoypadLoop
+ dec a
+ ld [wCurPartyMon], a
+ ld b, a
+ ld a, [wMonType]
+ and a
+ jr nz, EggStats_ScrollToLoadMon
+ ld a, b
+ inc a
+ ld [wPartyMenuCursor], a
+; fall through
+
+EggStats_ScrollToLoadMon:
+ jp StatsScreenMain
+
+StatsScreen_LoadPageJumptable:
+; entries correspond to *_PAGE constants
+ dw LoadPinkPage
+ dw LoadGreenPage
+ dw LoadBluePage
+
+StatsScreen_InitUpperHalf:
+ push bc
+ xor a
+ ldh [hBGMapMode], a
+ ld a, [wBaseDexNo]
+ ld [wDeciramBuffer], a
+ ld [wCurSpecies], a
+ hlcoord 8, 0
+ ld [hl], "№"
+ inc hl
+ ld [hl], "."
+ inc hl
+ ld de, wDeciramBuffer
+ lb bc, PRINTNUM_LEADINGZEROS | 1, 3
+ call PrintNum
+ hlcoord 14, 0
+ call PrintLevel
+ ld hl, .NicknamePointers
+ call GetNicknamePointer
+; Nickname
+ ld a, [wMonType]
+ cp BOXMON
+ ld a, BANK(sBoxMonNicknames)
+ call z, OpenSRAM
+ ld d, h
+ ld e, l
+ hlcoord 8, 2
+ call PlaceString
+ ld a, [wMonType]
+ cp BOXMON
+ call z, CloseSRAM
+; Gender character
+ call GetGender
+ jr c, .next
+ ld a, "♂"
+ jr nz, .got_gender
+ ld a, "♀"
+.got_gender
+ hlcoord 18, 0
+ ld [hl], a
+.next
+ hlcoord 9, 4
+ ld a, "/"
+ ld [hli], a
+ ld a, [wBaseDexNo]
+ ld [wNamedObjectIndexBuffer], a
+ call GetPokemonName
+ call PlaceString
+ call StatsScreen_PlaceHorizontalDivider
+ call StatsScreen_PlacePageSwitchArrows
+ call StatsScreen_PlaceShinyIcon
+; Place HP bar
+ ld hl, wTempMonHP
+ ld a, [hli]
+ ld b, a
+ ld c, [hl]
+ ld hl, wTempMonMaxHP
+ ld a, [hli]
+ ld d, a
+ ld e, [hl]
+ callfar ComputeHPBarPixels
+ ld hl, wCurHPPal
+ call SetHPPal
+ ld b, SCGB_STATS_SCREEN_HP_PALS
+ call GetSGBLayout
+ pop bc
+ ret
+
+.NicknamePointers:
+ dw wPartyMonNicknames
+ dw wOTPartyMonNicknames
+ dw sBoxMonNicknames
+ dw wBufferMonNick
+
+LoadPinkPage:
+ push bc
+ push bc
+ xor a
+ ldh [hBGMapMode], a
+ ld a, [wBaseDexNo]
+ ld [wDeciramBuffer], a
+ ld [wCurSpecies], a
+ ld b, PINK_PAGE
+ call StatsScreen_LoadPageIndicators
+
+; Load graphics
+ hlcoord 0, 8
+ lb bc, 10, 20
+ call ClearBox
+ hlcoord 0, 9
+ ld b, 0
+ call DrawPlayerHP
+ hlcoord 8, 9
+ ld [hl], $41 ; right HP/exp bar end cap
+ hlcoord 0, 12
+ ld de, .Status_Type
+ call PlaceString
+ ld a, [wTempMonPokerusStatus]
+ ld b, a
+ and $f
+ jr nz, .HasPokerus
+ ld a, b
+ and $f0
+ jr z, .NotImmuneToPkrs
+ hlcoord 8, 8
+ ld [hl], "." ; Pokérus immunity dot
+.NotImmuneToPkrs:
+ ld a, [wMonType]
+ cp BOXMON
+ jr z, .StatusOK
+ hlcoord 6, 13
+ push hl
+ ld de, wTempMonStatus
+ call PlaceStatusString
+ pop hl
+ jr .StatusOK
+.HasPokerus:
+ ld de, .PkrsStr
+ hlcoord 1, 13
+ call PlaceString
+ jr .done_status
+.StatusOK:
+ ld de, .OK_str
+ call z, PlaceString
+.done_status
+ hlcoord 1, 15
+ call PrintMonTypes
+ ld bc, 9
+ decoord 0, 16
+ hlcoord 0, 17
+ call CopyBytes
+ ld a, " "
+ ld bc, 9
+ hlcoord 0, 17
+ call ByteFill
+ hlcoord 9, 8
+ ld de, SCREEN_WIDTH
+ ld b, 10
+ ld a, $31 ; vertical divider
+.vertical_divider
+ ld [hl], a
+ add hl, de
+ dec b
+ jr nz, .vertical_divider
+ hlcoord 10, 9
+ ld de, .ExpPointStr
+ call PlaceString
+; print next level
+ ld a, [wTempMonLevel]
+ push af
+ cp MAX_LEVEL
+ jr z, .got_level
+ inc a
+ ld [wTempMonLevel], a
+.got_level
+ hlcoord 17, 14
+ call PrintLevel
+ pop af
+ ld [wTempMonLevel], a
+ ld de, wTempMonExp
+ hlcoord 13, 10
+ lb bc, 3, 7
+ call PrintNum
+; level-up graphics and strings
+ call .CalcExpToNextLevel
+ ld de, wBuffer1
+ hlcoord 13, 13
+ lb bc, 3, 7
+ call PrintNum
+ hlcoord 10, 12
+ ld de, .LevelUpStr
+ call PlaceString
+ hlcoord 14, 14
+ ld de, .ToStr
+ call PlaceString
+ ld a, [wTempMonLevel]
+ ld b, a
+ ld de, wTempMonExp + 2
+ hlcoord 11, 16
+ predef FillInExpBar
+ hlcoord 10, 16
+ ld [hl], $40 ; left exp bar end cap
+ hlcoord 19, 16
+ ld [hl], $41 ; right exp bar end cap
+
+; Load palettes / place frontpic
+ pop bc
+ farcall LoadStatsScreenPals
+ call WaitBGMap
+ ld a, 1
+ ldh [hBGMapMode], a
+ pop bc
+ ld a, b
+ and a
+ jp z, StatsScreen_PlaceFrontpic
+ ret
+
+.CalcExpToNextLevel:
+ ld a, [wTempMonLevel]
+ cp MAX_LEVEL
+ jr z, .AlreadyAtMaxLevel
+ inc a
+ ld d, a
+ call CalcExpAtLevel
+ ld hl, wTempMonExp + 2
+ ld hl, wTempMonExp + 2
+ ldh a, [hQuotient + 3]
+ sub [hl]
+ dec hl
+ ld [wBuffer3], a
+ ldh a, [hQuotient + 2]
+ sbc [hl]
+ dec hl
+ ld [wBuffer2], a
+ ldh a, [hQuotient + 1]
+ sbc [hl]
+ ld [wBuffer1], a
+ ret
+
+.AlreadyAtMaxLevel:
+ ld hl, wBuffer1
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+.Status_Type:
+ db "STATUS/"
+ next "TYPE/@"
+
+.OK_str:
+ db "OK @"
+
+.ExpPointStr:
+ db "EXP POINTS@"
+
+.LevelUpStr:
+ db "LEVEL UP@"
+
+.ToStr:
+ db "TO@"
+
+.PkrsStr:
+ db "#RUS@"
+
+Unreferenced_Function50f4d:
+ hlcoord 7, 0
+ ld bc, SCREEN_WIDTH
+ ld d, SCREEN_HEIGHT
+.loop
+ ld a, $31 ; vertical divider
+ ld [hl], a
+ add hl, bc
+ dec d
+ jr nz, .loop
+ ret
+
+StatsScreen_PlaceHorizontalDivider:
+ hlcoord 0, 7
+ ld b, SCREEN_WIDTH
+ ld a, $62 ; horizontal divider (empty HP/exp bar)
+.loop
+ ld [hli], a
+ dec b
+ jr nz, .loop
+ ret
+
+StatsScreen_PlacePageSwitchArrows:
+ hlcoord 12, 6
+ ld [hl], "◀"
+ hlcoord 19, 6
+ ld [hl], "▶"
+ ret
+
+StatsScreen_PlaceShinyIcon:
+ ld bc, wTempMonDVs
+ callfar CheckShininess
+ ret nc
+ hlcoord 19, 0
+ ld [hl], "⁂"
+ ret
+
+LoadGreenPage:
+ push bc
+ push bc
+ xor a
+ ldh [hBGMapMode], a
+ ld b, GREEN_PAGE
+ call StatsScreen_LoadPageIndicators
+
+; Load graphics
+ hlcoord 0, 8
+ lb bc, 10, 20
+ call ClearBox
+; item info
+ hlcoord 0, 8
+ ld de, .Item
+ call PlaceString
+ ld a, [wTempMonItem]
+ and a
+ ld de, .ThreeDashes
+ jr z, .got_item_name
+ ld b, a
+ farcall TimeCapsule_ReplaceTeruSama
+ ld a, b
+ ld [wNamedObjectIndexBuffer], a
+ call GetItemName
+.got_item_name
+ hlcoord 6, 8
+ call PlaceString
+; move info
+ ld hl, wTempMonMoves
+ ld de, wListMoves_MoveIndicesBuffer
+ ld bc, NUM_MOVES
+ call CopyBytes
+ hlcoord 0, 10
+ ld de, .Move
+ call PlaceString
+ hlcoord 8, 10
+ ld a, SCREEN_WIDTH * 2
+ ld [wBuffer1], a
+ call ListMoves
+ hlcoord 12, 11
+ ld a, SCREEN_WIDTH * 2
+ ld [wBuffer1], a
+ call ListMovePP
+
+; Load palettes / place frontpic
+ pop bc
+ farcall LoadStatsScreenPals
+ call WaitBGMap
+ ld a, 1
+ ldh [hBGMapMode], a
+ pop bc
+ ld a, b
+ and a
+ jp z, StatsScreen_PlaceFrontpic
+ ret
+
+.Item:
+ db "ITEM@"
+
+.ThreeDashes:
+ db "---@"
+
+.Move:
+ db "MOVE@"
+
+LoadBluePage:
+ push bc
+ push bc
+ xor a
+ ldh [hBGMapMode], a
+ ld b, BLUE_PAGE
+ call StatsScreen_LoadPageIndicators
+
+; Load graphics
+ hlcoord 0, 8
+ lb bc, 10, 20
+ call ClearBox
+ call .PlaceOTInfo
+ hlcoord 10, 8
+ ld de, SCREEN_WIDTH
+ ld b, 10
+ ld a, $31 ; vertical divider
+.vertical_divider
+ ld [hl], a
+ add hl, de
+ dec b
+ jr nz, .vertical_divider
+ hlcoord 11, 8
+ ld bc, 6
+ call PrintTempMonStats
+
+; Load palettes / place frontpic
+ pop bc
+ farcall LoadStatsScreenPals
+ call WaitBGMap
+ ld a, 1
+ ldh [hBGMapMode], a
+ pop bc
+ ld a, b
+ and a
+ jp z, StatsScreen_PlaceFrontpic
+ ret
+
+.PlaceOTInfo:
+ hlcoord 0, 9
+ ld de, IDNoString
+ call PlaceString
+ hlcoord 0, 12
+ ld de, OTString
+ call PlaceString
+ hlcoord 2, 10
+ ld de, wTempMonID
+ lb bc, PRINTNUM_LEADINGZEROS | 2, 5
+ call PrintNum
+ ld hl, .OTNamePointers
+ call GetNicknamePointer
+; OT name
+ ld a, [wMonType]
+ cp BOXMON
+ ld a, BANK(sBoxMonOT)
+ call z, OpenSRAM
+ ld de, wStringBuffer1
+ push de
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ pop de
+ ld a, [wMonType]
+ cp BOXMON
+ call z, CloseSRAM
+ callfar CorrectNickErrors
+ push de
+
+; Adjust coordinate of OT name based on index of nickname terminator
+ lb bc, 0, -1
+.loop
+ inc c
+ ld a, [de]
+ inc de
+ cp "@"
+ jr nz, .loop
+; remove left padding if name was 8-10 chars (somehow?)
+ ld a, NAME_LENGTH - 1
+ sub c
+ cp 3 ; NAME_LENGTH - PLAYER_NAME_LENGTH
+; otherwise, use 2 spaces of left padding
+ jr c, .ok
+ ld a, 2 ; NAME_LENGTH - PLAYER_NAME_LENGTH - 1
+.ok
+ ld c, a
+ hlcoord 0, 13
+ add hl, bc
+; that's finally over ... place string, quit forever
+ pop de
+ call PlaceString
+ ret
+
+.OTNamePointers:
+ dw wPartyMonOT
+ dw wOTPartyMonOT
+ dw sBoxMonOT
+ dw wBufferMonOT
+
+IDNoString:
+ db "<ID>№.@"
+
+OTString:
+ db "OT/@"
+
+StatsScreen_PlaceFrontpic:
+ push bc
+ call SetPalettes
+ ld hl, wTempMonDVs
+ call GetUnownLetter
+ hlcoord 0, 0
+ ld a, [wCurPartySpecies]
+ cp UNOWN
+ jr z, .unown
+
+ call PrepMonFrontpic
+ jr .play_cry
+
+.unown
+ xor a
+ ld [wBoxAlignment], a
+ call _PrepMonFrontpic
+
+.play_cry
+ ld a, [wCurPartySpecies]
+ call PlayMonCry
+ pop bc
+ ld b, 1
+ ret
+
+EggStatsScreen:
+ ld hl, wCurHPPal
+ call SetHPPal
+ ld b, SCGB_STATS_SCREEN_HP_PALS
+ call GetSGBLayout
+ call StatsScreen_PlaceHorizontalDivider
+ hlcoord 8, 1
+ ld de, EggString
+ call PlaceString
+ hlcoord 8, 3
+ ld de, IDNoString
+ call PlaceString
+ hlcoord 8, 5
+ ld de, OTString
+ call PlaceString
+ hlcoord 11, 3
+ ld de, FiveQMarkString
+ call PlaceString
+ hlcoord 11, 5
+ ld de, FiveQMarkString
+ call PlaceString
+ ld a, [wTempMonHappiness] ; egg status
+ ld de, EggSoonString
+ cp $6
+ jr c, .picked
+ ld de, EggCloseString
+ cp $b
+ jr c, .picked
+ ld de, EggMoreTimeString
+ cp $29
+ jr c, .picked
+ ld de, EggALotMoreTimeString
+.picked
+ hlcoord 1, 9
+ call PlaceString
+ call WaitBGMap
+ ld a, 1
+ ldh [hBGMapMode], a
+ call SetPalettes ; pals
+ hlcoord 0, 0
+ call PrepMonFrontpic
+ ld a, [wTempMonHappiness]
+ cp 6
+ ret nc
+ ld de, SFX_2_BOOPS
+ call PlaySFX
+ call WaitSFX
+ ret
+
+EggString:
+ db "EGG@"
+
+FiveQMarkString:
+ db "?????@"
+
+EggSoonString:
+ db "It's making sounds"
+ next "inside. It's going"
+ next "to hatch soon!@"
+
+EggCloseString:
+ db "It moves around"
+ next "inside sometimes."
+ next "It must be close"
+ next "to hatching.@"
+
+EggMoreTimeString:
+ db "Wonder what's"
+ next "inside? It needs"
+ next "more time, though.@"
+
+EggALotMoreTimeString:
+ db "This EGG needs a"
+ next "lot more time to"
+ next "hatch.@"
+
+StatsScreen_LoadPageIndicators:
+ hlcoord 13, 5
+ ld a, $36 ; first of 4 small square tiles
+ call .load_square
+ hlcoord 15, 5
+ ld a, $36 ; " " " "
+ call .load_square
+ hlcoord 17, 5
+ ld a, $36 ; " " " "
+ call .load_square
+ ld a, b
+ cp GREEN_PAGE
+ ld a, $3a ; first of 4 large square tiles
+ hlcoord 13, 5 ; PINK_PAGE (< GREEN_PAGE)
+ jr c, .load_square
+ hlcoord 15, 5 ; GREEN_PAGE (= GREEN_PAGE)
+ jr z, .load_square
+ hlcoord 17, 5 ; BLUE_PAGE (> GREEN_PAGE)
+.load_square
+ ld [hli], a
+ inc a
+ ld [hld], a
+ push bc
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ inc a
+ ld [hli], a
+ inc a
+ ld [hl], a
+ ret
+
+GetNicknamePointer:
+ ld a, [wMonType]
+ add a
+ ld c, a
+ ld b, 0
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wMonType]
+ cp TEMPMON
+ ret z
+ ld a, [wCurPartyMon]
+ jp SkipNames
diff --git a/engine/pokemon/switchpartymons.asm b/engine/pokemon/switchpartymons.asm
new file mode 100755
index 00000000..24d19df6
--- /dev/null
+++ b/engine/pokemon/switchpartymons.asm
@@ -0,0 +1,145 @@
+_SwitchPartyMons:
+ ld a, [wSwitchMon]
+ dec a
+ ld [wBuffer3], a
+ ld b, a
+ ld a, [wMenuCursorY]
+ dec a
+ ld [wBuffer2], a
+ cp b
+ jr z, .skip
+ call .SwapMonAndMail
+ ld a, [wBuffer3]
+ call .ClearSprite
+ ld a, [wBuffer2]
+ call .ClearSprite
+.skip
+ ret
+
+.ClearSprite:
+ push af
+ hlcoord 0, 1
+ ld bc, 2 * SCREEN_WIDTH
+ call AddNTimes
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, " "
+ call ByteFill
+ pop af
+ ld hl, wVirtualOAMSprite00
+ ld bc, 4 * SPRITEOAMSTRUCT_LENGTH
+ call AddNTimes
+ ld de, SPRITEOAMSTRUCT_LENGTH
+ ld c, 4
+.gfx_loop
+ ld [hl], SCREEN_WIDTH_PX ; y (off-screen)
+ add hl, de
+ dec c
+ jr nz, .gfx_loop
+ ld de, SFX_SWITCH_POKEMON
+ call WaitPlaySFX
+ ret
+
+.SwapMonAndMail:
+ push hl
+ push de
+ push bc
+ ld bc, wPartySpecies
+ ld a, [wBuffer2]
+ ld l, a
+ ld h, $0
+ add hl, bc
+ ld d, h
+ ld e, l
+ ld a, [wBuffer3]
+ ld l, a
+ ld h, $0
+ add hl, bc
+ ld a, [hl]
+ push af
+ ld a, [de]
+ ld [hl], a
+ pop af
+ ld [de], a
+ ld a, [wBuffer2]
+ ld hl, wPartyMon1Species
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ push hl
+ ld de, wceed
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call CopyBytes
+ ld a, [wBuffer3]
+ ld hl, wPartyMon1
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ pop de
+ push hl
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call CopyBytes
+ pop de
+ ld hl, wceed
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call CopyBytes
+ ld a, [wBuffer2]
+ ld hl, wPartyMonOT
+ call SkipNames
+ push hl
+ call .CopyNameTowceed
+ ld a, [wBuffer3]
+ ld hl, wPartyMonOT
+ call SkipNames
+ pop de
+ push hl
+ call .CopyName
+ pop de
+ ld hl, wceed
+ call .CopyName
+ ld hl, wPartyMonNicknames
+ ld a, [wBuffer2]
+ call SkipNames
+ push hl
+ call .CopyNameTowceed
+ ld hl, wPartyMonNicknames
+ ld a, [wBuffer3]
+ call SkipNames
+ pop de
+ push hl
+ call .CopyName
+ pop de
+ ld hl, wceed
+ call .CopyName
+ ld hl, sPartyMail
+ ld a, [wBuffer2]
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ push hl
+ ld de, wceed
+ ld bc, MAIL_STRUCT_LENGTH
+ ld a, BANK(sPartyMail)
+ call OpenSRAM
+ call CopyBytes
+ ld hl, sPartyMail
+ ld a, [wBuffer3]
+ ld bc, MAIL_STRUCT_LENGTH
+ call AddNTimes
+ pop de
+ push hl
+ ld bc, MAIL_STRUCT_LENGTH
+ call CopyBytes
+ pop de
+ ld hl, wceed
+ ld bc, MAIL_STRUCT_LENGTH
+ call CopyBytes
+ call CloseSRAM
+ pop bc
+ pop de
+ pop hl
+ ret
+
+.CopyNameTowceed:
+ ld de, wceed
+
+.CopyName:
+ ld bc, NAME_LENGTH
+ call CopyBytes
+ ret
diff --git a/engine/pokemon/tempmon.asm b/engine/pokemon/tempmon.asm
new file mode 100755
index 00000000..97ce1ee7
--- /dev/null
+++ b/engine/pokemon/tempmon.asm
@@ -0,0 +1,127 @@
+CopyMonToTempMon:
+; gets the BaseData of a mon
+; and copies the party_struct to wTempMon
+
+ ld a, [wCurPartyMon]
+ ld e, a
+ call GetMonSpecies
+ ld a, [wCurPartySpecies]
+ ld [wCurSpecies], a
+ call GetBaseData
+
+ ld a, [wMonType]
+ ld hl, wPartyMon1Species
+ ld bc, PARTYMON_STRUCT_LENGTH
+ and a
+ jr z, .copywholestruct
+ ld hl, wOTPartyMon1Species
+ ld bc, PARTYMON_STRUCT_LENGTH
+ cp OTPARTYMON
+ jr z, .copywholestruct
+ ld bc, BOXMON_STRUCT_LENGTH
+ callfar CopyBoxmonToTempMon
+ jr .done
+
+.copywholestruct
+ ld a, [wCurPartyMon]
+ call AddNTimes
+ ld de, wTempMon
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call CopyBytes
+
+.done
+ ret
+
+CalcBufferMonStats:
+ ld bc, wBufferMon
+ jr _TempMonStatsCalculation
+
+CalcTempmonStats:
+ ld bc, wTempMon
+_TempMonStatsCalculation:
+ ld hl, MON_LEVEL
+ add hl, bc
+ ld a, [hl]
+ ld [wCurPartyLevel], a
+ ld hl, MON_MAXHP
+ add hl, bc
+ ld d, h
+ ld e, l
+ ld hl, MON_STAT_EXP - 1
+ add hl, bc
+ push bc
+ ld b, TRUE
+ predef CalcMonStats
+ pop bc
+ ld hl, MON_HP
+ add hl, bc
+ ld d, h
+ ld e, l
+ ld a, [wCurPartySpecies]
+ cp EGG
+ jr nz, .not_egg
+ xor a
+ ld [de], a
+ inc de
+ ld [de], a
+ jr .zero_status
+
+.not_egg
+ push bc
+ ld hl, MON_MAXHP
+ add hl, bc
+ ld bc, 2
+ call CopyBytes
+ pop bc
+
+.zero_status
+ ld hl, MON_STATUS
+ add hl, bc
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+GetMonSpecies:
+; [wMonType] has the type of the mon
+; e = Nr. of mon (i.e. [wCurPartyMon])
+
+ ld a, [wMonType]
+ and a ; PARTYMON
+ jr z, .partymon
+ cp OTPARTYMON
+ jr z, .otpartymon
+ cp BOXMON
+ jr z, .boxmon
+ cp TEMPMON
+ jr z, .breedmon
+ ; WILDMON
+
+.partymon
+ ld hl, wPartySpecies
+ jr .done
+
+.otpartymon
+ ld hl, wOTPartySpecies
+ jr .done
+
+.boxmon
+ ld a, BANK(sBoxSpecies)
+ call OpenSRAM
+ ld hl, sBoxSpecies
+ call .done
+ call CloseSRAM
+ ret
+
+.breedmon
+ ld a, [wBreedMon1Species]
+ jr .done2
+
+.done
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+
+.done2
+ ld [wCurPartySpecies], a
+ ret
diff --git a/engine/pokemon/types.asm b/engine/pokemon/types.asm
new file mode 100755
index 00000000..3c9d28cd
--- /dev/null
+++ b/engine/pokemon/types.asm
@@ -0,0 +1,92 @@
+PrintMonTypes:
+; Print one or both types of [wCurSpecies]
+; on the stats screen at hl.
+
+ push hl
+ call GetBaseData
+ pop hl
+
+ push hl
+ ld a, [wBaseType1]
+ call .Print
+
+ ; Single-typed monsters really
+ ; have two of the same type.
+ ld a, [wBaseType1]
+ ld b, a
+ ld a, [wBaseType2]
+ cp b
+ pop hl
+ jr z, .hide_type_2
+
+ ld bc, $28
+ add hl, bc
+
+.Print:
+ ld b, a
+ jr PrintType
+
+.hide_type_2
+ ; Erase any type name that was here before.
+ ; Seems to be pointless in localized versions.
+ ld a, " "
+ ld bc, SCREEN_WIDTH - 3
+ add hl, bc
+ ld [hl], a
+ inc bc
+ add hl, bc
+ ld bc, NAME_LENGTH_JAPANESE - 1
+ jp ByteFill
+
+PrintMoveType:
+; Print the type of move b at hl.
+
+ push hl
+ ld a, b
+ dec a
+ ld bc, MOVE_LENGTH
+ ld hl, Moves
+ call AddNTimes
+ ld de, wStringBuffer1
+ ld a, BANK(Moves)
+ call FarCopyBytes
+ ld a, [wStringBuffer1 + MOVE_TYPE]
+ pop hl
+
+ ld b, a
+
+PrintType:
+; Print type b at hl.
+
+ ld a, b
+
+ push hl
+ add a
+ ld hl, TypeNames
+ ld e, a
+ ld d, 0
+ add hl, de
+ ld a, [hli]
+ ld e, a
+ ld d, [hl]
+ pop hl
+
+ jp PlaceString
+
+GetTypeName:
+; Copy the name of type [wNamedObjectIndexBuffer] to wStringBuffer1.
+
+ ld a, [wNamedObjectIndexBuffer]
+ ld hl, TypeNames
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wStringBuffer1
+ ld bc, MOVE_NAME_LENGTH
+ jp CopyBytes
+
+INCLUDE "data/types/names.asm"