First Commit

Upload literally everything from the pokecrystal16 expand-move-ID branch
This commit is contained in:
Zeta_Null 2023-09-10 12:35:35 -04:00
commit 2f8a41f833
4618 changed files with 480386 additions and 0 deletions

2694
engine/pokemon/bills_pc.asm Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,266 @@
_BillsPC:
call .CheckCanUsePC
ret c
call .LogIn
call .UseBillsPC
jp .LogOut
.CheckCanUsePC:
ld a, [wPartyCount]
and a
ret nz
ld hl, .PCGottaHavePokemonText
call MenuTextboxBackup
scf
ret
.PCGottaHavePokemonText:
text_far _PCGottaHavePokemonText
text_end
.LogIn:
xor a
ldh [hBGMapMode], a
call LoadStandardMenuHeader
call ClearPCItemScreen
ld hl, wOptions
ld a, [hl]
push af
set NO_TEXT_SCROLL, [hl]
ld hl, .PCWhatText
call PrintText
pop af
ld [wOptions], a
call LoadFontsBattleExtra
ret
.PCWhatText:
text_far _PCWhatText
text_end
.LogOut:
call CloseSubmenu
ret
.UseBillsPC:
call .clear_current_reserved_mon
ld hl, .MenuHeader
call LoadMenuHeader
ld a, $1
.loop
ld [wMenuCursorPosition], a
call SetPalettes
xor a
ld [wWhichIndexSet], a
ldh [hBGMapMode], a
call DoNthMenu
jr c, .cancel
ld a, [wMenuCursorPosition]
push af
ld a, [wMenuSelection]
ld hl, .Jumptable
rst JumpTable
pop bc
ld a, b
jr nc, .loop
.cancel
call CloseWindow
.clear_current_reserved_mon
ld l, LOCKED_MON_ID_CURRENT_MENU
xor a
jp LockPokemonID
.MenuHeader:
db MENU_BACKUP_TILES ; flags
menu_coords 0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
dw .MenuData
db 1 ; default option
.MenuData:
db STATICMENU_CURSOR ; flags
db 0 ; items
dw .items
dw PlaceMenuStrings
dw .strings
.strings
db "WITHDRAW <PK><MN>@"
db "DEPOSIT <PK><MN>@"
db "CHANGE BOX@"
db "MOVE <PK><MN> W/O MAIL@"
db "SEE YA!@"
.Jumptable:
dw BillsPC_WithdrawMenu
dw BillsPC_DepositMenu
dw BillsPC_ChangeBoxMenu
dw BillsPC_MovePKMNMenu
dw BillsPC_SeeYa
.items
db 5 ; # items
db 0 ; WITHDRAW
db 1 ; DEPOSIT
db 2 ; CHANGE BOX
db 3 ; MOVE PKMN
db 4 ; SEE YA!
db -1
BillsPC_SeeYa:
scf
ret
BillsPC_MovePKMNMenu:
call LoadStandardMenuHeader
farcall IsAnyMonHoldingMail
jr nc, .no_mail
ld hl, .PCMonHoldingMailText
call PrintText
jr .quit
.no_mail
farcall StartMoveMonWOMail_SaveGame
jr c, .quit
farcall _MovePKMNWithoutMail
call ReturnToMapFromSubmenu
call ClearPCItemScreen
.quit
call CloseWindow
and a
ret
.PCMonHoldingMailText:
text_far _PCMonHoldingMailText
text_end
BillsPC_DepositMenu:
call LoadStandardMenuHeader
farcall _DepositPKMN
call ReturnToMapFromSubmenu
call ClearPCItemScreen
call CloseWindow
and a
ret
BillsPC_Deposit_CheckPartySize: ; unreferenced
ld a, [wPartyCount]
and a
jr z, .no_mon
cp 2
jr c, .only_one_mon
and a
ret
.no_mon
ld hl, .PCNoSingleMonText
call MenuTextboxBackup
scf
ret
.only_one_mon
ld hl, .PCCantDepositLastMonText
call MenuTextboxBackup
scf
ret
.PCNoSingleMonText:
text_far _PCNoSingleMonText
text_end
.PCCantDepositLastMonText:
text_far _PCCantDepositLastMonText
text_end
CheckCurPartyMonFainted:
ld hl, wPartyMon1HP
ld de, PARTYMON_STRUCT_LENGTH
ld b, $0
.loop
ld a, [wCurPartyMon]
cp b
jr z, .skip
ld a, [hli]
or [hl]
jr nz, .notfainted
dec hl
.skip
inc b
ld a, [wPartyCount]
cp b
jr z, .done
add hl, de
jr .loop
.done
scf
ret
.notfainted
and a
ret
BillsPC_WithdrawMenu:
call LoadStandardMenuHeader
farcall _WithdrawPKMN
call ReturnToMapFromSubmenu
call ClearPCItemScreen
call CloseWindow
and a
ret
BillsPC_Withdraw_CheckPartySize: ; unreferenced
ld a, [wPartyCount]
cp PARTY_LENGTH
jr nc, .party_full
and a
ret
.party_full
ld hl, PCCantTakeText
call MenuTextboxBackup
scf
ret
PCCantTakeText:
text_far _PCCantTakeText
text_end
BillsPC_ChangeBoxMenu:
farcall _ChangeBox
and a
ret
ClearPCItemScreen:
call DisableSpriteUpdates
xor a
ldh [hBGMapMode], a
call ClearBGPalettes
call ClearSprites
hlcoord 0, 0
ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
ld a, " "
call ByteFill
hlcoord 0, 0
lb bc, 10, 18
call Textbox
hlcoord 0, 12
lb bc, 4, 18
call Textbox
call WaitBGMap2
call SetPalettes ; load regular palettes?
ret
CopyBoxmonToTempMon:
ld a, [wCurPartyMon]
ld hl, sBoxMon1Species
ld bc, BOXMON_STRUCT_LENGTH
call AddNTimes
ld de, wTempMonSpecies
ld bc, BOXMON_STRUCT_LENGTH
ld a, BANK(sBoxMon1Species)
call OpenSRAM
call CopyBytes
call CloseSRAM
ret

993
engine/pokemon/breeding.asm Normal file
View file

