diff --git a/data/maps/setup_script_pointers.asm b/data/maps/setup_script_pointers.asm index 22b5897d5..b5bc99d23 100644 --- a/data/maps/setup_script_pointers.asm +++ b/data/maps/setup_script_pointers.asm @@ -57,4 +57,5 @@ MapSetupCommands: add_mapsetup BackupMapObjects ; 32 add_mapsetup LoadDisabledSpaces ; 33 add_mapsetup MapCallbackAtEndMapSetup ; 34 - add_mapsetup RepositionMockedPlayerObject ; 35 + add_mapsetup RepositionMockedPlayerObjects_Connection ; 35 + add_mapsetup RepositionMockedPlayerObjects_NextPlayer ; 36 diff --git a/data/maps/setup_scripts.asm b/data/maps/setup_scripts.asm index 2d4048ee7..402cc5a58 100644 --- a/data/maps/setup_scripts.asm +++ b/data/maps/setup_scripts.asm @@ -93,7 +93,7 @@ MapSetupScript_Connection: mapsetup RefreshPlayerCoords mapsetup LoadBlockData mapsetup LoadDisabledSpaces - mapsetup RepositionMockedPlayerObject + mapsetup RepositionMockedPlayerObjects_Connection mapsetup LoadMapTileset mapsetup SaveScreen mapsetup LoadMapObjects @@ -149,6 +149,7 @@ MapSetupScript_NextPlayer: mapsetup GetMapScreenCoords mapsetup LoadBlockData mapsetup LoadDisabledSpaces + mapsetup RepositionMockedPlayerObjects_NextPlayer mapsetup BufferScreen mapsetup LoadMapGraphics mapsetup LoadMapTimeOfDay diff --git a/docs/usage/index.md b/docs/usage/index.md index 5218a03ce..171ba3299 100755 --- a/docs/usage/index.md +++ b/docs/usage/index.md @@ -248,7 +248,7 @@ 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. +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 *RepositionMockedPlayerObjects_Connection*), 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 diff --git a/engine/overworld/player_object.asm b/engine/overworld/player_object.asm index 1d3d75a42..ddf463a04 100644 --- a/engine/overworld/player_object.asm +++ b/engine/overworld/player_object.asm @@ -854,26 +854,60 @@ QueueFollowerFirstStep: scf ret -PositionAllPlayerObjectsExceptCurrent: -; called by MAPSETUP_NEXTPLAYER -; calls RepositionMockedPlayerObject for each player according to wNumLevelPlayers, -; except for the player at wCurTurnPlayer. - ret +RepositionMockedPlayerObjects_NextPlayer: +; map setup command called by MAPSETUP_NEXTPLAYER after LoadBlockData, +; once the new map blocks have been loaded to wOverworldMapBlocks. +; position all players according to wNumLevelPlayers, except for the player at wCurTurnPlayer (which isn't being mocked). + ld a, [wNumLevelPlayers] + maskbits MAX_PLAYERS + cp 1 + ret z ; return if single player mode +.loop + dec a + cp -1 + ret z + ld hl, wCurTurnPlayer + cp [hl] + jr z, .loop + ld [wMockingWhichPlayer], a + push af + call RepositionMockedPlayerObject + pop af + jr .loop -RepositionMockedPlayerObject:: +RepositionMockedPlayerObjects_Connection:: ; map setup command called by map setup script MAPSETUP_CONNECTION after LoadBlockData, ; once the new map blocks have been loaded to wOverworldMapBlocks. -; Only applies during BOARDEVENT_VIEW_MAP_MODE +; During BOARDEVENT_VIEW_MAP_MODE: +; position all players according to wNumLevelPlayers. +; Otherwise: +; position all players according to wNumLevelPlayers, except for the player at wCurTurnPlayer (which isn't being mocked). +; this mode is the same as RepositionMockedPlayerObjects_NextPlayer ldh a, [hCurBoardEvent] cp BOARDEVENT_VIEW_MAP_MODE - ret nz + jr nz, RepositionMockedPlayerObjects_NextPlayer + ld a, [wNumLevelPlayers] + maskbits MAX_PLAYERS +.loop + dec a + cp -1 + ret z + ld [wMockingWhichPlayer], a + push af + call RepositionMockedPlayerObject + pop af + jr .loop -; if map at wPlayer1MapGroup, wPlayer1MapNumber is not the current map, -; or a map connected to the current map, we are done. - ld hl, wPlayer1MapGroup - ld a, [hli] +RepositionMockedPlayerObject: +; if map at wPlayer*MapGroup, wPlayer*MapNumber is not the current map, do nothing. +; otherwise mock this player object. + ld a, [wMockingWhichPlayer] + ld hl, wPlayer1Location + ld bc, wPlayer2Location - wPlayer1Location + call AddNTimes + ld a, [hli] ; wPlayer*MapGroup ld b, a - ld c, [hl] ; wPlayer1MapNumber + ld c, [hl] ; wPlayer*MapNumber ld a, [wMapGroup] cp b jr nz, .next_map_1 @@ -917,10 +951,14 @@ RepositionMockedPlayerObject:: ld [wTempByteValue], a ld hl, .got_sprite_coords push hl - ld a, [wPlayer1XCoord] - ld d, a - ld a, [wPlayer1YCoord] + ld a, [wMockingWhichPlayer] + ld hl, wPlayer1YCoord + ld bc, wPlayer2YCoord - wPlayer1YCoord + call AddNTimes + ld a, [hli] ; wPlayer*YCoord ld e, a + ld a, [hl] ; wPlayer*XCoord + ld d, a jumptable_bc .Jumptable, wTempByteValue .Jumptable: @@ -931,27 +969,21 @@ RepositionMockedPlayerObject:: .got_sprite_coords ret nc ; return if sprite is not in visible part of connected map - xor a ; PLAYER_1 - ld [wMockingWhichPlayer], a - jr MockPlayerObject.loaded_player_mock_coords - -MockPlayerObject_Multiplayer:: -; input: a: value to write into wMockingWhichPlayer - maskbits MAX_PLAYERS - ld [wMockingWhichPlayer], a -; ld a, [wMockingWhichPlayer] +; hl is y,x coordinates: load them into wPlayer*MockYCoord and wPlayer*MockXCoord + push hl + ld a, [wMockingWhichPlayer] ld hl, wPlayer1MockYCoord ld bc, wPlayer2MockYCoord - wPlayer1MockYCoord call AddNTimes - ld d, h - ld e, l - ld a, [wMockingWhichPlayer] - ld hl, wPlayer1YCoord - ld bc, wPlayer2YCoord - wPlayer1YCoord - call AddNTimes - jr MockPlayerObject + pop de + ld [hl], d + inc hl + ld [hl], e + jr MockPlayerObject.loaded_player_mock_coords MockPlayerObject_ViewMapMode:: +; called from .EnterViewMapMode either in board menu or branch space. +; mocks just PLAYER_1 to wMapObject{d:PLAYER_1_MOCK_OBJECT}. farcall RefreshPlayerCoords ; refresh wPlayerObjectYCoord and wPlayerObjectXCoord (not strictly necessary) xor a ; PLAYER_1 ld [wMockingWhichPlayer], a @@ -1226,8 +1258,8 @@ GetWestConnectedSpriteCoords: xor a ret ; nc -; load into wPlayer1MockYCoord and wPlayer1MockXCoord the coordinates -; that correspond to wOverworldMapBlocks address at hl. +; load into h and l the y and x coordinates that correspond to wOverworldMapBlocks address at hl. +; return nc if either X or Y coord is too negative to be visible in the screen. ConvertConnectedOverworldMapBlockAddressToXYCoords: ld bc, -wOverworldMapBlocks + $10000 add hl, bc @@ -1254,20 +1286,20 @@ ConvertConnectedOverworldMapBlockAddressToXYCoords: ; substract 6 tiles from y, substract 6 tiles from x. ; the '6's correspond to the 3 extra blocks in each margin of wOverworldMapBlocks. sub 6 - ld [wPlayer1MockXCoord], a + ld l, a ld a, d sub 6 - ld [wPlayer1MockYCoord], a - call CheckPlayerMockSpriteOutOfScreen + ld h, a + call .CheckPlayerMockSpriteOutOfScreen ret ; c or nc ; return nc if either X or Y coord is too negative to be visible in the screen. ; this corresponds to half-block coords -5 and -6, which are visible by wOverworldMapBlocks, ; but not by the map sprite engine when it adds 4 to X and to Y to obtain wPlayerObject coords. -CheckPlayerMockSpriteOutOfScreen: - ld a, [wPlayer1MockXCoord] +.CheckPlayerMockSpriteOutOfScreen: + ld a, l ; x coord ld b, a - ld a, [wPlayer1MockYCoord] + ld a, h ; y coord ld c, a ld a, -5 cp b diff --git a/ram/wram.asm b/ram/wram.asm index b46374b60..f79746b59 100644 --- a/ram/wram.asm +++ b/ram/wram.asm @@ -2164,10 +2164,11 @@ wBreedingCompatibility:: wMoveGrammar:: wApplyStatLevelMultipliersToEnemy:: wUsePPUp:: -wMockingWhichPlayer:: db -wFailedToFlee:: db +wFailedToFlee:: +wMockingWhichPlayer:: + db wNumFleeAttempts:: db wMonTriedToEvolve:: db @@ -2520,7 +2521,7 @@ wBikeStep:: dw wKurtApricornQuantity:: db wCurLevel:: db -wNumLevelPlayers:: db +wNumLevelPlayers:: db ; 1-4 wPlayer1Id:: db wPlayer2Id:: db wPlayer3Id:: db @@ -2579,7 +2580,7 @@ wPlayer2Location:: player_location wPlayer2 wPlayer3Location:: player_location wPlayer3 wPlayer4Location:: player_location wPlayer4 -; used in MockPlayerObject_* and RepositionMockedPlayerObject +; used in MockPlayerObject_* and RepositionMockedPlayerObjects_Connection ; player 1: used during a View Map mode session or in multiplayer ; player 2-4: used in multiplayer wPlayer1MockYCoord:: db