diff --git a/constants/player_constants.asm b/constants/player_constants.asm index 9d13adaa0..77b9688d7 100755 --- a/constants/player_constants.asm +++ b/constants/player_constants.asm @@ -17,3 +17,11 @@ DEF PLAYERDATA_FRONTPIC rw DEF PLAYERDATA_BACKPIC rw DEF PLAYERDATA_PIC_PAL rw DEF PLAYERDATA_LENGTH EQU _RS +; see data/players/objects.asm + const_def + const PLAYER_DEFAULT ; 0 + const PLAYER_YOUNGSTER_1 ; 1 + const PLAYER_YOUNGSTER_2 ; 2 + const PLAYER_YOUNGSTER_3 ; 3 + const PLAYER_BUG_CATCHER_1 ; 4 +DEF NUM_PLAYER_CHARACTERS EQU const_value diff --git a/data/players/objects.asm b/data/players/objects.asm new file mode 100755 index 000000000..b48f74d0f --- /dev/null +++ b/data/players/objects.asm @@ -0,0 +1,53 @@ +PlayerObjects: + table_width 2, PlayerObjects + dw .Default ; PLAYER_DEAFULT + dw .Youngster1 ; PLAYER_YOUNGSTER_1 + dw .Youngster2 ; PLAYER_YOUNGSTER_2 + dw .Youngster3 ; PLAYER_YOUNGSTER_3 + dw .BugCatcher1 ; PLAYER_BUG_CATCHER_1 + assert_table_length NUM_PLAYER_CHARACTERS + +.Default: + db -1 ; MAPOBJECT_OBJECT_STRUCT_ID + object_event 0, 0, SPRITE_CHRIS, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, PAL_NPC_RED, OBJECTTYPE_SCRIPT, 0, ObjectEvent, -1 +.DefaultFields: +; [wPlayerGender], [wPlayerState], sprite id, palette + db 0, PLAYER_NORMAL, SPRITE_CHRIS, PAL_NPC_RED << 4 | OBJECTTYPE_SCRIPT + db 1 << PLAYERGENDER_FEMALE_F, PLAYER_NORMAL, SPRITE_KRIS, PAL_NPC_BLUE << 4 | OBJECTTYPE_SCRIPT + db 0, PLAYER_SURF, SPRITE_SURF, PAL_NPC_RED << 4 | OBJECTTYPE_SCRIPT + db 1 << PLAYERGENDER_FEMALE_F, PLAYER_SURF, SPRITE_SURF, PAL_NPC_BLUE << 4 | OBJECTTYPE_SCRIPT + db 0, PLAYER_BIKE, SPRITE_CHRIS_BIKE, PAL_NPC_RED << 4 | OBJECTTYPE_SCRIPT + db 1 << PLAYERGENDER_FEMALE_F, PLAYER_BIKE, SPRITE_KRIS_BIKE, PAL_NPC_BLUE << 4 | OBJECTTYPE_SCRIPT + db -1 + +.Youngster1: + object_event 0, 0, SPRITE_YOUNGSTER, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, PAL_NPC_RED, OBJECTTYPE_SCRIPT, 0, ObjectEvent, -1 +; [wPlayerState], sprite id, palette + db PLAYER_NORMAL, SPRITE_YOUNGSTER, PAL_NPC_RED << 4 | OBJECTTYPE_SCRIPT + db PLAYER_SURF, SPRITE_SURF, PAL_NPC_RED << 4 | OBJECTTYPE_SCRIPT + db PLAYER_BIKE, SPRITE_CHRIS_BIKE, PAL_NPC_RED << 4 | OBJECTTYPE_SCRIPT + db -1 + +.Youngster2: + object_event 0, 0, SPRITE_YOUNGSTER, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, PAL_NPC_BLUE, OBJECTTYPE_SCRIPT, 0, ObjectEvent, -1 +; [wPlayerState], sprite id, palette + db PLAYER_NORMAL, SPRITE_YOUNGSTER, PAL_NPC_BLUE << 4 | OBJECTTYPE_SCRIPT + db PLAYER_SURF, SPRITE_YOUNGSTER, PAL_NPC_BLUE << 4 | OBJECTTYPE_SCRIPT + db PLAYER_BIKE, SPRITE_YOUNGSTER, PAL_NPC_BLUE << 4 | OBJECTTYPE_SCRIPT + db -1 + +.Youngster3: + object_event 0, 0, SPRITE_YOUNGSTER, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, PAL_NPC_GREEN, OBJECTTYPE_SCRIPT, 0, ObjectEvent, -1 +; [wPlayerState], sprite id, palette + db PLAYER_NORMAL, SPRITE_YOUNGSTER, PAL_NPC_GREEN << 4 | OBJECTTYPE_SCRIPT + db PLAYER_SURF, SPRITE_YOUNGSTER, PAL_NPC_GREEN << 4 | OBJECTTYPE_SCRIPT + db PLAYER_BIKE, SPRITE_YOUNGSTER, PAL_NPC_GREEN << 4 | OBJECTTYPE_SCRIPT + db -1 + +.BugCatcher1: + object_event 0, 0, SPRITE_BUG_CATCHER, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, PAL_NPC_BROWN, OBJECTTYPE_SCRIPT, 0, ObjectEvent, -1 +; [wPlayerState], sprite id, palette + db PLAYER_NORMAL, SPRITE_YOUNGSTER, PAL_NPC_BROWN << 4 | OBJECTTYPE_SCRIPT + db PLAYER_SURF, SPRITE_YOUNGSTER, PAL_NPC_BROWN << 4 | OBJECTTYPE_SCRIPT + db PLAYER_BIKE, SPRITE_YOUNGSTER, PAL_NPC_BROWN << 4 | OBJECTTYPE_SCRIPT + db -1 diff --git a/docs/usage/index.md b/docs/usage/index.md index e1a68b2dd..3deccac4a 100755 --- a/docs/usage/index.md +++ b/docs/usage/index.md @@ -228,13 +228,15 @@ The view map mode is like a moving camera. The player sprite stays static while Off-limits means that tiles that have special collision value *COLL_OUT_OF_BOUNDS* (specifically defined for this) can't be crossed, and that map limits can't be crossed unless there is a connection to another map. Additionally, a maximum view map mode range that the player is allowed in either direction, counting from the coordinates where view map mode was started, is governed by *wViewMapModeRange* (in number of tiles). Initialization or unlocking of *wViewMapModeRange* is your design choice. -View map mode is exited by pressing the B button. Exiting view map mode effectively triggers a warp to where the player was at before entering view map mode, with whatever the state was. - ![View map mode](img/view_map_mode.bmp) -While in view map mode, *hCurBoardEvent* contains *BOARDEVENT_VIEW_MAP_MODE*. Transition from view map mode to the "regular" overworld occurs with *hCurBoardEvent* containing *BOARDEVENT_REDISPLAY_MENU* (if view map mode entered from board menu) or *BOARDEVENT_RESUME_BRANCH* (if view map mode entered from branch space). As with other board event values, they have a specific handler in *CheckBoardEvent*. +While in view map mode, *hCurBoardEvent* contains *BOARDEVENT_VIEW_MAP_MODE*. When view map mode is entered, the player sprite is temporarily "turned into" an NPC by copying its data to the last object slot in *wMapObjects* (see *MockPlayerObject*), whilst the actual player sprite is made transparent. -A rough workflow of the view map mode engine is available in [docs/develop/workflows.md](docs/develop/workflows.asm). View map mode player movement logic is at *DoPlayerMovement* in [engine/overworld/player_movement.md](engine/overworld/player_movement.asm) along with other types of player movement. Logic for entering view map mode is embedded into the board menu code or the branch space code. When view map mode is entered, the player sprite is temporarily "turned into" an NPC (see *MockPlayerObject*), whilst the actual player sprite is made transparent. +View map mode is exited by pressing the B button. Exiting view map mode effectively triggers a warp to where the player was at before entering view map mode, with whatever the state was. Transition from view map mode to the "regular" overworld occurs with *hCurBoardEvent* containing *BOARDEVENT_REDISPLAY_MENU* (if view map mode entered from board menu) or *BOARDEVENT_RESUME_BRANCH* (if view map mode entered from branch space). As with other board event values, they have a specific handler in *CheckBoardEvent*. + +View map mode player movement logic is at *DoPlayerMovement* in [engine/overworld/player_movement.md](engine/overworld/player_movement.asm) along with other types of player movement. Logic for entering view map mode is embedded into the board menu code or the branch space code. + +A rough workflow of the view map mode engine is available in [docs/develop/workflows.md](docs/develop/workflows.asm). ## Map state preservation @@ -246,6 +248,8 @@ The backing up of disabled spaces to WRAM is done individually per space the mom When a map is entered during a level, if the map has been visited before during the current level, there will be backup disabled space and map object data for it. Its existence is looked up in *wDisabledSpacesBackups* and *wMapObjectsBackups* by searching for an entry matching the map group and map id of the map being entered (*LoadDisabledSpaces* map setup command and an extension to *CopyMapObjectEvents* all the way from the *LoadMapAttributes* map setup command). +Regarding map connections, note that, while a mocked player sprite during view map mode remains visible when crossing a connection by "respawning" it in the destination map (see *RepositionMockedPlayerObject*), the "respawning" of other map objects across map connections isn't supported. If you for example put an NPC too close to a map connection, it will disappear from the screen when crossing the connection, just like in Pokemon Crystal. + # Game navigation and progression The main menus (in some cases just mocks) outside the overworld provided in pokecrystal-board are: diff --git a/engine/overworld/events.asm b/engine/overworld/events.asm index 97d6ad21a..df3889e69 100644 --- a/engine/overworld/events.asm +++ b/engine/overworld/events.asm @@ -153,6 +153,19 @@ StartMap: cp MAPSETUP_ENTERLEVEL jr nz, .not_starting_level +; initialize board players + ld a, 1 + ld [wNumLevelPlayers], a + ld hl, wPlayer1Id + ld a, PLAYER_DEFAULT + ld [hli], a ; wPlayer1Id + ld a, PLAYER_YOUNGSTER_1 + ld [hli], a ; wPlayer2Id + ld a, PLAYER_YOUNGSTER_3 + ld [hli], a ; wPlayer3Id + ld a, PLAYER_BUG_CATCHER_1 + ld [hl], a ; wPlayer4Id + ; initialize board state xor a ld hl, wCurTurn diff --git a/engine/overworld/player_object.asm b/engine/overworld/player_object.asm index 637651451..4d479c5d8 100644 --- a/engine/overworld/player_object.asm +++ b/engine/overworld/player_object.asm @@ -940,18 +940,29 @@ MockPlayerObject:: ; refresh wPlayerObjectYCoord and wPlayerObjectXCoord (not strictly necessary) farcall RefreshPlayerCoords ; copy default sprite object to the last object struct - ld hl, .DefaultPlayerObject + ld hl, PlayerObjects.Default ld de, wMapObject{d:LAST_OBJECT} - ld bc, OBJECT_EVENT_SIZE + 1 + ld a, -1 ; MAPOBJECT_OBJECT_STRUCT_ID + ld [de], a + inc de + ld bc, OBJECT_EVENT_SIZE call CopyBytes -; adjust palette number - ld a, [wPlayerCharacter] - ld e, PLAYERDATA_OW_PAL - call GetPlayerField - add PAL_NPC ; convert from PAL_OW to PAL_NPC - swap a - or OBJECTTYPE_SCRIPT +; adjust sprite id and palette number + ld hl, PlayerObjects.Default + (PlayerObjects.DefaultFields - PlayerObjects.Default) +.loop + ld a, [wPlayerGender] + cp [hl] + inc hl + jr nz, .next1 + ld a, [wPlayerState] + cp [hl] + inc hl + jr nz, .next2 +; found a match + ld a, [hli] ; sprite + ld [wMapObject{d:LAST_OBJECT}Sprite], a + ld a, [hl] ; palette | objecttype ld [wMapObject{d:LAST_OBJECT}Palette], a ; also wMapObject{d:LAST_OBJECT}Type ; adjust sprite id @@ -985,10 +996,6 @@ MockPlayerObject:: call UnmaskCopyMapObjectStruct ret -.DefaultPlayerObject: - db -1 ; MAPOBJECT_OBJECT_STRUCT_ID - object_event 0, 0, SPRITE_CHRIS, SPRITEMOVEDATA_STANDING_DOWN, 0, 0, -1, -1, PAL_NPC_RED, OBJECTTYPE_SCRIPT, 0, ObjectEvent, -1 - GetSouthConnectedSpriteCoords: ; ycoord / 2 <= 2 ld a, e @@ -1192,3 +1199,5 @@ CheckPlayerMockSpriteOutOfScreen: ret z ; nc scf ret + +INCLUDE "data/players/objects.asm" diff --git a/ram/wram.asm b/ram/wram.asm index c444c6d60..7d732b441 100644 --- a/ram/wram.asm +++ b/ram/wram.asm @@ -2531,6 +2531,12 @@ wBikeStep:: dw wKurtApricornQuantity:: db wCurLevel:: db +wNumLevelPlayers:: db +wPlayer1Id:: db +wPlayer2Id:: db +wPlayer3Id:: db +wPlayer4Id:: db + wDefaultLevelSelectionMenuLandmark:: db wLevelSelectionMenuEntryEventQueue:: flag_array NUM_LSM_EVENTS @@ -2571,6 +2577,8 @@ wCurSpace:: db wCurLevelCoins:: ds 3 wCurLevelExp:: ds 3 +wCurTurnPlayer:: db + wCurSpaceStruct:: space_struct wCurSpace wCurSpaceStructEnd::