@ -0,0 +1,993 @@
CheckBreedmonCompatibility:
call .CheckBreedingGroupCompatibility
ld c, $0
jp nc, .done
ld a, [wBreedMon1Species]
ld [wCurPartySpecies], a
ld a, [wBreedMon1DVs]
ld [wTempMonDVs], a
ld a, [wBreedMon1DVs + 1]
ld [wTempMonDVs + 1], a
ld a, TEMPMON
ld [wMonType], a
predef GetGender
jr c, .genderless
ld b, $1
jr nz, .breedmon2
inc b
.breedmon2
push bc
ld a, [wBreedMon2Species]
ld [wCurPartySpecies], a
ld a, [wBreedMon2DVs]
ld [wTempMonDVs], a
ld a, [wBreedMon2DVs + 1]
ld [wTempMonDVs + 1], a
ld a, TEMPMON
ld [wMonType], a
predef GetGender
pop bc
jr c, .genderless
ld a, $1
jr nz, .compare_gender
inc a
.compare_gender
cp b
jr nz, .compute
.genderless
ld hl, DITTO
call GetPokemonIDFromIndex
ld b, a
ld c, $0
ld a, [wBreedMon1Species]
cp b
jr z, .ditto1
ld a, [wBreedMon2Species]
cp b
jr nz, .done
jr .compute
.ditto1
ld a, [wBreedMon2Species]
cp b
jr z, .done
.compute
call .CheckDVs
ld c, 255
jp z, .done
ld a, [wBreedMon2Species]
ld b, a
ld a, [wBreedMon1Species]
cp b
ld c, 254
jr z, .compare_ids
ld c, 128
.compare_ids
; Speed up
ld a, [wBreedMon1ID]
ld b, a
ld a, [wBreedMon2ID]
cp b
jr nz, .done
ld a, [wBreedMon1ID + 1]
ld b, a
ld a, [wBreedMon2ID + 1]
cp b
jr nz, .done
ld a, c
sub 77
ld c, a
.done
ld a, c
ld [wBreedingCompatibility], a
ret
.CheckDVs:
; If Defense DVs match and the lower 3 bits of the Special DVs match,
; avoid breeding
ld a, [wBreedMon1DVs]
and %1111
ld b, a
ld a, [wBreedMon2DVs]
and %1111
cp b
ret nz
ld a, [wBreedMon1DVs + 1]
and %111
ld b, a
ld a, [wBreedMon2DVs + 1]
and %111
cp b
ret
.CheckBreedingGroupCompatibility:
; If either mon is in the No Eggs group,
; they are not compatible.
ld a, [wBreedMon2Species]
ld [wCurSpecies], a
call GetBaseData
ld a, [wBaseEggGroups]
cp EGG_NONE * $11
jr z, .Incompatible
ld a, [wBreedMon1Species]
ld [wCurSpecies], a
call GetBaseData
ld a, [wBaseEggGroups]
cp EGG_NONE * $11
jr z, .Incompatible
; Ditto is automatically compatible with everything.
; If not Ditto, load the breeding groups into b/c and d/e.
ld hl, DITTO
call GetPokemonIDFromIndex
ld d, a
ld a, [wBreedMon2Species]
cp d
jr z, .Compatible
ld [wCurSpecies], a
call GetBaseData
ld a, [wBaseEggGroups]
push af
and $f
ld b, a
pop af
and $f0
swap a
ld c, a
ld a, [wBreedMon1Species]
cp d
jr z, .Compatible
ld [wCurSpecies], a
push bc
call GetBaseData
pop bc
ld a, [wBaseEggGroups]
push af
and $f
ld d, a
pop af
and $f0
swap a
ld e, a
ld a, d
cp b
jr z, .Compatible
cp c
jr z, .Compatible
ld a, e
cp b
jr z, .Compatible
cp c
jr z, .Compatible
.Incompatible:
and a
ret
.Compatible:
scf
ret
DoEggStep::
ld de, wPartySpecies
ld hl, wPartyMon1Happiness
ld c, 0
.loop
ld a, [de]
inc de
cp -1
ret z
cp EGG
jr nz, .next
dec [hl]
jr nz, .next
ld a, 1
and a
ret
.next
push de
ld de, PARTYMON_STRUCT_LENGTH
add hl, de
pop de
jr .loop
OverworldHatchEgg::
call RefreshScreen
call LoadStandardMenuHeader
call HatchEggs
call ExitAllMenus
call RestartMapMusic
jp CloseText
HatchEggs:
ld de, wPartySpecies
ld hl, wPartyMon1Happiness
xor a
ld [wCurPartyMon], a
.loop
ld a, [de]
inc de
cp -1
jp z, .done
push de
push hl
cp EGG
jp nz, .next
ld a, [hl]
and a
jp nz, .next
ld [hl], $78
push de
farcall SetEggMonCaughtData
farcall StubbedTrainerRankings_EggsHatched
ld a, [wCurPartyMon]
ld hl, wPartyMon1Species
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [hl]
ld [wCurPartySpecies], a
call SetSeenAndCaughtMon
ld a, [wCurPartySpecies]
call GetPokemonIndexFromID
ld a, l
sub LOW(TOGEPI)
if HIGH(TOGEPI) == 0
or h
else
jr nz, .nottogepi
if HIGH(TOGEPI) == 1
dec h
else
ld a, h
cp HIGH(TOGEPI)
endc
endc
jr nz, .nottogepi
; set the event flag for hatching togepi
ld de, EVENT_TOGEPI_HATCHED
ld b, SET_FLAG
call EventFlagAction
.nottogepi
pop de
ld a, [wCurPartySpecies]
dec de
ld [de], a
ld [wNamedObjectIndex], a
ld [wCurSpecies], a
call GetPokemonName
xor a
ld [wUnusedEggHatchFlag], a
call GetBaseData
ld a, [wCurPartyMon]
ld hl, wPartyMon1
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
push hl
ld bc, MON_MAXHP
add hl, bc
ld d, h
ld e, l
pop hl
push hl
ld bc, MON_LEVEL
add hl, bc
ld a, [hl]
ld [wCurPartyLevel], a
pop hl
push hl
ld bc, MON_STATUS
add hl, bc
xor a
ld [hli], a
ld [hl], a
pop hl
push hl
ld bc, MON_STAT_EXP - 1
add hl, bc
ld b, FALSE
predef CalcMonStats
pop bc
ld hl, MON_MAXHP
add hl, bc
ld d, h
ld e, l
ld hl, MON_HP
add hl, bc
ld a, [de]
inc de
ld [hli], a
ld a, [de]
ld [hl], a
ld hl, MON_ID
add hl, bc
ld a, [wPlayerID]
ld [hli], a
ld a, [wPlayerID + 1]
ld [hl], a
ld a, [wCurPartyMon]
ld hl, wPartyMonOTs
ld bc, NAME_LENGTH
call AddNTimes
ld d, h
ld e, l
ld hl, wPlayerName
call CopyBytes
ld hl, .Text_HatchEgg
call PrintText
ld a, [wCurPartyMon]
ld hl, wPartyMonNicknames
ld bc, MON_NAME_LENGTH
call AddNTimes
ld d, h
ld e, l
push de
ld hl, .BreedAskNicknameText
call PrintText
call YesNoBox
pop de
jr c, .nonickname
ld a, TRUE
ld [wUnusedEggHatchFlag], a
xor a
ld [wMonType], a
push de
ld b, NAME_MON
farcall NamingScreen
pop hl
ld de, wStringBuffer1
call InitName
jr .next
.nonickname
ld hl, wStringBuffer1
ld bc, MON_NAME_LENGTH
call CopyBytes
.next
ld hl, wCurPartyMon
inc [hl]
pop hl
ld de, PARTYMON_STRUCT_LENGTH
add hl, de
pop de
jp .loop
.done
ret
.Text_HatchEgg:
; Huh? @ @
text_far Text_BreedHuh
text_asm
ld hl, wVramState
res 0, [hl]
push hl
push de
push bc
ld a, [wCurPartySpecies]
push af
call EggHatch_AnimationSequence
ld hl, .BreedClearboxText
call PrintText
pop af
ld [wCurPartySpecies], a
pop bc
pop de
pop hl
ld hl, .BreedEggHatchText
ret
.BreedClearboxText:
text_far _BreedClearboxText
text_end
.BreedEggHatchText:
text_far _BreedEggHatchText
text_end
.BreedAskNicknameText:
text_far _BreedAskNicknameText
text_end
InitEggMoves:
call GetHeritableMoves
ld d, h
ld e, l
ld b, NUM_MOVES
.loop
ld a, [de]
and a
jr z, .done
ld hl, wEggMonMoves
ld c, NUM_MOVES
.next
ld a, [de]
cp [hl]
jr z, .skip
inc hl
dec c
jr nz, .next
call GetEggMove
jr nc, .skip
call LoadEggMove
.skip
inc de
dec b
jr nz, .loop
.done
ret
GetEggMove:
push bc
push de
call GetBreedmonMovePointer
ld b, NUM_MOVES
ld a, [de]
ld c, a
.breedmon_loop
ld a, [hli]
and a
jr z, .not_breedmon
cp c
jr z, .breedmon_found
dec b
jr nz, .breedmon_loop
.not_breedmon
ld a, c
call GetMoveIndexFromID
ld d, h
ld e, l
.not_learnset_move
ld a, [wEggMonSpecies]
call GetPokemonIndexFromID
ld b, h
ld c, l
ld hl, EggMovePointers
ld a, BANK(EggMovePointers)
call LoadDoubleIndirectPointer
.egg_move_loop
push hl
call GetFarWord
ld a, h
and l
ld c, a
ld a, h
cp d
jr nz, .no_egg_match
ld a, l
cp e
.no_egg_match
pop hl
jr z, .is_egg_move
inc hl
inc hl
ld a, b
inc c
jr nz, .egg_move_loop
ld bc, TMHMMoves
.tmhm_loop
ld a, BANK(TMHMMoves)
ld h, b
ld l, c
call GetFarWord
ld a, h
and l
jr z, .done
inc bc
inc bc
ld a, h
cp d
jr nz, .tmhm_loop
ld a, l
cp e
jr nz, .tmhm_loop
pop de
ld a, [de]
push de
ld [wPutativeTMHMMove], a
predef CanLearnTMHMMove
xor a
cp c ;will carry if non-zero
jr .done
.breedmon_found
call GetMoveIndexFromID
ld d, h
ld e, l
ld a, [wEggMonSpecies]
call GetPokemonIndexFromID
ld b, h
ld c, l
ld hl, EvosAttacksPointers
ld a, BANK(EvosAttacksPointers)
call LoadDoubleIndirectPointer
call FarSkipEvolutions
.learnset_loop
ld a, b
call GetFarByte
inc hl
and a
jr z, .not_learnset_move
push hl
call GetFarWord
ld a, l
cp e
ld a, h
pop hl
inc hl
inc hl
jr nz, .learnset_loop
cp d
jr nz, .learnset_loop
.is_egg_move
scf
.done
pop de
pop bc
ret
LoadEggMove:
push de
push bc
ld a, [de]
ld b, a
ld hl, wEggMonMoves
ld c, NUM_MOVES
.loop
ld a, [hli]
and a
jr z, .done
dec c
jr nz, .loop
ld de, wEggMonMoves
ld hl, wEggMonMoves + 1
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
inc de
ld a, [hli]
ld [de], a
.done
dec hl
ld [hl], b
ld hl, wEggMonMoves
ld de, wEggMonPP
predef FillPP
pop bc
pop de
ret
GetHeritableMoves:
ld hl, DITTO
call GetPokemonIDFromIndex
ld b, a
ld hl, wBreedMon2Moves
ld a, [wBreedMon1Species]
cp b
jr z, .ditto1
ld a, [wBreedMon2Species]
cp b
jr z, .ditto2
ld a, [wBreedMotherOrNonDitto]
and a
ret z
ld hl, wBreedMon1Moves
ret
.ditto1
ld a, [wCurPartySpecies]
push af
ld a, [wBreedMon2Species]
ld [wCurPartySpecies], a
ld a, [wBreedMon2DVs]
ld [wTempMonDVs], a
ld a, [wBreedMon2DVs + 1]
ld [wTempMonDVs + 1], a
ld a, TEMPMON
ld [wMonType], a
predef GetGender
jr c, .inherit_mon2_moves
jr nz, .inherit_mon2_moves
jr .inherit_mon1_moves
.ditto2
ld a, [wCurPartySpecies]
push af
ld a, [wBreedMon1Species]
ld [wCurPartySpecies], a
ld a, [wBreedMon1DVs]
ld [wTempMonDVs], a
ld a, [wBreedMon1DVs + 1]
ld [wTempMonDVs + 1], a
ld a, TEMPMON
ld [wMonType], a
predef GetGender
jr c, .inherit_mon1_moves
jr nz, .inherit_mon1_moves
.inherit_mon2_moves
ld hl, wBreedMon2Moves
pop af
ld [wCurPartySpecies], a
ret
.inherit_mon1_moves
ld hl, wBreedMon1Moves
pop af
ld [wCurPartySpecies], a
ret
GetBreedmonMovePointer:
ld hl, DITTO
call GetPokemonIDFromIndex
ld b, a
ld hl, wBreedMon1Moves
ld a, [wBreedMon1Species]
cp b
ret z
ld a, [wBreedMon2Species]
cp b
jr z, .ditto
ld a, [wBreedMotherOrNonDitto]
and a
ret z
.ditto
ld hl, wBreedMon2Moves
ret
GetEggFrontpic:
; BUG: A hatching Unown egg would not show the right letter (see docs/bugs_and_glitches.md)
push de
ld [wCurPartySpecies], a
ld [wCurSpecies], a
call GetBaseData
ld hl, wBattleMonDVs
predef GetUnownLetter
pop de
predef_jump GetMonFrontpic
GetHatchlingFrontpic:
push de
ld [wCurPartySpecies], a
ld [wCurSpecies], a
call GetBaseData
ld hl, wBattleMonDVs
predef GetUnownLetter
pop de
predef_jump GetAnimatedFrontpic
Hatch_UpdateFrontpicBGMapCenter:
push af
call WaitTop
push hl
push bc
hlcoord 0, 0
ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
ld a, " "
call ByteFill
pop bc
pop hl
ld a, b
ldh [hBGMapAddress + 1], a
ld a, c
ldh [hGraphicStartTile], a
lb bc, 7, 7
predef PlaceGraphic
pop af
call Hatch_LoadFrontpicPal
call SetPalettes
jp WaitBGMap
EggHatch_DoAnimFrame:
push hl
push de
push bc
callfar PlaySpriteAnimations
call DelayFrame
pop bc
pop de
pop hl
ret
EggHatch_AnimationSequence:
ld a, [wNamedObjectIndex]
ld [wJumptableIndex], a
ld a, [wCurSpecies]
push af
ld de, MUSIC_NONE
call PlayMusic
farcall BlankScreen
call DisableLCD
ld hl, EggHatchGFX
ld de, vTiles0 tile $00
ld bc, 2 tiles
ld a, BANK(EggHatchGFX)
call FarCopyBytes
farcall ClearSpriteAnims
ld de, vTiles2 tile $00
ld a, [wJumptableIndex]
call GetHatchlingFrontpic
ld de, vTiles2 tile $31
ld a, EGG
call GetEggFrontpic
ld de, MUSIC_EVOLUTION
call PlayMusic
call EnableLCD
hlcoord 7, 4
ld b, HIGH(vBGMap0)
ld c, $31 ; Egg tiles start here
ld a, EGG
call Hatch_UpdateFrontpicBGMapCenter
ld c, 80
call DelayFrames
xor a
ld [wFrameCounter], a
ldh a, [hSCX]
ld b, a
.outerloop
ld hl, wFrameCounter
ld a, [hl]
inc [hl]
cp 8
jr nc, .done
ld e, [hl]
.loop
; wobble e times
ld a, 2
ldh [hSCX], a
ld a, -2
ld [wGlobalAnimXOffset], a
call EggHatch_DoAnimFrame
ld c, 2
call DelayFrames
ld a, -2
ldh [hSCX], a
ld a, 2
ld [wGlobalAnimXOffset], a
call EggHatch_DoAnimFrame
ld c, 2
call DelayFrames
dec e
jr nz, .loop
ld c, 16
call DelayFrames
call EggHatch_CrackShell
jr .outerloop
.done
ld de, SFX_EGG_HATCH
call PlaySFX
xor a
ldh [hSCX], a
ld [wGlobalAnimXOffset], a
call ClearSprites
call Hatch_InitShellFragments
hlcoord 6, 3
ld b, HIGH(vBGMap0)
ld c, $00 ; Hatchling tiles start here
ld a, [wJumptableIndex]
call Hatch_UpdateFrontpicBGMapCenter
call Hatch_ShellFragmentLoop
call WaitSFX
ld a, [wJumptableIndex]
ld [wCurPartySpecies], a
hlcoord 6, 3
ld d, $0
ld e, ANIM_MON_HATCH
predef AnimateFrontpic
pop af
ld [wCurSpecies], a
ret
Hatch_LoadFrontpicPal:
ld [wPlayerHPPal], a
ld b, SCGB_EVOLUTION
ld c, $0
jp GetSGBLayout
EggHatch_CrackShell:
ld a, [wFrameCounter]
dec a
and $7
cp $7
ret z
srl a
ret nc
swap a
srl a
add 9 * 8 + 4
ld d, a
ld e, 11 * 8
ld a, SPRITE_ANIM_INDEX_EGG_CRACK
call InitSpriteAnimStruct
ld hl, SPRITEANIMSTRUCT_TILE_ID
add hl, bc
ld [hl], $0
ld de, SFX_EGG_CRACK
jp PlaySFX
EggHatchGFX:
INCBIN "gfx/evo/egg_hatch.2bpp"
Hatch_InitShellFragments:
farcall ClearSpriteAnims
ld hl, .SpriteData
.loop
ld a, [hli]
cp -1
jr z, .done
ld e, a
ld a, [hli]
ld d, a
ld a, [hli]
ld c, a
ld a, [hli]
ld b, a
push hl
push bc
ld a, SPRITE_ANIM_INDEX_EGG_HATCH
call InitSpriteAnimStruct
ld hl, SPRITEANIMSTRUCT_TILE_ID
add hl, bc
ld [hl], $0
pop de
ld a, e
ld hl, SPRITEANIMSTRUCT_FRAMESET_ID
add hl, bc
add [hl]
ld [hl], a
ld hl, SPRITEANIMSTRUCT_JUMPTABLE_INDEX
add hl, bc
ld [hl], d
pop hl
jr .loop
.done
ld de, SFX_EGG_HATCH
call PlaySFX
call EggHatch_DoAnimFrame
ret
MACRO shell_fragment
; y tile, y pxl, x tile, x pxl, frameset offset, ???
db (\1 * 8) % $100 + \2, (\3 * 8) % $100 + \4, \5 - SPRITE_ANIM_FRAMESET_EGG_HATCH_1, \6
ENDM
.SpriteData:
shell_fragment 10, 4, 9, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_1, $3c
shell_fragment 11, 4, 9, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_2, $04
shell_fragment 10, 4, 10, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_1, $30
shell_fragment 11, 4, 10, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_2, $10
shell_fragment 10, 4, 11, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_3, $24
shell_fragment 11, 4, 11, 0, SPRITE_ANIM_FRAMESET_EGG_HATCH_4, $1c
shell_fragment 10, 0, 9, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_1, $36
shell_fragment 12, 0, 9, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_2, $0a
shell_fragment 10, 0, 10, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_3, $2a
shell_fragment 12, 0, 10, 4, SPRITE_ANIM_FRAMESET_EGG_HATCH_4, $16
db -1
Hatch_ShellFragmentLoop:
ld c, 129
.loop
call EggHatch_DoAnimFrame
dec c
jr nz, .loop
ret
DayCareMon1:
ld hl, LeftWithDayCareManText
call PrintText
ld a, [wBreedMon1Species]
call PlayMonCry
ld a, [wDayCareLady]
bit DAYCARELADY_HAS_MON_F, a
jr z, DayCareMonCursor
call PromptButton
ld hl, wBreedMon2Nickname
call DayCareMonCompatibilityText
jp PrintText
DayCareMon2:
ld hl, LeftWithDayCareLadyText
call PrintText
ld a, [wBreedMon2Species]
call PlayMonCry
ld a, [wDayCareMan]
bit DAYCAREMAN_HAS_MON_F, a
jr z, DayCareMonCursor
call PromptButton
ld hl, wBreedMon1Nickname
call DayCareMonCompatibilityText
jp PrintText
DayCareMonCursor:
jp WaitPressAorB_BlinkCursor
LeftWithDayCareLadyText:
text_far _LeftWithDayCareLadyText
text_end
LeftWithDayCareManText:
text_far _LeftWithDayCareManText
text_end
DayCareMonCompatibilityText:
push bc
ld de, wStringBuffer1
ld bc, NAME_LENGTH
call CopyBytes
call CheckBreedmonCompatibility
pop bc
ld a, [wBreedingCompatibility]
ld hl, .BreedBrimmingWithEnergyText
cp -1
jr z, .done
ld hl, .BreedNoInterestText
and a
jr z, .done
ld hl, .BreedAppearsToCareForText
cp 230
jr nc, .done
cp 70
ld hl, .BreedFriendlyText
jr nc, .done
ld hl, .BreedShowsInterestText
.done
ret
.BreedBrimmingWithEnergyText:
text_far _BreedBrimmingWithEnergyText
text_end
.BreedNoInterestText:
text_far _BreedNoInterestText
text_end
.BreedAppearsToCareForText:
text_far _BreedAppearsToCareForText
text_end
.BreedFriendlyText:
text_far _BreedFriendlyText
text_end
.BreedShowsInterestText:
text_far _BreedShowsInterestText
text_end
DayCareMonPrintEmptyString: ; unreferenced
ld hl, .string
ret
.string
db "@"

View file

@ -0,0 +1,27 @@
GetBreedMon1LevelGrowth:
ld hl, wBreedMon1
ld de, wTempMon
ld bc, BOXMON_STRUCT_LENGTH
call CopyBytes
callfar CalcLevel
ld a, [wBreedMon1Level]
ld b, a
ld a, d
ld e, a
sub b
ld d, a
ret
GetBreedMon2LevelGrowth:
ld hl, wBreedMon2
ld de, wTempMon
ld bc, BOXMON_STRUCT_LENGTH
call CopyBytes
callfar CalcLevel
ld a, [wBreedMon2Level]
ld b, a
ld a, d
ld e, a
sub b
ld d, a
ret

View file

@ -0,0 +1,246 @@
CheckPartyFullAfterContest:
ld a, [wContestMonSpecies]
and a
jp z, .DidntCatchAnything
ld [wCurPartySpecies], a
ld [wCurSpecies], a
call GetBaseData
ld hl, wPartyCount
ld a, [hl]
cp PARTY_LENGTH
jp nc, .TryAddToBox
inc a
ld [hl], a
ld c, a
ld b, 0
add hl, bc
ld a, [wContestMonSpecies]
ld [hli], a
ld [wCurSpecies], a
ld a, -1
ld [hl], a
ld hl, wPartyMon1Species
ld a, [wPartyCount]
dec a
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld d, h
ld e, l
ld hl, wContestMon
ld bc, PARTYMON_STRUCT_LENGTH
call CopyBytes
ld a, [wPartyCount]
dec a
ld hl, wPartyMonOTs
call SkipNames
ld d, h
ld e, l
ld hl, wPlayerName
call CopyBytes
ld a, [wCurPartySpecies]
ld [wNamedObjectIndex], a
call GetPokemonName
ld hl, wStringBuffer1
ld de, wMonOrItemNameBuffer
ld bc, MON_NAME_LENGTH
call CopyBytes
call GiveANickname_YesNo
jr c, .Party_SkipNickname
ld a, [wPartyCount]
dec a
ld [wCurPartyMon], a
xor a
ld [wMonType], a
ld de, wMonOrItemNameBuffer
callfar InitNickname
.Party_SkipNickname:
ld a, [wPartyCount]
dec a
ld hl, wPartyMonNicknames
call SkipNames
ld d, h
ld e, l
ld hl, wMonOrItemNameBuffer
call CopyBytes
ld a, [wPartyCount]
dec a
ld hl, wPartyMon1Level
call GetPartyLocation
ld a, [hl]
ld [wCurPartyLevel], a
call SetCaughtData
ld a, [wPartyCount]
dec a
ld hl, wPartyMon1CaughtLocation
call GetPartyLocation
ld a, [hl]
and CAUGHT_GENDER_MASK
ld b, LANDMARK_NATIONAL_PARK
or b
ld [hl], a
xor a
ld [wContestMonSpecies], a
and a ; BUGCONTEST_CAUGHT_MON
ld [wScriptVar], a
ret
.TryAddToBox:
ld a, BANK(sBoxCount)
call OpenSRAM
ld hl, sBoxCount
ld a, [hl]
cp MONS_PER_BOX
call CloseSRAM
jr nc, .BoxFull
xor a
ld [wCurPartyMon], a
ld hl, wContestMon
ld de, wBufferMon
ld bc, BOXMON_STRUCT_LENGTH
call CopyBytes
ld hl, wPlayerName
ld de, wBufferMonOT
ld bc, NAME_LENGTH
call CopyBytes
callfar InsertPokemonIntoBox
ld a, [wCurPartySpecies]
ld [wNamedObjectIndex], a
call GetPokemonName
call GiveANickname_YesNo
ld hl, wStringBuffer1
jr c, .Box_SkipNickname
ld a, BOXMON
ld [wMonType], a
ld de, wMonOrItemNameBuffer
callfar InitNickname
ld hl, wMonOrItemNameBuffer
.Box_SkipNickname:
ld a, BANK(sBoxMonNicknames)
call OpenSRAM
ld de, sBoxMonNicknames
ld bc, MON_NAME_LENGTH
call CopyBytes
call CloseSRAM
.BoxFull:
ld a, BANK(sBoxMon1Level)
call OpenSRAM
ld a, [sBoxMon1Level]
ld [wCurPartyLevel], a
call CloseSRAM
call SetBoxMonCaughtData
ld a, BANK(sBoxMon1CaughtLocation)
call OpenSRAM
ld hl, sBoxMon1CaughtLocation
ld a, [hl]
and CAUGHT_GENDER_MASK
ld b, LANDMARK_NATIONAL_PARK
or b
ld [hl], a
call CloseSRAM
xor a
ld [wContestMon], a
ld a, BUGCONTEST_BOXED_MON
ld [wScriptVar], a
ret
.DidntCatchAnything:
ld a, BUGCONTEST_NO_CATCH
ld [wScriptVar], a
ret
GiveANickname_YesNo:
ld hl, CaughtAskNicknameText
call PrintText
jp YesNoBox
CaughtAskNicknameText:
text_far _CaughtAskNicknameText
text_end
SetCaughtData:
ld a, [wPartyCount]
dec a
ld hl, wPartyMon1CaughtLevel
call GetPartyLocation
SetBoxmonOrEggmonCaughtData:
ld a, [wTimeOfDay]
inc a
rrca
rrca
ld b, a
ld a, [wCurPartyLevel]
or b
ld [hli], a
ld a, [wMapGroup]
ld b, a
ld a, [wMapNumber]
ld c, a
cp MAP_POKECENTER_2F
jr nz, .NotPokecenter2F
ld a, b
cp GROUP_POKECENTER_2F
jr nz, .NotPokecenter2F
ld a, [wBackupMapGroup]
ld b, a
ld a, [wBackupMapNumber]
ld c, a
.NotPokecenter2F:
call GetWorldMapLocation
ld b, a
ld a, [wPlayerGender]
rrca ; shift bit 0 (PLAYERGENDER_FEMALE_F) to bit 7 (CAUGHT_GENDER_MASK)
or b
ld [hl], a
ret
SetBoxMonCaughtData:
ld a, BANK(sBoxMon1CaughtLevel)
call OpenSRAM
ld hl, sBoxMon1CaughtLevel
call SetBoxmonOrEggmonCaughtData
call CloseSRAM
ret
SetGiftBoxMonCaughtData:
push bc
ld a, BANK(sBoxMon1CaughtLevel)
call OpenSRAM
ld hl, sBoxMon1CaughtLevel
pop bc
call SetGiftMonCaughtData
call CloseSRAM
ret
SetGiftPartyMonCaughtData:
ld a, [wPartyCount]
dec a
ld hl, wPartyMon1CaughtLevel
push bc
call GetPartyLocation
pop bc
SetGiftMonCaughtData:
xor a
ld [hli], a
ld a, LANDMARK_GIFT
rrc b
or b
ld [hl], a
ret
SetEggMonCaughtData:
ld a, [wCurPartyMon]
ld hl, wPartyMon1CaughtLevel
call GetPartyLocation
ld a, [wCurPartyLevel]
push af
ld a, CAUGHT_EGG_LEVEL
ld [wCurPartyLevel], a
call SetBoxmonOrEggmonCaughtData
pop af
ld [wCurPartyLevel], a
ret

