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

View file

@ -0,0 +1,301 @@
ClearCmdQueue::
ld hl, wCmdQueue
ld de, CMDQUEUE_ENTRY_SIZE
ld c, CMDQUEUE_CAPACITY
xor a
.loop
ld [hl], a
add hl, de
dec c
jr nz, .loop
ret
HandleCmdQueue::
ld hl, wCmdQueue
xor a
.loop
ldh [hMapObjectIndex], a
ld a, [hl]
and a
jr z, .skip
push hl
ld b, h
ld c, l
call HandleQueuedCommand
pop hl
.skip
ld de, CMDQUEUE_ENTRY_SIZE
add hl, de
ldh a, [hMapObjectIndex]
inc a
cp CMDQUEUE_CAPACITY
jr nz, .loop
ret
GetNthCmdQueueEntry: ; unreferenced
ld hl, wCmdQueue
ld bc, CMDQUEUE_ENTRY_SIZE
call AddNTimes
ld b, h
ld c, l
ret
WriteCmdQueue::
push bc
push de
call .GetNextEmptyEntry
ld d, h
ld e, l
pop hl
pop bc
ret c
ld a, b
ld bc, CMDQUEUE_ENTRY_SIZE - 1
call FarCopyBytes
xor a
ld [hl], a
ret
.GetNextEmptyEntry:
ld hl, wCmdQueue
ld de, CMDQUEUE_ENTRY_SIZE
ld c, CMDQUEUE_CAPACITY
.loop
ld a, [hl]
and a
jr z, .done
add hl, de
dec c
jr nz, .loop
scf
ret
.done
ld a, CMDQUEUE_CAPACITY
sub c
and a
ret
DelCmdQueue::
ld hl, wCmdQueue
ld de, CMDQUEUE_ENTRY_SIZE
ld c, CMDQUEUE_CAPACITY
.loop
ld a, [hl]
cp b
jr z, .done
add hl, de
dec c
jr nz, .loop
and a
ret
.done
xor a
ld [hl], a
scf
ret
_DelCmdQueue:
ld hl, CMDQUEUE_TYPE
add hl, bc
ld [hl], 0
ret
HandleQueuedCommand:
ld hl, CMDQUEUE_TYPE
add hl, bc
ld a, [hl]
cp NUM_CMDQUEUE_TYPES
jr c, .okay
xor a
.okay
ld e, a
ld d, 0
ld hl, .Jumptable
add hl, de
add hl, de
add hl, de
ld a, [hli]
push af
ld a, [hli]
ld h, [hl]
ld l, a
pop af
rst FarCall
ret
.Jumptable:
dba CmdQueue_Null
dba CmdQueue_Type1
dba CmdQueue_StoneTable
dba CmdQueue_Type3
dba CmdQueue_Type4
CmdQueues_AnonJumptable:
ld hl, CMDQUEUE_JUMPTABLE_INDEX
add hl, bc
ld a, [hl]
pop hl
rst JumpTable
ret
CmdQueues_IncAnonJumptableIndex:
ld hl, CMDQUEUE_JUMPTABLE_INDEX
add hl, bc
inc [hl]
ret
CmdQueues_DecAnonJumptableIndex:
ld hl, CMDQUEUE_JUMPTABLE_INDEX
add hl, bc
dec [hl]
ret
CmdQueue_Null:
ret
CmdQueue_Type1:
ret
CmdQueue_Type4:
call CmdQueues_AnonJumptable
.anon_dw
dw .zero
dw .one
.zero
ldh a, [hSCY]
ld hl, CMDQUEUE_04
add hl, bc
ld [hl], a
call CmdQueues_IncAnonJumptableIndex
.one
ld hl, CMDQUEUE_ADDR
add hl, bc
ld a, [hl]
dec a
ld [hl], a
jr z, .finish
and 1
jr z, .add
ld hl, CMDQUEUE_02
add hl, bc
ldh a, [hSCY]
sub [hl]
ldh [hSCY], a
ret
.add
ld hl, CMDQUEUE_02
add hl, bc
ldh a, [hSCY]
add [hl]
ldh [hSCY], a
ret
.finish
ld hl, CMDQUEUE_04
add hl, bc
ld a, [hl]
ldh [hSCY], a
call _DelCmdQueue
ret
CmdQueue_Type3:
call CmdQueues_AnonJumptable
.anon_dw
dw .zero
dw .one
dw .two
.zero
call .IsPlayerFacingDown
jr z, .PlayerNotFacingDown
call CmdQueues_IncAnonJumptableIndex
.one
call .IsPlayerFacingDown
jr z, .PlayerNotFacingDown
call CmdQueues_IncAnonJumptableIndex
ld hl, CMDQUEUE_02
add hl, bc
ld a, [hl]
ld [wd173], a
ret
.two
call .IsPlayerFacingDown
jr z, .PlayerNotFacingDown
call CmdQueues_DecAnonJumptableIndex
ld hl, CMDQUEUE_03
add hl, bc
ld a, [hl]
ld [wd173], a
ret
.PlayerNotFacingDown:
ld a, $7f
ld [wd173], a
ld hl, CMDQUEUE_JUMPTABLE_INDEX
add hl, bc
ld [hl], 0
ret
.IsPlayerFacingDown:
push bc
ld bc, wPlayerStruct
call GetSpriteDirection
and a
pop bc
ret
CmdQueue_StoneTable:
ld de, wPlayerStruct
ld a, NUM_OBJECT_STRUCTS
.loop
push af
ld hl, OBJECT_SPRITE
add hl, de
ld a, [hl]
and a
jr z, .next
ld hl, OBJECT_MOVEMENT_TYPE
add hl, de
ld a, [hl]
cp SPRITEMOVEDATA_STRENGTH_BOULDER
jr nz, .next
ld hl, OBJECT_TILE
add hl, de
ld a, [hl]
call CheckPitTile
jr nz, .next
ld hl, OBJECT_WALKING
add hl, de
ld a, [hl]
cp STANDING
jr nz, .next
call HandleStoneQueue
jr c, .fall_down_hole
.next
ld hl, OBJECT_LENGTH
add hl, de
ld d, h
ld e, l
pop af
dec a
jr nz, .loop
ret
.fall_down_hole
pop af
ret

File diff suppressed because it is too large Load diff

1350
engine/overworld/events.asm Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,104 @@
ReanchorBGMap_NoOAMUpdate::
call DelayFrame
ldh a, [hOAMUpdate]
push af
ld a, $1
ldh [hOAMUpdate], a
ldh a, [hBGMapMode]
push af
xor a
ldh [hBGMapMode], a
call .ReanchorBGMap
pop af
ldh [hBGMapMode], a
pop af
ldh [hOAMUpdate], a
ld hl, wVramState
set 6, [hl]
ret
.ReanchorBGMap:
xor a
ldh [hLCDCPointer], a
ldh [hBGMapMode], a
ld a, $90
ldh [hWY], a
call OverworldTextModeSwitch
ld a, HIGH(vBGMap1)
call .LoadBGMapAddrIntoHRAM
call _OpenAndCloseMenu_HDMATransferTilemapAndAttrmap
farcall LoadOW_BGPal7
farcall ApplyPals
ld a, TRUE
ldh [hCGBPalUpdate], a
xor a
ldh [hBGMapMode], a
ldh [hWY], a
farcall HDMATransfer_FillBGMap0WithBlack ; no need to farcall
ld a, HIGH(vBGMap0)
call .LoadBGMapAddrIntoHRAM
xor a ; LOW(vBGMap0)
ld [wBGMapAnchor], a
ld a, HIGH(vBGMap0)
ld [wBGMapAnchor + 1], a
xor a
ldh [hSCX], a
ldh [hSCY], a
call ApplyBGMapAnchorToObjects
ret
.LoadBGMapAddrIntoHRAM:
ldh [hBGMapAddress + 1], a
xor a
ldh [hBGMapAddress], a
ret
LoadFonts_NoOAMUpdate::
ldh a, [hOAMUpdate]
push af
ld a, $1
ldh [hOAMUpdate], a
call .LoadGFX
pop af
ldh [hOAMUpdate], a
ret
.LoadGFX:
call LoadFontsExtra
ld a, $90
ldh [hWY], a
call SafeUpdateSprites
call LoadStandardFont
ret
HDMATransfer_FillBGMap0WithBlack:
ldh a, [rSVBK]
push af
ld a, BANK(wDecompressScratch)
ldh [rSVBK], a
ld a, "■"
ld hl, wDecompressScratch
ld bc, wScratchAttrmap - wDecompressScratch
call ByteFill
ld a, HIGH(wDecompressScratch)
ldh [rHDMA1], a
ld a, LOW(wDecompressScratch)
ldh [rHDMA2], a
ld a, HIGH(vBGMap0 - VRAM_Begin)
ldh [rHDMA3], a
ld a, LOW(vBGMap0 - VRAM_Begin)
ldh [rHDMA4], a
ld a, $3f
ldh [hDMATransfer], a
call DelayFrame
pop af
ldh [rSVBK], a
ret

View file

@ -0,0 +1,82 @@
GetLandmarkCoords:
; Return coordinates (d, e) of landmark e.
push hl
ld l, e
ld h, 0
add hl, hl
add hl, hl
ld de, Landmarks
add hl, de
ld a, [hli]
ld e, a
ld d, [hl]
pop hl
ret
GetLandmarkName::
; Copy the name of landmark e to wStringBuffer1.
push hl
push de
push bc
ld l, e
ld h, 0
add hl, hl
add hl, hl
ld de, Landmarks + 2
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
ld de, wStringBuffer1
ld c, 18
.copy
ld a, [hli]
ld [de], a
inc de
dec c
jr nz, .copy
pop bc
pop de
pop hl
ret
INCLUDE "data/maps/landmarks.asm"
RegionCheck:
; Checks if the player is in Kanto or Johto.
; If in Johto, returns 0 in e.
; If in Kanto, returns 1 in e.
ld a, [wMapGroup]
ld b, a
ld a, [wMapNumber]
ld c, a
call GetWorldMapLocation
cp LANDMARK_FAST_SHIP ; S.S. Aqua
jr z, .johto
cp LANDMARK_SPECIAL
jr nz, .checkagain
; In a special map, get the backup map group / map id
ld a, [wBackupMapGroup]
ld b, a
ld a, [wBackupMapNumber]
ld c, a
call GetWorldMapLocation
.checkagain
cp KANTO_LANDMARK
jr c, .johto
; Victory Road area is considered to be Johto.
cp LANDMARK_VICTORY_ROAD
jr c, .kanto
.johto
ld e, JOHTO_REGION
ret
.kanto
ld e, KANTO_REGION
ret

View file

@ -0,0 +1,36 @@
_LoadMapPart::
ld hl, wSurroundingTiles
ld a, [wPlayerMetatileY]
and a
jr z, .top_row
ld bc, SURROUNDING_WIDTH * 2
add hl, bc
.top_row
ld a, [wPlayerMetatileX]
and a
jr z, .left_column
inc hl
inc hl
.left_column
decoord 0, 0
ld b, SCREEN_HEIGHT
.loop
ld c, SCREEN_WIDTH
.loop2
ld a, [hli]
ld [de], a
inc de
dec c
jr nz, .loop2
ld a, l
add METATILE_WIDTH
ld l, a
jr nc, .carry
inc h
.carry
dec b
jr nz, .loop
ret

View file

@ -0,0 +1,298 @@
ObjectActionPairPointers:
; entries correspond to OBJECT_ACTION_* constants (see constants/map_object_constants.asm)
table_width 2 + 2, ObjectActionPairPointers
; normal action, frozen action
dw SetFacingStanding, SetFacingStanding
dw SetFacingStandAction, SetFacingCurrent
dw SetFacingStepAction, SetFacingCurrent
dw SetFacingBumpAction, SetFacingCurrent
dw SetFacingCounterclockwiseSpin, SetFacingCurrent
dw SetFacingCounterclockwiseSpin2, SetFacingStanding
dw SetFacingFish, SetFacingFish
dw SetFacingShadow, SetFacingStanding
dw SetFacingEmote, SetFacingEmote
dw SetFacingBigDollSym, SetFacingBigDollSym
dw SetFacingBounce, SetFacingFreezeBounce
dw SetFacingWeirdTree, SetFacingCurrent
dw SetFacingBigDollAsym, SetFacingBigDollAsym
dw SetFacingBigDoll, SetFacingBigDoll
dw SetFacingBoulderDust, SetFacingStanding
dw SetFacingGrassShake, SetFacingStanding
dw SetFacingSkyfall, SetFacingCurrent
assert_table_length NUM_OBJECT_ACTIONS
SetFacingStanding:
ld hl, OBJECT_FACING
add hl, bc
ld [hl], STANDING
ret
SetFacingCurrent:
call GetSpriteDirection
or FACING_STEP_DOWN_0 ; useless
ld hl, OBJECT_FACING
add hl, bc
ld [hl], a
ret
SetFacingStandAction:
ld hl, OBJECT_FACING
add hl, bc
ld a, [hl]
and 1
jr nz, SetFacingStepAction
jp SetFacingCurrent
SetFacingStepAction:
ld hl, OBJECT_FLAGS1
add hl, bc
bit SLIDING_F, [hl]
jp nz, SetFacingCurrent
ld hl, OBJECT_STEP_FRAME
add hl, bc
ld a, [hl]
inc a
and %00001111
ld [hl], a
rrca
rrca
maskbits NUM_DIRECTIONS
ld d, a
call GetSpriteDirection
or FACING_STEP_DOWN_0 ; useless
or d
ld hl, OBJECT_FACING
add hl, bc
ld [hl], a
ret
SetFacingSkyfall:
ld hl, OBJECT_FLAGS1
add hl, bc
bit SLIDING_F, [hl]
jp nz, SetFacingCurrent
ld hl, OBJECT_STEP_FRAME
add hl, bc
ld a, [hl]
add 2
and %00001111
ld [hl], a
rrca
rrca
maskbits NUM_DIRECTIONS
ld d, a
call GetSpriteDirection
or FACING_STEP_DOWN_0 ; useless
or d
ld hl, OBJECT_FACING
add hl, bc
ld [hl], a
ret
SetFacingBumpAction:
ld hl, OBJECT_FLAGS1
add hl, bc
bit SLIDING_F, [hl]
jp nz, SetFacingCurrent
ld hl, OBJECT_STEP_FRAME
add hl, bc
inc [hl]
ld a, [hl]
rrca
rrca
rrca
maskbits NUM_DIRECTIONS
ld d, a
call GetSpriteDirection
or FACING_STEP_DOWN_0 ; useless
or d
ld hl, OBJECT_FACING
add hl, bc
ld [hl], a
ret
SetFacingCounterclockwiseSpin:
call CounterclockwiseSpinAction
ld hl, OBJECT_DIRECTION
add hl, bc
ld a, [hl]
or FACING_STEP_DOWN_0 ; useless
ld hl, OBJECT_FACING
add hl, bc
ld [hl], a
ret
SetFacingCounterclockwiseSpin2:
call CounterclockwiseSpinAction
jp SetFacingStanding
CounterclockwiseSpinAction:
; Here, OBJECT_STEP_FRAME consists of two 2-bit components,
; using only bits 0,1 and 4,5.
; bits 0,1 is a timer (4 overworld frames)
; bits 4,5 determines the facing - the direction is counterclockwise.
ld hl, OBJECT_STEP_FRAME
add hl, bc
ld a, [hl]
and %11110000
ld e, a
ld a, [hl]
inc a
and %00001111
ld d, a
cp 4
jr c, .ok
ld d, 0
ld a, e
add $10
and %00110000
ld e, a
.ok
ld a, d
or e
ld [hl], a
swap e
ld d, 0
ld hl, .facings
add hl, de
ld a, [hl]
ld hl, OBJECT_DIRECTION
add hl, bc
ld [hl], a
ret
.facings:
db OW_DOWN
db OW_RIGHT
db OW_UP
db OW_LEFT
SetFacingFish:
call GetSpriteDirection
rrca
rrca
add FACING_FISH_DOWN
ld hl, OBJECT_FACING
add hl, bc
ld [hl], a
ret
SetFacingShadow:
ld hl, OBJECT_FACING
add hl, bc
ld [hl], FACING_SHADOW
ret
SetFacingEmote:
ld hl, OBJECT_FACING
add hl, bc
ld [hl], FACING_EMOTE
ret
SetFacingBigDollSym:
ld hl, OBJECT_FACING
add hl, bc
ld [hl], FACING_BIG_DOLL_SYM
ret
SetFacingBounce:
ld hl, OBJECT_STEP_FRAME
add hl, bc
ld a, [hl]
inc a
and %00001111
ld [hl], a
and %00001000
jr z, SetFacingFreezeBounce
ld hl, OBJECT_FACING
add hl, bc
ld [hl], FACING_STEP_UP_0
ret
SetFacingFreezeBounce:
ld hl, OBJECT_FACING
add hl, bc
ld [hl], FACING_STEP_DOWN_0
ret
SetFacingWeirdTree:
ld hl, OBJECT_STEP_FRAME
add hl, bc
ld a, [hl]
inc a
ld [hl], a
maskbits NUM_DIRECTIONS, 2
rrca
rrca
add FACING_WEIRD_TREE_0
ld hl, OBJECT_FACING
add hl, bc
ld [hl], a
ret
SetFacingBigDollAsym:
ld hl, OBJECT_FACING
add hl, bc
ld [hl], FACING_BIG_DOLL_ASYM
ret
SetFacingBigDoll:
ld a, [wVariableSprites + SPRITE_BIG_DOLL - SPRITE_VARS]
ld d, FACING_BIG_DOLL_SYM ; symmetric
cp SPRITE_BIG_SNORLAX
jr z, .ok
cp SPRITE_BIG_LAPRAS
jr z, .ok
ld d, FACING_BIG_DOLL_ASYM ; asymmetric
.ok
ld hl, OBJECT_FACING
add hl, bc
ld [hl], d
ret
SetFacingBoulderDust:
ld hl, OBJECT_STEP_FRAME
add hl, bc
inc [hl]
ld a, [hl]
ld hl, OBJECT_FACING
add hl, bc
and 2
ld a, FACING_BOULDER_DUST_1
jr z, .ok
inc a
assert FACING_BOULDER_DUST_1 + 1 == FACING_BOULDER_DUST_2
.ok
ld [hl], a
ret
SetFacingGrassShake:
ld hl, OBJECT_STEP_FRAME
add hl, bc
inc [hl]
ld a, [hl]
ld hl, OBJECT_FACING
add hl, bc
and 4
ld a, FACING_GRASS_1
jr z, .ok
inc a ; FACING_GRASS_2
.ok
ld [hl], a
ret

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,70 @@
LoadObjectMasks:
ld hl, wObjectMasks
xor a
ld bc, NUM_OBJECTS
call ByteFill
nop
ld bc, wMapObjects
ld de, wObjectMasks
xor a
.loop
push af
push bc
push de
call GetObjectTimeMask
jr c, .next
call CheckObjectFlag
.next
pop de
ld [de], a
inc de
pop bc
ld hl, MAPOBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
pop af
inc a
cp NUM_OBJECTS
jr nz, .loop
ret
CheckObjectFlag:
ld hl, MAPOBJECT_SPRITE
add hl, bc
ld a, [hl]
and a
jr z, .masked
ld hl, MAPOBJECT_EVENT_FLAG
add hl, bc
ld a, [hli]
ld e, a
ld a, [hl]
ld d, a
cp -1
jr nz, .check
ld a, e
cp -1
jr z, .unmasked
jr .masked
.check
ld b, CHECK_FLAG
call EventFlagAction
ld a, c
and a
jr nz, .masked
.unmasked
xor a
ret
.masked
ld a, -1
scf
ret
GetObjectTimeMask:
call CheckObjectTime
ld a, -1
ret c
xor a
ret

