sprite animation testing
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
12KB

  1. ; MIT License
  2. ;
  3. ; Copyright (c) 2018-2019 Eldred Habert
  4. ; Originally hosted at https://github.com/ISSOtm/rgbds-structs
  5. ;
  6. ; Permission is hereby granted, free of charge, to any person obtaining a copy
  7. ; of this software and associated documentation files (the "Software"), to deal
  8. ; in the Software without restriction, including without limitation the rights
  9. ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. ; copies of the Software, and to permit persons to whom the Software is
  11. ; furnished to do so, subject to the following conditions:
  12. ;
  13. ; The above copyright notice and this permission notice shall be included in all
  14. ; copies or substantial portions of the Software.
  15. ;
  16. ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. ; SOFTWARE.
  23. ; !!! WARNING ABOUT READABILITY OF THIS CODE !!!
  24. ;
  25. ; RGBDS, being the venerable/old/decrepit (pick on depending on mood) assembler that it is, requires
  26. ; all label, variable etc. definitions to be on column 0. As in, no whitespace allowed (otherwise, syntax error)
  27. ; Meanwhile, these macros tend to use a lot of nesting (requiring indenting for readability),
  28. ; as well as variable definitions (requiring none to work).
  29. ; As you can probably tell, those two conflict and result in very poor readability
  30. ; Sadly, there is nothing I can do against that short of using a special preprocessor,
  31. ; which I refuse to do for usability's sake.
  32. ; You have all my apologies, how little they may matter, if you are trying to read this code
  33. ; I still did my best to use explicit comments and variable names, hope they will help!
  34. ; strreplace variable_name, original_char, new_char
  35. strreplace: MACRO
  36. DOT_POS = STRIN("{\1}", \2)
  37. IF DOT_POS != 0
  38. TMP equs STRCAT(STRSUB("{\1}", 1, DOT_POS + (-1)), STRCAT(\3, STRSUB("{\1}", DOT_POS + 1, STRLEN("{\1}") - DOT_POS)))
  39. PURGE \1
  40. \1 equs "{TMP}"
  41. PURGE TMP
  42. strreplace \1, \2, \3
  43. ENDC
  44. IF DEF(DOT_POS)
  45. PURGE DOT_POS
  46. ENDC
  47. ENDM
  48. ; rgbds_structs_version version_string
  49. ; Call with the expected version string to ensure you're using a compatible version
  50. ; Example: rgbds_structs_version 1.0.0
  51. rgbds_structs_version: MACRO
  52. CURRENT_VERSION equs "1,2,1"
  53. EXPECTED_VERSION equs "\1"
  54. strreplace EXPECTED_VERSION, ".", "\,"
  55. check_ver: MACRO
  56. IF \1 != \4 || \2 > \5 || \3 > \6
  57. PURGE EXPECTED_VERSION
  58. ENDC
  59. ENDM
  60. CHECK_VER_CALL equs "check_ver {EXPECTED_VERSION},{CURRENT_VERSION}"
  61. CHECK_VER_CALL
  62. IF !DEF(EXPECTED_VERSION)
  63. strreplace CURRENT_VERSION, "\,", "."
  64. FAIL "RGBDS-structs version \1 is required, which is incompatible with current version {CURRENT_VERSION}"
  65. ENDC
  66. PURGE CHECK_VER_CALL
  67. PURGE check_ver
  68. PURGE CURRENT_VERSION
  69. PURGE EXPECTED_VERSION
  70. ENDM
  71. ; struct struct_name
  72. ; Begins a struct declaration
  73. struct: MACRO
  74. IF DEF(NB_FIELDS)
  75. FAIL "Please close struct definitions using `end_struct`"
  76. ENDC
  77. STRUCT_NAME equs "\1"
  78. NB_FIELDS = 0
  79. RSRESET
  80. ENDM
  81. ; end_struct
  82. ; Ends a struct declaration
  83. end_struct: MACRO
  84. ; Set nb of fields
  85. STRUCT_NB_FIELDS equs "{STRUCT_NAME}_nb_fields"
  86. STRUCT_NB_FIELDS = NB_FIELDS
  87. PURGE STRUCT_NB_FIELDS
  88. ; Set size of struct
  89. STRUCT_SIZEOF equs "sizeof_{STRUCT_NAME}"
  90. STRUCT_SIZEOF RB 0
  91. PURGE STRUCT_SIZEOF
  92. PURGE NB_FIELDS
  93. PURGE STRUCT_NAME
  94. ENDM
  95. ; get_nth_field_info field_id
  96. ; Defines EQUS strings pertaining to a struct's Nth field
  97. ; For internal use, please do not use externally
  98. get_nth_field_info: MACRO
  99. ; Field's name
  100. STRUCT_FIELD equs "{STRUCT_NAME}_field{d:\1}"
  101. STRUCT_FIELD_NAME equs "{STRUCT_FIELD}_name"
  102. STRUCT_FIELD_TYPE equs "{STRUCT_FIELD}_type"
  103. STRUCT_FIELD_NBEL equs "{STRUCT_FIELD}_nb_el" ; Number of elements
  104. STRUCT_FIELD_SIZE equs "{STRUCT_FIELD}_size" ; sizeof(type) * nb_el
  105. ENDM
  106. ; new_field nb_elems, rs_type, field_name
  107. ; For internal use, please do not use externally
  108. new_field: MACRO
  109. IF !DEF(STRUCT_NAME) || !DEF(NB_FIELDS)
  110. FAIL "Please start defining a struct, using `define_struct`"
  111. ENDC
  112. get_nth_field_info NB_FIELDS
  113. ; Set field name (keep in mind `STRUCT_FIELD_NAME` is *itself* an EQUS!)
  114. STRUCT_FIELD_NAME equs "\"\3\""
  115. PURGE STRUCT_FIELD_NAME
  116. ; Set field offset
  117. STRUCT_FIELD \2 (\1)
  118. ; Alias this in a human-comprehensive manner
  119. STRUCT_FIELD_NAME equs "{STRUCT_NAME}_\3"
  120. STRUCT_FIELD_NAME = STRUCT_FIELD
  121. ; Compute field size
  122. CURRENT_RS RB 0
  123. STRUCT_FIELD_SIZE = CURRENT_RS - STRUCT_FIELD
  124. ; Set properties
  125. STRUCT_FIELD_NBEL = \1
  126. STRUCT_FIELD_TYPE equs STRSUB("\2", 2, 1)
  127. PURGE STRUCT_FIELD
  128. PURGE STRUCT_FIELD_NAME
  129. PURGE STRUCT_FIELD_TYPE
  130. PURGE STRUCT_FIELD_NBEL
  131. PURGE STRUCT_FIELD_SIZE
  132. PURGE CURRENT_RS
  133. NB_FIELDS = NB_FIELDS + 1
  134. ENDM
  135. ; bytes nb_bytes, field_name
  136. ; Defines a field of N bytes
  137. bytes: MACRO
  138. new_field \1, RB, \2
  139. ENDM
  140. ; words nb_words, field_name
  141. ; Defines a field of N*2 bytes
  142. words: MACRO
  143. new_field \1, RW, \2
  144. ENDM
  145. ; longs nb_longs, field_name
  146. ; Defines a field of N*4 bytes
  147. longs: MACRO
  148. new_field \1, RL, \2
  149. ENDM
  150. ; dstruct struct_type, INSTANCE_NAME[, ...]
  151. ; Allocates space for a struct in memory
  152. ; If no further arguments are supplied, the space is simply allocated (using `ds`)
  153. ; Otherwise, the data is written to memory using the appropriate types
  154. ; For example, a struct defined with `bytes 1, Field1` and `words 3, Field2` would have four extra arguments, one byte then three words.
  155. dstruct: MACRO
  156. NB_FIELDS equs "\1_nb_fields"
  157. IF !DEF(NB_FIELDS)
  158. FAIL "Struct \1 isn't defined!"
  159. ELIF _NARG != 2 && _NARG != NB_FIELDS + 2 ; We must have either a RAM declaration (no data args) or a ROM one (RAM args + data args)
  160. EXPECTED_NARG = 2 + NB_FIELDS
  161. FAIL "Invalid number of arguments, expected 2 or {d:EXPECTED_NARG} but got {d:_NARG}"
  162. ENDC
  163. ; Define the two fields required by `get_nth_field_info`
  164. STRUCT_NAME equs "\1" ; Which struct `get_nth_field_info` should pull info about
  165. INSTANCE_NAME equs "\2" ; The instance's base name
  166. ; RGBASM always expands `\X` macro args, so `IF _NARG > 2 && STRIN("\3", "=")` will error out when there are only 2 args
  167. ; Therefore, the condition is checked here (we can't nest the `IF`s over there because that doesn't translate well to `ELSE`)
  168. IS_NAMED_INVOCATION = 0
  169. IF _NARG > 2
  170. IF STRIN("\3", "=")
  171. IS_NAMED_INVOCATION = 1
  172. ENDC
  173. ENDC
  174. IF IS_NAMED_INVOCATION
  175. ; This is a named instantiation, translate that to an ordered one
  176. ; This is needed because data has to be laid out in order, so some translation is needed anyways
  177. ; And finally, it's better to re-use the existing code at the cost of a single nested macro, I believe
  178. MACRO_CALL equs "dstruct \1, \2" ; This will be used later, but define it now because `SHIFT` will be run
  179. ; In practice `SHIFT` has no effect outside of one when invoked inside of a REPT block, but I hope this behavior is changed (causes a problem elsewhere)
  180. ARG_NUM = 3
  181. REPT NB_FIELDS
  182. ; Find out which argument the current one is
  183. CUR_ARG equs "\3"
  184. ; Remove all whitespace to obtain something like ".name=value" (whitespace are unnecessary and complexify parsing)
  185. strreplace CUR_ARG, " ", ""
  186. strreplace CUR_ARG, "\t", ""
  187. EQUAL_POS = STRIN("{CUR_ARG}", "=")
  188. IF EQUAL_POS == 0
  189. FAIL "Argument #{ARG_NUM} (\3) does not contain an equal sign in this named instantiation"
  190. ELIF STRCMP(STRSUB("{CUR_ARG}", 1, 1), ".")
  191. FAIL "Argument #{ARG_NUM} (\3) does not start with a period"
  192. ENDC
  193. FIELD_ID = -1
  194. CUR_FIELD_ID = 0
  195. REPT NB_FIELDS
  196. ; Get the name of the Nth field and compare
  197. TMP equs "{STRUCT_NAME}_field{d:CUR_FIELD_ID}_name"
  198. CUR_FIELD_NAME equs TMP
  199. PURGE TMP
  200. IF !STRCMP(STRUPR("{CUR_FIELD_NAME}"), STRUPR(STRSUB("{CUR_ARG}", 2, EQUAL_POS - 2)))
  201. ; Match found!
  202. IF FIELD_ID == -1
  203. FIELD_ID = CUR_FIELD_ID
  204. ELSE
  205. TMP equs "{STRUCT_NAME}_field{d:CUR_FIELD_ID}_name"
  206. CONFLICTING_FIELD_NAME equs TMP
  207. PURGE TMP
  208. FAIL "Fields {CUR_FIELD_NAME} and {CONFLICTING_FIELD_NAME} have conflicting names (case-insensitive), cannot perform named instantiation"
  209. ENDC
  210. ENDC
  211. PURGE CUR_FIELD_NAME
  212. CUR_FIELD_ID = CUR_FIELD_ID + 1
  213. ENDR
  214. PURGE CUR_FIELD_ID
  215. IF FIELD_ID == -1
  216. FAIL "Argument #{d:ARG_NUM} (\3) does not match any field of the struct"
  217. ENDC
  218. INITIALIZER_NAME equs "FIELD_{d:FIELD_ID}_INITIALIZER"
  219. INITIALIZER_NAME equs STRSUB("{CUR_ARG}", EQUAL_POS + 1, STRLEN("{CUR_ARG}") - EQUAL_POS)
  220. PURGE INITIALIZER_NAME
  221. ; Go to next arg
  222. ARG_NUM = ARG_NUM + 1
  223. SHIFT
  224. PURGE CUR_ARG
  225. ENDR
  226. ; Now that we matched each named initializer to their order, invoke the macro again but without names
  227. FIELD_ID = 0
  228. REPT NB_FIELDS
  229. TMP equs "{MACRO_CALL}"
  230. PURGE MACRO_CALL
  231. INITIALIZER_VALUE equs "{FIELD_{d:FIELD_ID}_INITIALIZER}"
  232. DELETE_INITIALIZER equs "PURGE FIELD_{d:FIELD_ID}_INITIALIZER"
  233. DELETE_INITIALIZER
  234. PURGE DELETE_INITIALIZER
  235. MACRO_CALL equs "{TMP}, {INITIALIZER_VALUE}"
  236. PURGE TMP
  237. PURGE INITIALIZER_VALUE
  238. FIELD_ID = FIELD_ID + 1
  239. ENDR
  240. PURGE FIELD_ID
  241. ; Clean up vars for nested invocation, otherwise some `equs` will be expanded
  242. PURGE INSTANCE_NAME
  243. PURGE STRUCT_NAME
  244. PURGE IS_NAMED_INVOCATION
  245. PURGE NB_FIELDS
  246. MACRO_CALL ; Now do call the macro
  247. PURGE MACRO_CALL
  248. ELSE
  249. INSTANCE_NAME:: ; Declare the struct's root
  250. ; Define instance's properties from struct's
  251. \2_nb_fields = NB_FIELDS
  252. sizeof_\2 = sizeof_\1
  253. ; Start defining fields
  254. FIELD_ID = 0
  255. REPT NB_FIELDS
  256. get_nth_field_info FIELD_ID
  257. FIELD_NAME equs STRCAT("{INSTANCE_NAME}_", STRUCT_FIELD_NAME)
  258. FIELD_NAME::
  259. ; We have defined a label, but now we also need the data backing it
  260. ; There are basically two options:
  261. IF _NARG == 2 ; RAM definition, no data
  262. ds STRUCT_FIELD_SIZE
  263. ELSE
  264. DATA_TYPE equs STRCAT("D", {{STRUCT_FIELD_TYPE}})
  265. REPT STRUCT_FIELD_NBEL
  266. DATA_TYPE \3
  267. SHIFT
  268. ENDR
  269. PURGE DATA_TYPE
  270. ENDC
  271. ; Clean up vars for next iteration
  272. PURGE STRUCT_FIELD
  273. PURGE STRUCT_FIELD_NAME
  274. PURGE STRUCT_FIELD_TYPE
  275. PURGE STRUCT_FIELD_NBEL
  276. PURGE STRUCT_FIELD_SIZE
  277. PURGE FIELD_NAME
  278. FIELD_ID = FIELD_ID + 1
  279. ENDR
  280. ; Clean up
  281. PURGE FIELD_ID
  282. ; Make sure to keep what's here in sync with cleanup at the end of a named invocation
  283. PURGE INSTANCE_NAME
  284. PURGE STRUCT_NAME
  285. PURGE IS_NAMED_INVOCATION
  286. PURGE NB_FIELDS
  287. ENDC
  288. ENDM
  289. ; dstructs nb_structs, struct_type, INSTANCE_NAME
  290. ; Allocates space for an array of structs in memory
  291. ; Each struct will have the index appended to its name **as hex**
  292. ; (for example: `dstructs 32, NPC, wNPC` will define wNPC0, wNPC1, and so on until wNPC1F)
  293. ; This is a limitation because RGBASM does not provide an easy way to get the decimal representation of a number
  294. ; Does not support data declarations because I think each struct should be defined individually for that purpose
  295. dstructs: MACRO
  296. STRUCT_ID = 0
  297. REPT \1
  298. dstruct \2, \3{X:STRUCT_ID}
  299. STRUCT_ID = STRUCT_ID + 1
  300. ENDR
  301. PURGE STRUCT_ID
  302. ENDM