View file

@ -0,0 +1,74 @@
CorrectNickErrors::
; error-check monster nick before use
; must be a peace offering to gamesharkers
; input: de = nick location
push bc
push de
ld b, MON_NAME_LENGTH
.checkchar
; end of nick?
ld a, [de]
cp "@" ; terminator
jr z, .end
; check if this char is a text command
ld hl, .textcommands
dec hl
.loop
; next entry
inc hl
; reached end of commands table?
ld a, [hl]
cp -1
jr z, .done
; is the current char between this value (inclusive)...
ld a, [de]
cp [hl]
inc hl
jr c, .loop
; ...and this one?
cp [hl]
jr nc, .loop
; replace it with a "?"
ld a, "?"
ld [de], a
jr .loop
.done
; next char
inc de
; reached end of nick without finding a terminator?
dec b
jr nz, .checkchar
; change nick to "?@"
pop de
push de
ld a, "?"
ld [de], a
inc de
ld a, "@"
ld [de], a
.end
; if the nick has any errors at this point it's out of our hands
pop de
pop bc
ret
.textcommands
; table defining which characters are actually text commands
; format:
; ≥ <
db "<NULL>", "ガ"
db "<PLAY_G>", "<JP_18>" + 1
db "<NI>", "<NO>" + 1
db "<ROUTE>", "<GREEN>" + 1
db "<ENEMY>", "<ENEMY>" + 1
db "<MOM>", "<TM>" + 1
db "<ROCKET>", "┘" + 1
db -1 ; end

View file

@ -0,0 +1,231 @@
CorrectPartyErrors: ; unreferenced
ld hl, wPartyCount
ld a, [hl]
and a
ret z
cp PARTY_LENGTH + 1
jr c, .party_length_okay
ld a, PARTY_LENGTH
ld [hl], a
.party_length_okay
inc hl
ld b, a
ld c, 0
.loop1
ld a, [hl]
call IsAPokemon
jr nc, .next_species
push hl
ld hl, SMEARGLE
call GetPokemonIDFromIndex
pop hl
ld [hl], a
push hl
push bc
push af
ld a, c
ld hl, wPartyMon1Species
call GetPartyLocation
pop af
ld [hl], a
pop bc
pop hl
.next_species
inc hl
inc c
dec b
jr nz, .loop1
ld [hl], $ff
ld hl, wPartyMon1
ld a, [wPartyCount]
ld d, a
ld e, 0
.loop2
push de
push hl
ld b, h
ld c, l
ld a, [hl]
call IsAPokemon
jr nc, .check_level
push hl
ld hl, SMEARGLE
call GetPokemonIDFromIndex
pop hl
ld [hl], a
push de
ld d, 0
ld hl, wPartySpecies
add hl, de
pop de
ld [hl], a
.check_level
ld [wCurSpecies], a
call GetBaseData
ld hl, MON_LEVEL
add hl, bc
ld a, [hl]
cp MIN_LEVEL
ld a, MIN_LEVEL
jr c, .invalid_level
ld a, [hl]
cp MAX_LEVEL
jr c, .load_level
ld a, MAX_LEVEL
.invalid_level
ld [hl], a
.load_level
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
ld b, TRUE
predef CalcMonStats
pop hl
ld bc, PARTYMON_STRUCT_LENGTH
add hl, bc
pop de
inc e
dec d
jr nz, .loop2
ld de, wPartyMonNicknames
ld a, [wPartyCount]
ld b, a
ld c, 0
.loop3
push bc
call .GetLengthOfStringWith6CharCap
push de
farcall CheckStringForErrors
pop hl
pop bc
jr nc, .valid_nickname
push bc
push hl
ld hl, wPartySpecies
push bc
ld b, 0
add hl, bc
pop bc
ld a, [hl]
cp EGG
ld hl, .TAMAGO
jr z, .got_nickname
ld [wNamedObjectIndex], a
call GetPokemonName
ld hl, wStringBuffer1
.got_nickname
pop de
ld bc, MON_NAME_LENGTH
call CopyBytes
pop bc
.valid_nickname
inc c
dec b
jr nz, .loop3
ld de, wPartyMonOTs
ld a, [wPartyCount]
ld b, a
ld c, 0
.loop4
push bc
call .GetLengthOfStringWith6CharCap
push de
farcall CheckStringForErrors
pop hl
jr nc, .valid_ot_name
ld d, h
ld e, l
ld hl, wPlayerName
ld bc, NAME_LENGTH
call CopyBytes
.valid_ot_name
pop bc
inc c
dec b
jr nz, .loop4
ld hl, wPartyMon1Moves
ld a, [wPartyCount]
ld b, a
.loop5
push hl
ld c, NUM_MOVES
ld a, [hl]
and a
jr z, .invalid_move
cp MOVE_TABLE_ENTRIES + 1
jr c, .moves_loop
.invalid_move
push hl
ld hl, POUND
call GetMoveIDFromIndex
pop hl
ld [hl], a
.moves_loop
ld a, [hl]
and a
jr z, .fill_invalid_moves
cp MOVE_TABLE_ENTRIES + 1
jr c, .next_move
.fill_invalid_moves
xor a
ld [hli], a
dec c
jr nz, .fill_invalid_moves
jr .next_pokemon
.next_move
inc hl
dec c
jr nz, .moves_loop
.next_pokemon
pop hl
push bc
ld bc, PARTYMON_STRUCT_LENGTH
add hl, bc
pop bc
dec b
jr nz, .loop5
ret
.TAMAGO:
db "タマゴ@@@"
.GetLengthOfStringWith6CharCap:
push de
ld c, 1
ld b, NAME_LENGTH_JAPANESE
.search_loop
ld a, [de]
cp "@"
jr z, .done
inc de
inc c
dec b
jr nz, .search_loop
dec c
dec de
ld a, "@"
ld [de], a
.done
pop de
ret

View file

@ -0,0 +1,118 @@
ParseMailLanguage:
ld c, MAIL_LANG_ENGLISH
ld hl, sPartyMon1MailNationality - sPartyMon1Mail
add hl, de
ld a, [hli]
cp "E"
ret nz
ld a, [hli]
inc c ; MAIL_LANG_FRENCH
cp "F"
ret z
inc c ; MAIL_LANG_GERMAN
cp "G"
ret z
inc c ; MAIL_LANG_ITALIAN
cp "I"
ret z
inc c ; MAIL_LANG_SPANISH
cp "S"
ret z
ld c, MAIL_LANG_ENGLISH
ret
; The regular font.
StandardEnglishFont:
INCBIN "gfx/font/english.1bpp"
; An extended font.
FrenchGermanFont:
INCBIN "gfx/font/french_german.1bpp"
; An even more extended font.
SpanishItalianFont:
INCBIN "gfx/font/spanish_italian.1bpp"
ConvertFrenchGermanMailToEnglish:
; Called if mail is French or German
; Converts 's 't 'v from French/German character set to English
ld b, sPartyMon1MailAuthor - sPartyMon1Mail
ld h, d
ld l, e
.loop
ld a, [hl]
cp $dc ; 's in French/German font
jr nz, .check_intermediate_chars
ld a, "'s"
jr .replace
.check_intermediate_chars
sub "'s"
jr c, .dont_replace
cp "'v" - "'s" + 1
jr nc, .dont_replace
add $cd
.replace
ld [hl], a
.dont_replace
inc hl
dec b
jr nz, .loop
ret
ConvertEnglishMailToFrenchGerman:
; Called if mail is English and game is French or German
; Converts 's 't 'v from English character set to French/German
ld b, sPartyMon1MailAuthor - sPartyMon1Mail
ld h, d
ld l, e
.loop
ld a, [hl]
cp "'s"
jr nz, .check_intermediate_chars
ld a, $dc ; 's in French/German font
jr .replace
.check_intermediate_chars
sub $cd
jr c, .dont_replace
cp "'v" - "'s" + 1
jr nc, .dont_replace
add "'s"
.replace
ld [hl], a
.dont_replace
inc hl
dec b
jr nz, .loop
ret
ConvertSpanishItalianMailToEnglish:
; Called if mail is Spanish or Italian
; Converts 'd 'l 'm 'r 's 't 'v from Spanish/Italian character set to English
ConvertEnglishMailToSpanishItalian:
; Called if mail is English and game is Spanish or Italian
; Converts 'd 'l 'm 'r 's 't 'v from English character set to Spanish/Italian
ld b, sPartyMon1MailAuthor - sPartyMon1Mail
ld h, d
ld l, e
.loop
ld a, [hl]
and $f0
cp $d0
jr nz, .dont_replace
ld a, [hl]
add $8
and $f
or $d0
ld [hl], a
.dont_replace
inc hl
dec b
jr nz, .loop
ret

686
engine/pokemon/evolve.asm Normal file
View file