View file

@ -0,0 +1,200 @@
RunMapSetupScript::
ldh a, [hMapEntryMethod]
and $f
dec a
ld c, a
ld b, 0
ld hl, MapSetupScripts
add hl, bc
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
call ReadMapSetupScript
ret
INCLUDE "data/maps/setup_scripts.asm"
ReadMapSetupScript:
.loop
ld a, [hli]
cp -1 ; end?
ret z
push hl
ld c, a
ld b, 0
ld hl, MapSetupCommands
add hl, bc
add hl, bc
add hl, bc
; bank
ld b, [hl]
inc hl
; address
ld a, [hli]
ld h, [hl]
ld l, a
; Bit 7 of the bank indicates a parameter.
; This is left unused.
bit 7, b
jr z, .go
pop de
ld a, [de]
ld c, a
inc de
push de
.go
ld a, b
and $7f
rst FarCall
pop hl
jr .loop
INCLUDE "data/maps/setup_script_pointers.asm"
EnableTextAcceleration:
xor a
ld [wDisableTextAcceleration], a
ret
ActivateMapAnims:
ld a, TRUE
ldh [hMapAnims], a
ret
SuspendMapAnims:
xor a ; FALSE
ldh [hMapAnims], a
ret
LoadMapObjects:
ld a, MAPCALLBACK_OBJECTS
call RunMapCallback
farcall LoadObjectMasks
farcall InitializeVisibleSprites
ret
MapSetup_DummyFunction: ; unreferenced
ret
ResetPlayerObjectAction:
ld hl, wPlayerSpriteSetupFlags
set PLAYERSPRITESETUP_RESET_ACTION_F, [hl]
ret
SkipUpdateMapSprites:
ld hl, wPlayerSpriteSetupFlags
set PLAYERSPRITESETUP_SKIP_RELOAD_GFX_F, [hl]
ret
CheckUpdatePlayerSprite:
nop
call .CheckBiking
jr c, .ok
call .CheckSurfing
jr c, .ok
call .CheckSurfing2
jr c, .ok
ret
.ok
call UpdatePlayerSprite
ret
.CheckBiking:
and a
ld hl, wBikeFlags
bit BIKEFLAGS_ALWAYS_ON_BIKE_F, [hl]
ret z
ld a, PLAYER_BIKE
ld [wPlayerState], a
scf
ret
.CheckSurfing2:
ld a, [wPlayerState]
cp PLAYER_NORMAL
jr z, .nope
cp PLAYER_SKATE
jr z, .nope
cp PLAYER_SURF
jr z, .surfing
cp PLAYER_SURF_PIKA
jr z, .surfing
call GetMapEnvironment
cp INDOOR
jr z, .no_biking
cp ENVIRONMENT_5
jr z, .no_biking
cp DUNGEON
jr z, .no_biking
jr .nope
.no_biking
ld a, [wPlayerState]
cp PLAYER_BIKE
jr nz, .nope
.surfing
ld a, PLAYER_NORMAL
ld [wPlayerState], a
scf
ret
.nope
and a
ret
.CheckSurfing:
call CheckOnWater
jr nz, .nope2
ld a, [wPlayerState]
cp PLAYER_SURF
jr z, .is_surfing
cp PLAYER_SURF_PIKA
jr z, .is_surfing
ld a, PLAYER_SURF
ld [wPlayerState], a
.is_surfing
scf
ret
.nope2
and a
ret
FadeOutMapMusic:
ld a, 6
call SkipMusic
ret
ApplyMapPalettes:
farcall _UpdateTimePals
ret
FadeMapMusicAndPalettes:
ld e, LOW(MUSIC_NONE)
ld a, [wMusicFadeID]
ld d, HIGH(MUSIC_NONE)
ld a, [wMusicFadeID + 1]
ld a, $4
ld [wMusicFade], a
call RotateThreePalettesRight
ret
ForceMapMusic:
ld a, [wPlayerState]
cp PLAYER_BIKE
jr nz, .notbiking
call MinVolume
ld a, $88
ld [wMusicFade], a
.notbiking
call TryRestartMapMusic
ret

View file

@ -0,0 +1,778 @@
MovementPointers:
; entries correspond to movement_* constants (see macros/scripts/movement.asm)
table_width 2, MovementPointers
dw Movement_turn_head_down ; 00
dw Movement_turn_head_up ; 01
dw Movement_turn_head_left ; 02
dw Movement_turn_head_right ; 03
dw Movement_turn_step_down ; 04
dw Movement_turn_step_up ; 05
dw Movement_turn_step_left ; 06
dw Movement_turn_step_right ; 07
dw Movement_slow_step_down ; 08
dw Movement_slow_step_up ; 09
dw Movement_slow_step_left ; 0a
dw Movement_slow_step_right ; 0b
dw Movement_step_down ; 0c
dw Movement_step_up ; 0d
dw Movement_step_left ; 0e
dw Movement_step_right ; 0f
dw Movement_big_step_down ; 10
dw Movement_big_step_up ; 11
dw Movement_big_step_left ; 12
dw Movement_big_step_right ; 13
dw Movement_slow_slide_step_down ; 14
dw Movement_slow_slide_step_up ; 15
dw Movement_slow_slide_step_left ; 16
dw Movement_slow_slide_step_right ; 17
dw Movement_slide_step_down ; 18
dw Movement_slide_step_up ; 19
dw Movement_slide_step_left ; 1a
dw Movement_slide_step_right ; 1b
dw Movement_fast_slide_step_down ; 1c
dw Movement_fast_slide_step_up ; 1d
dw Movement_fast_slide_step_left ; 1e
dw Movement_fast_slide_step_right ; 1f
dw Movement_turn_away_down ; 20
dw Movement_turn_away_up ; 21
dw Movement_turn_away_left ; 22
dw Movement_turn_away_right ; 23
dw Movement_turn_in_down ; 24
dw Movement_turn_in_up ; 25
dw Movement_turn_in_left ; 26
dw Movement_turn_in_right ; 27
dw Movement_turn_waterfall_down ; 28
dw Movement_turn_waterfall_up ; 29
dw Movement_turn_waterfall_left ; 2a
dw Movement_turn_waterfall_right ; 2b
dw Movement_slow_jump_step_down ; 2c
dw Movement_slow_jump_step_up ; 2d
dw Movement_slow_jump_step_left ; 2e
dw Movement_slow_jump_step_right ; 2f
dw Movement_jump_step_down ; 30
dw Movement_jump_step_up ; 31
dw Movement_jump_step_left ; 32
dw Movement_jump_step_right ; 33
dw Movement_fast_jump_step_down ; 34
dw Movement_fast_jump_step_up ; 35
dw Movement_fast_jump_step_left ; 36
dw Movement_fast_jump_step_right ; 37
dw Movement_remove_sliding ; 38
dw Movement_set_sliding ; 39
dw Movement_remove_fixed_facing ; 3a
dw Movement_fix_facing ; 3b
dw Movement_show_object ; 3c
dw Movement_hide_object ; 3d
dw Movement_step_sleep_1 ; 3e
dw Movement_step_sleep_2 ; 3f
dw Movement_step_sleep_3 ; 40
dw Movement_step_sleep_4 ; 41
dw Movement_step_sleep_5 ; 42
dw Movement_step_sleep_6 ; 43
dw Movement_step_sleep_7 ; 44
dw Movement_step_sleep_8 ; 45
dw Movement_step_sleep ; 46
dw Movement_step_end ; 47
dw Movement_48 ; 48
dw Movement_remove_object ; 49
dw Movement_step_loop ; 4a
dw Movement_4b ; 4b
dw Movement_teleport_from ; 4c
dw Movement_teleport_to ; 4d
dw Movement_skyfall ; 4e
dw Movement_step_dig ; 4f
dw Movement_step_bump ; 50
dw Movement_fish_got_bite ; 51
dw Movement_fish_cast_rod ; 52
dw Movement_hide_emote ; 53
dw Movement_show_emote ; 54
dw Movement_step_shake ; 55
dw Movement_tree_shake ; 56
dw Movement_rock_smash ; 57
dw Movement_return_dig ; 58
dw Movement_skyfall_top ; 59
assert_table_length NUM_MOVEMENT_CMDS
Movement_teleport_from:
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_TELEPORT_FROM
ret
Movement_teleport_to:
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_TELEPORT_TO
ret
Movement_skyfall:
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_SKYFALL
ret
Movement_skyfall_top:
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_SKYFALL_TOP
ret
Movement_step_dig:
call GetSpriteDirection
rlca
rlca
ld hl, OBJECT_STEP_FRAME
add hl, bc
ld [hl], a
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_SPIN
call JumpMovementPointer
ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_SLEEP
ld hl, OBJECT_WALKING
add hl, bc
ld [hl], STANDING
ret
Movement_return_dig:
call GetSpriteDirection
rlca
rlca
ld hl, OBJECT_STEP_FRAME
add hl, bc
ld [hl], a
call JumpMovementPointer
ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
ld hl, OBJECT_WALKING
add hl, bc
ld [hl], STANDING
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_RETURN_DIG
ret
Movement_fish_got_bite:
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_FISHING
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_GOT_BITE
ret
Movement_rock_smash:
call JumpMovementPointer
ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_STAND
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_ROCK_SMASH
ret
Movement_fish_cast_rod:
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_FISHING
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_FROM_MOVEMENT
ret
Movement_step_loop:
ld hl, OBJECT_MOVEMENT_INDEX
add hl, bc
ld [hl], $0
jp ContinueReadingMovement
Movement_step_end:
call RestoreDefaultMovement
ld hl, OBJECT_MOVEMENT_TYPE
add hl, bc
ld [hl], a
ld hl, OBJECT_MOVEMENT_INDEX
add hl, bc
ld [hl], $0
ld hl, wVramState
res 7, [hl]
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_FROM_MOVEMENT
ret
Movement_48:
call RestoreDefaultMovement
ld hl, OBJECT_MOVEMENT_TYPE
add hl, bc
ld [hl], a
ld hl, OBJECT_MOVEMENT_INDEX
add hl, bc
ld [hl], $0
call JumpMovementPointer
ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_SLEEP
ld hl, wVramState
res 7, [hl]
ret
Movement_remove_object:
call DeleteMapObject
ld hl, wObjectFollow_Leader
ldh a, [hMapObjectIndex]
cp [hl]
jr nz, .not_leading
ld [hl], -1
.not_leading
ld hl, wVramState
res 7, [hl]
ret
Movement_4b:
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_STAND
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_STANDING
ld hl, wVramState
res 7, [hl]
ret
Movement_step_sleep_1:
ld a, 1
jr Movement_step_sleep_common
Movement_step_sleep_2:
ld a, 2
jr Movement_step_sleep_common
Movement_step_sleep_3:
ld a, 3
jr Movement_step_sleep_common
Movement_step_sleep_4:
ld a, 4
jr Movement_step_sleep_common
Movement_step_sleep_5:
ld a, 5
jr Movement_step_sleep_common
Movement_step_sleep_6:
ld a, 6
jr Movement_step_sleep_common
Movement_step_sleep_7:
ld a, 7
jr Movement_step_sleep_common
Movement_step_sleep_8:
ld a, 8
jr Movement_step_sleep_common
Movement_step_sleep:
; parameters:
; duration (DecimalParam)
call JumpMovementPointer
jr Movement_step_sleep_common
Movement_step_sleep_common:
ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_SLEEP
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_STAND
ld hl, OBJECT_WALKING
add hl, bc
ld [hl], STANDING
ret
Movement_step_bump:
ld a, 1
ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_BUMP
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_BUMP
ld hl, OBJECT_WALKING
add hl, bc
ld [hl], STANDING
ret
Movement_tree_shake:
ld a, 24
ld hl, OBJECT_STEP_DURATION
add hl, bc
ld [hl], a
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_SLEEP
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_WEIRD_TREE
ld hl, OBJECT_WALKING
add hl, bc
ld [hl], STANDING
ret
Movement_remove_sliding:
ld hl, OBJECT_FLAGS1
add hl, bc
res SLIDING_F, [hl]
jp ContinueReadingMovement
Movement_set_sliding:
ld hl, OBJECT_FLAGS1
add hl, bc
set SLIDING_F, [hl]
jp ContinueReadingMovement
Movement_remove_fixed_facing:
ld hl, OBJECT_FLAGS1
add hl, bc
res FIXED_FACING_F, [hl]
jp ContinueReadingMovement
Movement_fix_facing:
ld hl, OBJECT_FLAGS1
add hl, bc
set FIXED_FACING_F, [hl]
jp ContinueReadingMovement
Movement_show_object:
ld hl, OBJECT_FLAGS1
add hl, bc
res INVISIBLE_F, [hl]
jp ContinueReadingMovement
Movement_hide_object:
ld hl, OBJECT_FLAGS1
add hl, bc
set INVISIBLE_F, [hl]
jp ContinueReadingMovement
Movement_hide_emote:
call DespawnEmote
jp ContinueReadingMovement
Movement_show_emote:
call SpawnEmote
jp ContinueReadingMovement
Movement_step_shake:
; parameters:
; displacement (DecimalParam)
call JumpMovementPointer
call ShakeScreen
jp ContinueReadingMovement
Movement_turn_head_down:
ld a, OW_DOWN
jr TurnHead
Movement_turn_head_up:
ld a, OW_UP
jr TurnHead
Movement_turn_head_left:
ld a, OW_LEFT
jr TurnHead
Movement_turn_head_right:
ld a, OW_RIGHT
jr TurnHead
TurnHead:
ld hl, OBJECT_DIRECTION
add hl, bc
ld [hl], a
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_STAND
ld hl, OBJECT_WALKING
add hl, bc
ld [hl], STANDING
ret
Movement_slow_step_down:
ld a, STEP_SLOW << 2 | DOWN
jp NormalStep
Movement_slow_step_up:
ld a, STEP_SLOW << 2 | UP
jp NormalStep
Movement_slow_step_left:
ld a, STEP_SLOW << 2 | LEFT
jp NormalStep
Movement_slow_step_right:
ld a, STEP_SLOW << 2 | RIGHT
jp NormalStep
Movement_step_down:
ld a, STEP_WALK << 2 | DOWN
jp NormalStep
Movement_step_up:
ld a, STEP_WALK << 2 | UP
jp NormalStep
Movement_step_left:
ld a, STEP_WALK << 2 | LEFT
jp NormalStep
Movement_step_right:
ld a, STEP_WALK << 2 | RIGHT
jp NormalStep
Movement_big_step_down:
ld a, STEP_BIKE << 2 | DOWN
jp NormalStep
Movement_big_step_up:
ld a, STEP_BIKE << 2 | UP
jp NormalStep
Movement_big_step_left:
ld a, STEP_BIKE << 2 | LEFT
jp NormalStep
Movement_big_step_right:
ld a, STEP_BIKE << 2 | RIGHT
jp NormalStep
Movement_turn_away_down:
ld a, STEP_SLOW << 2 | DOWN
jp TurningStep
Movement_turn_away_up:
ld a, STEP_SLOW << 2 | UP
jp TurningStep
Movement_turn_away_left:
ld a, STEP_SLOW << 2 | LEFT
jp TurningStep
Movement_turn_away_right:
ld a, STEP_SLOW << 2 | RIGHT
jp TurningStep
Movement_turn_in_down:
ld a, STEP_WALK << 2 | DOWN
jp TurningStep
Movement_turn_in_up:
ld a, STEP_WALK << 2 | UP
jp TurningStep
Movement_turn_in_left:
ld a, STEP_WALK << 2 | LEFT
jp TurningStep
Movement_turn_in_right:
ld a, STEP_WALK << 2 | RIGHT
jp TurningStep
Movement_turn_waterfall_down:
ld a, STEP_BIKE << 2 | DOWN
jp TurningStep
Movement_turn_waterfall_up:
ld a, STEP_BIKE << 2 | UP
jp TurningStep
Movement_turn_waterfall_left:
ld a, STEP_BIKE << 2 | LEFT
jp TurningStep
Movement_turn_waterfall_right:
ld a, STEP_BIKE << 2 | RIGHT
jp TurningStep
Movement_slow_slide_step_down:
ld a, STEP_SLOW << 2 | DOWN
jp SlideStep
Movement_slow_slide_step_up:
ld a, STEP_SLOW << 2 | UP
jp SlideStep
Movement_slow_slide_step_left:
ld a, STEP_SLOW << 2 | LEFT
jp SlideStep
Movement_slow_slide_step_right:
ld a, STEP_SLOW << 2 | RIGHT
jp SlideStep
Movement_slide_step_down:
ld a, STEP_WALK << 2 | DOWN
jp SlideStep
Movement_slide_step_up:
ld a, STEP_WALK << 2 | UP
jp SlideStep
Movement_slide_step_left:
ld a, STEP_WALK << 2 | LEFT
jp SlideStep
Movement_slide_step_right:
ld a, STEP_WALK << 2 | RIGHT
jp SlideStep
Movement_fast_slide_step_down:
ld a, STEP_BIKE << 2 | DOWN
jp SlideStep
Movement_fast_slide_step_up:
ld a, STEP_BIKE << 2 | UP
jp SlideStep
Movement_fast_slide_step_left:
ld a, STEP_BIKE << 2 | LEFT
jp SlideStep
Movement_fast_slide_step_right:
ld a, STEP_BIKE << 2 | RIGHT
jp SlideStep
Movement_slow_jump_step_down:
ld a, STEP_SLOW << 2 | DOWN
jp JumpStep
Movement_slow_jump_step_up:
ld a, STEP_SLOW << 2 | UP
jp JumpStep
Movement_slow_jump_step_left:
ld a, STEP_SLOW << 2 | LEFT
jp JumpStep
Movement_slow_jump_step_right:
ld a, STEP_SLOW << 2 | RIGHT
jp JumpStep
Movement_jump_step_down:
ld a, STEP_WALK << 2 | DOWN
jp JumpStep
Movement_jump_step_up:
ld a, STEP_WALK << 2 | UP
jp JumpStep
Movement_jump_step_left:
ld a, STEP_WALK << 2 | LEFT
jp JumpStep
Movement_jump_step_right:
ld a, STEP_WALK << 2 | RIGHT
jp JumpStep
Movement_fast_jump_step_down:
ld a, STEP_BIKE << 2 | DOWN
jp JumpStep
Movement_fast_jump_step_up:
ld a, STEP_BIKE << 2 | UP
jp JumpStep
Movement_fast_jump_step_left:
ld a, STEP_BIKE << 2 | LEFT
jp JumpStep
Movement_fast_jump_step_right:
ld a, STEP_BIKE << 2 | RIGHT
jp JumpStep
Movement_turn_step_down:
ld a, OW_DOWN
jr TurnStep
Movement_turn_step_up:
ld a, OW_UP
jr TurnStep
Movement_turn_step_left:
ld a, OW_LEFT
jr TurnStep
Movement_turn_step_right:
ld a, OW_RIGHT
jr TurnStep
TurnStep:
ld hl, OBJECT_1D ; new facing
add hl, bc
ld [hl], a
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_STEP
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_TURN
ret
NormalStep:
call InitStep
call UpdateTallGrassFlags
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_STEP
ld hl, OBJECT_TILE
add hl, bc
ld a, [hl]
call CheckSuperTallGrassTile
jr z, .shake_grass
call CheckGrassTile
jr c, .skip_grass
.shake_grass
call ShakeGrass
.skip_grass
ld hl, wCenteredObject
ldh a, [hMapObjectIndex]
cp [hl]
jr z, .player
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_NPC_WALK
ret
.player
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_PLAYER_WALK
ret
TurningStep:
call InitStep
call UpdateTallGrassFlags
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_SPIN
ld hl, wCenteredObject
ldh a, [hMapObjectIndex]
cp [hl]
jr z, .player
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_NPC_WALK
ret
.player
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_PLAYER_WALK
ret
SlideStep:
call InitStep
call UpdateTallGrassFlags
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_STAND
ld hl, wCenteredObject
ldh a, [hMapObjectIndex]
cp [hl]
jr z, .player
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_NPC_WALK
ret
.player
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_PLAYER_WALK
ret
JumpStep:
call InitStep
ld hl, OBJECT_JUMP_HEIGHT
add hl, bc
ld [hl], $0
ld hl, OBJECT_FLAGS2
add hl, bc
res OVERHEAD_F, [hl]
ld hl, OBJECT_ACTION
add hl, bc
ld [hl], OBJECT_ACTION_STEP
call SpawnShadow
ld hl, wCenteredObject
ldh a, [hMapObjectIndex]
cp [hl]
jr z, .player
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_NPC_JUMP
ret
.player
ld hl, OBJECT_STEP_TYPE
add hl, bc
ld [hl], STEP_TYPE_PLAYER_JUMP
ret

