Guest User

pokegold link.asm comments

a guest
Dec 8th, 2020
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. SerialExchangeBytes: sends and receives a number of bytes (send from hl, receive in de)
  2. the sent data is typically no longer useful after being sent and the game will often reuse the buffer afterwards
  4. when a buffer with leading preamble bytes is sent, the game accounts for the possibility of receiving a different
  5. number of preamble bytes (which in fact does happen at times), so receive buffers never have fixed addresses/offsets
  6. and are always used as staging areas
  8. Patch sets:
  9. The link hardware has no way of sending "nothing". While the link is idle, the game sends $FE (SERIAL_NO_DATA_BYTE).
  10. Therefore, actual data cannot contain any $FE bytes. Since the original data can definitely contain those values, the
  11. game "patches" the data that will be sent to avoid this. The format of a patch set is simple: an $FF-terminated list
  12. of offsets where the data originally contained $FE bytes; those bytes themselves are replaced by $FF when the data is
  13. sent. (Both the terminator $FF and the replacement $FF are identified as SERIAL_PATCH_LIST_PART_TERMINATOR, but those
  14. two values are in fact unrelated.)
  15. Patch sets cannot contain any offset larger than $FC, and thus the game will concatenate multiple patch sets. Oddly,
  16. the offsets in patch sets are 1-based, and address computations account for this. (For example, the first patch set is
  17. for the buffer starting at wLinkData + 25, and if this address had to be patched, the patch set would contain $01.)
  19. FixDataForLinkTransfer: will scan a buffer for $FE bytes and replace them with dummy $FF while creating a list of
  20. patches for the receiving side to apply to the received data. This creates a buffer in $c508 (wc508, one of those
  21. buffers used for everything).
  22. This function also prepares the random number data to be exchanged, for some reason.
  23. Patch preparation process:
  24. 1) initialize the patch buffer (at wc508) with 3 preamble bytes
  25. 2) fill the subsequent 200 bytes with zeros (this is larger than the patch sets could ever be)
  26. 3) hl = (wLinkData + SERIAL_PREAMBLE_LENGTH + NAME_LENGTH + PARTY_LENGTH + 2) - 1, de = wc508 + 10 (3 preamble, 7 ???)
  27. note: this makes hl points to the mon data structs. Notably, the player name is skipped. What happens if the player
  28. name somehow has an 8 ($FE) in it?
  29. 4) loop for $FC bytes and create the first patch set; terminate it with $FF
  30. (note that b is used as a loop limit (the loop will iterate b-1 times), but b = 0 for this first loop, so the loop
  31. will exit early due to c >= $FD)
  32. if $FC is defined as a constant (say, PATCH_SET_LENGTH), then cp SERIAL_PREAMBLE_BYTE right after .loop2 should be
  33. changed to cp PATCH_SET_LENGTH + 1
  34. 5) b = $D (for gen 1) or $27 (for gen 2), making a total of $108/$122 bytes to patch (the loop runs b-1 times)
  35. notes:
  36. for gen 1, $108 = PARTY_LENGTH * REDMON_STRUCT_LENGTH
  37. for gen 2, $122 = 2 (for the player ID) + PARTY_LENGTH * PARTYMON_STRUCT_LENGTH
  38. the value of b can be calculated as (limit - $FC) + 1
  39. 6) loop again and make a second patch set, terminating it with $FF (this time b will limit the loop)
  40. note: hl hasn't been updated, so this patch set continues from $FC bytes after the first patch set
  41. When creating patch sets, this function will replace the patched bytes with $FF. This value is just a replacement,
  42. which is ignored by the receiving side (as it will immediately overwrite these bytes with $FE); the replacement value
  43. is incorrectly identified as SERIAL_PATCH_LIST_PART_TERMINATOR, but it is in fact independent from the terminator.
  45. Gen2ToGen1LinkComms:
  46. 0) Link_PrepPartyData_Gen1 + FixDataForLinkTransfer: stage party data to be sent in wLinkData and wc508
  47. 1) exchange random numbers
  48. 2) exchange party data
  49. $1a8 = SERIAL_PREAMBLE_LENGTH (preamble) + NAME_LENGTH (player name) +
  50. PARTY_LENGTH + 2 (party count, data, terminator) + PARTY_LENGTH * REDMON_STRUCT_LENGTH (party data) +
  51. PARTY_LENGTH * NAME_LENGTH * 2 (OT names, nicknames) + 3 (not used, probably just in case the other side
  52. sends too many preamble bytes)
  53. data received in OT data (wOTPlayerName onwards); this is just staging and it doesn't have fixed addresses because
  54. the number of preamble bytes received may vary
  55. 3) exchange patch sets (200 bytes at wc508); there's no particular meaning to the number 200 other than that patch
  56. sets should never be this long (send in wc508, receive in wTrademons -- used as a temporary buffer)
  57. 4) copy back random numbers and set hl = wOTPlayerName (receive buffer for party data) advanced to the first real data
  58. byte (i.e., not control, not zero)
  59. 5) test the received party count byte and exit with a link error if the party count isn't between 1 and 6 (cp 7 should
  60. be cp PARTY_LENGTH + 1)
  61. 6) de = wLinkData, bc = $1a2 (same constant as step 2 minus SERIAL_PREAMBLE_LENGTH), copy received data from hl (which
  62. points to the temporary buffer at wOTPlayerName + whatever offset to the beginning of the real data) to wLinkData
  63. 7) de = wPlayerTrademon (= wTrademons from step 3), hl = wTradeCapsulePlayerData (= wLinkData + NAME_LENGTH +
  64. PARTY_LENGTH + 2, i.e., the offset from step 3 in FixDataForLinkTransfer without the serial preamble), and apply
  65. the first patch set
  66. 8) hl = wc80f (= previous hl + $FC, see FixDataForLinkTransfer step 6), apply the second patch set
  67. 9) convert received gen 1 data to gen 2 format (loading it into wOTxxxxx) and finish up (opening the trade menu)
  69. Gen2ToGen2LinkComms:
  70. 0, 1) same as gen 1 (calling Link_PrepPartyData_Gen2 instead -- which will also handle mail data; see below)
  71. 2) same as gen 1, exchange $1c2 bytes
  72. $1c2 = SERIAL_PREAMBLE_LENGTH + NAME_LENGTH + (PARTY_LENGTH + 2) + 2 (player ID) +
  74. 3) same as gen 1
  75. 4) if the open link is a trade, exchange mail data (390 bytes, send from wc8f4, receive in wca84; see the description
  76. of Link_PrepPartyData_Gen2 below for the layout of this data)
  77. 5) same as gen 1 step 4
  78. 6, 7, 8) same as gen 1 (copied amount is $1b9, which is $1c2 - SERIAL_PREAMBLE_LENGTH - the 3 at the end)
  79. 9) if the open link is a trade, handle the mail data: (otherwise, jump to .skip_mail)
  80. - hl = wca84, then skip the preamble bytes (custom preamble, $20, incorrectly identified as MAIL_MSG_LENGTH here)
  81. - again, skip custom preamble (incorrect: MAIL_MSG_LENGTH) bytes and $FE (SERIAL_NO_DATA_BYTE) bytes (unclear why
  82. this is done twice? Probably GF being GF... this could be a single loop)
  83. - copy 400 bytes (!!! 10 more than the exchanged bytes in step 4) to wca84, reusing the same buffer (it is
  84. interesting to note that wca84 - wc8f4 = 400; perhaps they just took the size of that block?)
  85. note: this is copying from wca84 to *itself*, with the source pointer incremented by a few bytes (after having
  86. skipped the preamble); this relies on the fact that CopyBytes does a forwards copy. To my knowledge, this is the
  87. only time CopyBytes is called with overlapping buffer pointers
  88. - iterate through the next 198 (PARTY_LENGTH * (MAIL_MSG_LENGTH + 1)) bytes, replacing $21 bytes with $FE (this is
  89. undoing step 3 of Link_PrepPartyData_Gen2; the $21 is incorrectly identified as MAIL_MSG_LENGTH + 1 here)
  90. - de = wcb9e (= wca84 + PARTY_LENGTH * MAIL_STRUCT_LENGTH, pointing at the patch set in the received data), and
  91. apply the patch set based on wcb4a (= wca84 + PARTY_LENGTH * (MAIL_MSG_LENGTH + 1), pointing at the mail headers)
  92. - copy the mail data into wc8f4 (reusing the send buffer), reassembling the mail structs by interleaving the bodies
  93. and the headers (bodies are copied first, leaving space for the headers; headers are copied afterwards)
  94. - write a zero byte at wca0e (= wc8f4 + PARTY_LENGTH * MAIL_STRUCT_LENGTH), after the six received mail structs
  95. 10) load all of the received trainer data into wOTxxxxx
  96. 11) if the link is a battle, set up the battle initial variables and fire it up
  97. 12) otherwise, finish up and pop up the trade menu
  99. Exchanged data (gen 1): three blocks of data:
  100. Random numbers: 7 bytes preamble, 10 bytes data
  101. Trainer data:
  103. Name: 11 (NAME_LENGTH)
  104. Party list: 8 (count, 6 species, terminator, pad with $00)
  105. Party data: 6 * 44 (REDMON_STRUCT_LENGTH), just the party struct with $FE (SERIAL_NO_DATA_BYTE) bytes replaced
  106. OT names: 6 * 11
  107. Nicknames: 6 * 11
  108. Dummy filler: 3 (probably padding the length of the buffer in case more than 6 preamble bytes are received)
  109. Patch sets:
  110. Preamble: 3 bytes of $FD
  111. Dummy: 7 bytes of $00 (don't seem to be particularly useful)
  112. Patch set 1 (variable length, for the first $FC bytes starting at the party data)
  113. Patch set 2 (variable length, for the remaining $C bytes)
  114. $00 padding up to 200 bytes
  115. Link_PrepPartyData_Gen1 fills in the trainer data in a pretty straightforward way; ConvertMon_2to1 is called to
  116. transform the party structs into gen 1 structs
  118. Exchanged data (gen 2): four blocks of data:
  119. Random numbers: 7 bytes preamble, 10 bytes data
  120. Trainer data:
  122. Name: 11 (NAME_LENGTH)
  123. Party list: 8 (count, 6 species, terminator, pad with $00)
  124. Player ID: 2 bytes ($FE bytes replaced)
  125. Party data: 6 * 48 (PARTYMON_STRUCT_LENGTH) with $FE (SERIAL_NO_DATA_BYTE) bytes replaced
  126. OT names: 6 * 11
  127. Nicknames: 6 * 11
  128. Dummy filler: 3 (probably padding the length of the buffer in case more than 6 preamble bytes are received)
  129. Patch sets:
  130. Preamble: 3 bytes of $FD
  131. Dummy: 7 bytes of $00 (don't seem to be particularly useful)
  132. Patch set 1 (variable length, for the first $FC bytes starting at the player ID)
  133. Patch set 2 (variable length, for the remaining $26 bytes of party data)
  134. $00 padding up to 200 bytes
  135. Mail (sent only if trading, not battling):
  136. Preamble: 5 bytes of $20 (custom preamble probably because $FD is a valid mail data byte)
  137. Mail bodies: 6 * 33 (MAIL_MSG_LENGTH + 1, includes the terminator), with $FE bytes replaced with $21
  138. Mail headers: 6 * 14 (size of the rest of the mail struct), with $FE bytes replaced with $FF
  139. Patch set (variable length) for the mail headers
  140. $00 padding up to 390 bytes
  141. Link_PrepPartyData_Gen2 fills in the trainer data in an unremarkable way. If the open link is a trade, it also loads
  142. the mail data into wc8f4:
  143. 1) write five bytes of $20 (custom preamble) to wc8f4
  144. note: for the rest of this description, assume SERIAL_MAIL_PREAMBLE_LENGTH = 5 (new constant)
  145. 2) copy the mail bodies, then the mail headers
  146. 3) hl = wc8f4 + SERIAL_MAIL_PREAMBLE_LENGTH, iterate through the mail bodies and replace all $FE (SERIAL_NO_DATA_BYTE)
  147. bytes with $21 (a custom replacement byte, incorrectly identified as sPartyMon1MailAuthor - sPartyMon1Mail right
  148. above .skip2)
  149. 4) hl = wc8f4 + SERIAL_MAIL_PREAMBLE_LENGTH + PARTY_LENGTH * (MAIL_MSG_LENGTH + 1), pointing at the mail headers
  150. (redundant, since it will already exit the previous loop at this address), de = pointing to the patch sets
  151. (= the address above + PARTY_LENGTH * (sPartyMon1MailEnd - sPartyMon1MailAuthor)), b = length of mail headers
  152. 5) manually build a patch set for the b bytes at hl, write at de (as all patch sets, the offsets are 1-based), while
  153. replacing the patched bytes with $FF (incorrectly identified as SERIAL_PATCH_LIST_PART_TERMINATOR; see a similar
  154. note in FixDataForLinkTransfer)
  155. 6) write the patch set terminator and exit
  156. The mail data process uses several unnamed labels which are simply offsets into the mail data block:
  157. - wc8f4: beginning
  158. - wc8f9: mail bodies, wc8f4 + SERIAL_MAIL_PREAMBLE_LENGTH
  159. - wc9bf: mail headers, previous + PARTY_LENGTH * (MAIL_MSG_LENGTH + 1)
  160. - wca13: patch set, previous + PARTY_LENGTH * (sPartyMon1MailEnd - sPartyMon1MailAuthor)
  161. The game will exchange 390 bytes at wc8f4, so this area technically ends at $ca7a. This leaves 103 bytes for the patch
  162. set; it's naturally never even close to that long, but the block is large just in case.
  164. ***
  166. These notes only cover the first half of link.asm. The code starting at InitTradeMenuDisplay is generally well
  167. understood and doesn't need as much fixing as the code that actually exchanges data when a link is opened.
  169. ***
  171. Buffers used by the exchange:
  173. The initial exchange uses several buffers, sometimes reusing them as the exchange progresses. The following steps can
  174. be seen in the code:
  175. 1) To-be-sent data staging
  176. 2) Received data staging (exchange the staged data with the received data)
  177. 3) Data fixing
  179. Notably, while the first two steps cannot use overlapping buffers, the rest of the code can and will; the location
  180. where the received data will be finally deposited after being fixed is also used as a staging area. This requires
  181. treating the whole link data area as a union.
  183. Link data is located mainly in a very large buffer that starts at $c700 (wLinkData) and ends at $cc14 (wLinkDataEnd).
  184. This is a 1300-byte buffer -- this value is not at all a coincidence, as the memory region spans exactly the same
  185. WRAM area as the overworld map buffer. Many sub-regions from this block are used at various points throughout the link
  186. code to hold data; other parts are unused, but the whole 1300-byte block is nonetheless cleared (set to zero) by the
  187. ClearLinkData function before any data staging or exchange takes place.
  189. After all the transfers are done, the only part of this region that will contain persistent meaningful data is the
  190. buffer at wc8f4 during gen 2 to gen 2 trades, which contains six mailmsg structs followed by a single zero byte
  191. (probably a terminator). During battles or Time Capsule trades, there will be no data left over in wLinkData.
  193. The link code also uses a generic buffer at $c508 to stage patch sets to be sent. This is a multipurpose buffer used
  194. by many parts of the code, right after the tilemap; the link code only uses 200 bytes of that buffer, although it is
  195. in fact 480 bytes long.
  197. Data staging before sending:
  198. wLinkBattleRNPreamble, wLinkBattleRNs: self-explanatory
  199. wLinkData: trainer data, with different layouts for gen 1 and gen 2
  200. wc8f4: mail data (see the layout in the Link_PrepPartyData_Gen2 description)
  201. wc508: patch sets for trainer data
  203. Received data staging:
  204. (note that the received data has no explicit layout because the game assumes that the number of preamble/no data bytes
  205. at the beginning may vary. This actually does happen in practice, and thus any structure given to these buffers is
  206. meaningless, although the structure after the initial dummy bytes is obviously identical to the sent data structure.)
  207. wEnemyMon: the received random numbers; the game (correctly) assumes that this buffer is not in use here
  208. OT variables (wOTPlayerName through wOTPartyDataEnd): received trainer data
  209. wTrademons: received patch sets for trainer data
  210. wca84: received mail data
  212. Data fixing:
  213. (this is where received data is temporarily copied for fixing before loading into its final destination; patch sets
  214. (except for the one in the mail data) are never copied since they are applied directly to the data fixed here, and
  215. random numbers are not copied since they don't need any fixing)
  216. wLinkData: trainer data, with the same layout as the sent data (different for gen 1 and gen 2) but without the initial
  217. preamble bytes (and, for gen 2, without the trailing dummy bytes)
  218. wca84: mail data, with the same layout as the sent data, but without the initial preamble bytes -- this data is copied
  219. onto itself, but shifted slightly to get rid of the leading preamble bytes
  221. Final destination for received data:
  222. wLinkBattleRNs: self-explanatory
  223. OT variables: trainer and party data
  224. wc8f4: mail data (six mailmsg structs plus a terminator byte); this is the only part of the data that remains in the
  225. wLinkData block
RAW Paste Data