@ -0,0 +1,686 @@
EvolvePokemon:
ld hl, wEvolvableFlags
xor a
ld [hl], a
ld a, [wCurPartyMon]
ld c, a
ld b, SET_FLAG
call EvoFlagAction
EvolveAfterBattle:
xor a
ld [wMonTriedToEvolve], a
dec a
ld [wCurPartyMon], a
push hl
push bc
push de
ld hl, wPartyCount
push hl
EvolveAfterBattle_MasterLoop:
ld hl, wCurPartyMon
inc [hl]
pop hl
inc hl
ld a, [hl]
cp $ff
jp z, .ReturnToMap
ld [wEvolutionOldSpecies], a
push hl
ld a, [wCurPartyMon]
ld c, a
ld hl, wEvolvableFlags
ld b, CHECK_FLAG
call EvoFlagAction
ld a, c
and a
jp z, EvolveAfterBattle_MasterLoop
ld a, [wEvolutionOldSpecies]
call GetPokemonIndexFromID
ld b, h
ld c, l
ld hl, EvosAttacksPointers
ld a, BANK(EvosAttacksPointers)
call LoadDoubleIndirectPointer
ldh [hTemp], a
push hl
xor a
ld [wMonType], a
predef CopyMonToTempMon
pop hl
.loop
call GetNextEvoAttackByte
and a
jr z, EvolveAfterBattle_MasterLoop
ld b, a
cp EVOLVE_TRADE
jr z, .trade
ld a, [wLinkMode]
and a
jp nz, .dont_evolve_check
ld a, b
cp EVOLVE_ITEM
jp z, .item
ld a, [wForceEvolution]
and a
jp nz, .dont_evolve_check
ld a, b
cp EVOLVE_LEVEL
jp z, .level
cp EVOLVE_HAPPINESS
jr z, .happiness
; EVOLVE_STAT
call GetNextEvoAttackByte
ld c, a
ld a, [wTempMonLevel]
cp c
jp c, .skip_evolution_species_parameter
call IsMonHoldingEverstone
jp z, .skip_evolution_species_parameter
push hl
ld de, wTempMonAttack
ld hl, wTempMonDefense
ld c, 2
call CompareBytes
ld c, ATK_EQ_DEF
jr z, .got_tyrogue_evo
ld c, ATK_LT_DEF
jr c, .got_tyrogue_evo
ld c, ATK_GT_DEF
.got_tyrogue_evo
pop hl
call GetNextEvoAttackByte
cp c
jp nz, .skip_evolution_species
jp .proceed
.happiness
ld a, [wTempMonHappiness]
cp HAPPINESS_TO_EVOLVE
jp c, .skip_evolution_species_parameter
call IsMonHoldingEverstone
jp z, .skip_evolution_species_parameter
call GetNextEvoAttackByte
cp TR_ANYTIME
jr z, .proceed
cp TR_MORNDAY
jr z, .happiness_daylight
; TR_NITE
ld a, [wTimeOfDay]
cp NITE_F
jp nz, .skip_evolution_species
jr .proceed
.happiness_daylight
ld a, [wTimeOfDay]
cp NITE_F
jp z, .skip_evolution_species
jr .proceed
.trade
ld a, [wLinkMode]
and a
jp z, .skip_evolution_species_parameter
call IsMonHoldingEverstone
jp z, .skip_evolution_species_parameter
call GetNextEvoAttackByte
ld b, a
inc a
jr z, .proceed
ld a, [wLinkMode]
cp LINK_TIMECAPSULE
jp z, .skip_evolution_species
ld a, [wTempMonItem]
cp b
jp nz, .skip_evolution_species
xor a
ld [wTempMonItem], a
jr .proceed
.item
call GetNextEvoAttackByte
ld b, a
ld a, [wCurItem]
cp b
jp nz, .skip_evolution_species
ld a, [wForceEvolution]
and a
jp z, .skip_evolution_species
ld a, [wLinkMode]
and a
jp nz, .skip_evolution_species
jr .proceed
.level
call GetNextEvoAttackByte
ld b, a
ld a, [wTempMonLevel]
cp b
jp c, .skip_evolution_species
call IsMonHoldingEverstone
jp z, .skip_evolution_species
.proceed
ld a, [wTempMonLevel]
ld [wCurPartyLevel], a
ld a, $1
ld [wMonTriedToEvolve], a
ldh a, [hTemp]
call GetFarWord
call GetPokemonIDFromIndex
ld [wEvolutionNewSpecies], a
ld a, [wCurPartyMon]
ld hl, wPartyMonNicknames
call GetNickname
call CopyName1
ld hl, EvolvingText
call PrintText
ld c, 50
call DelayFrames
xor a
ldh [hBGMapMode], a
hlcoord 0, 0
lb bc, 12, 20
call ClearBox
ld a, $1
ldh [hBGMapMode], a
call ClearSprites
farcall EvolutionAnimation
push af
call ClearSprites
pop af
jp c, CancelEvolution
ld hl, CongratulationsYourPokemonText
call PrintText
ld a, [wEvolutionNewSpecies]
ld [wCurSpecies], a
ld [wTempMonSpecies], a
ld [wNamedObjectIndex], a
call GetPokemonName
push hl
ld hl, EvolvedIntoText
call PrintTextboxText
farcall StubbedTrainerRankings_MonsEvolved
ld de, MUSIC_NONE
call PlayMusic
ld de, SFX_CAUGHT_MON
call PlaySFX
call WaitSFX
ld c, 40
call DelayFrames
call ClearTilemap
call UpdateSpeciesNameIfNotNicknamed
call GetBaseData
ld hl, wTempMonExp + 2
ld de, wTempMonMaxHP
ld b, TRUE
predef CalcMonStats
ld a, [wCurPartyMon]
ld hl, wPartyMons
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld e, l
ld d, h
ld bc, MON_MAXHP
add hl, bc
ld a, [hli]
ld b, a
ld c, [hl]
ld hl, wTempMonMaxHP + 1
ld a, [hld]
sub c
ld c, a
ld a, [hl]
sbc b
ld b, a
ld hl, wTempMonHP + 1
ld a, [hl]
add c
ld [hld], a
ld a, [hl]
adc b
ld [hl], a
ld hl, wTempMonSpecies
ld bc, PARTYMON_STRUCT_LENGTH
call CopyBytes
ld a, [wCurSpecies]
ld [wTempSpecies], a
xor a
ld [wMonType], a
call LearnLevelMoves
ld a, [wTempSpecies]
call SetSeenAndCaughtMon
ld a, [wTempSpecies]
call GetPokemonIndexFromID
ld a, l
sub LOW(UNOWN)
if HIGH(UNOWN) == 0
or h
else
jr nz, .skip_unown
if HIGH(UNOWN) == 1
dec h
else
ld a, h
cp HIGH(UNOWN)
endc
endc
jr nz, .skip_unown
ld hl, wTempMonDVs
predef GetUnownLetter
callfar UpdateUnownDex
.skip_unown
pop de
pop hl
ld a, [wTempMonSpecies]
ld [hl], a
push hl
ld l, e
ld h, d
jp EvolveAfterBattle_MasterLoop
.dont_evolve_check
ld a, b
cp EVOLVE_STAT
jr nz, .skip_evolution_species_parameter
inc hl
.skip_evolution_species_parameter
inc hl
.skip_evolution_species
inc hl
inc hl
jp .loop
.UnusedReturnToMap: ; unreferenced
pop hl
.ReturnToMap:
pop de
pop bc
pop hl
ld a, [wLinkMode]
and a
ret nz
ld a, [wBattleMode]
and a
ret nz
ld a, [wMonTriedToEvolve]
and a
call nz, RestartMapMusic
ret
UpdateSpeciesNameIfNotNicknamed:
ld a, [wCurSpecies]
push af
ld a, [wBaseSpecies]
ld [wNamedObjectIndex], a
call GetPokemonName
pop af
ld [wCurSpecies], a
ld hl, wStringBuffer1
ld de, wStringBuffer2
.loop
ld a, [de]
inc de
cp [hl]
inc hl
ret nz
cp "@"
jr nz, .loop
ld a, [wCurPartyMon]
ld bc, MON_NAME_LENGTH
ld hl, wPartyMonNicknames
call AddNTimes
push hl
ld a, [wCurSpecies]
ld [wNamedObjectIndex], a
call GetPokemonName
ld hl, wStringBuffer1
pop de
ld bc, MON_NAME_LENGTH
jp CopyBytes
CancelEvolution:
ld hl, StoppedEvolvingText
call PrintText
call ClearTilemap
jp EvolveAfterBattle_MasterLoop
IsMonHoldingEverstone:
push hl
ld a, [wCurPartyMon]
ld hl, wPartyMon1Item
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [hl]
cp EVERSTONE
pop hl
ret
CongratulationsYourPokemonText:
text_far _CongratulationsYourPokemonText
text_end
EvolvedIntoText:
text_far _EvolvedIntoText
text_end
StoppedEvolvingText:
text_far _StoppedEvolvingText
text_end
EvolvingText:
text_far _EvolvingText
text_end
LearnLevelMoves:
ld a, [wTempSpecies]
ld [wCurPartySpecies], a
call GetPokemonIndexFromID
ld b, h
ld c, l
ld hl, EvosAttacksPointers
ld a, BANK(EvosAttacksPointers)
call LoadDoubleIndirectPointer
ldh [hTemp], a
call SkipEvolutions
.find_move
call GetNextEvoAttackByte
and a
jr z, .done
ld b, a
ld a, [wCurPartyLevel]
cp b
call GetNextEvoAttackByte
ld e, a
call GetNextEvoAttackByte
ld d, a
jr nz, .find_move
push hl
ld h, d
ld l, e
call GetMoveIDFromIndex
ld d, a
ld hl, wPartyMon1Moves
ld a, [wCurPartyMon]
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld b, NUM_MOVES
.check_move
call GetNextEvoAttackByte
cp d
jr z, .has_move
dec b
jr nz, .check_move
jr .learn
.has_move
pop hl
jr .find_move
.learn
ld a, d
ld [wPutativeTMHMMove], a
ld [wNamedObjectIndex], a
call GetMoveName
call CopyName1
predef LearnMove
pop hl
jr .find_move
.done
ld a, [wCurPartySpecies]
ld [wTempSpecies], a
ret
FillMoves:
; Fill in moves at de for wCurPartySpecies at wCurPartyLevel
push hl
push de
push bc
ld a, [wCurPartySpecies]
call GetPokemonIndexFromID
ld b, h
ld c, l
ld hl, EvosAttacksPointers
ld a, BANK(EvosAttacksPointers)
call LoadDoubleIndirectPointer
ldh [hTemp], a
call SkipEvolutions
jr .GetLevel
.NextMove:
pop de
.GetMove:
inc hl
inc hl
.GetLevel:
call GetNextEvoAttackByte
and a
jp z, .done
ld b, a
ld a, [wCurPartyLevel]
cp b
jp c, .done
ld a, [wSkipMovesBeforeLevelUp]
and a
jr z, .CheckMove
ld a, [wPrevPartyLevel]
cp b
jr nc, .GetMove
.CheckMove:
push de
ld c, NUM_MOVES
ldh a, [hTemp]
push hl
call GetFarWord
call GetMoveIDFromIndex
pop hl
ld b, a
.CheckRepeat:
ld a, [de]
inc de
cp b
jr z, .NextMove
dec c
jr nz, .CheckRepeat
pop de
push de
ld c, NUM_MOVES
.CheckSlot:
ld a, [de]
and a
jr z, .LearnMove
inc de
dec c
jr nz, .CheckSlot
pop de
push de
push hl
ld h, d
ld l, e
call ShiftMoves
ld a, [wEvolutionOldSpecies]
and a
jr z, .ShiftedMove
push de
ld bc, wPartyMon1PP - (wPartyMon1Moves + NUM_MOVES - 1)
add hl, bc
ld d, h
ld e, l
call ShiftMoves
pop de
.ShiftedMove:
pop hl
.LearnMove:
ldh a, [hTemp]
push hl
call GetFarWord
call GetMoveIDFromIndex
pop hl
ld b, a
ld [de], a
ld a, [wEvolutionOldSpecies]
and a
jr z, .NextMove
push hl
ld a, b
ld hl, MON_PP - MON_MOVES
add hl, de
push hl
ld l, a
ld a, MOVE_PP
call GetMoveAttribute
pop hl
ld [hl], a
pop hl
jp .NextMove
.done
pop bc
pop de
pop hl
ret
ShiftMoves:
ld c, NUM_MOVES - 1
.loop
inc de
ld a, [de]
ld [hli], a
dec c
jr nz, .loop
ret
EvoFlagAction:
push de
ld d, $0
predef SmallFarFlagAction
pop de
ret
GetLowestEvolutionStage:
; Return the first mon to evolve into wCurPartySpecies.
; Instead of looking it up, we just load it from a table. This is a lot more efficient.
ld a, [wCurPartySpecies]
call GetPokemonIndexFromID
ld bc, FirstEvoStages - 2
add hl, hl
add hl, bc
ld a, BANK(FirstEvoStages)
call GetFarWord
call GetPokemonIDFromIndex
ld [wCurPartySpecies], a
ret
SkipEvolutions::
; Receives a pointer to the evos and attacks for a mon in b:hl, and skips to the attacks.
ld a, b
call GetFarByte
inc hl
and a
ret z
cp EVOLVE_STAT
jr nz, .no_extra_skip
inc hl
.no_extra_skip
inc hl
inc hl
inc hl
jr SkipEvolutions
DetermineEvolutionItemResults::
; in: b:de: pointer to evos and attacks struct, wCurItem: item
; out: de: species ID or zero; a, b, hl: clobbered
ld h, d
ld l, e
ld de, 0
ld a, b
ldh [hTemp], a
.loop
call GetNextEvoAttackByte
and a
ret z
cp EVOLVE_STAT
jr z, .skip_species_two_parameters
cp EVOLVE_ITEM
jr nz, .skip_species_parameter
call GetNextEvoAttackByte
ld b, a
ld a, [wCurItem]
cp b
jr nz, .skip_species
ldh a, [hTemp]
call GetFarWord
ld d, h
ld e, l
ret
.skip_species_two_parameters
inc hl
.skip_species_parameter
inc hl
.skip_species
inc hl
inc hl
jr .loop
GetNextEvoAttackByte:
ldh a, [hTemp]
call GetFarByte
inc hl
ret

View file

@ -0,0 +1,163 @@
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
; BUG: Experience underflow for level 1 Pokémon with Medium-Slow growth rate (see docs/bugs_and_glitches.md)
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"

110
engine/pokemon/health.asm Normal file
View file

@ -0,0 +1,110 @@
HealParty:
xor a
ld [wCurPartyMon], a
ld hl, wPartySpecies
.loop
ld a, [hli]
cp -1
jr z, .done
cp EGG
jr z, .next
push hl
call HealPartyMon
pop hl
.next
ld a, [wCurPartyMon]
inc a
ld [wCurPartyMon], a
jr .loop
.done
ret
HealPartyMon:
ld a, MON_SPECIES
call GetPartyParamLocation
ld d, h
ld e, l
ld hl, MON_STATUS
add hl, de
xor a
ld [hli], a
ld [hl], a
ld hl, MON_MAXHP
add hl, de
; bc = MON_HP
ld b, h
ld c, l
dec bc
dec bc
ld a, [hli]
ld [bc], a
inc bc
ld a, [hl]
ld [bc], a
farcall RestoreAllPP
ret
ComputeHPBarPixels:
; e = bc * (6 * 8) / de
ld a, b
or c
jr z, .zero
push hl
xor a
ldh [hMultiplicand + 0], a
ld a, b
ldh [hMultiplicand + 1], a
ld a, c
ldh [hMultiplicand + 2], a
ld a, 6 * 8
ldh [hMultiplier], a
call Multiply
; We need de to be under 256 because hDivisor is only 1 byte.
ld a, d
and a
jr z, .divide
; divide de and hProduct by 4
srl d
rr e
srl d
rr e
ldh a, [hProduct + 2]
ld b, a
ldh a, [hProduct + 3]
srl b
rr a
srl b
rr a
ldh [hDividend + 3], a
ld a, b
ldh [hDividend + 2], a
.divide
ld a, e
ldh [hDivisor], a
ld b, 4
call Divide
ldh a, [hQuotient + 3]
ld e, a
pop hl
and a
ret nz
ld e, 1
ret
.zero
ld e, 0
ret
AnimateHPBar:
call WaitBGMap
call _AnimateHPBar
call WaitBGMap
ret

View file

@ -0,0 +1,24 @@
KnowsMove:
ld a, MON_MOVES
call GetPartyParamLocation
ld a, [wPutativeTMHMMove]
ld b, a
ld c, NUM_MOVES
.loop
ld a, [hli]
cp b
jr z, .knows_move
dec c
jr nz, .loop
and a
ret
.knows_move
ld hl, .KnowsMoveText
call PrintText
scf
ret
.KnowsMoveText:
text_far _KnowsMoveText
text_end

234
engine/pokemon/learn.asm Normal file
View file

@ -0,0 +1,234 @@
LearnMove:
call LoadTilemapToTempTilemap
ld a, [wCurPartyMon]
ld hl, wPartyMonNicknames
call GetNickname
ld hl, wStringBuffer1
ld de, wMonOrItemNameBuffer
ld bc, MON_NAME_LENGTH
call CopyBytes
.loop
ld hl, wPartyMon1Moves
ld bc, PARTYMON_STRUCT_LENGTH
ld a, [wCurPartyMon]
call AddNTimes
ld d, h
ld e, l
ld b, NUM_MOVES
; Get the first empty move slot. This routine also serves to
; determine whether the Pokemon learning the moves already has
; all four slots occupied, in which case one would need to be
; deleted.
.next
ld a, [hl]
and a
jr z, .learn
inc hl
dec b
jr nz, .next
; If we're here, we enter the routine for forgetting a move
; to make room for the new move we're trying to learn.
push de
call ForgetMove
pop de
jp c, .cancel
push hl
push de
ld [wNamedObjectIndex], a
ld b, a
ld a, [wBattleMode]
and a
jr z, .not_disabled
ld a, [wDisabledMove]
cp b
jr nz, .not_disabled
xor a
ld [wDisabledMove], a
ld [wPlayerDisableCount], a
.not_disabled
call GetMoveName
ld hl, Text_1_2_and_Poof ; 1, 2 and…
call PrintText
pop de
pop hl
.learn
ld a, [wPutativeTMHMMove]
ld [hl], a
ld bc, MON_PP - MON_MOVES
add hl, bc
push hl
ld l, a
ld a, MOVE_PP
call GetMoveAttribute
pop hl
ld [hl], a
ld a, [wBattleMode]
and a
jp z, .learned
ld a, [wCurPartyMon]
ld b, a
ld a, [wCurBattleMon]
cp b
jp nz, .learned
ld a, [wPlayerSubStatus5]
bit SUBSTATUS_TRANSFORMED, a
jp nz, .learned
ld h, d
ld l, e
ld de, wBattleMonMoves
ld bc, NUM_MOVES
call CopyBytes
ld bc, wPartyMon1PP - (wPartyMon1Moves + NUM_MOVES)
add hl, bc
ld de, wBattleMonPP
ld bc, NUM_MOVES
call CopyBytes
jp .learned
.cancel
ld hl, StopLearningMoveText
call PrintText
call YesNoBox
jp c, .loop
ld hl, DidNotLearnMoveText
call PrintText
ld b, 0
ret
.learned
ld hl, LearnedMoveText
call PrintText
ld b, 1
ret
ForgetMove:
push hl
ld hl, AskForgetMoveText
call PrintText
call YesNoBox
pop hl
ret c
ld bc, -NUM_MOVES
add hl, bc
push hl
ld de, wListMoves_MoveIndicesBuffer
ld bc, NUM_MOVES
call CopyBytes
pop hl
.loop
push hl
ld hl, MoveAskForgetText
call PrintText
hlcoord 5, 2
ld b, NUM_MOVES * 2
ld c, MOVE_NAME_LENGTH
call Textbox
hlcoord 5 + 2, 2 + 2
ld a, SCREEN_WIDTH * 2
ld [wListMovesLineSpacing], a
predef ListMoves
; w2DMenuData
ld a, $4
ld [w2DMenuCursorInitY], a
ld a, $6
ld [w2DMenuCursorInitX], a
ld a, [wNumMoves]
inc a
ld [w2DMenuNumRows], a
ld a, $1
ld [w2DMenuNumCols], a
ld [wMenuCursorY], a
ld [wMenuCursorX], a
ld a, $3
ld [wMenuJoypadFilter], a
ld a, $20
ld [w2DMenuFlags1], a
xor a
ld [w2DMenuFlags2], a
ld a, $20
ld [w2DMenuCursorOffsets], a
call StaticMenuJoypad
push af
call SafeLoadTempTilemapToTilemap
pop af
pop hl
bit 1, a
jr nz, .cancel
push hl
ld a, [wMenuCursorY]
dec a
ld c, a
ld b, 0
add hl, bc
ld a, [hl]
push af
push bc
call IsHMMove
pop bc
pop de
ld a, d
jr c, .hmmove
pop hl
add hl, bc
and a
ret
.hmmove
ld hl, MoveCantForgetHMText
call PrintText
pop hl
jr .loop
.cancel
scf
ret
LearnedMoveText:
text_far _LearnedMoveText
text_end
MoveAskForgetText:
text_far _MoveAskForgetText
text_end
StopLearningMoveText:
text_far _StopLearningMoveText
text_end
DidNotLearnMoveText:
text_far _DidNotLearnMoveText
text_end
AskForgetMoveText:
text_far _AskForgetMoveText
text_end
Text_1_2_and_Poof:
text_far Text_MoveForgetCount ; 1, 2 and…
text_asm
push de
ld de, SFX_SWITCH_POKEMON
call PlaySFX
pop de
ld hl, .MoveForgotText
ret
.MoveForgotText:
text_far _MoveForgotText
text_end
MoveCantForgetHMText:
text_far _MoveCantForgetHMText
text_end