View file

@ -0,0 +1,562 @@
CanObjectMoveInDirection:
ld hl, OBJECT_PALETTE
add hl, bc
bit SWIMMING_F, [hl]
jr z, .not_swimming
; BUG: Swimming NPCs aren't limited by their movement radius (see docs/bugs_and_glitches.md)
ld hl, OBJECT_FLAGS1
add hl, bc
bit NOCLIP_TILES_F, [hl]
push hl
push bc
call WillObjectBumpIntoLand
pop bc
pop hl
ret c
jr .continue
.not_swimming
ld hl, OBJECT_FLAGS1
add hl, bc
bit NOCLIP_TILES_F, [hl]
jr nz, .noclip_tiles
push hl
push bc
call WillObjectBumpIntoWater
pop bc
pop hl
ret c
.noclip_tiles
.continue
bit NOCLIP_OBJS_F, [hl]
jr nz, .noclip_objs
push hl
push bc
call WillObjectBumpIntoSomeoneElse
pop bc
pop hl
ret c
.noclip_objs
bit MOVE_ANYWHERE_F, [hl]
jr nz, .move_anywhere
push hl
call HasObjectReachedMovementLimit
pop hl
ret c
push hl
call IsObjectMovingOffEdgeOfScreen
pop hl
ret c
.move_anywhere
and a
ret
WillObjectBumpIntoWater:
call CanObjectLeaveTile
ret c
ld hl, OBJECT_MAP_X
add hl, bc
ld d, [hl]
ld hl, OBJECT_MAP_Y
add hl, bc
ld e, [hl]
ld hl, OBJECT_PALETTE
add hl, bc
bit OAM_PRIORITY, [hl]
jp nz, WillObjectRemainOnWater
ld hl, OBJECT_TILE
add hl, bc
ld a, [hl]
ld d, a
call GetTileCollision
and a ; LAND_TILE
jr z, WillObjectBumpIntoTile
scf
ret
WillObjectBumpIntoLand:
call CanObjectLeaveTile
ret c
ld hl, OBJECT_TILE
add hl, bc
ld a, [hl]
call GetTileCollision
cp WATER_TILE
jr z, WillObjectBumpIntoTile
scf
ret
WillObjectBumpIntoTile:
ld hl, OBJECT_TILE
add hl, bc
ld a, [hl]
call GetSideWallDirectionMask
ret nc
push af
ld hl, OBJECT_WALKING
add hl, bc
ld a, [hl]
maskbits NUM_DIRECTIONS
ld e, a
ld d, 0
ld hl, .dir_masks
add hl, de
pop af
and [hl]
ret z
scf
ret
.dir_masks
db DOWN_MASK ; DOWN
db UP_MASK ; UP
db RIGHT_MASK ; LEFT
db LEFT_MASK ; RIGHT
CanObjectLeaveTile:
ld hl, OBJECT_LAST_TILE
add hl, bc
ld a, [hl]
call GetSideWallDirectionMask
ret nc
push af
ld hl, OBJECT_WALKING
add hl, bc
maskbits NUM_DIRECTIONS
ld e, a
ld d, 0
ld hl, .dir_masks
add hl, de
pop af
and [hl]
ret z
scf
ret
.dir_masks
db UP_MASK ; DOWN
db DOWN_MASK ; UP
db LEFT_MASK ; LEFT
db RIGHT_MASK ; RIGHT
GetSideWallDirectionMask:
ld d, a
and $f0
cp HI_NYBBLE_SIDE_WALLS
jr z, .continue
cp HI_NYBBLE_SIDE_BUOYS
jr z, .continue
xor a
ret
.continue
ld a, d
and $7
ld e, a
ld d, 0
ld hl, .side_wall_masks
add hl, de
ld a, [hl]
scf
ret
.side_wall_masks
db RIGHT_MASK ; COLL_RIGHT_WALL/BUOY
db LEFT_MASK ; COLL_LEFT_WALL/BUOY
db DOWN_MASK ; COLL_UP_WALL/BUOY
db UP_MASK ; COLL_DOWN_WALL/BUOY
db UP_MASK | RIGHT_MASK ; COLL_DOWN_RIGHT_WALL/BUOY
db UP_MASK | LEFT_MASK ; COLL_DOWN_LEFT_WALL/BUOY
db DOWN_MASK | RIGHT_MASK ; COLL_UP_RIGHT_WALL/BUOY
db DOWN_MASK | LEFT_MASK ; COLL_UP_LEFT_WALL/BUOY
WillObjectRemainOnWater:
ld hl, OBJECT_WALKING
add hl, bc
ld a, [hl]
maskbits NUM_DIRECTIONS
jr z, .down
dec a
jr z, .up
dec a
jr z, .left
jr .right
.down
inc e
push de
inc d
jr .continue
.up
push de
inc d
jr .continue
.left
push de
inc e
jr .continue
.right
inc d
push de
inc e
.continue
call GetCoordTile
call GetTileCollision
pop de
and a ; LAND_TILE
jr nz, .not_land
call GetCoordTile
call GetTileCollision
and a ; LAND_TILE
jr nz, .not_land
xor a
ret
.not_land
scf
ret
CheckFacingObject::
call GetFacingTileCoord
; Double the distance for counter tiles.
call CheckCounterTile
jr nz, .not_counter
ld a, [wPlayerMapX]
sub d
cpl
inc a
add d
ld d, a
ld a, [wPlayerMapY]
sub e
cpl
inc a
add e
ld e, a
.not_counter
ld bc, wObjectStructs ; redundant
ld a, 0
ldh [hMapObjectIndex], a
call IsNPCAtCoord
ret nc
ld hl, OBJECT_WALKING
add hl, bc
ld a, [hl]
cp STANDING
jr z, .standing
xor a
ret
.standing
scf
ret
WillObjectBumpIntoSomeoneElse:
ld hl, OBJECT_MAP_X
add hl, bc
ld d, [hl]
ld hl, OBJECT_MAP_Y
add hl, bc
ld e, [hl]
jr IsNPCAtCoord
IsObjectFacingSomeoneElse: ; unreferenced
ldh a, [hMapObjectIndex]
call GetObjectStruct
call .GetFacingCoords
call IsNPCAtCoord
ret
.GetFacingCoords:
ld hl, OBJECT_MAP_X
add hl, bc
ld d, [hl]
ld hl, OBJECT_MAP_Y
add hl, bc
ld e, [hl]
call GetSpriteDirection
and a ; OW_DOWN?
jr z, .down
cp OW_UP
jr z, .up
cp OW_LEFT
jr z, .left
; OW_RIGHT
inc d
ret
.down
inc e
ret
.up
dec e
ret
.left
dec d
ret
IsNPCAtCoord:
ld bc, wObjectStructs
xor a
.loop
ldh [hObjectStructIndex], a
call DoesObjectHaveASprite
jr z, .next
ld hl, OBJECT_FLAGS1
add hl, bc
bit 7, [hl]
jr nz, .next
ld hl, OBJECT_PALETTE
add hl, bc
bit BIG_OBJECT_F, [hl]
jr z, .not_big
call WillObjectIntersectBigObject
jr nc, .check_current_coords
jr .continue
.not_big
ld hl, OBJECT_MAP_X
add hl, bc
ld a, [hl]
cp d
jr nz, .check_current_coords
ld hl, OBJECT_MAP_Y
add hl, bc
ld a, [hl]
cp e
jr nz, .check_current_coords
.continue
ldh a, [hMapObjectIndex]
ld l, a
ldh a, [hObjectStructIndex]
cp l
jr nz, .yes
.check_current_coords
ld hl, OBJECT_LAST_MAP_X
add hl, bc
ld a, [hl]
cp d
jr nz, .next
ld hl, OBJECT_LAST_MAP_Y
add hl, bc
ld a, [hl]
cp e
jr nz, .next
ldh a, [hMapObjectIndex]
ld l, a
ldh a, [hObjectStructIndex]
cp l
jr nz, .yes
.next
ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
ldh a, [hObjectStructIndex]
inc a
cp NUM_OBJECT_STRUCTS
jr nz, .loop
and a
ret
.yes
scf
ret
HasObjectReachedMovementLimit:
ld hl, OBJECT_RADIUS
add hl, bc
ld a, [hl]
and a
jr z, .nope
and $f
jr z, .check_y
ld e, a
ld d, a
ld hl, OBJECT_INIT_X
add hl, bc
ld a, [hl]
sub d
ld d, a
ld a, [hl]
add e
ld e, a
ld hl, OBJECT_MAP_X
add hl, bc
ld a, [hl]
cp d
jr z, .yes
cp e
jr z, .yes
.check_y
ld hl, OBJECT_RADIUS
add hl, bc
ld a, [hl]
swap a
and $f
jr z, .nope
ld e, a
ld d, a
ld hl, OBJECT_INIT_Y
add hl, bc
ld a, [hl]
sub d
ld d, a
ld a, [hl]
add e
ld e, a
ld hl, OBJECT_MAP_Y
add hl, bc
ld a, [hl]
cp d
jr z, .yes
cp e
jr z, .yes
.nope
xor a
ret
.yes
scf
ret
IsObjectMovingOffEdgeOfScreen:
ld hl, OBJECT_MAP_X
add hl, bc
ld a, [wXCoord]
cp [hl]
jr z, .check_y
jr nc, .yes
add $9
cp [hl]
jr c, .yes
.check_y
ld hl, OBJECT_MAP_Y
add hl, bc
ld a, [wYCoord]
cp [hl]
jr z, .nope
jr nc, .yes
add $8
cp [hl]
jr c, .yes
.nope
and a
ret
.yes
scf
ret
IsNPCAtPlayerCoord: ; unreferenced
ld a, [wPlayerMapX]
ld d, a
ld a, [wPlayerMapY]
ld e, a
ld bc, wObjectStructs
xor a
.loop
ldh [hObjectStructIndex], a
call DoesObjectHaveASprite
jr z, .next
ld hl, OBJECT_MOVEMENT_TYPE
add hl, bc
ld a, [hl]
cp SPRITEMOVEDATA_BIGDOLLSYM
jr nz, .not_big
call WillObjectIntersectBigObject
jr c, .yes
jr .next
.not_big
ld hl, OBJECT_MAP_Y
add hl, bc
ld a, [hl]
cp e
jr nz, .check_current_coords
ld hl, OBJECT_MAP_X
add hl, bc
ld a, [hl]
cp d
jr nz, .check_current_coords
ldh a, [hObjectStructIndex]
cp PLAYER_OBJECT
jr z, .next
jr .yes
.check_current_coords
ld hl, OBJECT_LAST_MAP_Y
add hl, bc
ld a, [hl]
cp e
jr nz, .next
ld hl, OBJECT_LAST_MAP_X
add hl, bc
ld a, [hl]
cp d
jr nz, .next
jr .yes
.next
ld hl, OBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
ldh a, [hObjectStructIndex]
inc a
cp NUM_OBJECT_STRUCTS
jr nz, .loop
xor a
ret
.yes
scf
ret
WillObjectIntersectBigObject:
ld hl, OBJECT_MAP_X
add hl, bc
ld a, d
sub [hl]
jr c, .nope
cp 2 ; big doll width
jr nc, .nope
ld hl, OBJECT_MAP_Y
add hl, bc
ld a, e
sub [hl]
jr c, .nope
cp 2 ; big doll height
jr nc, .nope
scf
ret
.nope
and a
ret

