diff --git a/constants/serial_constants.asm b/constants/serial_constants.asm index 71c4e6de..71057859 100644 --- a/constants/serial_constants.asm +++ b/constants/serial_constants.asm @@ -42,7 +42,10 @@ DEF SERIAL_RN_PREAMBLE_LENGTH EQU 7 DEF SERIAL_PATCH_PREAMBLE_LENGTH EQU 3 DEF SERIAL_RNS_LENGTH EQU 10 +DEF SERIAL_PADDING_LENGTH EQU 3 + DEF SERIAL_MAIL_PREAMBLE_BYTE EQU $20 DEF SERIAL_MAIL_PREAMBLE_LENGTH EQU 5 +DEF SERIAL_MAIL_DATA_END EQU $21 ; used to replace SERIAL_NO_DATA_BYTE -DEF SERIAL_MAIL_REPLACEMENT_BYTE EQU $21 +DEF SERIAL_MAIL_REPLACEMENT_BYTE EQU $22 diff --git a/engine/link/link.asm b/engine/link/link.asm index 75ef83ef..b696bfff 100644 --- a/engine/link/link.asm +++ b/engine/link/link.asm @@ -68,15 +68,15 @@ Gen2ToGen1LinkComms: ld a, IE_SERIAL ldh [rIE], a ld hl, wLinkBattleRNPreamble - ld de, wEnemyMon + ld de, wOTLinkBattleRNData ld bc, SERIAL_RN_PREAMBLE_LENGTH + SERIAL_RNS_LENGTH call Serial_ExchangeBytes ld a, SERIAL_NO_DATA_BYTE ld [de], a - ld hl, wLinkData - ld de, wOTPlayerName - ld bc, PLAYER_NAME_LENGTH + (1 + PARTY_LENGTH + 1) + (REDMON_STRUCT_LENGTH + PLAYER_NAME_LENGTH * 2) * PARTY_LENGTH + 3 + ld hl, wLinkSendTimeCapsuleParty + ld de, wLinkReceivedPartyData + ld bc, wLinkSendTimeCapsulePartyEnd - wLinkSendTimeCapsuleParty call Serial_ExchangeBytes ld a, SERIAL_NO_DATA_BYTE ld [de], a @@ -91,16 +91,16 @@ Gen2ToGen1LinkComms: ld de, MUSIC_NONE call PlayMusic call Link_CopyRandomNumbers - ld hl, wOTPlayerName + ld hl, wLinkReceivedPartyData call Link_FindFirstNonControlCharacter_SkipZero - ld de, wLinkData - ld bc, PLAYER_NAME_LENGTH + (1 + PARTY_LENGTH + 1) + (REDMON_STRUCT_LENGTH + PLAYER_NAME_LENGTH * 2) * PARTY_LENGTH + 3 + ld de, wLinkTimeCapsulePartyData + ld bc, wLinkTimeCapsulePartyDataEnd - wLinkTimeCapsulePartyData call Link_CopyOTData - ld de, wPlayerTrademon - ld hl, wLinkPlayerData - ld c, $02 + ld de, wOTPatchLists + ld hl, wTimeCapsulePatchedData + ld c, 2 ; number of patch lists .loop ld a, [de] @@ -112,7 +112,7 @@ Gen2ToGen1LinkComms: cp SERIAL_NO_DATA_BYTE jr z, .loop cp SERIAL_PATCH_LIST_PART_TERMINATOR - jr z, .next + jr z, .next_patch_list push hl push bc ld b, 0 @@ -125,12 +125,12 @@ Gen2ToGen1LinkComms: pop hl jr .loop -.next +.next_patch_list ld hl, wLinkPlayerData + SERIAL_PATCH_DATA_SIZE dec c jr nz, .loop - ld hl, wLinkData + ld hl, wLinkTimeCapsulePlayerName ld de, wOTPlayerName ld bc, PLAYER_NAME_LENGTH call CopyBytes @@ -140,10 +140,10 @@ Gen2ToGen1LinkComms: ld [de], a inc de -.party_loop +.species_loop ld a, [hli] cp -1 - jr z, .done_party + jr z, .convert_party_struct ld [wTempByteValue], a push hl push de @@ -153,9 +153,9 @@ Gen2ToGen1LinkComms: ld a, [wTempByteValue] ld [de], a inc de - jr .party_loop + jr .species_loop -.done_party: +.convert_party_struct: ld [de], a ld hl, wLinkPlayerData call Link_ConvertPartyStruct1to2 @@ -221,15 +221,15 @@ Gen2ToGen2LinkComms: ldh [rIE], a ld hl, wLinkBattleRNPreamble - ld de, wEnemyMon + ld de, wOTLinkBattleRNData ld bc, SERIAL_RN_PREAMBLE_LENGTH + SERIAL_RNS_LENGTH call Serial_ExchangeBytes ld a, SERIAL_NO_DATA_BYTE ld [de], a - ld hl, wLinkData + ld hl, wLinkSendParty ld de, wOTPlayerName - ld bc, SERIAL_PREAMBLE_LENGTH + PLAYER_NAME_LENGTH + (1 + PARTY_LENGTH + 1) + (PARTYMON_STRUCT_LENGTH + PLAYER_NAME_LENGTH * 2) * PARTY_LENGTH + 7 + ld bc, wLinkSendPartyEnd - wLinkSendParty call Serial_ExchangeBytes ld a, SERIAL_NO_DATA_BYTE ld [de], a @@ -242,9 +242,9 @@ Gen2ToGen2LinkComms: ld a, [wLinkMode] cp LINK_TRADECENTER jr nz, .not_trading - ld hl, wLinkPlayerMail - ld de, wBattle - ld bc, wLinkPlayerMailEnd - wLinkPlayerMail + ld hl, wLinkSendMail + ld de, wLinkReceivedMail + ld bc, wLinkSendMailEnd - wLinkSendMail call ExchangeBytes .not_trading ld a, IE_JOYPAD | IE_SERIAL | IE_TIMER | IE_VBLANK @@ -255,22 +255,22 @@ Gen2ToGen2LinkComms: ld hl, wOTPlayerName call Link_FindFirstNonControlCharacter_SkipZero - ld de, wLinkData - ld bc, PLAYER_NAME_LENGTH + (1 + PARTY_LENGTH + 1) + (PARTYMON_STRUCT_LENGTH + PLAYER_NAME_LENGTH * 2) * PARTY_LENGTH + ld de, wLinkPlayerPartyData + ld bc, wLinkPlayerPartyDataEnd - wLinkPlayerPartyData call Link_CopyOTData ld de, wPlayerTrademon ld hl, wLinkPlayerData ld c, 2 -.loop1: +.party_patch_loop: ld a, [de] inc de and a - jr z, .loop1 + jr z, .party_patch_loop cp SERIAL_PREAMBLE_BYTE - jr z, .loop1 + jr z, .party_patch_loop cp SERIAL_NO_DATA_BYTE - jr z, .loop1 + jr z, .party_patch_loop cp SERIAL_PATCH_LIST_PART_TERMINATOR jr z, .next1 push hl @@ -283,58 +283,58 @@ Gen2ToGen2LinkComms: ld [hl], a pop bc pop hl - jr .loop1 + jr .party_patch_loop .next1: - ld hl, wPicrossLayoutBuffer + 1 + ld hl, wLinkPlayerData + SERIAL_PATCH_DATA_SIZE dec c - jr nz, .loop1 + jr nz, .party_patch_loop ld a, [wLinkMode] cp LINK_TRADECENTER jr nz, .skip_mail ld hl, wBattle -.loop2 +.find_mail_preamble ld a, [hli] cp SERIAL_MAIL_PREAMBLE_BYTE - jr nz, .loop2 -.loop3 + jr nz, .find_mail_preamble +.skip_mail_preamble ld a, [hli] cp SERIAL_NO_DATA_BYTE - jr z, .loop3 + jr z, .skip_mail_preamble cp SERIAL_MAIL_PREAMBLE_BYTE - jr z, .loop3 + jr z, .skip_mail_preamble dec hl - ld de, wLinkPlayerMail -.loop4 + ld de, wLinkSendMail +.mail_body_patch_loop ld a, [hli] cp SERIAL_NO_DATA_BYTE - jr z, .loop4 + jr z, .mail_body_patch_loop ld [de], a inc de - cp SERIAL_MAIL_REPLACEMENT_BYTE - jr nz, .loop4 - ld de, wLinkPlayerMail -.loop5: + cp SERIAL_MAIL_DATA_END + jr nz, .mail_body_patch_loop + ld de, wLinkSendMail +.mail_metadata_patch_loop: ld a, [de] inc de - cp SERIAL_MAIL_REPLACEMENT_BYTE + cp SERIAL_MAIL_DATA_END jr z, .okay - cp $22 - jr nz, .loop5 + cp SERIAL_MAIL_REPLACEMENT_BYTE + jr nz, .mail_metadata_patch_loop dec de ld a, SERIAL_NO_DATA_BYTE ld [de], a inc de - jr .loop5 + jr .mail_metadata_patch_loop .okay: dec de xor a ld [de], a .skip_mail: - ld hl, wLinkData + ld hl, wLinkPlayerName ld de, wOTPlayerName ld bc, PLAYER_NAME_LENGTH call CopyBytes @@ -456,20 +456,20 @@ endr dec b jr nz, .clear_loop - ld hl, wLinkData + SERIAL_PREAMBLE_LENGTH + PLAYER_NAME_LENGTH + (1 + PARTY_LENGTH + 1) - 1 + ld hl, wLinkSendPartyPartyEnd ld de, wPlayerPatchLists + SERIAL_RNS_LENGTH lb bc, 0, 0 .patch_loop: -; Check if we've gone over the entire area +; If we're processing the first patch area, check if we've reached the end inc c ld a, c cp SERIAL_PATCH_DATA_SIZE + 1 jr z, .data1_done -; If we're processing the second patch area, check if we've reached the end ld a, b dec a jr nz, .process +; If we're processing the second patch area, check if we've reached the end push bc ld a, [wLinkMode] cp LINK_TIMECAPSULE @@ -507,14 +507,14 @@ endr ret Link_PrepPartyData_Gen1: - ld de, wLinkData + ld de, wLinkSendTimeCapsuleParty ld a, SERIAL_PREAMBLE_BYTE ld b, SERIAL_PREAMBLE_LENGTH -.loop1 +.preamble_loop ld [de], a inc de dec b - jr nz, .loop1 + jr nz, .preamble_loop ld hl, wPlayerName ld bc, PLAYER_NAME_LENGTH @@ -525,10 +525,10 @@ Link_PrepPartyData_Gen1: ld a, [hli] ld [de], a inc de -.loop2 +.species_loop ld a, [hli] cp -1 - jr z, .done_party + jr z, .convert_party_struct ld [wTempByteValue], a push hl push de @@ -538,9 +538,9 @@ Link_PrepPartyData_Gen1: ld a, [wTempByteValue] ld [de], a inc de - jr .loop2 + jr .species_loop -.done_party +.convert_party_struct ld [de], a pop de ld hl, 1 + PARTY_LENGTH + 1 @@ -661,7 +661,7 @@ Link_PrepPartyData_Gen1: ret Link_PrepPartyData_Gen2: - ld de, wLinkData + ld de, wLinkSendParty ld a, SERIAL_PREAMBLE_BYTE ld b, SERIAL_PREAMBLE_LENGTH .preamble_loop: @@ -695,8 +695,8 @@ Link_PrepPartyData_Gen2: cp LINK_TRADECENTER ret nz -; Fill 5 bytes at wLinkPlayerMailPreamble with $20 - ld de, wLinkPlayerMail +; Fill 5 bytes at wLinkSendMailPreamble with $20 + ld de, wLinkSendMail ld a, SERIAL_MAIL_PREAMBLE_BYTE call Link_CopyMailPreamble @@ -707,17 +707,17 @@ Link_PrepPartyData_Gen2: call CopyBytes call CloseSRAM - ld a, MAIL_MSG_LENGTH + 1 + ld a, SERIAL_MAIL_DATA_END ld [de], a - ld hl, wLinkPlayerMailMessages + ld hl, wLinkSendMailMessages .loop: ld a, [hli] - cp SERIAL_MAIL_REPLACEMENT_BYTE + cp SERIAL_MAIL_DATA_END jr z, .end cp SERIAL_NO_DATA_BYTE jr nz, .loop dec hl - ld [hl], $22 + ld [hl], SERIAL_MAIL_REPLACEMENT_BYTE inc hl jr .loop @@ -866,7 +866,7 @@ Link_ConvertPartyStruct1to2: ld a, BASE_HAPPINESS ld [hli], a xor a - ld [hli], a + ld [hli], a ; wOTPartyMon*PokerusStatus ld [hli], a ld [hl], a pop hl @@ -891,7 +891,7 @@ Link_CopyRandomNumbers: ldh a, [hSerialConnectionStatus] cp USING_INTERNAL_CLOCK ret z - ld hl, wEnemyMon + ld hl, wOTLinkBattleRNData call Link_FindFirstNonControlCharacter_AllowZero ld de, wLinkBattleRNs ld c, SERIAL_RNS_LENGTH @@ -1514,7 +1514,7 @@ LinkTrade: ld bc, MAIL_STRUCT_LENGTH call AddNTimes push hl - ld hl, wLinkPlayerMail + ld hl, wLinkSendMail ld a, [wCurOTTradePartyMon] ld bc, MAIL_STRUCT_LENGTH call AddNTimes diff --git a/ram/wram.asm b/ram/wram.asm index b3337629..73458136 100644 --- a/ram/wram.asm +++ b/ram/wram.asm @@ -324,30 +324,96 @@ wMapBufferEnd:: UNION -wLinkData:: wOverworldMapBlocks:: ds 1300 -wLinkDataEnd:: wOverworldMapBlocksEnd:: NEXTU - ds 700 -wLinkPlayerMail:: -wLinkPlayerMailPreamble:: ds SERIAL_MAIL_PREAMBLE_LENGTH -wLinkPlayerMailMessages:: ds MAIL_STRUCT_LENGTH * PARTY_LENGTH -wLinkPlayerMailPatchSet:: ds 35 -wLinkPlayerMailEnd:: - ds 10 + +; This section union is 1300 bytes, the largest of all link data unions inside "Overworld Map" +wLinkData:: + +; player's party data, formatted for link transfer (Gen 2 link session) +wLinkSendParty:: +wLinkSendPartyPreamble:: ds SERIAL_PREAMBLE_LENGTH +wLinkSendPartyPlayerName:: ds PLAYER_NAME_LENGTH +wLinkSendPartyPartyCount:: db +wLinkSendPartyPartySpecies:: ds PARTY_LENGTH +wLinkSendPartyPartyEnd:: db ; older code doesn't check PartyCount +wLinkSendPartyPlayerID:: dw +; wLinkSendPartyPlayerPartyMon1 - wLinkSendPartyPlayerPartyMon6 +for n, 1, PARTY_LENGTH + 1 +wLinkSendPartyPlayerPartyMon{d:n}:: party_struct wLinkSendPartyPlayerPartyMon{d:n} +endr +; wLinkSendPartyPlayerPartyMon1OT - wLinkSendPartyPlayerPartyMon6OT +for n, 1, PARTY_LENGTH + 1 +wLinkSendPartyPlayerPartyMon{d:n}OT:: ds PLAYER_NAME_LENGTH +endr +; wLinkSendPartyPlayerPartyMon1Nickname - wLinkSendPartyPlayerPartyMon6Nickname +for n, 1, PARTY_LENGTH + 1 +wLinkSendPartyPlayerPartyMon{d:n}Nickname:: ds MON_NAME_LENGTH +endr +wLinkSendPartyPadding:: ds 5 +wLinkSendPartyEnd:: + + ds 313 + +; player's party mail, formatted for link transfer, during a link session +wLinkSendMail:: +wLinkSendMailPreamble:: ds SERIAL_MAIL_PREAMBLE_LENGTH +wLinkSendMailMessages:: ds (MAIL_MSG_LENGTH + 2) * PARTY_LENGTH +wLinkSendMailMetadata:: ds (MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 2)) * PARTY_LENGTH +wLinkSendMailPatchSet:: ds (MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 2)) * PARTY_LENGTH - 1 +wLinkSendMailEnd:: + ds 20 +UNION +wLinkReceivedMail:: +; during a link session, the other player's raw mail data is initially stored here + ds SERIAL_MAIL_PREAMBLE_LENGTH + ds MAIL_STRUCT_LENGTH * PARTY_LENGTH + ds (MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 2)) * PARTY_LENGTH -1 +wLinkReceivedMailEnd:: + +NEXTU +; it's then processed on location to align data start with wLinkReceivedMailMessages, +; before applying the mail patch +wLinkReceivedMailMessages:: ds (MAIL_MSG_LENGTH + 2) * PARTY_LENGTH +wLinkReceivedMailMetadata:: ds (MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 2)) * PARTY_LENGTH +wLinkReceivedMailPatchSet:: ds (MAIL_STRUCT_LENGTH - (MAIL_MSG_LENGTH + 2)) * PARTY_LENGTH -1 +ENDU + ds 20 +wLinkDataEnd:: NEXTU -wLYOverrides:: ds SCREEN_HEIGHT_PX -wLYOverridesEnd:: db - ds 15 -wLYOverrides2:: ds SCREEN_HEIGHT_PX -wLYOverrides2End:: +; player's party data, formatted for link transfer (Time Capsule link session) +wLinkSendTimeCapsuleParty:: +wLinkSendTimeCapsulePartyPlayerName:: ds PLAYER_NAME_LENGTH +wLinkSendTimeCapsulePartyPartyCount:: db +wLinkSendTimeCapsulePartyPartySpecies:: ds PARTY_LENGTH +wLinkSendTimeCapsulePartyPartyEnd:: db ; older code doesn't check PartyCount +; wLinkSendTimeCapsulePartyMon1 - wLinkSendTimeCapsulePartyMon6 +for n, 1, PARTY_LENGTH + 1 +wLinkSendTimeCapsulePartyMon{d:n}:: red_party_struct wLinkSendTimeCapsulePartyMon{d:n} +endr +wLinkSendTimeCapsulePartyMonOTs:: +; wLinkSendTimeCapsulePartyMon1OT - wLinkSendTimeCapsulePartyMon6OT +for n, 1, PARTY_LENGTH + 1 +wLinkSendTimeCapsulePartyMon{d:n}OT:: ds PLAYER_NAME_LENGTH +endr +wLinkSendTimeCapsulePartyMonNicknames:: +; wLinkSendTimeCapsulePartyMon1Nickname - wLinkSendTimeCapsulePartyMon6Nickname +for n, 1, PARTY_LENGTH + 1 +wLinkSendTimeCapsulePartyMon{d:n}Nickname:: ds MON_NAME_LENGTH +endr +wLinkSendTimeCapsulePartyPadding:: ds SERIAL_PADDING_LENGTH +wLinkSendTimeCapsulePartyEnd:: NEXTU +; after the initial link session (Gen 2), the other player's party data +; is temporarily stored here before applying patch data +wLinkPlayerPartyData:: + ; link data members wLinkPlayerName:: ds PLAYER_NAME_LENGTH wLinkPartyCount:: db @@ -364,17 +430,65 @@ endr wLinkPlayerPartyMonOTs:: ; wLinkPlayerPartyMon1OT - wLinkPlayerPartyMon6OT for n, 1, PARTY_LENGTH + 1 -wLinkPlayerPartyMon{d:n}OT:: ds NAME_LENGTH +wLinkPlayerPartyMon{d:n}OT:: ds PLAYER_NAME_LENGTH endr wLinkPlayerPartyMonNicknames:: ; wLinkPlayerPartyMon1Nickname - wLinkPlayerPartyMon6Nickname for n, 1, PARTY_LENGTH + 1 -wLinkPlayerPartyMon{d:n}Nickname:: ds NAME_LENGTH +wLinkPlayerPartyMon{d:n}Nickname:: ds MON_NAME_LENGTH endr +wLinkPlayerPartyDataEnd:: + NEXTU +UNION +; after the initial link session (Gen 1), the other player's party data +; is temporarily stored here before applying patch data +wLinkTimeCapsulePartyData:: + +; link player's name and party species are not patched, +; as they normally don't contain SERIAL_NO_DATA_BYTE +wLinkTimeCapsulePlayerName:: ds PLAYER_NAME_LENGTH +wLinkTimeCapsulePartyCount:: db +wLinkTimeCapsulePartySpecies:: ds PARTY_LENGTH +wLinkTimeCapsulePartyEnd:: db ; older code doesn't check PartyCount + +wTimeCapsulePatchedData:: +; wTimeCapsulePartyMon1 - wTimeCapsulePartyMon6 +for n, 1, PARTY_LENGTH + 1 +wTimeCapsulePartyMon{d:n}:: red_party_struct wTimeCapsulePartyMon{d:n} +endr + +wTimeCapsulePartyMonOTs:: +; wTimeCapsulePartyMon1OT - wTimeCapsulePartyMon6OT +for n, 1, PARTY_LENGTH + 1 +wTimeCapsulePartyMon{d:n}OT:: ds PLAYER_NAME_LENGTH +endr + +wTimeCapsulePartyMonNicknames:: +; wTimeCapsulePartyMon1Nickname - wTimeCapsulePartyMon6Nickname +for n, 1, PARTY_LENGTH + 1 +wTimeCapsulePartyMon{d:n}Nickname:: ds MON_NAME_LENGTH +endr + +ENDU +wLinkTimeCapsulePartyPadding:: ds SERIAL_PADDING_LENGTH + +wLinkTimeCapsulePartyDataEnd:: +; link player's name and party species are not patched, +; as they normally don't contain SERIAL_NO_DATA_BYTE + +NEXTU + +wLYOverrides:: ds SCREEN_HEIGHT_PX +wLYOverridesEnd:: db + ds 15 +wLYOverrides2:: ds SCREEN_HEIGHT_PX +wLYOverrides2End:: + +NEXTU ; Pikachu minigame wPikachuMinigamePikachuObjectPointer:: dw @@ -1336,11 +1450,15 @@ wLinkBattleRNs:: ds 10 wTempEnemyMonSpecies:: db wTempBattleMonSpecies:: db +UNION +wOTLinkBattleRNData:: ds SERIAL_RN_PREAMBLE_LENGTH + SERIAL_RNS_LENGTH +NEXTU wEnemyMon:: battle_struct wEnemyMon wEnemyMonBaseStats:: ds NUM_EXP_STATS wEnemyMonCatchRate:: db wEnemyMonBaseExp:: db wEnemyMonEnd:: +ENDU wBattleMode:: db wTempWildMonSpecies:: db @@ -1843,8 +1961,30 @@ wBreedMon2:: box_struct wBreedMon2 ; Uses the last two bits to keep track of your breeder mons' genders. ; Bit clear = male, bit set = female wBreedMonGenders:: db -wOTPlayerName:: ds PLAYER_NAME_LENGTH +; This union spans 353 bytes. +UNION + +; During a link session, other player's raw party data is initially stored here. +; The actual data is contained between SERIAL_PREAMBLE_LENGTH and SERIAL_PADDING_LENGTH, +; allowing possible data shift due to hardware behavior. +wLinkReceivedPartyData:: + ; Gen 2 link format + ds PLAYER_NAME_LENGTH + ds 1 + PARTY_LENGTH + 1 + ds (PARTYMON_STRUCT_LENGTH + PLAYER_NAME_LENGTH * 2) * PARTY_LENGTH + ds SERIAL_PADDING_LENGTH +NEXTU + ; Gen 1 link format + ds PLAYER_NAME_LENGTH + ds 1 + PARTY_LENGTH + 1 + ds (REDMON_STRUCT_LENGTH + PLAYER_NAME_LENGTH * 2) * PARTY_LENGTH + ds SERIAL_PADDING_LENGTH +wLinkReceivedPartyEnd:: db + +NEXTU + +wOTPlayerName:: ds PLAYER_NAME_LENGTH ds 15 wOTPartyData:: @@ -1889,6 +2029,8 @@ wPokemonDataEnd:: wBox:: box wBox +ENDU + SECTION "Stack Bottom", WRAM0