Implement clearing level in RAM according to End Space effect, supporting up to 4 clearable stages per level; Implement unlocking levels [Commit 1] (#35)

This commit is contained in:
xCrystal 2024-01-18 19:22:21 +01:00
parent 8757112152
commit 38ffe06a2c
12 changed files with 183 additions and 11 deletions

View File

@ -1,4 +1,4 @@
; Landmarks indexes (see data/level_selection_menu.asm)
; Landmarks indexes (see data/levels/level_selection_menu.asm)
const_def
const LANDMARK_LEVEL_1 ; 00
if DEF(_DEBUG)
@ -9,6 +9,7 @@ if DEF(_DEBUG)
const LANDMARK_DEBUGLEVEL_5 ; 05
endc
DEF NUM_LANDMARKS EQU const_value
assert NUM_LANDMARKS <= 254
; used in CaughtData (legacy)
const_def $7f, -1

View File

@ -1,4 +1,4 @@
; Level indexes (see data/level_selection_menu.asm)
; Level constants (see data/levels/level_selection_menu.asm)
const_def
const LEVEL_1 ; 00
if DEF(_DEBUG)
@ -9,3 +9,17 @@ if DEF(_DEBUG)
const DEBUGLEVEL_5 ; 05
endc
DEF NUM_LEVELS EQU const_value
assert NUM_LEVELS <= 254
; Level stages
const_def
const STAGE_1 ; 00
const STAGE_2 ; 01
const STAGE_3 ; 02
const STAGE_4 ; 03
; requirement types to unlock a given level
const_def
const UNLOCK_WHEN_LEVELS_CLEARED ; 00
const UNLOCK_WHEN_NUMBER_OF_LEVELS_CLEARED ; 01
const UNLOCK_WHEN_TECHNIQUES_CLEARED ; 02

View File

@ -3,6 +3,13 @@ DEF FIRST_SPACE_METATILE EQU $80
DEF FIRST_GREY_SPACE_METATILE EQU $e0
DEF UNIQUE_SPACE_METATILES_MASK EQU %11111
; End Space effect constants (denotes which stage of the level is cleared by this space; equivalent to STAGE_* constants)
const_def
const ES1 ; 0
const ES2 ; 1
const ES3 ; 2
const ES4 ; 3
; Branch Space special direction values
const_def 255, -1
const BRANCH_DIRECTION_INVALID ; -1

41
data/levels/levels.asm Executable file
View File

@ -0,0 +1,41 @@
MACRO level_unlock_req
; a list of levels that must be cleared (each must be in the form of: <Level>, STAGE_*)
if !STRCMP("\1", "LEVELS_CLEARED")
db UNLOCK_WHEN_\1
rept (_NARG - 1) / 2
db \2, \3
shift
shift
endr
; an amount of levels that must be cleared (regardless of stage)
elif !STRCMP("\1", "NUMBER_OF_LEVELS_CLEARED")
db UNLOCK_WHEN_\1
db \2
; a list of techniques that must be cleared
elif !STRCMP("\1", "TECHNIQUES_CLEARED")
db UNLOCK_WHEN_\1
rept _NARG - 1
db \2
shift
endr
; else no requirements
endc
db $ff
REDEF x += 1
ENDM
LevelUnlockRequirements:
DEF x = 0
level_unlock_req NONE ; LEVEL_1 (irrelevant)
if DEF(_DEBUG)
level_unlock_req NONE ; DEBUGLEVEL_1
level_unlock_req LEVELS_CLEARED, DEBUGLEVEL_1, STAGE_1 ; DEBUGLEVEL_2
level_unlock_req LEVELS_CLEARED, DEBUGLEVEL_2, STAGE_1 ; DEBUGLEVEL_3
level_unlock_req LEVELS_CLEARED, DEBUGLEVEL_3, STAGE_1 ; DEBUGLEVEL_4
level_unlock_req LEVELS_CLEARED, DEBUGLEVEL_4, STAGE_1 ; DEBUGLEVEL_5
endc
assert x == NUM_LEVELS

View File

@ -82,7 +82,8 @@
- **wDieRoll**
- **wSpacesLeft**
- Addresses within *wCurMapData* ~ *wCurMapDataEnd*: preserved on save. Initialized when entering a level, and updated accordingly throughout the level. Includes:
- Addresses within *wCurMapData* ~ *wCurMapDataEnd*: preserved on save. Initialized when entering a level (in StartMap), and updated accordingly throughout the level. Includes:
- **wCurLevel**: this one is not initialized in StartMap, but in LevelSelectionMenu, and stays static during the level.
- **wCurTurn**
- **wCurSpace**
- **wCurLevelCoins**
@ -95,6 +96,7 @@
- Addresses within *wPlayerData* ~ *wPlayerDataEnd*: preserved on save. Includes:
- **wUnlockedLevels**: flag array that tracks progression regarding which levels have been unlocked.
- **wClearedLevelsStage<N>**: flag array that tracks progression regarding which levels have been cleared. Each level can have up to four clearable endings (N).
- **wUnlockedTechniques**: flag array that tracks progression regarding which techniques have been unlocked.
- **wCurOverworldMiscPal**

View File

@ -30,6 +30,8 @@ ClearedLevelScreen:
jr z, .loop
.exit
call AddLevelCoinsToBalance
call ClearLevel
call UnlockLevels
ld c, 30
jp DelayFrames
@ -58,3 +60,98 @@ AddLevelCoinsToBalance:
pop bc
farcall GiveCoins
ret
ClearLevel:
ld a, [wCurSpaceEffect] ; End Space effect byte contains STAGE_*
call GetClearedLevelsStageAddress
ld b, SET_FLAG
ld d, 0
ld a, [wCurLevel]
ld e, a
call FlagAction
ret
UnlockLevels:
ld hl, LevelUnlockRequirements
ld de, wUnlockedLevels - 1
ld b, 0
.next_byte
ld c, 8
inc de
ld a, [de]
.next_bit
srl a
push af
call nc, .CheckUnlockLevel ; skip if level is already unlocked
inc b
ld a, b
cp NUM_LEVELS
jr z, .done
; advance hl to next level in LevelUnlockRequirements
.loop
ld a, [hli]
inc a ; cp $ff
jr nz, .loop
pop af
dec c
jr z, .next_byte
jr .next_bit
.done
pop af
ret
; check if the LevelUnlockRequirements[b] at hl for unlocking level b are met.
; return hl pointing to up to the $ff byte of this LevelUnlockRequirements entry.
.CheckUnlockLevel:
push de
push bc
ld a, [hl]
cp $ff
jr z, .reqs_met ; jump if no specific reqs to unlock this level
inc hl
cp UNLOCK_WHEN_LEVELS_CLEARED
jr z, .check_levels_cleared_loop
cp UNLOCK_WHEN_NUMBER_OF_LEVELS_CLEARED
cp UNLOCK_WHEN_TECHNIQUES_CLEARED
.check_levels_cleared_loop
ld a, [hli] ; which level
ld e, a
inc a ; cp $ff
jr z, .reqs_met ; jump when no more required levels and all passed so far
ld a, [hli] ; which stage
push hl
call GetClearedLevelsStageAddress
ld b, CHECK_FLAG
ld d, 0
call FlagAction
pop hl
jr z, .reqs_not_met ; if this level is not cleared, requirements aren't met
jr .check_levels_cleared_loop ; otherwise check next level in list
.reqs_met
pop bc
pop de
ret
.reqs_not_met
pop bc
pop de
ret
; return hl = wClearedLevelsStage* given STAGE_ constant in a
GetClearedLevelsStageAddress:
ld hl, wClearedLevelsStage1
cp ES1
ret z
ld hl, wClearedLevelsStage2
cp ES2
ret z
ld hl, wClearedLevelsStage3
cp ES3
ret z
ld hl, wClearedLevelsStage4
ret
INCLUDE "data/levels/levels.asm"

View File

@ -118,6 +118,13 @@ LevelSelectionMenu::
jr .main_loop
.enter_level
ld a, [wLevelSelectionMenuCurrentLandmark]
ld e, a
ld d, 0
ld hl, LandmarkToLevelTable
add hl, de
ld a, [hl]
ld [wCurLevel], a
ld a, [wLevelSelectionMenuCurrentLandmark]
call LevelSelectionMenu_GetLandmarkSpawnPoint
ld [wDefaultSpawnpoint], a
@ -521,12 +528,10 @@ LevelSelectionMenu_GetLandmarkName::
LevelSelectionMenu_GetLandmarkSpawnPoint:
; Return SPAWN_* (a) of landmark a.
push hl
ld hl, LevelSelectionMenu_Landmarks + $5
ld bc, LevelSelectionMenu_Landmarks.landmark2 - LevelSelectionMenu_Landmarks.landmark1
call AddNTimes
ld a, [hl]
pop hl
ret
LevelSelectionMenu_GetValidKeys:
@ -744,7 +749,7 @@ _LevelSelectionMenuHandleTransition:
xor a
ret
INCLUDE "data/level_selection_menu.asm"
INCLUDE "data/levels/level_selection_menu.asm"
LevelSelectionMenuGFX:
INCBIN "gfx/level_selection_menu/background.2bpp.lz"

View File

@ -37,7 +37,7 @@ DebugLevel2_Map1_MapEvents:
DebugLevel2_Map1_MapSpaces:
space 6, 16, $0, 1 ; 0
space 6, 14, $0, 2 ; 1
space 6, 12, .BS1 ; 2 .BS1
space 6, 12, .BS1 ; 2
space 6, 10, $0, GO_UP ; 3
space 20, 2, $0, 5 ; 4
space 22, 2, $0, 6 ; 5
@ -47,7 +47,7 @@ DebugLevel2_Map1_MapSpaces:
space 22, 14, $0, 10 ; 9
space 20, 14, $0, 11 ; 10
space 20, 16, $0, 12 ; 11
space 20, 18, $0, 12 ; 12
space 20, 18, ES1, 12 ; 12
space 4, 12, $0, 14 ; 13
space 2, 12, $0, 15 ; 14

View File

@ -30,4 +30,4 @@ DebugLevel2_Map2_MapSpaces:
space 4, 2, $0, 8 ; 7
space 6, 2, $0, 9 ; 8
space 6, 6, $0, 10 ; 9
space 6, 8, $0, 10 ; 10
space 6, 8, ES2, 10 ; 10

View File

@ -105,7 +105,7 @@ DebugLevel5_Map1_MapSpaces:
space 8, 8, $0, 32 ; 31
space 10, 8, $0, 33 ; 32
space 12, 8, $0, 34 ; 33
space 14, 8, $0, 34 ; 34
space 14, 8, ES1, 34 ; 34
space 6, 2, $0, 36 ; 35
space 6, 0, .BS36 ; 36

View File

@ -2441,7 +2441,11 @@ wMooMooBerries:: db
wUndergroundSwitchPositions:: db
wFarfetchdPosition:: db
wUnlockedLevels:: flag_array NUM_LANDMARKS
wUnlockedLevels:: flag_array NUM_LEVELS
wClearedLevelsStage1:: flag_array NUM_LEVELS
wClearedLevelsStage2:: flag_array NUM_LEVELS
wClearedLevelsStage3:: flag_array NUM_LEVELS
wClearedLevelsStage4:: flag_array NUM_LEVELS
wUnlockedTechniques:: flag_array NUM_TECHNIQUES
@ -2560,6 +2564,7 @@ wYCoord:: db
wXCoord:: db
wScreenSave:: ds SCREEN_META_WIDTH * SCREEN_META_HEIGHT
wCurLevel:: db
wCurTurn:: dw
wCurSpace:: db
wCurLevelCoins:: ds 3