View file

@ -0,0 +1,672 @@
GetEmote2bpp:
ld a, $1
ldh [rVBK], a
call Get2bpp
xor a
ldh [rVBK], a
ret
_UpdatePlayerSprite::
call GetPlayerSprite
ld a, [wUsedSprites]
ldh [hUsedSpriteIndex], a
ld a, [wUsedSprites + 1]
ldh [hUsedSpriteTile], a
call GetUsedSprite
ret
_RefreshSprites: ; mobile
ld hl, wSpriteFlags
ld a, [hl]
push af
res 7, [hl]
set 6, [hl]
call LoadUsedSpritesGFX
pop af
ld [wSpriteFlags], a
ret
_ClearSprites: ; mobile
ld hl, wSpriteFlags
ld a, [hl]
push af
set 7, [hl]
res 6, [hl]
call LoadUsedSpritesGFX
pop af
ld [wSpriteFlags], a
ret
RefreshSprites::
call .Refresh
call LoadUsedSpritesGFX
ret
.Refresh:
xor a
ld bc, wUsedSpritesEnd - wUsedSprites
ld hl, wUsedSprites
call ByteFill
call GetPlayerSprite
call AddMapSprites
call LoadAndSortSprites
ret
GetPlayerSprite:
; Get Chris or Kris's sprite.
ld hl, ChrisStateSprites
ld a, [wPlayerSpriteSetupFlags]
bit PLAYERSPRITESETUP_FEMALE_TO_MALE_F, a
jr nz, .go
ld a, [wPlayerGender]
bit PLAYERGENDER_FEMALE_F, a
jr z, .go
ld hl, KrisStateSprites
.go
ld a, [wPlayerState]
ld c, a
.loop
ld a, [hli]
cp c
jr z, .good
inc hl
cp -1
jr nz, .loop
; Any player state not in the array defaults to Chris's sprite.
xor a ; ld a, PLAYER_NORMAL
ld [wPlayerState], a
ld a, SPRITE_CHRIS
jr .finish
.good
ld a, [hl]
.finish
ld [wUsedSprites + 0], a
ld [wPlayerSprite], a
ld [wPlayerObjectSprite], a
ret
INCLUDE "data/sprites/player_sprites.asm"
AddMapSprites:
call GetMapEnvironment
call CheckOutdoorMap
jr z, .outdoor
call AddIndoorSprites
ret
.outdoor
call AddOutdoorSprites
ret
AddIndoorSprites:
ld hl, wMap1ObjectSprite
ld a, 1
.loop
push af
ld a, [hl]
call AddSpriteGFX
ld de, MAPOBJECT_LENGTH
add hl, de
pop af
inc a
cp NUM_OBJECTS
jr nz, .loop
ret
AddOutdoorSprites:
ld a, [wMapGroup]
dec a
ld c, a
ld b, 0
ld hl, OutdoorSprites
add hl, bc
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
ld c, MAX_OUTDOOR_SPRITES
.loop
push bc
ld a, [hli]
call AddSpriteGFX
pop bc
dec c
jr nz, .loop
ret
LoadUsedSpritesGFX:
ld a, MAPCALLBACK_SPRITES
call RunMapCallback
call GetUsedSprites
call LoadMiscTiles
ret
LoadMiscTiles:
ld a, [wSpriteFlags]
bit 6, a
ret nz
ld c, EMOTE_SHADOW
farcall LoadEmote
call GetMapEnvironment
call CheckOutdoorMap
ld c, EMOTE_GRASS_RUSTLE
jr z, .outdoor
ld c, EMOTE_BOULDER_DUST
.outdoor
farcall LoadEmote
ret
SafeGetSprite:
push hl
call GetSprite
pop hl
ret
GetSprite:
call GetMonSprite
ret c
ld hl, OverworldSprites + SPRITEDATA_ADDR
dec a
ld c, a
ld b, 0
ld a, NUM_SPRITEDATA_FIELDS
call AddNTimes
; load the address into de
ld a, [hli]
ld e, a
ld a, [hli]
ld d, a
; load the length into c
ld a, [hli]
swap a
ld c, a
; load the sprite bank into both b and h
ld b, [hl]
ld a, [hli]
; load the sprite type into l
ld l, [hl]
ld h, a
ret
GetMonSprite:
; Return carry if a monster sprite was loaded.
cp SPRITE_POKEMON
jr c, .Normal
cp SPRITE_DAY_CARE_MON_1
jr z, .BreedMon1
cp SPRITE_DAY_CARE_MON_2
jr z, .BreedMon2
cp SPRITE_VARS
jr nc, .Variable
jr .Icon
.Normal:
and a
ret
.Icon:
sub SPRITE_POKEMON
ld e, a
ld d, 0
ld hl, SpriteMons
add hl, de
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
call GetPokemonIDFromIndex
jr .Mon
.BreedMon1
ld a, [wBreedMon1Species]
jr .Mon
.BreedMon2
ld a, [wBreedMon2Species]
.Mon:
ld e, a
and a
jr z, .NoBreedmon
farcall LoadOverworldMonIcon
ld l, WALKING_SPRITE
ld h, 0
scf
ret
.Variable:
sub SPRITE_VARS
ld e, a
ld d, 0
ld hl, wVariableSprites
add hl, de
ld a, [hl]
and a
jp nz, GetMonSprite
.NoBreedmon:
ld a, WALKING_SPRITE
ld l, WALKING_SPRITE
ld h, 0
and a
ret
_DoesSpriteHaveFacings::
; Checks to see whether we can apply a facing to a sprite.
; Returns carry unless the sprite is a Pokemon or a Still Sprite.
cp SPRITE_POKEMON
jr nc, .only_down
push hl
push bc
ld hl, OverworldSprites + SPRITEDATA_TYPE
dec a
ld c, a
ld b, 0
ld a, NUM_SPRITEDATA_FIELDS
call AddNTimes
ld a, [hl]
pop bc
pop hl
cp STILL_SPRITE
jr nz, .only_down
scf
ret
.only_down
and a
ret
_GetSpritePalette::
ld a, c
call GetMonSprite
jr c, .is_pokemon
ld hl, OverworldSprites + SPRITEDATA_PALETTE
dec a
ld c, a
ld b, 0
ld a, NUM_SPRITEDATA_FIELDS
call AddNTimes
ld c, [hl]
ret
.is_pokemon
xor a
ld c, a
ret
LoadAndSortSprites:
call LoadSpriteGFX
call SortUsedSprites
call ArrangeUsedSprites
ret
AddSpriteGFX:
; Add any new sprite ids to a list of graphics to be loaded.
; Return carry if the list is full.
push hl
push bc
ld b, a
ld hl, wUsedSprites + 2
ld c, SPRITE_GFX_LIST_CAPACITY - 1
.loop
ld a, [hl]
cp b
jr z, .exists
and a
jr z, .new
inc hl
inc hl
dec c
jr nz, .loop
pop bc
pop hl
scf
ret
.exists
pop bc
pop hl
and a
ret
.new
ld [hl], b
pop bc
pop hl
and a
ret
LoadSpriteGFX:
ld hl, wUsedSprites
ld b, SPRITE_GFX_LIST_CAPACITY
.loop
ld a, [hli]
and a
jr z, .done
push hl
call .LoadSprite
pop hl
ld [hli], a
dec b
jr nz, .loop
.done
ret
.LoadSprite:
push bc
call GetSprite
pop bc
ld a, l
ret
SortUsedSprites:
; Bubble-sort sprites by type.
; Run backwards through wUsedSprites to find the last one.
ld c, SPRITE_GFX_LIST_CAPACITY
ld de, wUsedSprites + (SPRITE_GFX_LIST_CAPACITY - 1) * 2
.FindLastSprite:
ld a, [de]
and a
jr nz, .FoundLastSprite
dec de
dec de
dec c
jr nz, .FindLastSprite
.FoundLastSprite:
dec c
jr z, .quit
; If the length of the current sprite is
; higher than a later one, swap them.
inc de
ld hl, wUsedSprites + 1
.CheckSprite:
push bc
push de
push hl
.CheckFollowing:
ld a, [de]
cp [hl]
jr nc, .loop
; Swap the two sprites.
ld b, a
ld a, [hl]
ld [hl], b
ld [de], a
dec de
dec hl
ld a, [de]
ld b, a
ld a, [hl]
ld [hl], b
ld [de], a
inc de
inc hl
; Keep doing this until everything's in order.
.loop
dec de
dec de
dec c
jr nz, .CheckFollowing
pop hl
inc hl
inc hl
pop de
pop bc
dec c
jr nz, .CheckSprite
.quit
ret
ArrangeUsedSprites:
; Get the length of each sprite and space them out in VRAM.
; Crystal introduces a second table in VRAM bank 0.
ld hl, wUsedSprites
ld c, SPRITE_GFX_LIST_CAPACITY
ld b, 0
.FirstTableLength:
; Keep going until the end of the list.
ld a, [hli]
and a
jr z, .quit
ld a, [hl]
call GetSpriteLength
; Spill over into the second table after $80 tiles.
add b
cp $80
jr z, .loop
jr nc, .SecondTable
.loop
ld [hl], b
inc hl
ld b, a
; Assumes the next table will be reached before c hits 0.
dec c
jr nz, .FirstTableLength
.SecondTable:
; The second tile table starts at tile $80.
ld b, $80
dec hl
.SecondTableLength:
; Keep going until the end of the list.
ld a, [hli]
and a
jr z, .quit
ld a, [hl]
call GetSpriteLength
; There are only two tables, so don't go any further than that.
add b
jr c, .quit
ld [hl], b
ld b, a
inc hl
dec c
jr nz, .SecondTableLength
.quit
ret
GetSpriteLength:
; Return the length of sprite type a in tiles.
cp WALKING_SPRITE
jr z, .AnyDirection
cp STANDING_SPRITE
jr z, .AnyDirection
cp STILL_SPRITE
jr z, .OneDirection
ld a, 12
ret
.AnyDirection:
ld a, 12
ret
.OneDirection:
ld a, 4
ret
GetUsedSprites:
ld hl, wUsedSprites
ld c, SPRITE_GFX_LIST_CAPACITY
.loop
ld a, [wSpriteFlags]
res 5, a
ld [wSpriteFlags], a
ld a, [hli]
and a
jr z, .done
ldh [hUsedSpriteIndex], a
ld a, [hli]
ldh [hUsedSpriteTile], a
bit 7, a
jr z, .dont_set
ld a, [wSpriteFlags]
set 5, a ; load VBank0
ld [wSpriteFlags], a
.dont_set
push bc
push hl
call GetUsedSprite
pop hl
pop bc
dec c
jr nz, .loop
.done
ret
GetUsedSprite:
ldh a, [hUsedSpriteIndex]
call SafeGetSprite
ldh a, [hUsedSpriteTile]
call .GetTileAddr
push hl
push de
push bc
ld a, [wSpriteFlags]
bit 7, a
jr nz, .skip
call .CopyToVram
.skip
pop bc
ld l, c
ld h, $0
rept 4
add hl, hl
endr
pop de
add hl, de
ld d, h
ld e, l
pop hl
ld a, [wSpriteFlags]
bit 5, a
jr nz, .done
bit 6, a
jr nz, .done
ldh a, [hUsedSpriteIndex]
call _DoesSpriteHaveFacings
jr c, .done
ld a, h
add HIGH(vTiles1 - vTiles0)
ld h, a
call .CopyToVram
.done
ret
.GetTileAddr:
; Return the address of tile (a) in (hl).
and $7f
ld l, a
ld h, 0
rept 4
add hl, hl
endr
ld a, l
add LOW(vTiles0)
ld l, a
ld a, h
adc HIGH(vTiles0)
ld h, a
ret
.CopyToVram:
ldh a, [rVBK]
push af
ld a, [wSpriteFlags]
bit 5, a
ld a, $1
jr z, .bankswitch
ld a, $0
.bankswitch
ldh [rVBK], a
call Get2bpp
pop af
ldh [rVBK], a
ret
LoadEmote::
; Get the address of the pointer to emote c.
ld a, c
ld bc, EMOTE_LENGTH
ld hl, Emotes
call AddNTimes
; Load the emote address into de
ld e, [hl]
inc hl
ld d, [hl]
; load the length of the emote (in tiles) into c
inc hl
ld c, [hl]
swap c
; load the emote pointer bank into b
inc hl
ld b, [hl]
; load the VRAM destination into hl
inc hl
ld a, [hli]
ld h, [hl]
ld l, a
; if the emote has a length of 0, do not proceed (error handling)
ld a, c
and a
ret z
call GetEmote2bpp
ret
INCLUDE "data/sprites/emotes.asm"
INCLUDE "data/sprites/sprite_mons.asm"
INCLUDE "data/maps/outdoor_sprites.asm"
INCLUDE "data/sprites/sprites.asm"

View file