View file

@ -0,0 +1,20 @@
LevelUpHappinessMod:
ld a, [wCurPartyMon]
ld hl, wPartyMon1CaughtLocation
call GetPartyLocation
ld a, [hl]
and CAUGHT_LOCATION_MASK
ld d, a
ld a, [wMapGroup]
ld b, a
ld a, [wMapNumber]
ld c, a
call GetWorldMapLocation
cp d
ld c, HAPPINESS_GAINLEVEL
jr nz, .ok
ld c, HAPPINESS_GAINLEVELATHOME
.ok
callfar ChangeHappiness
ret

567
engine/pokemon/mail.asm Normal file
View file

@ -0,0 +1,567 @@
SendMailToPC:
ld a, MON_ITEM
call GetPartyParamLocation
ld d, [hl]
farcall ItemIsMail
jr nc, .full
call GetMailboxCount
cp MAILBOX_CAPACITY
jr nc, .full
ld bc, MAIL_STRUCT_LENGTH
ld hl, sMailboxes
call AddNTimes
ld d, h
ld e, l
ld a, [wCurPartyMon]
ld bc, MAIL_STRUCT_LENGTH
ld hl, sPartyMail
call AddNTimes
push hl
ld a, BANK(sMailboxCount)
call OpenSRAM
ld bc, MAIL_STRUCT_LENGTH
call CopyBytes
pop hl
xor a
ld bc, MAIL_STRUCT_LENGTH
call ByteFill
ld a, MON_ITEM
call GetPartyParamLocation
ld [hl], 0
ld hl, sMailboxCount
inc [hl]
call CloseSRAM
xor a
ret
.full
scf
ret
DeleteMailFromPC:
; Shift all mail messages in the mailbox
ld a, BANK(sMailboxCount)
call OpenSRAM
ld a, b
push bc
ld hl, sMailboxes
ld bc, MAIL_STRUCT_LENGTH
call AddNTimes
push hl
add hl, bc
pop de
pop bc
.loop
ld a, b
cp MAILBOX_CAPACITY - 1
jr z, .done
push bc
ld bc, MAIL_STRUCT_LENGTH
call CopyBytes
pop bc
inc b
jr .loop
.done
ld h, d
ld l, e
xor a
ld bc, MAIL_STRUCT_LENGTH
call ByteFill
ld hl, sMailboxCount
dec [hl]
jp CloseSRAM
ReadMailMessage:
ld a, b
ld hl, sMailboxes
ld bc, MAIL_STRUCT_LENGTH
call AddNTimes
ld d, h
ld e, l
farcall ReadAnyMail
ret
MoveMailFromPCToParty:
ld a, BANK(sMailboxCount)
call OpenSRAM
push bc
ld a, b
ld bc, MAIL_STRUCT_LENGTH
ld hl, sMailboxes
call AddNTimes
push hl
ld a, [wCurPartyMon]
ld bc, MAIL_STRUCT_LENGTH
ld hl, sPartyMail
call AddNTimes
ld d, h
ld e, l
pop hl
push hl
ld bc, MAIL_STRUCT_LENGTH
call CopyBytes
pop hl
ld de, PARTYMON_STRUCT_LENGTH - MON_MOVES
add hl, de
ld d, [hl]
ld a, [wCurPartyMon]
ld hl, wPartyMon1Item
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld [hl], d
call CloseSRAM
pop bc
jp DeleteMailFromPC
GetMailboxCount:
ld a, BANK(sMailboxCount)
call OpenSRAM
ld a, [sMailboxCount]
ld c, a
jp CloseSRAM
CheckPokeMail::
push bc
push de
farcall SelectMonFromParty
ld a, POKEMAIL_REFUSED
jr c, .pop_return
ld a, [wCurPartyMon]
ld hl, wPartyMon1Item
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld d, [hl]
farcall ItemIsMail
ld a, POKEMAIL_NO_MAIL
jr nc, .pop_return
ld a, BANK(sPartyMail)
call OpenSRAM
ld a, [wCurPartyMon]
ld hl, sPartyMail
ld bc, MAIL_STRUCT_LENGTH
call AddNTimes
ld d, h
ld e, l
pop hl
pop bc
; Compare the mail message, byte for byte, with the expected message.
ld a, MAIL_MSG_LENGTH
ld [wTempByteValue], a
.loop
ld a, [de]
ld c, a
ld a, b
call GetFarByte
cp "@"
jr z, .done
cp c
ld a, POKEMAIL_WRONG_MAIL
jr nz, .close_sram_return
inc hl
inc de
ld a, [wTempByteValue]
dec a
ld [wTempByteValue], a
jr nz, .loop
.done
farcall CheckCurPartyMonFainted
ld a, POKEMAIL_LAST_MON
jr c, .close_sram_return
xor a ; REMOVE_PARTY
ld [wPokemonWithdrawDepositParameter], a
farcall RemoveMonFromPartyOrBox
ld a, POKEMAIL_CORRECT
.close_sram_return
call CloseSRAM
jr .return
.pop_return
pop de
pop bc
.return
ld [wScriptVar], a
ret
GivePokeMail::
ld a, [wPartyCount]
dec a
push af
push bc
ld hl, wPartyMon1Item
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
pop bc
ld [hl], b
pop af
push bc
push af
ld hl, sPartyMail
ld bc, MAIL_STRUCT_LENGTH
call AddNTimes
ld d, h
ld e, l
ld hl, wMonMailMessageBuffer
ld bc, MAIL_MSG_LENGTH + 1
ld a, BANK(sPartyMail)
call OpenSRAM
call CopyBytes
pop af
push af
ld hl, wPartyMonOTs
ld bc, NAME_LENGTH
call AddNTimes
ld bc, NAME_LENGTH - 1
call CopyBytes
pop af
ld hl, wPartyMon1ID
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [hli]
ld [de], a
inc de
ld a, [hl]
ld [de], a
inc de
ld a, [wCurPartySpecies]
ld [de], a
inc de
pop bc
ld a, b
ld [de], a
jp CloseSRAM
BackupPartyMonMail:
ld a, BANK(sPartyMail)
call OpenSRAM
ld hl, sPartyMail
ld de, sPartyMailBackup
ld bc, PARTY_LENGTH * MAIL_STRUCT_LENGTH
call CopyBytes
ld hl, sMailboxCount
ld de, sMailboxCountBackup
ld bc, 1 + MAILBOX_CAPACITY * MAIL_STRUCT_LENGTH
call CopyBytes
jp CloseSRAM
RestorePartyMonMail:
ld a, BANK(sPartyMail)
call OpenSRAM
ld hl, sPartyMailBackup
ld de, sPartyMail
ld bc, PARTY_LENGTH * MAIL_STRUCT_LENGTH
call CopyBytes
ld hl, sMailboxCountBackup
ld de, sMailboxCount
ld bc, 1 + MAILBOX_CAPACITY * MAIL_STRUCT_LENGTH
call CopyBytes
jp CloseSRAM
DeletePartyMonMail:
ld a, BANK(sPartyMail)
call OpenSRAM
xor a
ld hl, sPartyMail
ld bc, PARTY_LENGTH * MAIL_STRUCT_LENGTH
call ByteFill
xor a
ld hl, sMailboxCount
ld bc, 1 + MAILBOX_CAPACITY * MAIL_STRUCT_LENGTH
call ByteFill
jp CloseSRAM
IsAnyMonHoldingMail:
ld a, [wPartyCount]
and a
jr z, .no_mons
ld e, a
ld hl, wPartyMon1Item
.loop
ld d, [hl]
push hl
push de
farcall ItemIsMail
pop de
pop hl
ret c
ld bc, PARTYMON_STRUCT_LENGTH
add hl, bc
dec e
jr nz, .loop
.no_mons
and a
ret
_PlayerMailBoxMenu:
call InitMail
jr z, .nomail
call LoadStandardMenuHeader
call MailboxPC
jp CloseWindow
.nomail
ld hl, .EmptyMailboxText
jp MenuTextboxBackup
.EmptyMailboxText:
text_far _EmptyMailboxText
text_end
InitMail:
; return z if no mail
ld a, BANK(sMailboxCount)
call OpenSRAM
ld a, [sMailboxCount]
call CloseSRAM
; initialize wMailboxCount from sMailboxCount
ld hl, wMailboxCount
ld [hli], a
assert wMailboxCount + 1 == wMailboxItems
and a
jr z, .done ; if no mail, we're done
; initialize wMailboxItems with incrementing values starting at 1
ld b, a
ld a, 1
.loop
ld [hli], a
inc a
dec b
jr nz, .loop
.done
ld [hl], -1 ; terminate
ld a, [wMailboxCount]
and a
ret
MailboxPC_GetMailAuthor:
dec a
ld hl, sMailbox1Author
ld bc, MAIL_STRUCT_LENGTH
call AddNTimes
ld a, BANK(sMailboxCount)
call OpenSRAM
ld de, wStringBuffer2
push de
ld bc, NAME_LENGTH - 1
call CopyBytes
ld a, "@"
ld [de], a
call CloseSRAM
pop de
ret
MailboxPC_PrintMailAuthor:
push de
ld a, [wMenuSelection]
call MailboxPC_GetMailAuthor
pop hl
jp PlaceString
MailboxPC:
xor a
ld [wCurMessageScrollPosition], a
ld a, 1
ld [wCurMessageIndex], a
.loop
call InitMail
ld hl, .TopMenuHeader
call CopyMenuHeader
xor a
ldh [hBGMapMode], a
call InitScrollingMenu
call UpdateSprites
ld a, [wCurMessageIndex]
ld [wMenuCursorPosition], a
ld a, [wCurMessageScrollPosition]
ld [wMenuScrollPosition], a
call ScrollingMenu
ld a, [wMenuScrollPosition]
ld [wCurMessageScrollPosition], a
ld a, [wMenuCursorY]
ld [wCurMessageIndex], a
ld a, [wMenuJoypad]
cp B_BUTTON
jr z, .exit
call .Submenu
jr .loop
.exit
xor a
ret
.Submenu:
ld hl, .SubMenuHeader
call LoadMenuHeader
call VerticalMenu
call ExitMenu
jr c, .subexit
ld a, [wMenuCursorY]
dec a
ld hl, .Jumptable
rst JumpTable
.subexit
ret
.Jumptable:
dw .ReadMail
dw .PutInPack
dw .AttachMail
dw .Cancel
.ReadMail:
call FadeToMenu
ld a, [wMenuSelection]
dec a
ld b, a
call ReadMailMessage
jp CloseSubmenu
.PutInPack:
ld hl, .MailMessageLostText
call MenuTextbox
call YesNoBox
call ExitMenu
ret c
ld a, [wMenuSelection]
dec a
call .GetMailType
ld a, 1
ld [wItemQuantityChange], a
ld hl, wNumItems
call ReceiveItem
jr c, .put_in_bag
ld hl, .MailPackFullText
jp MenuTextboxBackup
.put_in_bag
ld a, [wMenuSelection]
dec a
ld b, a
call DeleteMailFromPC
ld hl, .MailClearedPutAwayText
jp MenuTextboxBackup
.MailClearedPutAwayText:
text_far _MailClearedPutAwayText
text_end
.MailPackFullText:
text_far _MailPackFullText
text_end
.MailMessageLostText:
text_far _MailMessageLostText
text_end
.GetMailType:
push af
ld a, BANK(sMailboxCount)
call OpenSRAM
pop af
ld hl, sMailbox1Type
ld bc, MAIL_STRUCT_LENGTH
call AddNTimes
ld a, [hl]
ld [wCurItem], a
jp CloseSRAM
.AttachMail:
call FadeToMenu
xor a
ld [wPartyMenuActionText], a
call ClearBGPalettes
.try_again
farcall LoadPartyMenuGFX
farcall InitPartyMenuWithCancel
farcall InitPartyMenuGFX
farcall WritePartyMenuTilemap
farcall PrintPartyMenuText
call WaitBGMap
call SetPalettes
call DelayFrame
farcall PartyMenuSelect
jr c, .exit2
ld a, [wCurPartySpecies]
cp EGG
jr z, .egg
ld a, MON_ITEM
call GetPartyParamLocation
ld a, [hl]
and a
jr z, .attach_mail
ld hl, .MailAlreadyHoldingItemText
call PrintText
jr .try_again
.egg
ld hl, .MailEggText
call PrintText
jr .try_again
.attach_mail
ld a, [wMenuSelection]
dec a
ld b, a
call MoveMailFromPCToParty
ld hl, .MailMovedFromBoxText
call PrintText
.exit2
jp CloseSubmenu
.MailAlreadyHoldingItemText:
text_far _MailAlreadyHoldingItemText
text_end
.MailEggText:
text_far _MailEggText
text_end
.MailMovedFromBoxText:
text_far _MailMovedFromBoxText
text_end
.Cancel:
ret
.TopMenuHeader:
db MENU_BACKUP_TILES ; flags
menu_coords 8, 1, SCREEN_WIDTH - 2, 10
dw .TopMenuData
db 1 ; default option
.TopMenuData:
db SCROLLINGMENU_DISPLAY_ARROWS ; flags
db 4, 0 ; rows, columns
db SCROLLINGMENU_ITEMS_NORMAL ; item format
dbw 0, wMailboxCount
dba MailboxPC_PrintMailAuthor
dba NULL
dba NULL
.SubMenuHeader:
db MENU_BACKUP_TILES ; flags
menu_coords 0, 0, 13, 9
dw .SubMenuData
db 1 ; default option
.SubMenuData:
db STATICMENU_CURSOR ; flags
db 4 ; items
db "READ MAIL@"
db "PUT IN PACK@"
db "ATTACH MAIL@"
db "CANCEL@"

947
engine/pokemon/mail_2.asm Normal file
View file

