Multiplayer engine: player mocking and player turn rotation stuff [Commit 3] (#40)

This commit is contained in:
xCrystal
2024-03-03 14:24:01 +01:00
parent 49040c9bdd
commit fb8edba97e
13 changed files with 177 additions and 41 deletions

View File

@@ -17,14 +17,16 @@ BoardMenuScript::
ldh a, [hCurBoardEvent]
cp BOARDEVENT_REDISPLAY_MENU
ret z
; in multiplayer, a turn from wCurTurn involves all players:
; skip autosave and don't update wCurTurn if [wCurTurnPlayer] != PLAYER_1
ld a, [wCurTurnPlayer]
and a ; PLAYER_1?
jr nz, .next
.player_1
; save after opentext to reanchor map first
; save before processing variables like wCurTurn due to BoardMenuScript reentry after game reset
farcall AutoSaveGameInOverworld
; reset turn-scoped variables (wDieRoll, wSpacesLeft) and update wCurTurn
ld hl, wTurnData
ld bc, wTurnDataEnd - wTurnData
xor a
call ByteFill
; update wCurTurn and reset turn-scoped variables (wDieRoll, wSpacesLeft)
ld hl, wCurTurn
ld a, [hli]
cp MAX_TURNS / $100
@@ -39,6 +41,10 @@ BoardMenuScript::
inc [hl]
jr .next
.next
ld hl, wTurnData
ld bc, wTurnDataEnd - wTurnData
xor a
call ByteFill
; apply wCurTurn and wDieRoll in overworld HUD
call RefreshOverworldHUD
; reset turn-scoped event flags

View File

@@ -0,0 +1,15 @@
GotoNextPlayerScript::
callasm .RotateTurnPlayer
reloadmaptonextplayer
end
.RotateTurnPlayer:
ld hl, wNumLevelPlayers
ld a, [wCurTurnPlayer]
inc a
cp [hl]
jr c, .this_player_ok
xor a ; PLAYER_1
.this_player_ok
ld [wCurTurnPlayer], a
ret

View File

@@ -143,8 +143,8 @@ LandedInRegularSpaceScript_AfterSpaceEffect:
ld [hl], a
; backup the disabled space to preserve it on map reload
call BackupDisabledSpace
; trigger end of turn
ld a, BOARDEVENT_END_TURN
; trigger end of this player's turn
ld a, BOARDEVENT_END_PLAYER_TURN
ldh [hCurBoardEvent], a
ret

View File

@@ -149,13 +149,15 @@ StartMap:
farcall InitCallReceiveDelay
call ClearJoypad
ld a, [hMapEntryMethod]
ldh a, [hMapEntryMethod]
cp MAPSETUP_ENTERLEVEL
jr nz, .not_starting_level
; initialize board players
ld a, 1
ld [wNumLevelPlayers], a
xor a ; PLAYER_1
ld [wCurTurnPlayer], a
ld hl, wPlayer1Id
ld a, [wPlayerGender] ; PLAYER_DEFAULT_MALE or PLAYER_DEFAULT_FEMALE
ld [hli], a ; wPlayer1Id
@@ -391,13 +393,13 @@ PlayerEvents:
call CheckTimeEvents
jr c, .ok
; BOARDEVENT_END_TURN is used as turn cleanup after BOARDEVENT_HANDLE_BOARD.
; BOARDEVENT_END_PLAYER_TURN is used as turn cleanup after BOARDEVENT_HANDLE_BOARD.
; when we make it here, it means there's finally nothing else to do (e.g. a trainer),
; so return with BOARDEVENT_DISPLAY_MENU for the next MapEvents iteration.
; so return with BOARDEVENT_GOTO_NEXT_PLAYER for the next MapEvents iteration.
ldh a, [hCurBoardEvent]
cp BOARDEVENT_END_TURN
cp BOARDEVENT_END_PLAYER_TURN
jr nz, .continue
ld a, BOARDEVENT_DISPLAY_MENU
ld a, BOARDEVENT_GOTO_NEXT_PLAYER
ldh [hCurBoardEvent], a
xor a
ret
@@ -425,18 +427,35 @@ CheckBoardEvent:
.Jumptable:
table_width 2, .Jumptable
dw .none
dw .menu ; BOARDEVENT_DISPLAY_MENU
dw .board ; BOARDEVENT_HANDLE_BOARD
dw .none ; BOARDEVENT_END_TURN
dw .viewmap ; BOARDEVENT_VIEW_MAP_MODE
dw .menu ; BOARDEVENT_REDISPLAY_MENU
dw .branch ; BOARDEVENT_RESUME_BRANCH
dw .menu ; BOARDEVENT_DISPLAY_MENU
dw .board ; BOARDEVENT_HANDLE_BOARD
dw .none ; BOARDEVENT_END_PLAYER_TURN
dw .viewmap ; BOARDEVENT_VIEW_MAP_MODE
dw .menu ; BOARDEVENT_REDISPLAY_MENU
dw .branch ; BOARDEVENT_RESUME_BRANCH
dw .nextplayer ; BOARDEVENT_GOTO_NEXT_PLAYER
assert_table_length NUM_BOARD_EVENTS + 1
.none
xor a
ret
.nextplayer
; in single player mode, this board event is just a bridge to BOARDEVENT_DISPLAY_MENU
ld a, [wNumLevelPlayers]
dec a
jr z, .single_player
ld a, BANK(GotoNextPlayerScript)
ld hl, GotoNextPlayerScript
call CallScript
scf
ret
.single_player
ld a, BOARDEVENT_DISPLAY_MENU
ld [hCurBoardEvent], a
; fallthrough
.menu
ld a, BANK(BoardMenuScript)
ld hl, BoardMenuScript

View File

@@ -935,16 +935,15 @@ MockAllPlayerObjectsExceptCurrent:
ret
MockPlayerObject_Multiplayer::
maskbits MAX_PLAYERS
ld [wMockingWhichPlayer], a
; ld a, [wMockingWhichPlayer]
maskbits MAX_PLAYERS
ld hl, wPlayer1MockYCoord
ld bc, wPlayer2MockYCoord - wPlayer1MockYCoord
call AddNTimes
ld d, h
ld e, l
ld a, [wMockingWhichPlayer]
maskbits MAX_PLAYERS
ld hl, wPlayer1YCoord
ld bc, wPlayer2YCoord - wPlayer1YCoord
call AddNTimes
@@ -984,8 +983,9 @@ MockPlayerObject:
ld l, a
; copy player object to the last map object entry
ld de, wMapObject{d:PLAYER_1_MOCK_OBJECT}
ld a, -1 ; MAPOBJECT_OBJECT_STRUCT_ID
ld de, MAPOBJECT_OBJECT_STRUCT_ID
call .GetMockingPlayerObjectField
ld a, -1
ld [de], a
inc de
ld bc, OBJECT_EVENT_SIZE
@@ -999,10 +999,14 @@ MockPlayerObject:
inc hl
jr nz, .next
; found a match
ld de, MAPOBJECT_SPRITE
call .GetMockingPlayerObjectField
ld a, [hli] ; sprite
ld [wMapObject{d:PLAYER_1_MOCK_OBJECT}Sprite], a
ld [de], a
ld de, MAPOBJECT_PALETTE ; also MAPOBJECT_TYPE
call .GetMockingPlayerObjectField
ld a, [hl] ; palette | objecttype
ld [wMapObject{d:PLAYER_1_MOCK_OBJECT}Palette], a ; also wMapObject{d:PLAYER_1_MOCK_OBJECT}Type
ld [de], a
jr .copy_player_coords
.next
inc hl
@@ -1018,19 +1022,28 @@ MockPlayerObject:
; copy player's coordinates
ld a, [wMockingWhichPlayer]
maskbits MAX_PLAYERS
ld hl, wPlayer1MockYCoord
ld bc, wPlayer2MockYCoord - wPlayer1MockYCoord
call AddNTimes
ld de, wMapObject{d:PLAYER_1_MOCK_OBJECT}YCoord
ld de, MAPOBJECT_Y_COORD
call .GetMockingPlayerObjectField
ld a, [hli]
add 4
ld [de], a
inc de
ld a, [hl] ; wPlayer1MockXCoord
ld a, [hl] ; wPlayer*MockXCoord
add 4
ld [de], a ; wMapObject{d:PLAYER_1_MOCK_OBJECT}XCoord
ld [de], a ; wMapObject{d:PLAYER_*_MOCK_OBJECT}XCoord
; set facing direction
; player objects have SPRITEMOVEDATA_STANDING_DOWN by default.
; the only instance of a player object possibly not looking down is PLAYER_1
; in view map mode from a branch space (only PLAYER_1 can enter view map mode).
ldh a, [hCurBoardEvent]
cp BOARDEVENT_VIEW_MAP_MODE
jr nz, .facing_direction_done
ld a, [wMockingWhichPlayer]
and a ; cp PLAYER_1
jr nz, .facing_direction_done
ld a, [wBeforeViewMapDirection]
srl a
srl a
@@ -1039,6 +1052,7 @@ MockPlayerObject:
add b
ld [wMapObject{d:PLAYER_1_MOCK_OBJECT}Movement], a
.facing_direction_done
; display mocked player object
; it will go to the last wMapObjects slot and to whichever wObjectStructs slot
; wObjectStructs[n][MAPOBJECT_OBJECT_STRUCT_ID] links both structs
@@ -1046,6 +1060,22 @@ MockPlayerObject:
call UnmaskCopyMapObjectStruct
ret
.GetMockingPlayerObjectField:
; Return the location of map object's field de for [wMockingWhichPlayer] object in de. Preserves hl.
push hl
ld a, [wMockingWhichPlayer]
ld c, a
ld a, NUM_OBJECTS - 1
sub c
call GetMapObject
ld h, b
ld l, c
add hl, de
ld d, h
ld e, l
pop hl
ret
GetSouthConnectedSpriteCoords:
; ycoord / 2 <= 2
ld a, e

View File

@@ -237,6 +237,7 @@ ScriptCommandTable:
dw Script_exitoverworld ; aa
dw Script_reloadmapafterviewmapmode ; ab
dw Script_talkerscript ; ac
dw Script_reloadmaptonextplayer ; ad
assert_table_length NUM_EVENT_COMMANDS
StartScript:
@@ -1227,8 +1228,6 @@ Script_reloadmapafterbattle:
jp Script_reloadmap
Script_reloadmapafterviewmapmode:
xor a
ld [wBattleScriptFlags], a
ld a, MAPSETUP_EXITVIEWMAP
ldh [hMapEntryMethod], a
ld a, SPAWN_FROM_RAM
@@ -1269,6 +1268,16 @@ Script_reloadmapafterviewmapmode:
call StopScript
ret
Script_reloadmaptonextplayer:
ld a, MAPSETUP_NEXTPLAYER
ldh [hMapEntryMethod], a
ld a, SPAWN_FROM_RAM
ld [wDefaultSpawnpoint], a
ld a, MAPSTATUS_ENTER
call LoadMapStatus
call StopScript
ret
Script_reloadmap:
xor a
ld [wBattleScriptFlags], a
@@ -2185,6 +2194,7 @@ Script_warpfacing:
; fallthrough
Script_warp:
call GetScriptByte
ld [wMapGroup], a
call GetScriptByte
ld [wMapNumber], a

View File

@@ -6,7 +6,7 @@ EnterMapSpawnPoint:
push de
ld a, [wDefaultSpawnpoint]
cp SPAWN_N_A
jr z, .spawn_n_a
jr z, .done
cp SPAWN_FROM_RAM
jr z, .spawn_from_ram
ld l, a
@@ -28,16 +28,35 @@ EnterMapSpawnPoint:
ret
.spawn_from_ram
ldh a, [hMapEntryMethod]
cp MAPSETUP_EXITVIEWMAP
jr nz, .not_exit_view_map
; exiting from View Map mode
ld a, [wBeforeViewMapMapGroup]
ld [wMapGroup], a
ld a, [wBeforeViewMapMapNumber]
ld [wMapNumber], a
ld a, [wBeforeViewMapXCoord]
ld [wXCoord], a
ld a, [wBeforeViewMapYCoord]
ld [wYCoord], a
.spawn_n_a
ld a, [wBeforeViewMapXCoord]
ld [wXCoord], a
jr .done
.not_exit_view_map
; "moving camera" to next turn player
ld a, [wCurTurnPlayer]
ld hl, wPlayer1MapGroup
ld bc, wPlayer2MapGroup - wPlayer1MapGroup
call AddNTimes
ld a, [hli]
ld [wMapGroup], a
ld a, [hli]
ld [wMapNumber], a
ld a, [hli]
ld [wXCoord], a
ld a, [hl]
ld [wYCoord], a
.done
pop de
pop hl
ret