@ -0,0 +1,816 @@
DoPlayerMovement::
call .GetDPad
ld a, movement_step_sleep
ld [wMovementAnimation], a
xor a
ld [wWalkingIntoEdgeWarp], a
call .TranslateIntoMovement
ld c, a
ld a, [wMovementAnimation]
ld [wPlayerNextMovement], a
ret
.GetDPad:
ldh a, [hJoyDown]
ld [wCurInput], a
; Standing downhill instead moves down.
ld hl, wBikeFlags
bit BIKEFLAGS_DOWNHILL_F, [hl]
ret z
ld c, a
and D_PAD
ret nz
ld a, c
or D_DOWN
ld [wCurInput], a
ret
.TranslateIntoMovement:
ld a, [wPlayerState]
cp PLAYER_NORMAL
jr z, .Normal
cp PLAYER_SURF
jr z, .Surf
cp PLAYER_SURF_PIKA
jr z, .Surf
cp PLAYER_BIKE
jr z, .Normal
cp PLAYER_SKATE
jr z, .Ice
.Normal:
call .CheckForced
call .GetAction
call .CheckTile
ret c
call .CheckTurning
ret c
call .TryStep
ret c
call .TryJump
ret c
call .CheckWarp
ret c
jr .NotMoving
.Surf:
call .CheckForced
call .GetAction
call .CheckTile
ret c
call .CheckTurning
ret c
call .TrySurf
ret c
jr .NotMoving
.Ice:
call .CheckForced
call .GetAction
call .CheckTile
ret c
call .CheckTurning
ret c
call .TryStep
ret c
call .TryJump
ret c
call .CheckWarp
ret c
ld a, [wWalkingDirection]
cp STANDING
jr z, .HitWall
call .BumpSound
.HitWall:
call .StandInPlace
xor a
ret
.NotMoving:
ld a, [wWalkingDirection]
cp STANDING
jr z, .Standing
; Walking into an edge warp won't bump.
ld a, [wWalkingIntoEdgeWarp]
and a
jr nz, .CantMove
call .BumpSound
.CantMove:
call ._WalkInPlace
xor a
ret
.Standing:
call .StandInPlace
xor a
ret
.CheckTile:
; Tiles such as waterfalls and warps move the player
; in a given direction, overriding input.
ld a, [wPlayerTile]
ld c, a
call CheckWhirlpoolTile
jr c, .not_whirlpool
ld a, PLAYERMOVEMENT_FORCE_TURN
scf
ret
.not_whirlpool
and $f0
cp HI_NYBBLE_CURRENT
jr z, .water
cp HI_NYBBLE_WALK
jr z, .land1
cp HI_NYBBLE_WALK_ALT
jr z, .land2
cp HI_NYBBLE_WARPS
jr z, .warps
jr .no_walk
.water
ld a, c
maskbits NUM_DIRECTIONS
ld c, a
ld b, 0
ld hl, .water_table
add hl, bc
ld a, [hl]
ld [wWalkingDirection], a
jr .continue_walk
.water_table
db RIGHT ; COLL_WATERFALL_RIGHT
db LEFT ; COLL_WATERFALL_LEFT
db UP ; COLL_WATERFALL_UP
db DOWN ; COLL_WATERFALL
.land1
ld a, c
and 7
ld c, a
ld b, 0
ld hl, .land1_table
add hl, bc
ld a, [hl]
cp STANDING
jr z, .no_walk
ld [wWalkingDirection], a
jr .continue_walk
.land1_table
db STANDING ; COLL_BRAKE
db RIGHT ; COLL_WALK_RIGHT
db LEFT ; COLL_WALK_LEFT
db UP ; COLL_WALK_UP
db DOWN ; COLL_WALK_DOWN
db STANDING ; COLL_BRAKE_45
db STANDING ; COLL_BRAKE_46
db STANDING ; COLL_BRAKE_47
.land2
ld a, c
and 7
ld c, a
ld b, 0
ld hl, .land2_table
add hl, bc
ld a, [hl]
cp STANDING
jr z, .no_walk
ld [wWalkingDirection], a
jr .continue_walk
.land2_table
db RIGHT ; COLL_WALK_RIGHT_ALT
db LEFT ; COLL_WALK_LEFT_ALT
db UP ; COLL_WALK_UP_ALT
db DOWN ; COLL_WALK_DOWN_ALT
db STANDING ; COLL_BRAKE_ALT
db STANDING ; COLL_BRAKE_55
db STANDING ; COLL_BRAKE_56
db STANDING ; COLL_BRAKE_57
.warps
ld a, c
cp COLL_DOOR
jr z, .down
cp COLL_DOOR_79
jr z, .down
cp COLL_STAIRCASE
jr z, .down
cp COLL_CAVE
jr nz, .no_walk
.down
ld a, DOWN
ld [wWalkingDirection], a
jr .continue_walk
.no_walk
xor a
ret
.continue_walk
ld a, STEP_WALK
call .DoStep
ld a, PLAYERMOVEMENT_CONTINUE
scf
ret
.CheckTurning:
; If the player is turning, change direction first. This also lets
; the player change facing without moving by tapping a direction.
ld a, [wPlayerTurningDirection]
cp 0
jr nz, .not_turning
ld a, [wWalkingDirection]
cp STANDING
jr z, .not_turning
ld e, a
ld a, [wPlayerDirection]
rrca
rrca
maskbits NUM_DIRECTIONS
cp e
jr z, .not_turning
ld a, STEP_TURN
call .DoStep
ld a, PLAYERMOVEMENT_TURN
scf
ret
.not_turning
xor a
ret
.TryStep:
; Surfing actually calls .TrySurf directly instead of passing through here.
ld a, [wPlayerState]
cp PLAYER_SURF
jr z, .TrySurf
cp PLAYER_SURF_PIKA
jr z, .TrySurf
call .CheckLandPerms
jr c, .bump
call .CheckNPC
and a
jr z, .bump
cp 2
jr z, .bump
ld a, [wPlayerTile]
call CheckIceTile
jr nc, .ice
; Downhill riding is slower when not moving down.
call .BikeCheck
jr nz, .walk
ld hl, wBikeFlags
bit BIKEFLAGS_DOWNHILL_F, [hl]
jr z, .fast
ld a, [wWalkingDirection]
cp DOWN
jr z, .fast
ld a, STEP_WALK
call .DoStep
scf
ret
.fast
ld a, STEP_BIKE
call .DoStep
scf
ret
.walk
ld a, STEP_WALK
call .DoStep
scf
ret
.ice
ld a, STEP_ICE
call .DoStep
scf
ret
.unused ; unreferenced
xor a
ret
.bump
xor a
ret
.TrySurf:
call .CheckSurfPerms
ld [wWalkingIntoLand], a
jr c, .surf_bump
call .CheckNPC
ld [wWalkingIntoNPC], a
and a
jr z, .surf_bump
cp 2
jr z, .surf_bump
ld a, [wWalkingIntoLand]
and a
jr nz, .ExitWater
ld a, STEP_WALK
call .DoStep
scf
ret
.ExitWater:
call .GetOutOfWater
call PlayMapMusic
ld a, STEP_WALK
call .DoStep
ld a, PLAYERMOVEMENT_EXIT_WATER
scf
ret
.surf_bump
xor a
ret
.TryJump:
ld a, [wPlayerTile]
ld e, a
and $f0
cp HI_NYBBLE_LEDGES
jr nz, .DontJump
ld a, e
and 7
ld e, a
ld d, 0
ld hl, .ledge_table
add hl, de
ld a, [wFacingDirection]
and [hl]
jr z, .DontJump
ld de, SFX_JUMP_OVER_LEDGE
call PlaySFX
ld a, STEP_LEDGE
call .DoStep
ld a, PLAYERMOVEMENT_JUMP
scf
ret
.DontJump:
xor a
ret
.ledge_table
db FACE_RIGHT ; COLL_HOP_RIGHT
db FACE_LEFT ; COLL_HOP_LEFT
db FACE_UP ; COLL_HOP_UP
db FACE_DOWN ; COLL_HOP_DOWN
db FACE_RIGHT | FACE_DOWN ; COLL_HOP_DOWN_RIGHT
db FACE_DOWN | FACE_LEFT ; COLL_HOP_DOWN_LEFT
db FACE_UP | FACE_RIGHT ; COLL_HOP_UP_RIGHT
db FACE_UP | FACE_LEFT ; COLL_HOP_UP_LEFT
.CheckWarp:
; BUG: No bump noise if standing on tile $3E (see docs/bugs_and_glitches.md)
ld a, [wWalkingDirection]
ld e, a
ld d, 0
ld hl, .EdgeWarps
add hl, de
ld a, [wPlayerTile]
cp [hl]
jr nz, .not_warp
ld a, TRUE
ld [wWalkingIntoEdgeWarp], a
ld a, [wWalkingDirection]
cp STANDING
jr z, .not_warp
ld e, a
ld a, [wPlayerDirection]
rrca
rrca
maskbits NUM_DIRECTIONS
cp e
jr nz, .not_warp
call WarpCheck
jr nc, .not_warp
call .StandInPlace
scf
ld a, PLAYERMOVEMENT_WARP
ret
.not_warp
xor a ; PLAYERMOVEMENT_NORMAL
ret
.EdgeWarps:
db COLL_WARP_CARPET_DOWN
db COLL_WARP_CARPET_UP
db COLL_WARP_CARPET_LEFT
db COLL_WARP_CARPET_RIGHT
.DoStep:
ld e, a
ld d, 0
ld hl, .Steps
add hl, de
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
ld a, [wWalkingDirection]
ld e, a
cp STANDING
jp z, .StandInPlace
add hl, de
ld a, [hl]
ld [wMovementAnimation], a
ld hl, .FinishFacing
add hl, de
ld a, [hl]
ld [wPlayerTurningDirection], a
ld a, PLAYERMOVEMENT_FINISH
ret
.Steps:
; entries correspond to STEP_* constants (see constants/map_object_constants.asm)
table_width 2, DoPlayerMovement.Steps
dw .SlowStep
dw .NormalStep
dw .FastStep
dw .JumpStep
dw .SlideStep
dw .TurningStep
dw .BackJumpStep
dw .FinishFacing
assert_table_length NUM_STEPS
.SlowStep:
slow_step DOWN
slow_step UP
slow_step LEFT
slow_step RIGHT
.NormalStep:
step DOWN
step UP
step LEFT
step RIGHT
.FastStep:
big_step DOWN
big_step UP
big_step LEFT
big_step RIGHT
.JumpStep:
jump_step DOWN
jump_step UP
jump_step LEFT
jump_step RIGHT
.SlideStep:
fast_slide_step DOWN
fast_slide_step UP
fast_slide_step LEFT
fast_slide_step RIGHT
.BackJumpStep:
jump_step UP
jump_step DOWN
jump_step RIGHT
jump_step LEFT
.TurningStep:
turn_step DOWN
turn_step UP
turn_step LEFT
turn_step RIGHT
.FinishFacing:
db $80 | DOWN
db $80 | UP
db $80 | LEFT
db $80 | RIGHT
.StandInPlace:
ld a, 0
ld [wPlayerTurningDirection], a
ld a, movement_step_sleep
ld [wMovementAnimation], a
xor a
ret
._WalkInPlace:
ld a, 0
ld [wPlayerTurningDirection], a
ld a, movement_step_bump
ld [wMovementAnimation], a
xor a
ret
.CheckForced:
; When sliding on ice, input is forced to remain in the same direction.
call CheckStandingOnIce
ret nc
ld a, [wPlayerTurningDirection]
cp 0
ret z
maskbits NUM_DIRECTIONS
ld e, a
ld d, 0
ld hl, .forced_dpad
add hl, de
ld a, [wCurInput]
and BUTTONS
or [hl]
ld [wCurInput], a
ret
.forced_dpad
db D_DOWN, D_UP, D_LEFT, D_RIGHT
.GetAction:
; Poll player input and update movement info.
ld hl, .action_table
ld de, .action_table_1_end - .action_table_1
ld a, [wCurInput]
bit D_DOWN_F, a
jr nz, .d_down
bit D_UP_F, a
jr nz, .d_up
bit D_LEFT_F, a
jr nz, .d_left
bit D_RIGHT_F, a
jr nz, .d_right
; Standing
jr .update
.d_down
add hl, de
.d_up
add hl, de
.d_left
add hl, de
.d_right
add hl, de
.update
ld a, [hli]
ld [wWalkingDirection], a
ld a, [hli]
ld [wFacingDirection], a
ld a, [hli]
ld [wWalkingX], a
ld a, [hli]
ld [wWalkingY], a
ld a, [hli]
ld h, [hl]
ld l, a
ld a, [hl]
ld [wWalkingTile], a
ret
MACRO player_action
; walk direction, facing, x movement, y movement, tile collision pointer
db \1, \2, \3, \4
dw \5
ENDM
.action_table:
.action_table_1
player_action STANDING, FACE_CURRENT, 0, 0, wPlayerTile
.action_table_1_end
player_action RIGHT, FACE_RIGHT, 1, 0, wTileRight
player_action LEFT, FACE_LEFT, -1, 0, wTileLeft
player_action UP, FACE_UP, 0, -1, wTileUp
player_action DOWN, FACE_DOWN, 0, 1, wTileDown
.CheckNPC:
; Returns 0 if there is an NPC in front that you can't move
; Returns 1 if there is no NPC in front
; Returns 2 if there is a movable NPC in front. The game actually treats
; this the same as an NPC in front (bump).
ld a, 0
ldh [hMapObjectIndex], a
; Load the next X coordinate into d
ld a, [wPlayerMapX]
ld d, a
ld a, [wWalkingX]
add d
ld d, a
; Load the next Y coordinate into e
ld a, [wPlayerMapY]
ld e, a
ld a, [wWalkingY]
add e
ld e, a
; Find an object struct with coordinates equal to d,e
ld bc, wObjectStructs ; redundant
farcall IsNPCAtCoord
jr nc, .no_npc
call .CheckStrengthBoulder
jr c, .no_bump
xor a ; bump
ret
.no_npc
ld a, 1
ret
.no_bump
ld a, 2
ret
.CheckStrengthBoulder:
ld hl, wBikeFlags
bit BIKEFLAGS_STRENGTH_ACTIVE_F, [hl]
jr z, .not_boulder
ld hl, OBJECT_WALKING
add hl, bc
ld a, [hl]
cp STANDING
jr nz, .not_boulder
ld hl, OBJECT_PALETTE
add hl, bc
bit STRENGTH_BOULDER_F, [hl]
jr z, .not_boulder
ld hl, OBJECT_FLAGS2
add hl, bc
set 2, [hl]
ld a, [wWalkingDirection]
ld d, a
ld hl, OBJECT_RANGE
add hl, bc
ld a, [hl]
and %11111100
or d
ld [hl], a
scf
ret
.not_boulder
xor a
ret
.CheckLandPerms:
; Return 0 if walking onto land and tile permissions allow it.
; Otherwise, return carry.
ld a, [wTilePermissions]
ld d, a
ld a, [wFacingDirection]
and d
jr nz, .NotWalkable
ld a, [wWalkingTile]
call .CheckWalkable
jr c, .NotWalkable
xor a
ret
.NotWalkable:
scf
ret
.CheckSurfPerms:
; Return 0 if moving in water, or 1 if moving onto land.
; Otherwise, return carry.
ld a, [wTilePermissions]
ld d, a
ld a, [wFacingDirection]
and d
jr nz, .NotSurfable
ld a, [wWalkingTile]
call .CheckSurfable
jr c, .NotSurfable
and a
ret
.NotSurfable:
scf
ret
.BikeCheck:
ld a, [wPlayerState]
cp PLAYER_BIKE
ret z
cp PLAYER_SKATE
ret
.CheckWalkable:
; Return 0 if tile a is land. Otherwise, return carry.
call GetTileCollision
and a ; LAND_TILE
ret z
scf
ret
.CheckSurfable:
; Return 0 if tile a is water, or 1 if land.
; Otherwise, return carry.
call GetTileCollision
cp WATER_TILE
jr z, .Water
; Can walk back onto land from water.
and a ; LAND_TILE
jr z, .Land
jr .Neither
.Water:
xor a
ret
.Land:
ld a, 1
and a
ret
.Neither:
scf
ret
.BumpSound:
call CheckSFX
ret c
ld de, SFX_BUMP
call PlaySFX
ret
.GetOutOfWater:
push bc
ld a, PLAYER_NORMAL
ld [wPlayerState], a
call UpdatePlayerSprite ; UpdateSprites
pop bc
ret
CheckStandingOnIce::
ld a, [wPlayerTurningDirection]
cp 0
jr z, .not_ice
cp $f0
jr z, .not_ice
ld a, [wPlayerTile]
call CheckIceTile
jr nc, .yep
ld a, [wPlayerState]
cp PLAYER_SKATE
jr nz, .not_ice
.yep
scf
ret
.not_ice
and a
ret
StopPlayerForEvent::
ld hl, wPlayerNextMovement
ld a, movement_step_sleep
cp [hl]
ret z
ld [hl], a
ld a, 0
ld [wPlayerTurningDirection], a
ret

View file