@ -0,0 +1,947 @@
; MailGFXPointers indexes
; LoadMailPalettes.MailPals indexes (see gfx/mail/mail.pal)
const_def
const FLOWER_MAIL_INDEX ; 0
const SURF_MAIL_INDEX ; 1
const LITEBLUEMAIL_INDEX ; 2
const PORTRAITMAIL_INDEX ; 3
const LOVELY_MAIL_INDEX ; 4
const EON_MAIL_INDEX ; 5
const MORPH_MAIL_INDEX ; 6
const BLUESKY_MAIL_INDEX ; 7
const MUSIC_MAIL_INDEX ; 8
const MIRAGE_MAIL_INDEX ; 9
DEF NUM_MAIL EQU const_value
ReadPartyMonMail:
ld a, [wCurPartyMon]
ld hl, sPartyMail
ld bc, MAIL_STRUCT_LENGTH
call AddNTimes
ld d, h
ld e, l
ReadAnyMail:
push de
call ClearBGPalettes
call ClearSprites
call ClearTilemap
call DisableLCD
call LoadFontsExtra
pop de
push de
ld a, BANK(sPartyMail)
call OpenSRAM
farcall ParseMailLanguage
call CloseSRAM
ld a, c
ld de, StandardEnglishFont
or a ; MAIL_LANG_ENGLISH
jr z, .got_font
ld de, FrenchGermanFont
sub MAIL_LANG_ITALIAN
jr c, .got_font
ld de, SpanishItalianFont
.got_font
ld hl, vTiles1
lb bc, BANK(StandardEnglishFont), $80
call Get1bpp
pop de
call .LoadGFX
call EnableLCD
call WaitBGMap
ld a, [wCurMailIndex]
ld e, a
farcall LoadMailPalettes
call SetPalettes
xor a
ldh [hJoyPressed], a
call .loop
call ClearBGPalettes
call DisableLCD
call LoadStandardFont
jp EnableLCD
.loop
call GetJoypad
ldh a, [hJoyPressed]
and A_BUTTON | B_BUTTON | START
jr z, .loop
vc_patch Forbid_printing_mail
if DEF(_CRYSTAL_VC)
and NO_INPUT
else
and START
endc
vc_patch_end
jr nz, .pressed_start
ret
.pressed_start
ld a, [wJumptableIndex]
push af
callfar PrintMailAndExit ; printer
pop af
ld [wJumptableIndex], a
jr .loop
.LoadGFX:
ld h, d
ld l, e
push hl
ld a, BANK(sPartyMail)
call OpenSRAM
ld de, sPartyMon1MailAuthorID - sPartyMon1Mail
add hl, de
ld a, [hli] ; author id
ld [wCurMailAuthorID], a
ld a, [hli]
ld [wCurMailAuthorID + 1], a
ld a, [hli] ; species
ld [wCurPartySpecies], a
ld b, [hl] ; type
call CloseSRAM
ld hl, MailGFXPointers
ld c, 0
.loop2
ld a, [hli]
cp b
jr z, .got_pointer
cp -1
jr z, .invalid
inc c
inc hl
inc hl
jr .loop2
.invalid
ld hl, MailGFXPointers
inc hl
.got_pointer
ld a, c
ld [wCurMailIndex], a
ld a, [hli]
ld h, [hl]
ld l, a
ld de, .done
pop bc
push de
jp hl
.done
ret
MailGFXPointers:
; entries correspond to *MAIL_INDEX constants
table_width 3, MailGFXPointers
dbw FLOWER_MAIL, LoadFlowerMailGFX
dbw SURF_MAIL, LoadSurfMailGFX
dbw LITEBLUEMAIL, LoadLiteBlueMailGFX
dbw PORTRAITMAIL, LoadPortraitMailGFX
dbw LOVELY_MAIL, LoadLovelyMailGFX
dbw EON_MAIL, LoadEonMailGFX
dbw MORPH_MAIL, LoadMorphMailGFX
dbw BLUESKY_MAIL, LoadBlueSkyMailGFX
dbw MUSIC_MAIL, LoadMusicMailGFX
dbw MIRAGE_MAIL, LoadMirageMailGFX
assert_table_length NUM_MAIL
db -1 ; end
LoadSurfMailGFX:
push bc
ld hl, vTiles2 tile $31
ld de, SurfMailBorderGFX
ld c, 8 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, MailLaprasGFX
ld c, 6 * LEN_1BPP_TILE
call LoadMailGFX_Color3
ld de, SurfMailWaveGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
jr FinishLoadingSurfLiteBlueMailGFX
LoadLiteBlueMailGFX:
push bc
ld hl, vTiles2 tile $31
ld de, LiteBlueMailBorderGFX
ld c, 8 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, MailDratiniGFX
ld c, 6 * LEN_1BPP_TILE
call LoadMailGFX_Color3
ld de, PortraitMailUnderlineGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
FinishLoadingSurfLiteBlueMailGFX:
ld de, SurfLiteBlueMailSmallShapesGFX
ld c, 2 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld c, 2 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, SurfLiteBlueMailLargeShapesGFX
ld c, 8 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld c, 8 * LEN_1BPP_TILE
call LoadMailGFX_Color2
call DrawMailBorder
hlcoord 2, 15
ld a, $3f
call Mail_Draw16TileRow
ld a, $39
hlcoord 15, 14
call Mail_Draw3x2Graphic
ld a, $44
hlcoord 2, 2
call Mail_Draw2x2Graphic
hlcoord 15, 11
call Mail_Draw2x2Graphic
ld a, $4c
hlcoord 3, 12
call Mail_Draw2x2Graphic
hlcoord 15, 2
call Mail_Draw2x2Graphic
ld a, $50
hlcoord 6, 3
call Mail_Draw2x2Graphic
ld a, $40
hlcoord 13, 2
ld [hli], a
hlcoord 6, 14
ld [hl], a
ld a, $41
hlcoord 4, 5
ld [hli], a
hlcoord 17, 5
ld [hli], a
hlcoord 13, 12
ld [hl], a
ld a, $42
hlcoord 9, 2
ld [hli], a
hlcoord 14, 5
ld [hli], a
hlcoord 3, 10
ld [hl], a
ld a, $43
hlcoord 6, 11
ld [hli], a
pop hl
jp MailGFX_PlaceMessage
LoadEonMailGFX:
push bc
ld hl, vTiles2 tile $31
ld de, EonMailBorder1GFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, EonMailBorder2GFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, EonMailBorder2GFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, EonMailBorder1GFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, SurfMailBorderGFX + 6 * LEN_1BPP_TILE
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, MailEeveeGFX
ld c, 6 * LEN_1BPP_TILE
call LoadMailGFX_Color3
ld hl, vTiles2 tile $3d
ld de, MailLargeCircleGFX
ld c, 4 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, EonMailBorder2GFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld a, $31
hlcoord 0, 0
call Mail_Place18TileAlternatingRow
hlcoord 1, 17
call Mail_Place18TileAlternatingRow
ld a, $33
hlcoord 0, 1
call Mail_Place16TileAlternatingColumn
hlcoord 19, 0
call Mail_Place16TileAlternatingColumn
hlcoord 2, 15
ld a, $35
call Mail_Draw16TileRow
inc a
hlcoord 15, 14
call Mail_Draw3x2Graphic
call LovelyEonMail_PlaceIcons
pop hl
jp MailGFX_PlaceMessage
LoadLovelyMailGFX:
push bc
ld hl, vTiles2 tile $31
ld de, LovelyMailBorderGFX
ld c, 5 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, MailPoliwagGFX
ld c, 6 * LEN_1BPP_TILE
call LoadMailGFX_Color3
ld de, LovelyMailUnderlineGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, LovelyMailLargeHeartGFX
ld c, 4 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, LovelyMailSmallHeartGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color1
call DrawMailBorder2
hlcoord 2, 15
ld a, $3c
call Mail_Draw16TileRow
ld a, $36
hlcoord 15, 14
call Mail_Draw3x2Graphic
call LovelyEonMail_PlaceIcons
pop hl
jp MailGFX_PlaceMessage
LovelyEonMail_PlaceIcons:
ld a, $3d
hlcoord 2, 2
call Mail_Draw2x2Graphic
hlcoord 16, 2
call Mail_Draw2x2Graphic
hlcoord 9, 4
call Mail_Draw2x2Graphic
hlcoord 2, 11
call Mail_Draw2x2Graphic
hlcoord 6, 12
call Mail_Draw2x2Graphic
hlcoord 12, 11
call Mail_Draw2x2Graphic
ld a, $41
hlcoord 5, 4
ld [hl], a
hlcoord 6, 2
ld [hl], a
hlcoord 12, 4
ld [hl], a
hlcoord 14, 2
ld [hl], a
hlcoord 3, 13
ld [hl], a
hlcoord 9, 11
ld [hl], a
hlcoord 16, 12
ld [hl], a
ret
LoadMorphMailGFX:
push bc
ld hl, vTiles2 tile $31
ld bc, 5 * LEN_1BPP_TILE
call MailGFX_GenerateMonochromeTilesColor2
ld de, MorphMailBorderCornerGFX + 3 * LEN_1BPP_TILE
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, MorphMailBorderCornerGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, MorphMailBorderGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, EonMailBorder1GFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, MorphMailDividerGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, MailDittoGFX
ld c, 6 * LEN_1BPP_TILE
call LoadMailGFX_Color3
call DrawMailBorder2
ld a, $31
hlcoord 1, 1
call Mail_Draw2x2Graphic
hlcoord 17, 15
call Mail_Draw2x2Graphic
hlcoord 1, 3
ld [hl], a
hlcoord 3, 1
ld [hl], a
hlcoord 16, 16
ld [hl], a
hlcoord 18, 14
ld [hl], a
ld a, $36
hlcoord 1, 4
ld [hl], a
hlcoord 2, 3
ld [hl], a
hlcoord 3, 2
ld [hl], a
hlcoord 4, 1
ld [hl], a
inc a
hlcoord 15, 16
ld [hl], a
hlcoord 16, 15
ld [hl], a
hlcoord 17, 14
ld [hl], a
hlcoord 18, 13
ld [hl], a
inc a
hlcoord 2, 15
ld b, $e
call Mail_DrawRowLoop
inc a
hlcoord 2, 11
call Mail_Draw16TileRow
hlcoord 2, 5
call Mail_Draw16TileRow
inc a
hlcoord 6, 1
call Mail_Draw13TileRow
hlcoord 1, 16
call Mail_Draw13TileRow
inc a
hlcoord 3, 13
call Mail_Draw3x2Graphic
pop hl
jp MailGFX_PlaceMessage
LoadBlueSkyMailGFX:
push bc
ld hl, vTiles2 tile $31
ld de, EonMailBorder1GFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld a, $ff
ld bc, 1 tiles
call ByteFill
ld de, BlueSkyMailGrassGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color3
ld de, MailDragoniteAndSentretGFX
ld c, 23 * LEN_1BPP_TILE
call LoadMailGFX_Color3
ld de, MailCloudGFX
ld c, 6 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, FlowerMailBorderGFX + 6 * LEN_1BPP_TILE
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, MailCloudGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, MailCloudGFX + 2 * LEN_1BPP_TILE
ld c, 2 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, MailCloudGFX + 5 * LEN_1BPP_TILE
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld a, $31
hlcoord 0, 0
call Mail_DrawFullWidthBorder
hlcoord 0, 1
call Mail_DrawLeftRightBorder
hlcoord 19, 1
call Mail_DrawLeftRightBorder
inc a
hlcoord 0, 17
call Mail_DrawFullWidthBorder
inc a
hlcoord 0, 16
call Mail_DrawFullWidthBorder
inc a
hlcoord 2, 2
call Mail_Place6TileRow
hlcoord 3, 3
call Mail_Place6TileRow
hlcoord 4, 4
call Mail_Place6TileRow
dec hl
ld [hl], $7f
dec a
hlcoord 15, 14
call Mail_Draw2x2Graphic
add $4
hlcoord 15, 16
ld [hli], a
inc a
ld [hl], a
inc a
push af
hlcoord 12, 1
call Mail_Draw3x2Graphic
pop af
hlcoord 15, 4
call Mail_Draw3x2Graphic
inc a
hlcoord 2, 11
call Mail_Draw16TileRow
inc a
hlcoord 10, 3
call Mail_Draw2x2Graphic
pop hl
jp MailGFX_PlaceMessage
Mail_Place6TileRow:
ld b, $6
.loop
ld [hli], a
inc a
dec b
jr nz, .loop
ret
LoadFlowerMailGFX:
push bc
ld hl, vTiles2 tile $31
ld de, FlowerMailBorderGFX
ld c, 8 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, MailOddishGFX
ld c, 4 * LEN_1BPP_TILE
call LoadMailGFX_Color3
ld de, FlowerMailBorderGFX + 6 * LEN_1BPP_TILE
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, FlowerMailFlowerGFX
ld c, 4 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld c, 4 * LEN_1BPP_TILE
call LoadMailGFX_Color2
call DrawMailBorder
hlcoord 2, 15
ld a, $3d ; underline
call Mail_Draw16TileRow
ld a, $39 ; oddish
hlcoord 16, 13
call Mail_Draw2x2Graphic
hlcoord 2, 13
call Mail_Draw2x2Graphic
ld a, $3e
hlcoord 2, 2
call Mail_Draw2x2Graphic
hlcoord 5, 3
call Mail_Draw2x2Graphic
hlcoord 10, 2
call Mail_Draw2x2Graphic
hlcoord 16, 3
call Mail_Draw2x2Graphic
hlcoord 5, 11
call Mail_Draw2x2Graphic
hlcoord 16, 10
call Mail_Draw2x2Graphic
ld a, $42
hlcoord 3, 4
call Mail_Draw2x2Graphic
hlcoord 12, 3
call Mail_Draw2x2Graphic
hlcoord 14, 2
call Mail_Draw2x2Graphic
hlcoord 2, 10
call Mail_Draw2x2Graphic
hlcoord 14, 11
call Mail_Draw2x2Graphic
pop hl
jp MailGFX_PlaceMessage
LoadPortraitMailGFX:
push bc
ld hl, vTiles2 tile $31
ld de, PortraitMailBorderGFX
ld c, 5 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, PortraitMailUnderlineGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld hl, vTiles2 tile $3d
ld de, PortraitMailLargePokeballGFX
ld c, 4 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, PortraitMailSmallPokeballGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
call DrawMailBorder2
hlcoord 8, 15
ld a, $36
ld b, $a
call Mail_DrawRowLoop
call LovelyEonMail_PlaceIcons
ld a, $1
ld [wUnownLetter], a
hlcoord 1, 10
call PrepMonFrontpic
pop hl
jp MailGFX_PlaceMessage
LoadMusicMailGFX:
push bc
ld hl, vTiles2 tile $31
ld de, MusicMailBorderGFX
ld c, 4 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, MorphMailBorderGFX
ld c, 2 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, MailNatuGFX
ld c, 6 * LEN_1BPP_TILE
call LoadMailGFX_Color3
xor a
ld bc, 1 tiles
call ByteFill
ld de, MusicMailLargeNoteGFX
ld c, 3 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, MusicMailSmallNoteGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld a, $31
hlcoord 0, 0
call Mail_Place18TileAlternatingRow
hlcoord 1, 17
call Mail_Place18TileAlternatingRow
ld a, $33
hlcoord 0, 1
call Mail_Place16TileAlternatingColumn
hlcoord 19, 0
call Mail_Place16TileAlternatingColumn
ld a, $35
hlcoord 2, 15
call Mail_Place14TileAlternatingRow
ld a, $37
hlcoord 15, 14
call Mail_Draw3x2Graphic
call LovelyEonMail_PlaceIcons
pop hl
jp MailGFX_PlaceMessage
LoadMirageMailGFX:
push bc
ld hl, vTiles2 tile $31
ld bc, 5 * LEN_1BPP_TILE
call MailGFX_GenerateMonochromeTilesColor2
ld de, BlueSkyMailGrassGFX
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, MailMewGFX
ld c, 18 * LEN_1BPP_TILE
call LoadMailGFX_Color2
ld de, LiteBlueMailBorderGFX + 1 * LEN_1BPP_TILE
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color1
ld de, LiteBlueMailBorderGFX + 6 * LEN_1BPP_TILE
ld c, 1 * LEN_1BPP_TILE
call LoadMailGFX_Color1
call DrawMailBorder2
ld a, $36
hlcoord 1, 16
call Mail_DrawTopBottomBorder
inc a
hlcoord 15, 14
call Mail_Draw3x2Graphic
inc a
hlcoord 15, 16
ld [hli], a
inc a
ld [hl], a
ld a, $3f
hlcoord 1, 1
call Mail_Place18TileAlternatingRow
ld a, $41
hlcoord 0, 2
call Mail_Place14TileAlternatingColumn
ld a, $43
hlcoord 19, 2
call Mail_Place14TileAlternatingColumn
ld a, $45
hlcoord 0, 1
ld [hl], a
inc a
hlcoord 19, 1
ld [hl], a
inc a
hlcoord 0, 16
ld [hl], a
inc a
hlcoord 19, 16
ld [hl], a
inc a
hlcoord 2, 5
call Mail_Draw16TileRow
inc a
hlcoord 2, 11
call Mail_Draw16TileRow
pop hl
jp MailGFX_PlaceMessage
MailGFX_GenerateMonochromeTilesColor2:
.loop
xor a
ld [hli], a
ld a, $ff
ld [hli], a
dec bc
ld a, b
or c
jr nz, .loop
ret
MailGFX_PlaceMessage:
ld bc, MAIL_STRUCT_LENGTH
ld de, wTempMail
ld a, BANK(sPartyMail)
call OpenSRAM
call CopyBytes
call CloseSRAM
ld hl, wTempMailAuthor
ld de, wMonOrItemNameBuffer
ld bc, NAME_LENGTH - 1
call CopyBytes
ld a, "@"
ld [wTempMailAuthor], a
ld [wMonOrItemNameBuffer + NAME_LENGTH - 1], a
ld de, wTempMailMessage
hlcoord 2, 7
call PlaceString
ld de, wMonOrItemNameBuffer
ld a, [de]
and a
ret z
ld a, [wCurMailIndex]
hlcoord 8, 14
cp PORTRAITMAIL_INDEX
jr z, .place_author
hlcoord 6, 14
cp MORPH_MAIL_INDEX
jr z, .place_author
hlcoord 5, 14
.place_author
jp PlaceString
InvertBytes: ; unreferenced
; invert bc bytes starting at hl
.loop
ld a, [hl]
xor $ff
ld [hli], a
dec bc
ld a, b
or c
jr nz, .loop
ret
DrawMailBorder:
hlcoord 0, 0
ld a, $31
ld [hli], a
inc a
call Mail_DrawTopBottomBorder
inc a
ld [hli], a
inc a
call Mail_DrawLeftRightBorder
ld a, $36
ld [hli], a
inc a
call Mail_DrawTopBottomBorder
hlcoord 19, 1
ld a, $35
call Mail_DrawLeftRightBorder
ld a, $38
ld [hl], a
ret
DrawMailBorder2:
hlcoord 0, 0
ld a, $31
ld [hli], a
inc a
call Mail_DrawTopBottomBorder
ld [hl], $31
inc hl
inc a
call Mail_DrawLeftRightBorder
ld [hl], $31
inc hl
inc a
call Mail_DrawTopBottomBorder
hlcoord 19, 1
ld a, $35
call Mail_DrawLeftRightBorder
ld [hl], $31
ret
Mail_Place14TileAlternatingRow:
push af
ld b, 14 / 2
jr Mail_PlaceAlternatingRow
Mail_Place16TileAlternatingRow: ; unreferenced
push af
ld b, 16 / 2
jr Mail_PlaceAlternatingRow
Mail_Place18TileAlternatingRow:
push af
ld b, 18 / 2
; fallthrough
Mail_PlaceAlternatingRow:
.loop
ld [hli], a
inc a
ld [hli], a
dec a
dec b
jr nz, .loop
ld [hl], a
pop af
ret
Mail_Place14TileAlternatingColumn:
push af
ld b, 14 / 2
jr Mail_PlaceAlternatingColumn
Mail_Place16TileAlternatingColumn:
push af
ld b, 16 / 2
Mail_PlaceAlternatingColumn:
.loop
ld [hl], a
ld de, SCREEN_WIDTH
add hl, de
inc a
ld [hl], a
add hl, de
dec a
dec b
jr nz, .loop
ld [hl], a
pop af
ret
Mail_Draw7TileRow: ; unreferenced
ld b, 7
jr Mail_DrawRowLoop
Mail_Draw13TileRow:
ld b, 13
jr Mail_DrawRowLoop
Mail_Draw16TileRow:
ld b, 16
jr Mail_DrawRowLoop
Mail_DrawTopBottomBorder:
ld b, SCREEN_WIDTH - 2
jr Mail_DrawRowLoop
Mail_DrawFullWidthBorder:
ld b, SCREEN_WIDTH
; fallthrough
Mail_DrawRowLoop:
.loop
ld [hli], a
dec b
jr nz, .loop
ret
Mail_DrawLeftRightBorder:
ld b, SCREEN_HEIGHT - 2
ld de, SCREEN_WIDTH
.loop
ld [hl], a
add hl, de
dec b
jr nz, .loop
ret
Mail_Draw2x2Graphic:
push af
ld [hli], a
inc a
ld [hl], a
ld bc, SCREEN_WIDTH - 1
add hl, bc
inc a
ld [hli], a
inc a
ld [hl], a
pop af
ret
Mail_Draw3x2Graphic:
ld [hli], a
inc a
ld [hli], a
inc a
ld [hl], a
ld bc, SCREEN_WIDTH - 2
add hl, bc
inc a
ld [hli], a
inc a
ld [hli], a
inc a
ld [hl], a
ret
LoadMailGFX_Color1:
.loop
ld a, [de]
inc de
ld [hli], a
xor a
ld [hli], a
dec c
jr nz, .loop
ret
LoadMailGFX_Color2:
.loop
xor a
ld [hli], a
ld a, [de]
inc de
ld [hli], a
dec c
jr nz, .loop
ret
LoadMailGFX_Color3:
.loop
ld a, [de]
inc de
ld [hli], a
ld [hli], a
dec c
jr nz, .loop
ret
INCLUDE "gfx/mail.asm"
ItemIsMail:
ld a, d
ld hl, MailItems
ld de, 1
jp IsInArray
INCLUDE "data/items/mail_items.asm"

