Multiplayer engine [Commit 1] (#40)

This commit is contained in:
xCrystal
2024-03-02 13:31:58 +01:00
parent 8ac177a144
commit d459273c62
6 changed files with 112 additions and 17 deletions

View File

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

53
data/players/objects.asm Executable file
View File

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

View File

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

View File

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

View File

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

View File

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