@ -0,0 +1,857 @@
BlankScreen:
call DisableSpriteUpdates
xor a
ldh [hBGMapMode], a
call ClearBGPalettes
call ClearSprites
hlcoord 0, 0
ld bc, wTilemapEnd - wTilemap
ld a, " "
call ByteFill
hlcoord 0, 0, wAttrmap
ld bc, wAttrmapEnd - wAttrmap
ld a, $7
call ByteFill
call WaitBGMap2
call SetPalettes
ret
SpawnPlayer:
ld a, -1
ld [wObjectFollow_Leader], a
ld [wObjectFollow_Follower], a
ld a, PLAYER
ld hl, PlayerObjectTemplate
call CopyPlayerObjectTemplate
ld b, PLAYER
call PlayerSpawn_ConvertCoords
ld a, PLAYER_OBJECT
call GetMapObject
ld hl, MAPOBJECT_PALETTE
add hl, bc
ln e, PAL_NPC_RED, OBJECTTYPE_SCRIPT
ld a, [wPlayerSpriteSetupFlags]
bit PLAYERSPRITESETUP_FEMALE_TO_MALE_F, a
jr nz, .ok
ld a, [wPlayerGender]
bit PLAYERGENDER_FEMALE_F, a
jr z, .ok
ln e, PAL_NPC_BLUE, OBJECTTYPE_SCRIPT
.ok
ld [hl], e
ld a, PLAYER_OBJECT
ldh [hMapObjectIndex], a
ld bc, wMapObjects
ld a, PLAYER_OBJECT
ldh [hObjectStructIndex], a
ld de, wObjectStructs
call CopyMapObjectToObjectStruct
ld a, PLAYER
ld [wCenteredObject], a
ret
PlayerObjectTemplate:
; A dummy map object used to initialize the player object.
; Shorter than the actual amount copied by two bytes.
; Said bytes seem to be unused.
object_event -4, -4, SPRITE_CHRIS, SPRITEMOVEDATA_PLAYER, 15, 15, -1, -1, 0, OBJECTTYPE_SCRIPT, 0, 0, -1
CopyDECoordsToMapObject::
push de
ld a, b
call GetMapObject
pop de
ld hl, MAPOBJECT_X_COORD
add hl, bc
ld [hl], d
ld hl, MAPOBJECT_Y_COORD
add hl, bc
ld [hl], e
ret
PlayerSpawn_ConvertCoords:
push bc
ld a, [wXCoord]
add 4
ld d, a
ld a, [wYCoord]
add 4
ld e, a
pop bc
call CopyDECoordsToMapObject
ret
WriteObjectXY::
ld a, b
call CheckObjectVisibility
ret c
ld hl, OBJECT_MAP_X
add hl, bc
ld d, [hl]
ld hl, OBJECT_MAP_Y
add hl, bc
ld e, [hl]
ldh a, [hMapObjectIndex]
ld b, a
call CopyDECoordsToMapObject
and a
ret
RefreshPlayerCoords:
ld a, [wXCoord]
add 4
ld d, a
ld hl, wPlayerMapX
sub [hl]
ld [hl], d
ld hl, wMapObjects + MAPOBJECT_X_COORD
ld [hl], d
ld hl, wPlayerLastMapX
ld [hl], d
ld d, a
ld a, [wYCoord]
add 4
ld e, a
ld hl, wPlayerMapY
sub [hl]
ld [hl], e
ld hl, wMapObjects + MAPOBJECT_Y_COORD
ld [hl], e
ld hl, wPlayerLastMapY
ld [hl], e
ld e, a
; the next three lines are useless
ld a, [wObjectFollow_Leader]
cp PLAYER
ret nz
ret
CopyObjectStruct::
call CheckObjectMask
and a
ret nz ; masked
ld hl, wObjectStructs + OBJECT_LENGTH * 1
ld a, 1
ld de, OBJECT_LENGTH
.loop
ldh [hObjectStructIndex], a
ld a, [hl]
and a
jr z, .done
add hl, de
ldh a, [hObjectStructIndex]
inc a
cp NUM_OBJECT_STRUCTS
jr nz, .loop
scf
ret ; overflow
.done
ld d, h
ld e, l
call CopyMapObjectToObjectStruct
ld hl, wVramState
bit 7, [hl]
ret z
ld hl, OBJECT_FLAGS2
add hl, de
set 5, [hl]
ret
CopyMapObjectToObjectStruct:
call .CopyMapObjectToTempObject
call CopyTempObjectToObjectStruct
ret
.CopyMapObjectToTempObject:
ldh a, [hObjectStructIndex]
ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld [hl], a
ldh a, [hMapObjectIndex]
ld [wTempObjectCopyMapObjectIndex], a
ld hl, MAPOBJECT_SPRITE
add hl, bc
ld a, [hl]
ld [wTempObjectCopySprite], a
call GetSpriteVTile
ld [wTempObjectCopySpriteVTile], a
ld a, [hl]
call GetSpritePalette
ld [wTempObjectCopyPalette], a
ld hl, MAPOBJECT_PALETTE
add hl, bc
ld a, [hl]
and MAPOBJECT_PALETTE_MASK
jr z, .skip_color_override
swap a
and PALETTE_MASK
ld [wTempObjectCopyPalette], a
.skip_color_override
ld hl, MAPOBJECT_MOVEMENT
add hl, bc
ld a, [hl]
ld [wTempObjectCopyMovement], a
ld hl, MAPOBJECT_SIGHT_RANGE
add hl, bc
ld a, [hl]
ld [wTempObjectCopyRange], a
ld hl, MAPOBJECT_X_COORD
add hl, bc
ld a, [hl]
ld [wTempObjectCopyX], a
ld hl, MAPOBJECT_Y_COORD
add hl, bc
ld a, [hl]
ld [wTempObjectCopyY], a
ld hl, MAPOBJECT_RADIUS
add hl, bc
ld a, [hl]
ld [wTempObjectCopyRadius], a
ret
InitializeVisibleSprites:
ld bc, wMap1Object
ld a, 1
.loop
ldh [hMapObjectIndex], a
ld hl, MAPOBJECT_SPRITE
add hl, bc
ld a, [hl]
and a
jr z, .next
ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
cp -1
jr nz, .next
ld a, [wXCoord]
ld d, a
ld a, [wYCoord]
ld e, a
ld hl, MAPOBJECT_X_COORD
add hl, bc
ld a, [hl]
add 1
sub d
jr c, .next
cp MAPOBJECT_SCREEN_WIDTH
jr nc, .next
ld hl, MAPOBJECT_Y_COORD
add hl, bc
ld a, [hl]
add 1
sub e
jr c, .next
cp MAPOBJECT_SCREEN_HEIGHT
jr nc, .next
push bc
call CopyObjectStruct
pop bc
jp c, .ret
.next
ld hl, MAPOBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
ldh a, [hMapObjectIndex]
inc a
cp NUM_OBJECTS
jr nz, .loop
ret
.ret
ret
CheckObjectEnteringVisibleRange::
nop
ld a, [wPlayerStepDirection]
cp STANDING
ret z
ld hl, .dw
rst JumpTable
ret
.dw
dw .Down
dw .Up
dw .Left
dw .Right
.Up:
ld a, [wYCoord]
sub 1
jr .Vertical
.Down:
ld a, [wYCoord]
add 9
.Vertical:
ld d, a
ld a, [wXCoord]
ld e, a
ld bc, wMap1Object
ld a, 1
.loop_v
ldh [hMapObjectIndex], a
ld hl, MAPOBJECT_SPRITE
add hl, bc
ld a, [hl]
and a
jr z, .next_v
ld hl, MAPOBJECT_Y_COORD
add hl, bc
ld a, d
cp [hl]
jr nz, .next_v
ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
cp -1
jr nz, .next_v
ld hl, MAPOBJECT_X_COORD
add hl, bc
ld a, [hl]
add 1
sub e
jr c, .next_v
cp MAPOBJECT_SCREEN_WIDTH
jr nc, .next_v
push de
push bc
call CopyObjectStruct
pop bc
pop de
.next_v
ld hl, MAPOBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
ldh a, [hMapObjectIndex]
inc a
cp NUM_OBJECTS
jr nz, .loop_v
ret
.Left:
ld a, [wXCoord]
sub 1
jr .Horizontal
.Right:
ld a, [wXCoord]
add 10
.Horizontal:
ld e, a
ld a, [wYCoord]
ld d, a
ld bc, wMap1Object
ld a, 1
.loop_h
ldh [hMapObjectIndex], a
ld hl, MAPOBJECT_SPRITE
add hl, bc
ld a, [hl]
and a
jr z, .next_h
ld hl, MAPOBJECT_X_COORD
add hl, bc
ld a, e
cp [hl]
jr nz, .next_h
ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
cp -1
jr nz, .next_h
ld hl, MAPOBJECT_Y_COORD
add hl, bc
ld a, [hl]
add 1
sub d
jr c, .next_h
cp MAPOBJECT_SCREEN_HEIGHT
jr nc, .next_h
push de
push bc
call CopyObjectStruct
pop bc
pop de
.next_h
ld hl, MAPOBJECT_LENGTH
add hl, bc
ld b, h
ld c, l
ldh a, [hMapObjectIndex]
inc a
cp NUM_OBJECTS
jr nz, .loop_h
ret
CopyTempObjectToObjectStruct:
ld a, [wTempObjectCopyMapObjectIndex]
ld hl, OBJECT_MAP_OBJECT_INDEX
add hl, de
ld [hl], a
ld a, [wTempObjectCopyMovement]
call CopySpriteMovementData
ld a, [wTempObjectCopyPalette]
ld hl, OBJECT_PALETTE
add hl, de
or [hl]
ld [hl], a
ld a, [wTempObjectCopyY]
call .InitYCoord
ld a, [wTempObjectCopyX]
call .InitXCoord
ld a, [wTempObjectCopySprite]
ld hl, OBJECT_SPRITE
add hl, de
ld [hl], a
ld a, [wTempObjectCopySpriteVTile]
ld hl, OBJECT_SPRITE_TILE
add hl, de
ld [hl], a
ld hl, OBJECT_STEP_TYPE
add hl, de
ld [hl], STEP_TYPE_RESET
ld hl, OBJECT_FACING
add hl, de
ld [hl], STANDING
ld a, [wTempObjectCopyRadius]
call .InitRadius
ld a, [wTempObjectCopyRange]
ld hl, OBJECT_RANGE
add hl, de
ld [hl], a
and a
ret
.InitYCoord:
ld hl, OBJECT_INIT_Y
add hl, de
ld [hl], a
ld hl, OBJECT_MAP_Y
add hl, de
ld [hl], a
ld hl, wYCoord
sub [hl]
and $f
swap a
ld hl, wPlayerBGMapOffsetY
sub [hl]
ld hl, OBJECT_SPRITE_Y
add hl, de
ld [hl], a
ret
.InitXCoord:
ld hl, OBJECT_INIT_X
add hl, de
ld [hl], a
ld hl, OBJECT_MAP_X
add hl, de
ld [hl], a
ld hl, wXCoord
sub [hl]
and $f
swap a
ld hl, wPlayerBGMapOffsetX
sub [hl]
ld hl, OBJECT_SPRITE_X
add hl, de
ld [hl], a
ret
.InitRadius:
ld h, a
inc a
and $f
ld l, a
ld a, h
add $10
and $f0
or l
ld hl, OBJECT_RADIUS
add hl, de
ld [hl], a
ret
TrainerWalkToPlayer:
ldh a, [hLastTalked]
call InitMovementBuffer
ld a, movement_step_sleep
call AppendToMovementBuffer
ld a, [wSeenTrainerDistance]
dec a
jr z, .TerminateStep
ldh a, [hLastTalked]
ld b, a
ld c, PLAYER
ld d, 1
call .GetPathToPlayer
call DecrementMovementBufferCount
.TerminateStep:
ld a, movement_step_end
call AppendToMovementBuffer
ret
.GetPathToPlayer:
push de
push bc
; get player object struct, load to de
ld a, c
call GetMapObject
ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
call GetObjectStruct
ld d, b
ld e, c
; get last talked object struct, load to bc
pop bc
ld a, b
call GetMapObject
ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
call GetObjectStruct
; get last talked coords, load to bc
ld hl, OBJECT_MAP_X
add hl, bc
ld a, [hl]
ld hl, OBJECT_MAP_Y
add hl, bc
ld c, [hl]
ld b, a
; get player coords, load to de
ld hl, OBJECT_MAP_X
add hl, de
ld a, [hl]
ld hl, OBJECT_MAP_Y
add hl, de
ld e, [hl]
ld d, a
pop af
call ComputePathToWalkToPlayer
ret
SurfStartStep:
call InitMovementBuffer
call .GetMovementData
call AppendToMovementBuffer
ld a, movement_step_end
call AppendToMovementBuffer
ret
.GetMovementData:
ld a, [wPlayerDirection]
srl a
srl a
maskbits NUM_DIRECTIONS
ld e, a
ld d, 0
ld hl, .movement_data
add hl, de
ld a, [hl]
ret
.movement_data
slow_step DOWN
slow_step UP
slow_step LEFT
slow_step RIGHT
FollowNotExact::
push bc
ld a, c
call CheckObjectVisibility
ld d, b
ld e, c
pop bc
ret c
ld a, b
call CheckObjectVisibility
ret c
; object 2 is now in bc, object 1 is now in de
ld hl, OBJECT_MAP_X
add hl, bc
ld a, [hl]
ld hl, OBJECT_MAP_Y
add hl, bc
ld c, [hl]
ld b, a
ld hl, OBJECT_MAP_X
add hl, de
ld a, [hl]
cp b
jr z, .same_x
jr c, .to_the_left
inc b
jr .continue
.to_the_left
dec b
jr .continue
.same_x
ld hl, OBJECT_MAP_Y
add hl, de
ld a, [hl]
cp c
jr z, .continue
jr c, .below
inc c
jr .continue
.below
dec c
.continue
ld hl, OBJECT_MAP_X
add hl, de
ld [hl], b
ld a, b
ld hl, wXCoord
sub [hl]
and $f
swap a
ld hl, wPlayerBGMapOffsetX
sub [hl]
ld hl, OBJECT_SPRITE_X
add hl, de
ld [hl], a
ld hl, OBJECT_MAP_Y
add hl, de
ld [hl], c
ld a, c
ld hl, wYCoord
sub [hl]
and $f
swap a
ld hl, wPlayerBGMapOffsetY
sub [hl]
ld hl, OBJECT_SPRITE_Y
add hl, de
ld [hl], a
ldh a, [hObjectStructIndex]
ld hl, OBJECT_RANGE
add hl, de
ld [hl], a
ld hl, OBJECT_MOVEMENT_TYPE
add hl, de
ld [hl], SPRITEMOVEDATA_FOLLOWNOTEXACT
ld hl, OBJECT_STEP_TYPE
add hl, de
ld [hl], STEP_TYPE_RESET
ret
GetRelativeFacing::
; Determines which way map object e would have to turn to face map object d. Returns carry if it's impossible for whatever reason.
ld a, d
call GetMapObject
ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
cp NUM_OBJECT_STRUCTS
jr nc, .carry
ld d, a
ld a, e
call GetMapObject
ld hl, MAPOBJECT_OBJECT_STRUCT_ID
add hl, bc
ld a, [hl]
cp NUM_OBJECT_STRUCTS
jr nc, .carry
ld e, a
call .GetFacing_e_relativeto_d
ret
.carry
scf
ret
.GetFacing_e_relativeto_d:
; Determines which way object e would have to turn to face object d. Returns carry if it's impossible.
; load the coordinates of object d into bc
ld a, d
call GetObjectStruct
ld hl, OBJECT_MAP_X
add hl, bc
ld a, [hl]
ld hl, OBJECT_MAP_Y
add hl, bc
ld c, [hl]
ld b, a
push bc
; load the coordinates of object e into de
ld a, e
call GetObjectStruct
ld hl, OBJECT_MAP_X
add hl, bc
ld d, [hl]
ld hl, OBJECT_MAP_Y
add hl, bc
ld e, [hl]
pop bc
; |x1 - x2|
ld a, b
sub d
jr z, .same_x_1
jr nc, .b_right_of_d_1
cpl
inc a
.b_right_of_d_1
; |y1 - y2|
ld h, a
ld a, c
sub e
jr z, .same_y_1
jr nc, .c_below_e_1
cpl
inc a
.c_below_e_1
; |y1 - y2| - |x1 - x2|
sub h
jr c, .same_y_1
.same_x_1
; compare the y coordinates
ld a, c
cp e
jr z, .same_x_and_y
jr c, .c_directly_below_e
; c directly above e
ld d, DOWN
and a
ret
.c_directly_below_e
ld d, UP
and a
ret
.same_y_1
ld a, b
cp d
jr z, .same_x_and_y
jr c, .b_directly_right_of_d
; b directly left of d
ld d, RIGHT
and a
ret
.b_directly_right_of_d
ld d, LEFT
and a
ret
.same_x_and_y
scf
ret
QueueFollowerFirstStep:
call .QueueFirstStep
jr c, .same
ld [wFollowMovementQueue], a
xor a
ld [wFollowerMovementQueueLength], a
ret
.same
ld a, -1
ld [wFollowerMovementQueueLength], a
ret
.QueueFirstStep:
ld a, [wObjectFollow_Leader]
call GetObjectStruct
ld hl, OBJECT_MAP_X
add hl, bc
ld d, [hl]
ld hl, OBJECT_MAP_Y
add hl, bc
ld e, [hl]
ld a, [wObjectFollow_Follower]
call GetObjectStruct
ld hl, OBJECT_MAP_X
add hl, bc
ld a, d
cp [hl]
jr z, .check_y
jr c, .left
and a
ld a, movement_step + RIGHT
ret
.left
and a
ld a, movement_step + LEFT
ret
.check_y
ld hl, OBJECT_MAP_Y
add hl, bc
ld a, e
cp [hl]
jr z, .same_xy
jr c, .up
and a
ld a, movement_step + DOWN
ret
.up
and a
ld a, movement_step + UP
ret
.same_xy
scf
ret

View file