1287
engine/pokemon/mon_menu.asm Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,491 @@
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
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]
call GetPokemonIndexFromID
ld b, h
ld c, l
ld hl, BaseData
ld a, BANK(BaseData)
call LoadIndirectPointer
ld bc, BASE_GENDER
add hl, bc
pop bc
jr z, .Genderless
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, [wListMovesLineSpacing]
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, [wListMovesLineSpacing]
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
BrokenPlacePPUnits: ; unreferenced
; Probably would have these parameters:
; hl = starting coordinate
; de = SCREEN_WIDTH or SCREEN_WIDTH * 2
; c = the number of moves (1-4)
.loop
ld [hl], $32 ; typo for P?
inc hl
ld [hl], $3e ; P
dec hl
add hl, de
dec c
jr nz, .loop
ret
Unused_PlaceEnemyHPLevel:
push hl
push hl
ld hl, wPartyMonNicknames
ld a, [wCurPartyMon]
call GetNickname
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:
; Return nz if the status is not OK
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, TRUE
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_MASK
jr z, .no_status
.place
call CopyStatusString
ld a, TRUE
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 [wListMovesLineSpacing] 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 [wNamedObjectIndex], a
call GetMoveName
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, [wListMovesLineSpacing]
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, [wListMovesLineSpacing]
ld c, a
ld b, 0
add hl, bc
pop af
inc a
cp NUM_MOVES
jr nz, .nonmove_loop
.done
ret

View file

@ -0,0 +1,291 @@
INCLUDE "data/mon_menu.asm"
MonSubmenu:
xor a
ldh [hBGMapMode], a
call GetMonSubmenuItems
farcall FreezeMonIcons
ld hl, .MenuHeader
call LoadMenuHeader
call .GetTopCoord
call PopulateMonMenu
ld a, 1
ldh [hBGMapMode], a
call MonMenuLoop
ld [wMenuSelection], a
call ExitMenu
ret
.MenuHeader:
db MENU_BACKUP_TILES ; flags
menu_coords 6, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
dw 0
db 1 ; default option
.GetTopCoord:
; [wMenuBorderTopCoord] = 1 + [wMenuBorderBottomCoord] - 2 * ([wMonSubmenuCount] + 1)
ld a, [wMonSubmenuCount]
inc a
add a
ld b, a
ld a, [wMenuBorderBottomCoord]
sub b
inc a
ld [wMenuBorderTopCoord], a
call MenuBox
ret
MonMenuLoop:
.loop
ld a, MENU_UNUSED_3 | MENU_BACKUP_TILES_2 ; flags
ld [wMenuDataFlags], a
ld a, [wMonSubmenuCount]
ld [wMenuDataItems], a
call InitVerticalMenuCursor
ld hl, w2DMenuFlags1
set 6, [hl]
call StaticMenuJoypad
ld de, SFX_READ_TEXT_2
call PlaySFX
ldh a, [hJoyPressed]
bit A_BUTTON_F, a
jr nz, .select
bit B_BUTTON_F, a
jr nz, .cancel
jr .loop
.cancel
ld a, MONMENUITEM_CANCEL
ret
.select
ld a, [wMenuCursorY]
dec a
ld c, a
ld b, 0
ld hl, wMonSubmenuItems
add hl, bc
ld a, [hl]
ret
PopulateMonMenu:
call MenuBoxCoord2Tile
ld bc, 2 * SCREEN_WIDTH + 2
add hl, bc
ld de, wMonSubmenuItems
.loop
ld a, [de]
inc de
cp -1
ret z
push de
push hl
call GetMonMenuString
pop hl
call PlaceString
ld bc, 2 * SCREEN_WIDTH
add hl, bc
pop de
jr .loop
GetMonMenuString:
ld hl, MonMenuOptions + 1
ld de, 4
call IsInArray
dec hl
ld a, [hli]
inc hl
cp MONMENU_MENUOPTION
jr z, .NotMove
ld a, [hli]
ld h, [hl]
ld l, a
call GetMoveIDFromIndex
ld [wNamedObjectIndex], a
jp GetMoveName
.NotMove:
ld a, [hli]
ld d, [hl]
ld e, a
ret
GetMonSubmenuItems:
call ResetMonSubmenu
ld a, [wCurPartySpecies]
cp EGG
jr z, .egg
ld a, [wLinkMode]
and a
jr nz, .skip_moves
ld a, MON_MOVES
call GetPartyParamLocation
ld d, h
ld e, l
ld c, NUM_MOVES
.loop
push bc
push de
ld a, [de]
and a
jr z, .next
push hl
call IsFieldMove
pop hl
jr nc, .next
call AddMonMenuItem
.next
pop de
inc de
pop bc
dec c
jr nz, .loop
.skip_moves
ld a, MONMENUITEM_STATS
call AddMonMenuItem
ld a, MONMENUITEM_SWITCH
call AddMonMenuItem
ld a, MONMENUITEM_MOVE
call AddMonMenuItem
ld a, [wLinkMode]
and a
jr nz, .skip2
push hl
ld a, MON_ITEM
call GetPartyParamLocation
ld d, [hl]
farcall ItemIsMail
pop hl
ld a, MONMENUITEM_MAIL
jr c, .ok
ld a, MONMENUITEM_ITEM
.ok
call AddMonMenuItem
.skip2
ld a, [wMonSubmenuCount]
cp NUM_MONMENU_ITEMS
jr z, .ok2
ld a, MONMENUITEM_CANCEL
call AddMonMenuItem
.ok2
call TerminateMonSubmenu
ret
.egg
ld a, MONMENUITEM_STATS
call AddMonMenuItem
ld a, MONMENUITEM_SWITCH
call AddMonMenuItem
ld a, MONMENUITEM_CANCEL
call AddMonMenuItem
call TerminateMonSubmenu
ret
IsFieldMove:
call GetMoveIndexFromID
ld b, h
ld c, l
ld hl, MonMenuOptions
.next
ld a, [hli]
cp -1
ret z
cp MONMENU_MENUOPTION
ret z
ld a, [hli]
ld d, a
ld a, [hli]
cp c
ld a, [hli]
jr nz, .next
cp b
jr nz, .next
ld a, d
scf
ret
ResetMonSubmenu:
xor a
ld [wMonSubmenuCount], a
ld hl, wMonSubmenuItems
ld bc, NUM_MONMENU_ITEMS + 1
call ByteFill
ret
TerminateMonSubmenu:
ld a, [wMonSubmenuCount]
ld e, a
ld d, 0
ld hl, wMonSubmenuItems
add hl, de
ld [hl], -1
ret
AddMonMenuItem:
push hl
push de
push af
ld a, [wMonSubmenuCount]
ld e, a
inc a
ld [wMonSubmenuCount], a
ld d, 0
ld hl, wMonSubmenuItems
add hl, de
pop af
ld [hl], a
pop de
pop hl
ret
BattleMonMenu:
ld hl, .MenuHeader
call CopyMenuHeader
xor a
ldh [hBGMapMode], a
call MenuBox
call UpdateSprites
call PlaceVerticalMenuItems
call WaitBGMap
call CopyMenuData
ld a, [wMenuDataFlags]
bit 7, a
jr z, .set_carry
call InitVerticalMenuCursor
ld hl, w2DMenuFlags1
set 6, [hl]
call StaticMenuJoypad
ld de, SFX_READ_TEXT_2
call PlaySFX
ldh a, [hJoyPressed]
bit B_BUTTON_F, a
jr z, .clear_carry
ret z
.set_carry
scf
ret
.clear_carry
and a
ret
.MenuHeader:
db 0 ; flags
menu_coords 11, 11, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1
dw .MenuData
db 1 ; default option
.MenuData:
db STATICMENU_CURSOR | STATICMENU_NO_TOP_SPACING ; flags
db 3 ; items
db "SWITCH@"
db "STATS@"
db "CANCEL@"

1847
engine/pokemon/move_mon.asm Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,133 @@
InsertPokemonIntoBox:
ld a, BANK(sBoxCount)
call OpenSRAM
ld hl, sBoxCount
call InsertSpeciesIntoBoxOrParty
ld a, [sBoxCount]
dec a
ld [wNextBoxOrPartyIndex], a
ld hl, sBoxMonNicknames
ld bc, MON_NAME_LENGTH
ld de, wBufferMonNickname
call InsertDataIntoBoxOrParty
ld a, [sBoxCount]
dec a
ld [wNextBoxOrPartyIndex], a
ld hl, sBoxMonOTs
ld bc, NAME_LENGTH
ld de, wBufferMonOT
call InsertDataIntoBoxOrParty
ld a, [sBoxCount]
dec a
ld [wNextBoxOrPartyIndex], a
ld hl, sBoxMons
ld bc, BOXMON_STRUCT_LENGTH
ld de, wBufferMon
call InsertDataIntoBoxOrParty
ld hl, wBufferMonMoves
ld de, wTempMonMoves
ld bc, NUM_MOVES
call CopyBytes
ld hl, wBufferMonPP
ld de, wTempMonPP
ld bc, NUM_MOVES
call CopyBytes
ld a, [wCurPartyMon]
ld b, a
farcall RestorePPOfDepositedPokemon
jp CloseSRAM
InsertPokemonIntoParty:
ld hl, wPartyCount
call InsertSpeciesIntoBoxOrParty
ld a, [wPartyCount]
dec a
ld [wNextBoxOrPartyIndex], a
ld hl, wPartyMonNicknames
ld bc, MON_NAME_LENGTH
ld de, wBufferMonNickname
call InsertDataIntoBoxOrParty
ld a, [wPartyCount]
dec a
ld [wNextBoxOrPartyIndex], a
ld hl, wPartyMonOTs
ld bc, NAME_LENGTH
ld de, wBufferMonOT
call InsertDataIntoBoxOrParty
ld a, [wPartyCount]
dec a
ld [wNextBoxOrPartyIndex], a
ld hl, wPartyMons
ld bc, PARTYMON_STRUCT_LENGTH
ld de, wBufferMon
call InsertDataIntoBoxOrParty
ret
InsertSpeciesIntoBoxOrParty:
inc [hl]
inc hl
ld a, [wCurPartyMon]
ld c, a
ld b, 0
add hl, bc
ld a, [wCurPartySpecies]
ld c, a
.loop
ld a, [hl]
ld [hl], c
inc hl
inc c
ld c, a
jr nz, .loop
ret
InsertDataIntoBoxOrParty:
push de
push hl
push bc
ld a, [wNextBoxOrPartyIndex]
dec a
call AddNTimes
push hl
add hl, bc
ld d, h
ld e, l
pop hl
.loop
push bc
ld a, [wNextBoxOrPartyIndex]
ld b, a
ld a, [wCurPartyMon]
cp b
pop bc
jr z, .insert
push hl
push de
push bc
call CopyBytes
pop bc
pop de
pop hl
push hl
ld a, l
sub c
ld l, a
ld a, h
sbc b
ld h, a
pop de
ld a, [wNextBoxOrPartyIndex]
dec a
ld [wNextBoxOrPartyIndex], a
jr .loop
.insert
pop bc
pop hl
ld a, [wCurPartyMon]
call AddNTimes
ld d, h
ld e, l
pop hl
call CopyBytes
ret

View file