@ -0,0 +1,270 @@
_HandlePlayerStep::
ld a, [wPlayerStepFlags]
and a
ret z
bit PLAYERSTEP_START_F, a
jr nz, .update_overworld_map
bit PLAYERSTEP_STOP_F, a
jr nz, .update_player_coords
bit PLAYERSTEP_CONTINUE_F, a
jr nz, .finish
ret
.update_overworld_map
ld a, 4
ld [wHandlePlayerStep], a
call UpdateOverworldMap
jr .finish
.update_player_coords
call UpdatePlayerCoords
jr .finish
.finish
call HandlePlayerStep
ld a, [wPlayerStepVectorX]
ld d, a
ld a, [wPlayerStepVectorY]
ld e, a
ld a, [wPlayerBGMapOffsetX]
sub d
ld [wPlayerBGMapOffsetX], a
ld a, [wPlayerBGMapOffsetY]
sub e
ld [wPlayerBGMapOffsetY], a
ret
ScrollScreen::
ld a, [wPlayerStepVectorX]
ld d, a
ld a, [wPlayerStepVectorY]
ld e, a
ldh a, [hSCX]
add d
ldh [hSCX], a
ldh a, [hSCY]
add e
ldh [hSCY], a
ret
HandlePlayerStep:
ld hl, wHandlePlayerStep
ld a, [hl]
and a
ret z
dec [hl]
ld a, [hl]
ld hl, .Jumptable
rst JumpTable
ret
.Jumptable:
dw GetMovementPermissions
dw BufferScreen
dw .mobile
dw .fail2
; The rest are never used. Ever.
dw .fail1
dw .fail1
dw .fail1
dw .fail1
dw .fail1
dw .fail1
dw .fail1
.fail1
ret
.mobile
farcall StubbedTrainerRankings_StepCount
ret
.fail2
ret
UpdatePlayerCoords:
ld a, [wPlayerStepDirection]
and a
jr nz, .check_step_down
ld hl, wYCoord
inc [hl]
ret
.check_step_down
cp UP
jr nz, .check_step_left
ld hl, wYCoord
dec [hl]
ret
.check_step_left
cp LEFT
jr nz, .check_step_right
ld hl, wXCoord
dec [hl]
ret
.check_step_right
cp RIGHT
ret nz
ld hl, wXCoord
inc [hl]
ret
UpdateOverworldMap:
ld a, [wPlayerStepDirection]
and a
jr z, .step_down
cp UP
jr z, .step_up
cp LEFT
jr z, .step_left
cp RIGHT
jr z, .step_right
ret
.step_down
call .ScrollOverworldMapDown
call LoadMapPart
call ScrollMapDown
ret
.step_up
call .ScrollOverworldMapUp
call LoadMapPart
call ScrollMapUp
ret
.step_left
call .ScrollOverworldMapLeft
call LoadMapPart
call ScrollMapLeft
ret
.step_right
call .ScrollOverworldMapRight
call LoadMapPart
call ScrollMapRight
ret
.ScrollOverworldMapDown:
ld a, [wBGMapAnchor]
add 2 * BG_MAP_WIDTH
ld [wBGMapAnchor], a
jr nc, .not_overflowed
ld a, [wBGMapAnchor + 1]
inc a
and %11
or HIGH(vBGMap0)
ld [wBGMapAnchor + 1], a
.not_overflowed
ld hl, wPlayerMetatileY
inc [hl]
ld a, [hl]
cp 2 ; was 1
jr nz, .done_down
ld [hl], 0
call .ScrollMapDataDown
.done_down
ret
.ScrollMapDataDown:
ld hl, wOverworldMapAnchor
ld a, [wMapWidth]
add 3 * 2 ; surrounding tiles
add [hl]
ld [hli], a
ret nc
inc [hl]
ret
.ScrollOverworldMapUp:
ld a, [wBGMapAnchor]
sub 2 * BG_MAP_WIDTH
ld [wBGMapAnchor], a
jr nc, .not_underflowed
ld a, [wBGMapAnchor + 1]
dec a
and %11
or HIGH(vBGMap0)
ld [wBGMapAnchor + 1], a
.not_underflowed
ld hl, wPlayerMetatileY
dec [hl]
ld a, [hl]
cp -1 ; was 0
jr nz, .done_up
ld [hl], $1
call .ScrollMapDataUp
.done_up
ret
.ScrollMapDataUp:
ld hl, wOverworldMapAnchor
ld a, [wMapWidth]
add 3 * 2 ; surrounding tiles
ld b, a
ld a, [hl]
sub b
ld [hli], a
ret nc
dec [hl]
ret
.ScrollOverworldMapLeft:
ld a, [wBGMapAnchor]
ld e, a
and $e0
ld d, a
ld a, e
sub $2
and $1f
or d
ld [wBGMapAnchor], a
ld hl, wPlayerMetatileX
dec [hl]
ld a, [hl]
cp -1
jr nz, .done_left
ld [hl], 1
call .ScrollMapDataLeft
.done_left
ret
.ScrollMapDataLeft:
ld hl, wOverworldMapAnchor
ld a, [hl]
sub 1
ld [hli], a
ret nc
dec [hl]
ret
.ScrollOverworldMapRight:
ld a, [wBGMapAnchor]
ld e, a
and $e0
ld d, a
ld a, e
add $2
and $1f
or d
ld [wBGMapAnchor], a
ld hl, wPlayerMetatileX
inc [hl]
ld a, [hl]
cp 2
jr nz, .done_right
ld [hl], 0
call .ScrollMapDataRight
.done_right
ret
.ScrollMapDataRight:
ld hl, wOverworldMapAnchor
ld a, [hl]
add 1
ld [hli], a
ret nc
inc [hl]
ret

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,172 @@
SelectMenu::
call CheckRegisteredItem
jr c, .NotRegistered
jp UseRegisteredItem
.NotRegistered:
call OpenText
ld b, BANK(MayRegisterItemText)
ld hl, MayRegisterItemText
call MapTextbox
call WaitButton
jp CloseText
MayRegisterItemText:
text_far _MayRegisterItemText
text_end
CheckRegisteredItem:
ld a, [wWhichRegisteredItem]
and a
jr z, .NoRegisteredItem
and REGISTERED_POCKET
rlca
rlca
ld hl, .Pockets
rst JumpTable
ret
.Pockets:
; entries correspond to *_POCKET constants
dw .CheckItem
dw .CheckBall
dw .CheckKeyItem
dw .CheckTMHM
.CheckItem:
ld hl, wNumItems
call .CheckRegisteredNo
jr c, .NoRegisteredItem
inc hl
ld e, a
ld d, 0
add hl, de
add hl, de
call .IsSameItem
jr c, .NoRegisteredItem
and a
ret
.CheckKeyItem:
ld a, [wRegisteredItem]
ld hl, wKeyItems
ld de, 1
call IsInArray
jr nc, .NoRegisteredItem
ld a, [wRegisteredItem]
ld [wCurItem], a
and a
ret
.CheckBall:
ld hl, wNumBalls
call .CheckRegisteredNo
jr nc, .NoRegisteredItem
inc hl
ld e, a
ld d, 0
add hl, de
add hl, de
call .IsSameItem
jr c, .NoRegisteredItem
ret
.CheckTMHM:
jr .NoRegisteredItem
.NoRegisteredItem:
xor a
ld [wWhichRegisteredItem], a
ld [wRegisteredItem], a
scf
ret
.CheckRegisteredNo:
ld a, [wWhichRegisteredItem]
and REGISTERED_NUMBER
dec a
cp [hl]
jr nc, .NotEnoughItems
ld [wCurItemQuantity], a
and a
ret
.NotEnoughItems:
scf
ret
.IsSameItem:
ld a, [wRegisteredItem]
cp [hl]
jr nz, .NotSameItem
ld [wCurItem], a
and a
ret
.NotSameItem:
scf
ret
UseRegisteredItem:
farcall CheckItemMenu
ld a, [wItemAttributeValue]
ld hl, .SwitchTo
rst JumpTable
ret
.SwitchTo:
; entries correspond to ITEMMENU_* constants
dw .CantUse
dw .NoFunction
dw .NoFunction
dw .NoFunction
dw .Current
dw .Party
dw .Overworld
.NoFunction:
call OpenText
call CantUseItem
call CloseText
and a
ret
.Current:
call OpenText
call DoItemEffect
call CloseText
and a
ret
.Party:
call RefreshScreen
call FadeToMenu
call DoItemEffect
call CloseSubmenu
call CloseText
and a
ret
.Overworld:
call RefreshScreen
ld a, 1
ld [wUsingItemWithSelect], a
call DoItemEffect
xor a
ld [wUsingItemWithSelect], a
ld a, [wItemEffectSucceeded]
cp 1
jr nz, ._cantuse
scf
ld a, HMENURETURN_SCRIPT
ldh [hMenuReturn], a
ret
.CantUse:
call RefreshScreen
._cantuse
call CantUseItem
call CloseText
and a
ret

View file

@ -0,0 +1,58 @@
INCLUDE "data/maps/spawn_points.asm"
EnterMapSpawnPoint:
; loads the spawn point in wDefaultSpawnpoint
push hl
push de
ld a, [wDefaultSpawnpoint]
cp SPAWN_N_A
jr z, .spawn_n_a
ld l, a
ld h, 0
add hl, hl
add hl, hl
ld de, SpawnPoints
add hl, de
ld a, [hli]
ld [wMapGroup], a
ld a, [hli]
ld [wMapNumber], a
ld a, [hli]
ld [wXCoord], a
ld a, [hli]
ld [wYCoord], a
.spawn_n_a
pop de
pop hl
ret
IsSpawnPoint:
; Checks if the map loaded in de is a spawn point. Returns carry if it's a spawn point.
ld hl, SpawnPoints
ld c, 0
.loop
ld a, [hl]
cp SPAWN_N_A
jr z, .nope
cp d
jr nz, .next
inc hl
ld a, [hld]
cp e
jr z, .yes
.next
push bc
ld bc, 4 ; length of a spawn table entry
add hl, bc
pop bc
inc c
jr .loop
.nope
and a
ret
.yes
scf
ret

View file

@ -0,0 +1,101 @@
CheckWarpCollision::
; Is this tile a warp?
ld a, [wPlayerTile]
cp COLL_PIT
jr z, .warp
cp COLL_PIT_68
jr z, .warp
and $f0
cp HI_NYBBLE_WARPS
jr z, .warp
and a
ret
.warp
scf
ret
CheckDirectionalWarp::
; If this is a directional warp, clear carry (press the designated button to warp).
; Else, set carry (immediate warp).
ld a, [wPlayerTile]
cp COLL_WARP_CARPET_DOWN
jr z, .directional
cp COLL_WARP_CARPET_LEFT
jr z, .directional
cp COLL_WARP_CARPET_UP
jr z, .directional
cp COLL_WARP_CARPET_RIGHT
jr z, .directional
scf
ret
.directional
xor a
ret
CheckWarpFacingDown:
ld de, 1
ld hl, .blocks
ld a, [wPlayerTile]
call IsInArray
ret
.blocks
db COLL_DOOR
db COLL_DOOR_79
db COLL_STAIRCASE
db COLL_STAIRCASE_73
db COLL_CAVE
db COLL_CAVE_74
db COLL_WARP_PANEL
db COLL_DOOR_75
db COLL_DOOR_7D
db -1
CheckGrassCollision::
ld a, [wPlayerTile]
ld hl, .blocks
ld de, 1
call IsInArray
ret
.blocks
db COLL_CUT_08
db COLL_TALL_GRASS
db COLL_LONG_GRASS
db COLL_CUT_28
db COLL_WATER
db COLL_GRASS_48
db COLL_GRASS_49
db COLL_GRASS_4A
db COLL_GRASS_4B
db COLL_GRASS_4C
db -1
CheckCutCollision:
ld a, c
ld hl, .blocks
ld de, 1
call IsInArray
ret
.blocks
db COLL_CUT_TREE
db COLL_CUT_TREE_1A
db COLL_TALL_GRASS_10
db COLL_TALL_GRASS
db COLL_LONG_GRASS
db COLL_LONG_GRASS_1C
db -1
GetWarpSFX::
ld a, [wPlayerTile]
ld de, SFX_ENTER_DOOR
cp COLL_DOOR
ret z
ld de, SFX_WARP_TO
cp COLL_WARP_PANEL
ret z
ld de, SFX_EXIT_BUILDING
ret

440
engine/overworld/time.asm Normal file
View file

@ -0,0 +1,440 @@
_InitializeStartDay:
call InitializeStartDay
ret
ClearDailyTimers:
xor a
ld [wLuckyNumberDayTimer], a
ld [wUnusedTwoDayTimer], a
ld [wDailyResetTimer], a
ret
InitCallReceiveDelay::
xor a
ld [wTimeCyclesSinceLastCall], a
NextCallReceiveDelay:
ld a, [wTimeCyclesSinceLastCall]
cp 3
jr c, .okay
ld a, 3
.okay
ld e, a
ld d, 0
ld hl, .ReceiveCallDelays
add hl, de
ld a, [hl]
if DEF(_DEBUG)
ld h, a
ld a, BANK(sDebugTimeCyclesSinceLastCall)
call OpenSRAM
ld a, [sDebugTimeCyclesSinceLastCall]
call CloseSRAM
dec a
cp 2
jr nc, .debug_ok
xor 1
ld h, a
.debug_ok
ld a, h
endc
jp RestartReceiveCallDelay
.ReceiveCallDelays:
db 20, 10, 5, 3
CheckReceiveCallTimer:
call CheckReceiveCallDelay ; check timer
ret nc
ld hl, wTimeCyclesSinceLastCall
ld a, [hl]
cp 3
jr nc, .ok
inc [hl]
.ok
call NextCallReceiveDelay ; restart timer
scf
ret
InitOneDayCountdown:
ld a, 1
InitNDaysCountdown:
ld [hl], a
push hl
call UpdateTime
pop hl
inc hl
call CopyDayToHL
ret
CheckDayDependentEventHL:
inc hl
push hl
call CalcDaysSince
call GetDaysSince
pop hl
dec hl
call UpdateTimeRemaining
ret
RestartReceiveCallDelay:
ld hl, wReceiveCallDelay_MinsRemaining
ld [hl], a
call UpdateTime
ld hl, wReceiveCallDelay_StartTime
call CopyDayHourMinToHL
ret
CheckReceiveCallDelay:
ld hl, wReceiveCallDelay_StartTime
call CalcMinsHoursDaysSince
call GetMinutesSinceIfLessThan60
ld hl, wReceiveCallDelay_MinsRemaining
call UpdateTimeRemaining
ret
RestartDailyResetTimer:
ld hl, wDailyResetTimer
jp InitOneDayCountdown
CheckDailyResetTimer::
ld hl, wDailyResetTimer
call CheckDayDependentEventHL
ret nc
xor a
ld hl, wDailyFlags1
ld [hli], a ; wDailyFlags1
ld [hli], a ; wDailyFlags2
ld [hli], a ; wSwarmFlags
ld [hl], a ; wSwarmFlags + 1
ld hl, wDailyRematchFlags
rept 4
ld [hli], a
endr
ld hl, wDailyPhoneItemFlags
rept 4
ld [hli], a
endr
ld hl, wDailyPhoneTimeOfDayFlags
rept 4
ld [hli], a
endr
ld hl, wKenjiBreakTimer
ld a, [hl]
and a
jr z, .RestartKenjiBreakCountdown
dec [hl]
jr nz, .DontRestartKenjiBreakCountdown
.RestartKenjiBreakCountdown:
call SampleKenjiBreakCountdown
.DontRestartKenjiBreakCountdown:
jr RestartDailyResetTimer
SampleKenjiBreakCountdown:
; Generate a random number between 3 and 6
call Random
and %11
add 3
ld [wKenjiBreakTimer], a
ret
StartBugContestTimer:
ld a, BUG_CONTEST_MINUTES
ld [wBugContestMinsRemaining], a
ld a, BUG_CONTEST_SECONDS
ld [wBugContestSecsRemaining], a
call UpdateTime
ld hl, wBugContestStartTime
call CopyDayHourMinSecToHL
ret
CheckBugContestTimer::
ld hl, wBugContestStartTime
call CalcSecsMinsHoursDaysSince
ld a, [wDaysSince]
and a
jr nz, .timed_out
ld a, [wHoursSince]
and a
jr nz, .timed_out
ld a, [wSecondsSince]
ld b, a
ld a, [wBugContestSecsRemaining]
sub b
jr nc, .okay
add 60
.okay
ld [wBugContestSecsRemaining], a
ld a, [wMinutesSince]
ld b, a
ld a, [wBugContestMinsRemaining]
sbc b
ld [wBugContestMinsRemaining], a
jr c, .timed_out
and a
ret
.timed_out
xor a
ld [wBugContestMinsRemaining], a
ld [wBugContestSecsRemaining], a
scf
ret
InitializeStartDay:
call UpdateTime
ld hl, wTimerEventStartDay
call CopyDayToHL
ret
CheckPokerusTick::
ld hl, wTimerEventStartDay
call CalcDaysSince
call GetDaysSince
and a
jr z, .done ; not even a day has passed since game start
ld b, a
farcall ApplyPokerusTick
.done
xor a
ret
SetUnusedTwoDayTimer: ; unreferenced
ld a, 2
ld hl, wUnusedTwoDayTimer
ld [hl], a
call UpdateTime
ld hl, wUnusedTwoDayTimerStartDate
call CopyDayToHL
ret
CheckUnusedTwoDayTimer:
ld hl, wUnusedTwoDayTimerStartDate
call CalcDaysSince
call GetDaysSince
ld hl, wUnusedTwoDayTimer
call UpdateTimeRemaining
ret
UnusedSetSwarmFlag: ; unreferenced
ld hl, wDailyFlags1
set DAILYFLAGS1_FISH_SWARM_F, [hl]
ret
UnusedCheckSwarmFlag: ; unreferenced
and a
ld hl, wDailyFlags1
bit DAILYFLAGS1_FISH_SWARM_F, [hl]
ret nz
scf
ret
RestartLuckyNumberCountdown:
call .GetDaysUntilNextFriday
ld hl, wLuckyNumberDayTimer
jp InitNDaysCountdown
.GetDaysUntilNextFriday:
call GetWeekday
ld c, a
ld a, FRIDAY
sub c
jr z, .friday_saturday
jr nc, .earlier ; could have done "ret nc"
.friday_saturday
add 7
.earlier
ret
_CheckLuckyNumberShowFlag:
ld hl, wLuckyNumberDayTimer
jp CheckDayDependentEventHL
DoMysteryGiftIfDayHasPassed:
ld a, BANK(sMysteryGiftTimer)
call OpenSRAM
ld hl, sMysteryGiftTimer
ld a, [hli]
ld [wTempMysteryGiftTimer], a
ld a, [hl]
ld [wTempMysteryGiftTimer + 1], a
call CloseSRAM
ld hl, wTempMysteryGiftTimer
call CheckDayDependentEventHL
jr nc, .not_timed_out
ld hl, wTempMysteryGiftTimer
call InitOneDayCountdown
call CloseSRAM
farcall ResetDailyMysteryGiftLimitIfUnlocked
.not_timed_out
ld a, BANK(sMysteryGiftTimer)
call OpenSRAM
ld hl, wTempMysteryGiftTimer
ld a, [hli]
ld [sMysteryGiftTimer], a
ld a, [hl]
ld [sMysteryGiftTimer + 1], a
call CloseSRAM
ret
UpdateTimeRemaining:
; If the amount of time elapsed exceeds the capacity of its
; unit, skip this part.
cp -1
jr z, .set_carry
ld c, a
ld a, [hl] ; time remaining
sub c
jr nc, .ok
xor a
.ok
ld [hl], a
jr z, .set_carry
xor a
ret
.set_carry
xor a
ld [hl], a
scf
ret
GetSecondsSinceIfLessThan60: ; unreferenced
ld a, [wDaysSince]
and a
jr nz, GetTimeElapsed_ExceedsUnitLimit
ld a, [wHoursSince]
and a
jr nz, GetTimeElapsed_ExceedsUnitLimit
ld a, [wMinutesSince]
jr nz, GetTimeElapsed_ExceedsUnitLimit
ld a, [wSecondsSince]
ret
GetMinutesSinceIfLessThan60:
ld a, [wDaysSince]
and a
jr nz, GetTimeElapsed_ExceedsUnitLimit
ld a, [wHoursSince]
and a
jr nz, GetTimeElapsed_ExceedsUnitLimit
ld a, [wMinutesSince]
ret
GetHoursSinceIfLessThan24: ; unreferenced
ld a, [wDaysSince]
and a
jr nz, GetTimeElapsed_ExceedsUnitLimit
ld a, [wHoursSince]
ret
GetDaysSince:
ld a, [wDaysSince]
ret
GetTimeElapsed_ExceedsUnitLimit:
ld a, -1
ret
CalcDaysSince:
xor a
jr _CalcDaysSince
CalcHoursDaysSince: ; unreferenced
inc hl
xor a
jr _CalcHoursDaysSince
CalcMinsHoursDaysSince:
inc hl
inc hl
xor a
jr _CalcMinsHoursDaysSince
CalcSecsMinsHoursDaysSince:
inc hl
inc hl
inc hl
ldh a, [hSeconds]
ld c, a
sub [hl]
jr nc, .skip
add 60
.skip
ld [hl], c ; current seconds
dec hl
ld [wSecondsSince], a ; seconds since
_CalcMinsHoursDaysSince:
ldh a, [hMinutes]
ld c, a
sbc [hl]
jr nc, .skip
add 60
.skip
ld [hl], c ; current minutes
dec hl
ld [wMinutesSince], a ; minutes since
_CalcHoursDaysSince:
ldh a, [hHours]
ld c, a
sbc [hl]
jr nc, .skip
add MAX_HOUR
.skip
ld [hl], c ; current hours
dec hl
ld [wHoursSince], a ; hours since
_CalcDaysSince:
ld a, [wCurDay]
ld c, a
sbc [hl]
jr nc, .skip
add 20 * 7
.skip
ld [hl], c ; current days
ld [wDaysSince], a ; days since
ret
CopyDayHourMinSecToHL:
ld a, [wCurDay]
ld [hli], a
ldh a, [hHours]
ld [hli], a
ldh a, [hMinutes]
ld [hli], a
ldh a, [hSeconds]
ld [hli], a
ret
CopyDayToHL:
ld a, [wCurDay]
ld [hl], a
ret
CopyDayHourToHL: ; unreferenced
ld a, [wCurDay]
ld [hli], a
ldh a, [hHours]
ld [hli], a
ret
CopyDayHourMinToHL:
ld a, [wCurDay]
ld [hli], a
ldh a, [hHours]
ld [hli], a
ldh a, [hMinutes]
ld [hli], a
ret