@ -0,0 +1,823 @@
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
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
dw PlacePartyMonMobileBattleSelection
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 GetNickname
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, .CancelString
call PlaceString
ret
.CancelString:
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_BARS
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]
call GetPokemonIndexFromID
ld b, h
ld c, l
ld hl, EvosAttacksPointers
ld a, BANK(EvosAttacksPointers)
call LoadDoubleIndirectPointer
ld d, h
ld e, l
farcall DetermineEvolutionItemResults
ld a, d
or e
ld de, .string_not_able
jr z, .got_string
ld de, .string_able
.got_string
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
.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@"
PlacePartyMonMobileBattleSelection:
ld a, [wPartyCount]
and a
ret z
ld c, a
ld b, 0
hlcoord 12, 1
.loop
push bc
push hl
ld de, .String_Sanka_Shinai
call PlaceString
pop hl
ld de, 2 * SCREEN_WIDTH
add hl, de
pop bc
inc b
dec c
jr nz, .loop
ld a, l
ld e, MON_NAME_LENGTH
sub e
ld l, a
ld a, h
sbc $0
ld h, a
ld de, .String_Kettei_Yameru
call PlaceString
ld b, $3
ld c, $0
ld hl, wd002
ld a, [hl]
.loop2
push hl
push bc
hlcoord 12, 1
.loop3
and a
jr z, .done
ld de, 2 * SCREEN_WIDTH
add hl, de
dec a
jr .loop3
.done
ld de, .String_Banme
push hl
call PlaceString
pop hl
pop bc
push bc
push hl
ld a, c
ld hl, .Strings_1_2_3
call GetNthString
ld d, h
ld e, l
pop hl
call PlaceString
pop bc
pop hl
inc hl
ld a, [hl]
inc c
dec b
ret z
jr .loop2
.String_Banme:
db " ばんめ  @" ; Place
.String_Sanka_Shinai:
db "さんかしない@" ; Cancel
.String_Kettei_Yameru:
db "けってい  やめる@" ; Quit
.Strings_1_2_3:
db "@", "@", "@" ; 1st, 2nd, 3rd
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 [hObjectStructIndex], a
.loop
push bc
push hl
ld hl, LoadMenuMonIcon
ld a, BANK(LoadMenuMonIcon)
ld e, MONICON_PARTYMENU
rst FarCall
ldh a, [hObjectStructIndex]
inc a
ldh [hObjectStructIndex], a
pop hl
pop bc
dec c
jr nz, .loop
callfar PlaySpriteAnimations
ret
InitPartyMenuWithCancel:
; with cancel
xor a
ld [wSwitchMon], a
ld de, PartyMenu2DMenuData
call Load2DMenuData
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, PartyMenu2DMenuData
call Load2DMenuData
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
PartyMenu2DMenuData:
db 1, 0 ; cursor start y, x
db 0, 1 ; rows, columns
db $60, $00 ; flags
dn 2, 0 ; cursor offset
db 0 ; accepted buttons
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: ; unreferenced
db "Choose a ♀<PK><MN>.@"
ChooseAMalePKMNString: ; unreferenced
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 GetNickname
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

View file

@ -0,0 +1,19 @@
PrintMoveDescription:
push hl
ld a, [wCurSpecies]
call GetMoveIndexFromID
ld b, h
ld c, l
ld a, BANK(MoveDescriptions)
ld hl, MoveDescriptions
call LoadDoubleIndirectPointer
jr nz, .ok
ld a, BANK(InvalidMoveDescription)
ld hl, InvalidMoveDescription
.ok
ld d, h
ld e, l
pop hl
jp FarPlaceString
INCLUDE "data/moves/descriptions.asm"

View file

@ -0,0 +1,362 @@
BeastsCheck:
; Check if the player owns all three legendary beasts.
; They must exist in either party or PC, and have the player's OT and ID.
; Return the result in wScriptVar.
ld hl, RAIKOU
call GetPokemonIDFromIndex
ld [wScriptVar], a
call CheckOwnMonAnywhere
jr nc, .notexist
ld hl, ENTEI
call GetPokemonIDFromIndex
ld [wScriptVar], a
call CheckOwnMonAnywhere
jr nc, .notexist
ld hl, SUICUNE
call GetPokemonIDFromIndex
ld [wScriptVar], a
call CheckOwnMonAnywhere
jr nc, .notexist
; they exist
ld a, 1
ld [wScriptVar], a
ret
.notexist
xor a
ld [wScriptVar], a
ret
MonCheck:
; Check if the player owns any Pokémon of the species in wScriptVar.
; Return the result in wScriptVar.
call CheckOwnMonAnywhere
jr c, .exists
; doesn't exist
xor a
ld [wScriptVar], a
ret
.exists
ld a, 1
ld [wScriptVar], a
ret
CheckOwnMonAnywhere:
; Check if the player owns any monsters of the species in wScriptVar.
; It must exist in either party or PC, and have the player's OT and ID.
; If there are no monsters in the party,
; the player must not own any yet.
ld a, [wPartyCount]
and a
ret z
; BUG: CheckOwnMon does not check the Day-Care (see docs/bugs_and_glitches.md)
ld d, a
ld e, 0
ld hl, wPartyMon1Species
ld bc, wPartyMonOTs
; Run CheckOwnMon on each Pokémon in the party.
.partymon
and a
call CheckOwnMon
ret c
push bc
ld bc, PARTYMON_STRUCT_LENGTH
add hl, bc
pop bc
call UpdateOTPointer
dec d
jr nz, .partymon
; Run CheckOwnMon on each Pokémon in the PC.
ld a, BANK(sBoxCount)
call OpenSRAM
ld a, [sBoxCount]
and a
jr z, .boxes
ld d, a
ld hl, sBoxMon1Species
ld bc, sBoxMonOTs
.openboxmon
and a
call CheckOwnMon
jr nc, .loop
call CloseSRAM
ret
.loop
push bc
ld bc, BOXMON_STRUCT_LENGTH
add hl, bc
pop bc
call UpdateOTPointer
dec d
jr nz, .openboxmon
; Run CheckOwnMon on each monster in the other 13 PC boxes.
.boxes
call CloseSRAM
ld a, [wSavedAtLeastOnce]
and a
ret z
ld c, 0
ld a, [wScriptVar]
call GetPokemonIndexFromID
ld d, h
ld e, l
.box
; Don't search the current box again.
ld a, [wCurBox]
and $f
cp c
jr z, .loopbox
; Load the box's indexes.
ld hl, BoxPokemonIndexesAddressTable
ld b, 0
add hl, bc
add hl, bc
add hl, bc
ld a, [hli]
ldh [hTemp], a
call OpenSRAM
ld a, [hli]
ld h, [hl]
ld l, a
.boxmon
ld a, [hli]
cp e
ld a, [hli]
jr nz, .loopboxmon
cp d
jr nz, .loopboxmon
push hl
push de
push bc
call GetBoxMonPointers
ld a, [wTempSpecies]
call IsAPokemon
ccf
call c, CheckOwnMon ;calls with carry set (skips species check)
pop bc
pop de
pop hl
jp c, CloseSRAM ;preserves flags
ldh a, [hTemp]
call OpenSRAM
.loopboxmon
inc b
ld a, b
cp MONS_PER_BOX
jr c, .boxmon
.loopbox
inc c
ld a, c
cp NUM_BOXES
jr c, .box
call CloseSRAM
and a
ret
CheckOwnMon:
; Check if a Pokémon belongs to the player and is of a specific species.
; We compare the species we are looking for in [wScriptVar] to the species
; we have in [hl].
; inputs:
; hl, pointer to PartyMonNSpecies
; bc, pointer to PartyMonNOT
; wScriptVar should contain the species we're looking for
; carry flag: if set, skip species check
; outputs:
; sets carry if monster matches species, ID, and OT name.
push bc
push hl
push de
ld d, b
ld e, c
; check species
jr c, .no_species_check
ld a, [wScriptVar]
ld b, [hl]
cp b
jr nz, .notfound
.no_species_check
; check ID number
ld bc, MON_ID
add hl, bc
ld a, [wPlayerID]
cp [hl]
jr nz, .notfound
inc hl
ld a, [wPlayerID + 1]
cp [hl]
jr nz, .notfound
; check OT
ld hl, wPlayerName
; BUG: CheckOwnMon only checks the first five letters of OT names (see docs/bugs_and_glitches.md)
rept NAME_LENGTH_JAPANESE - 2
ld a, [de]
cp [hl]
jr nz, .notfound
cp "@"
jr z, .found
inc hl
inc de
endr
ld a, [de]
cp [hl]
jr z, .found
.notfound
pop de
pop hl
pop bc
and a
ret
.found
pop de
pop hl
pop bc
scf
ret
GetBoxMonPointers::
; in: b = slot, c = box
; out: hl = pointer to mon struct, de = pointer to nickname, bc = pointer to OT
; also loads the corresponding box bank in SRAM and sets wTempSpecies to the party ID (or 0 for an empty slot)
ld e, b
ld b, 0
ld hl, SearchBoxAddressTable
add hl, bc
add hl, bc
add hl, bc
ld a, [hli]
call OpenSRAM
ld a, [hli]
ld h, [hl]
ld l, a
ld a, e
ld d, h
ld e, l
cp [hl]
ld c, a
ld a, b ;b = 0
jr nc, .got_ID
inc hl
add hl, bc
ld a, [hl]
.got_ID
ld [wTempSpecies], a
ld a, c
ld hl, sBoxMonOTs - sBox
add hl, de
ld c, NAME_LENGTH
push af
call AddNTimes
pop af
push hl
ld hl, sBoxMonNicknames - sBox
add hl, de
if MON_NAME_LENGTH != NAME_LENGTH
ld c, MON_NAME_LENGTH
endc
push af
call AddNTimes
pop af
push hl
ld hl, sBoxMons - sBox
add hl, de
pop de
ld c, BOXMON_STRUCT_LENGTH
call AddNTimes
pop bc
ret
GetBoxMonPokemonIndexPointer::
; in: b = slot, c = box
; out: b = bank, hl = pointer
; preserves de
ld a, b
ld b, 0
ld hl, BoxPokemonIndexesAddressTable
add hl, bc
add hl, bc
add hl, bc
ld c, a
ld a, [hli]
push af
ld a, [hli]
ld h, [hl]
ld l, a
ld b, 0
add hl, bc
add hl, bc
pop bc
ret
SearchBoxAddressTable:
table_width 3, SearchBoxAddressTable
for n, 1, NUM_BOXES + 1
dba sBox{d:n}
endr
assert_table_length NUM_BOXES
BoxPokemonIndexesAddressTable:
table_width 3, BoxPokemonIndexesAddressTable
dba sBox1PokemonIndexes
dba sBox2PokemonIndexes
dba sBox3PokemonIndexes
dba sBox4PokemonIndexes
dba sBox5PokemonIndexes
dba sBox6PokemonIndexes
dba sBox7PokemonIndexes
dba sBox8PokemonIndexes
dba sBox9PokemonIndexes
dba sBox10PokemonIndexes
dba sBox11PokemonIndexes
dba sBox12PokemonIndexes
dba sBox13PokemonIndexes
dba sBox14PokemonIndexes
assert_table_length NUM_BOXES
UpdateOTPointer:
push hl
ld hl, NAME_LENGTH
add hl, bc
ld b, h
ld c, l
pop hl
ret

View file

@ -0,0 +1,134 @@
_FindPartyMonAboveLevel:
ld hl, wPartyMon1Level
call FindAboveLevel
ret
_FindPartyMonAtLeastThatHappy:
ld hl, wPartyMon1Happiness
call FindAtLeastThatHappy
ret
_FindPartyMonThatSpecies:
ld hl, wPartyMon1Species
jp FindThatSpecies
_FindPartyMonThatSpeciesYourTrainerID:
ld hl, wPartyMon1Species
call FindThatSpecies
ret z
ld a, c
ld hl, wPartyMon1ID
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
ld a, [wPlayerID]
cp [hl]
jr nz, .nope
inc hl
ld a, [wPlayerID + 1]
cp [hl]
jr nz, .nope
ld a, $1
and a
ret
.nope
xor a
ret
FindAtLeastThatHappy:
; Sets the bits for the Pokemon that have a happiness greater than or equal to b.
; The lowest bits are used. Sets z if no Pokemon in your party is at least that happy.
ld c, $0
ld a, [wPartyCount]
ld d, a
.loop
ld a, d
dec a
push hl
push bc
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
pop bc
ld a, b
cp [hl]
pop hl
jr z, .greater_equal
jr nc, .lower
.greater_equal
ld a, c
or $1
ld c, a
.lower
sla c
dec d
jr nz, .loop
call RetroactivelyIgnoreEggs
ld a, c
and a
ret
FindAboveLevel:
ld c, $0
ld a, [wPartyCount]
ld d, a
.loop
ld a, d
dec a
push hl
push bc
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
pop bc
ld a, b
cp [hl]
pop hl
jr c, .greater
ld a, c
or $1
ld c, a
.greater
sla c
dec d
jr nz, .loop
call RetroactivelyIgnoreEggs
ld a, c
and a
ret
FindThatSpecies:
; Find species b in your party.
; If you have no Pokemon, returns c = -1 and z.
; If that species is in your party, returns its location in c, and nz.
; Otherwise, returns z.
ld c, -1
ld hl, wPartySpecies
.loop
ld a, [hli]
cp -1
ret z
inc c
cp b
jr nz, .loop
ld a, $1
and a
ret
RetroactivelyIgnoreEggs:
ld e, %11111110
ld hl, wPartySpecies
.loop
ld a, [hli]
cp -1
ret z
cp EGG
jr nz, .skip_notegg
ld a, c
and e
ld c, a
.skip_notegg
rlc e
jr .loop

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,145 @@
_SwitchPartyMons:
ld a, [wSwitchMon]
dec a
ld [wSwitchMonFrom], a
ld b, a
ld a, [wMenuCursorY]
dec a
ld [wSwitchMonTo], a
cp b
jr z, .skip
call .SwapMonAndMail
ld a, [wSwitchMonFrom]
call .ClearSprite
ld a, [wSwitchMonTo]
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, wShadowOAMSprite00
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, [wSwitchMonTo]
ld l, a
ld h, 0
add hl, bc
ld d, h
ld e, l
ld a, [wSwitchMonFrom]
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, [wSwitchMonTo]
ld hl, wPartyMon1Species
ld bc, PARTYMON_STRUCT_LENGTH
call AddNTimes
push hl
ld de, wSwitchMonBuffer
ld bc, PARTYMON_STRUCT_LENGTH
call CopyBytes
ld a, [wSwitchMonFrom]
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, wSwitchMonBuffer
ld bc, PARTYMON_STRUCT_LENGTH
call CopyBytes
ld a, [wSwitchMonTo]
ld hl, wPartyMonOTs
call SkipNames
push hl
call .CopyNameToSwitchMonBuffer
ld a, [wSwitchMonFrom]
ld hl, wPartyMonOTs
call SkipNames
pop de
push hl
call .CopyName
pop de
ld hl, wSwitchMonBuffer
call .CopyName
ld hl, wPartyMonNicknames
ld a, [wSwitchMonTo]
call SkipNames
push hl
call .CopyNameToSwitchMonBuffer
ld hl, wPartyMonNicknames
ld a, [wSwitchMonFrom]
call SkipNames
pop de
push hl
call .CopyName
pop de
ld hl, wSwitchMonBuffer
call .CopyName
ld hl, sPartyMail
ld a, [wSwitchMonTo]
ld bc, MAIL_STRUCT_LENGTH
call AddNTimes
push hl
ld de, wSwitchMonBuffer
ld bc, MAIL_STRUCT_LENGTH
ld a, BANK(sPartyMail)
call OpenSRAM
call CopyBytes
ld hl, sPartyMail
ld a, [wSwitchMonFrom]
ld bc, MAIL_STRUCT_LENGTH
call AddNTimes
pop de
push hl
ld bc, MAIL_STRUCT_LENGTH
call CopyBytes
pop de
ld hl, wSwitchMonBuffer
ld bc, MAIL_STRUCT_LENGTH
call CopyBytes
call CloseSRAM
pop bc
pop de
pop hl
ret
.CopyNameToSwitchMonBuffer:
ld de, wSwitchMonBuffer
.CopyName:
ld bc, NAME_LENGTH
call CopyBytes
ret

127
engine/pokemon/tempmon.asm Normal file
View file

@ -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

87
engine/pokemon/types.asm Normal file
View file

@ -0,0 +1,87 @@
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, SCREEN_WIDTH
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
ld de, wStringBuffer1
call GetMoveData
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 [wNamedObjectIndex] to wStringBuffer1.
ld a, [wNamedObjectIndex]
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"