View file

@ -0,0 +1,155 @@
_GetVarAction::
ld a, c
cp NUM_VARS
jr c, .valid
xor a
.valid
ld c, a
ld b, 0
ld hl, .VarActionTable
add hl, bc
add hl, bc
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
inc hl
ld b, [hl]
ld a, b
and RETVAR_EXECUTE
jr nz, .call
ld a, b
and RETVAR_ADDR_DE
ret nz
ld a, [de]
jr .loadstringbuffer2
.call
call _de_
ret
.loadstringbuffer2
ld de, wStringBuffer2
ld [de], a
ret
.VarActionTable:
; entries correspond to VAR_* constants
; RETVAR_STRBUF2: copy [de] to wStringBuffer2
; RETVAR_ADDR_DE: return address in de
; RETVAR_EXECUTE: call function
dwb wStringBuffer2, RETVAR_STRBUF2
dwb wPartyCount, RETVAR_STRBUF2
dwb .BattleResult, RETVAR_EXECUTE
dwb wBattleType, RETVAR_ADDR_DE
dwb wTimeOfDay, RETVAR_STRBUF2
dwb .CountCaughtMons, RETVAR_EXECUTE
dwb .CountSeenMons, RETVAR_EXECUTE
dwb .CountBadges, RETVAR_EXECUTE
dwb wPlayerState, RETVAR_ADDR_DE
dwb .PlayerFacing, RETVAR_EXECUTE
dwb hHours, RETVAR_STRBUF2
dwb .DayOfWeek, RETVAR_EXECUTE
dwb wMapGroup, RETVAR_STRBUF2
dwb wMapNumber, RETVAR_STRBUF2
dwb .UnownCaught, RETVAR_EXECUTE
dwb wEnvironment, RETVAR_STRBUF2
dwb .BoxFreeSpace, RETVAR_EXECUTE
dwb wBugContestMinsRemaining, RETVAR_STRBUF2
dwb wXCoord, RETVAR_STRBUF2
dwb wYCoord, RETVAR_STRBUF2
dwb wSpecialPhoneCallID, RETVAR_STRBUF2
dwb wNrOfBeatenBattleTowerTrainers, RETVAR_STRBUF2
dwb wKurtApricornQuantity, RETVAR_STRBUF2
dwb wCurCaller, RETVAR_ADDR_DE
dwb wBlueCardBalance, RETVAR_ADDR_DE
dwb wBuenasPassword, RETVAR_ADDR_DE
dwb wKenjiBreakTimer, RETVAR_STRBUF2
dwb .CountUncaughtMons, RETVAR_EXECUTE
.CountCaughtMons:
; Caught mons. Saturate at 255.
ld hl, wPokedexCaught
.count_caught_or_seen_mons
ld bc, wEndPokedexCaught - wPokedexCaught
call CountSetBits16
ld a, b
.load_or_saturate
add a, -1
sbc a
or c
jp .loadstringbuffer2
.CountSeenMons:
; Seen mons. Saturate at 255.
ld hl, wPokedexSeen
jr .count_caught_or_seen_mons
.CountUncaughtMons:
; Mons left to catch. Saturate at 255.
ld hl, wPokedexCaught
ld bc, wEndPokedexCaught - wPokedexCaught
call CountSetBits16
ld a, LOW(NUM_POKEMON)
sub c
ld c, a
ld a, HIGH(NUM_POKEMON)
sbc b
jr .load_or_saturate
.CountBadges:
; Number of owned badges.
ld hl, wBadges
ld b, 2
call CountSetBits
ld a, [wNumSetBits]
jp .loadstringbuffer2
.PlayerFacing:
; The direction the player is facing.
ld a, [wPlayerDirection]
and $c
rrca
rrca
jp .loadstringbuffer2
.DayOfWeek:
; The day of the week.
call GetWeekday
jp .loadstringbuffer2
.UnownCaught:
; Number of unique Unown caught.
call .count_unown
ld a, b
jp .loadstringbuffer2
.count_unown
ld hl, wUnownDex
ld b, 0
.loop
ld a, [hli]
and a
ret z
inc b
ld a, b
cp NUM_UNOWN
jr c, .loop
ret
.BoxFreeSpace:
; Remaining slots in the current box.
ld a, BANK(sBoxCount)
call OpenSRAM
ld hl, sBoxCount
ld a, MONS_PER_BOX
sub [hl]
ld b, a
call CloseSRAM
ld a, b
jp .loadstringbuffer2
.BattleResult:
ld a, [wBattleResult]
and ~BATTLERESULT_BITMASK
jp .loadstringbuffer2

View file

@ -0,0 +1,445 @@
HandleNewMap:
call ClearUnusedMapBuffer
call ResetMapBufferEventFlags
call ResetFlashIfOutOfCave
call GetCurrentMapSceneID
call ResetBikeFlags
call ResetMapLockedIDs
ld a, MAPCALLBACK_NEWMAP
call RunMapCallback
HandleContinueMap:
farcall ClearCmdQueue
ld a, MAPCALLBACK_CMDQUEUE
call RunMapCallback
call GetMapTimeOfDay
ld [wMapTimeOfDay], a
ret
ResetMapLockedIDs:
ld e, NUM_MAP_LOCKED_MON_IDS
.mon_loop
ld a, LOCKED_MON_ID_MAP_1 - 1
add a, e
ld l, a
xor a
call LockPokemonID
dec e
jr nz, .mon_loop
ret
EnterMapConnection:
; Return carry if a connection has been entered.
ld a, [wPlayerStepDirection]
and a ; DOWN
jp z, .south
cp UP
jp z, .north
cp LEFT
jp z, .west
cp RIGHT
jp z, .east
ret
.west
ld a, [wWestConnectedMapGroup]
ld [wMapGroup], a
ld a, [wWestConnectedMapNumber]
ld [wMapNumber], a
ld a, [wWestConnectionStripXOffset]
ld [wXCoord], a
ld a, [wWestConnectionStripYOffset]
ld hl, wYCoord
add [hl]
ld [hl], a
ld c, a
ld hl, wWestConnectionWindow
ld a, [hli]
ld h, [hl]
ld l, a
srl c
jr z, .skip_to_load
ld a, [wWestConnectedMapWidth]
add 6
ld e, a
ld d, 0
.loop
add hl, de
dec c
jr nz, .loop
.skip_to_load
ld a, l
ld [wOverworldMapAnchor], a
ld a, h
ld [wOverworldMapAnchor + 1], a
jp .done
.east
ld a, [wEastConnectedMapGroup]
ld [wMapGroup], a
ld a, [wEastConnectedMapNumber]
ld [wMapNumber], a
ld a, [wEastConnectionStripXOffset]
ld [wXCoord], a
ld a, [wEastConnectionStripYOffset]
ld hl, wYCoord
add [hl]
ld [hl], a
ld c, a
ld hl, wEastConnectionWindow
ld a, [hli]
ld h, [hl]
ld l, a
srl c
jr z, .skip_to_load2
ld a, [wEastConnectedMapWidth]
add 6
ld e, a
ld d, 0
.loop2
add hl, de
dec c
jr nz, .loop2
.skip_to_load2
ld a, l
ld [wOverworldMapAnchor], a
ld a, h
ld [wOverworldMapAnchor + 1], a
jp .done
.north
ld a, [wNorthConnectedMapGroup]
ld [wMapGroup], a
ld a, [wNorthConnectedMapNumber]
ld [wMapNumber], a
ld a, [wNorthConnectionStripYOffset]
ld [wYCoord], a
ld a, [wNorthConnectionStripXOffset]
ld hl, wXCoord
add [hl]
ld [hl], a
ld c, a
ld hl, wNorthConnectionWindow
ld a, [hli]
ld h, [hl]
ld l, a
ld b, 0
srl c
add hl, bc
ld a, l
ld [wOverworldMapAnchor], a
ld a, h
ld [wOverworldMapAnchor + 1], a
jp .done
.south
ld a, [wSouthConnectedMapGroup]
ld [wMapGroup], a
ld a, [wSouthConnectedMapNumber]
ld [wMapNumber], a
ld a, [wSouthConnectionStripYOffset]
ld [wYCoord], a
ld a, [wSouthConnectionStripXOffset]
ld hl, wXCoord
add [hl]
ld [hl], a
ld c, a
ld hl, wSouthConnectionWindow
ld a, [hli]
ld h, [hl]
ld l, a
ld b, 0
srl c
add hl, bc
ld a, l
ld [wOverworldMapAnchor], a
ld a, h
ld [wOverworldMapAnchor + 1], a
.done
scf
ret
EnterMapWarp:
call .SaveDigWarp
call .SetSpawn
ld a, [wNextWarp]
ld [wWarpNumber], a
ld a, [wNextMapGroup]
ld [wMapGroup], a
ld a, [wNextMapNumber]
ld [wMapNumber], a
ret
.SaveDigWarp:
call GetMapEnvironment
call CheckOutdoorMap
ret nz
ld a, [wNextMapGroup]
ld b, a
ld a, [wNextMapNumber]
ld c, a
call GetAnyMapEnvironment
call CheckIndoorMap
ret nz
; MOUNT_MOON_SQUARE and TIN_TOWER_ROOF are outdoor maps within indoor maps.
; Dig and Escape Rope should not take you to them.
ld a, [wPrevMapGroup]
cp GROUP_MOUNT_MOON_SQUARE
jr nz, .not_mt_moon_square_or_tin_tower_roof
assert GROUP_MOUNT_MOON_SQUARE == GROUP_TIN_TOWER_ROOF
ld a, [wPrevMapNumber]
cp MAP_MOUNT_MOON_SQUARE
ret z
cp MAP_TIN_TOWER_ROOF
ret z
.not_mt_moon_square_or_tin_tower_roof
ld a, [wPrevWarp]
ld [wDigWarpNumber], a
ld a, [wPrevMapGroup]
ld [wDigMapGroup], a
ld a, [wPrevMapNumber]
ld [wDigMapNumber], a
ret
.SetSpawn:
call GetMapEnvironment
call CheckOutdoorMap
ret nz
ld a, [wNextMapGroup]
ld b, a
ld a, [wNextMapNumber]
ld c, a
call GetAnyMapEnvironment
call CheckIndoorMap
ret nz
ld a, [wNextMapGroup]
ld b, a
ld a, [wNextMapNumber]
ld c, a
; Respawn in Pokémon Centers.
call GetAnyMapTileset
ld a, c
cp TILESET_POKECENTER
jr z, .pokecenter_pokecom
cp TILESET_POKECOM_CENTER
jr z, .pokecenter_pokecom
ret
.pokecenter_pokecom
ld a, [wPrevMapGroup]
ld [wLastSpawnMapGroup], a
ld a, [wPrevMapNumber]
ld [wLastSpawnMapNumber], a
ret
LoadMapTimeOfDay:
ld hl, wVramState
res 6, [hl]
ld a, $1
ld [wSpriteUpdatesEnabled], a
farcall ReplaceTimeOfDayPals
farcall UpdateTimeOfDayPal
call OverworldTextModeSwitch
call .ClearBGMap
call .PushAttrmap
ret
.ClearBGMap:
ld a, HIGH(vBGMap0)
ld [wBGMapAnchor + 1], a
xor a ; LOW(vBGMap0)
ld [wBGMapAnchor], a
ldh [hSCY], a
ldh [hSCX], a
farcall ApplyBGMapAnchorToObjects
ldh a, [rVBK]
push af
ld a, $1
ldh [rVBK], a
xor a
ld bc, vBGMap1 - vBGMap0
hlbgcoord 0, 0
call ByteFill
pop af
ldh [rVBK], a
ld a, "■"
ld bc, vBGMap1 - vBGMap0
hlbgcoord 0, 0
call ByteFill
ret
.PushAttrmap:
decoord 0, 0
call .copy
ldh a, [hCGB]
and a
ret z
decoord 0, 0, wAttrmap
ld a, $1
ldh [rVBK], a
.copy
hlbgcoord 0, 0
ld c, SCREEN_WIDTH
ld b, SCREEN_HEIGHT
.row
push bc
.column
ld a, [de]
inc de
ld [hli], a
dec c
jr nz, .column
ld bc, BG_MAP_WIDTH - SCREEN_WIDTH
add hl, bc
pop bc
dec b
jr nz, .row
ld a, $0
ldh [rVBK], a
ret
LoadMapGraphics:
call LoadMapTileset
call LoadTilesetGFX
xor a
ldh [hMapAnims], a
xor a
ldh [hTileAnimFrame], a
farcall RefreshSprites
call LoadFontsExtra
farcall LoadOverworldFont
ret
LoadMapPalettes:
ld b, SCGB_MAPPALS
jp GetSGBLayout
RefreshMapSprites:
call ClearSprites
farcall InitMapNameSign
call GetMovementPermissions
farcall RefreshPlayerSprite
farcall CheckUpdatePlayerSprite
ld hl, wPlayerSpriteSetupFlags
bit PLAYERSPRITESETUP_SKIP_RELOAD_GFX_F, [hl]
jr nz, .skip
ld hl, wVramState
set 0, [hl]
call SafeUpdateSprites
.skip
ld a, [wPlayerSpriteSetupFlags]
and (1 << PLAYERSPRITESETUP_FEMALE_TO_MALE_F) | (1 << 3) | (1 << 4)
ld [wPlayerSpriteSetupFlags], a
ret
CheckMovingOffEdgeOfMap::
ld a, [wPlayerStepDirection]
cp STANDING
ret z
and a ; DOWN
jr z, .down
cp UP
jr z, .up
cp LEFT
jr z, .left
cp RIGHT
jr z, .right
and a
ret
.down
ld a, [wPlayerMapY]
sub 4
ld b, a
ld a, [wMapHeight]
add a
cp b
jr z, .ok
and a
ret
.up
ld a, [wPlayerMapY]
sub 4
cp -1
jr z, .ok
and a
ret
.left
ld a, [wPlayerMapX]
sub 4
cp -1
jr z, .ok
and a
ret
.right
ld a, [wPlayerMapX]
sub 4
ld b, a
ld a, [wMapWidth]
add a
cp b
jr z, .ok
and a
ret
.ok
scf
ret
GetMapScreenCoords::
ld hl, wOverworldMapBlocks
ld a, [wXCoord]
bit 0, a
jr nz, .odd_x
; even x
srl a
add 1
jr .got_block_x
.odd_x
add 1
srl a
.got_block_x
ld c, a
ld b, 0
add hl, bc
ld a, [wMapWidth]
add MAP_CONNECTION_PADDING_WIDTH * 2
ld c, a
ld b, 0
ld a, [wYCoord]
bit 0, a
jr nz, .odd_y
; even y
srl a
add 1
jr .got_block_y
.odd_y
add 1
srl a
.got_block_y
call AddNTimes
ld a, l
ld [wOverworldMapAnchor], a
ld a, h
ld [wOverworldMapAnchor + 1], a
ld a, [wYCoord]
and 1
ld [wPlayerMetatileY], a
ld a, [wXCoord]
and 1
ld [wPlayerMetatileX], a
ret

File diff suppressed because it is too large Load diff