zzrtl uses a very minimalistic C implementation.The following C features are unsupported: - floating points         - for loops - the preprocessor        - goto - do-while                - all variables must be - break                     declared at beginning - +=, -=, etc.              of function - unsigned types          - arrays - declare-anywhere        - assigning variables - switch-case               during declaration - the struct keyword is   - function prototypes  reserved for built-in   - probably other stuff;  types                     proceed with cautionBesides what you write yourself, the only functions available to youare the ones listed below. A brief description is provided for each.zzrtl's built-in error checking reports errors and ends execution ifanything goes wrong, though there are exceptions. If you find thesenotes too cryptic, refer to the pre-made scripts. They are thoroughlycommented and show each function in action.libc functions:printfsprintfsscanfmallocfreefopenfprintffclosememsetmemcmpstrcmpstrcasecmpstrcatsystem(most of these have had error checking added so the program will throw an error if an invalid pointer is used with them)generic functions:die(char *fmt, ...)    terminate with a custom error messageget32(void *)          get 32-bit (4 byte) value from raw dataget24(void *)          get 24-bit (3 byte) value from raw dataget16(void *)          get 16-bit (2 byte) value from raw dataget8(void *)           get 8-bit (1 byte) value from raw dataput32(void *, int)     put 32-bit (4 byte) value into raw dataput24(void *, int)     put 24-bit (3 byte) value into raw dataput16(void *, int)     put 16-bit (2 byte) value into raw dataput8(void *, int)      put 8-bit (1 byte) value into raw datau8(char)               get unsigned equivalent of signed chars8(int)                get signed char equivalent of intu16(int)               cast int to unsigned shorts16(int)               cast int to signed shortu32op(a, *op, b)       cast a and b to u32 and do operation;                       example: u32op(apples, ">=", oranges)                       the reason this exists is as a workaround for                       situations where signedness may cause behavior                       that is undesirable;                       valid options for op:                       "+" "-" "*" "/" "&" "|" "<" ">" "<="                       ">=" "==" "%"substring(*list, idx)  get string at index `idx` in string `*list`;                       returns 0 if anything goes awryfind_bytes             find ndl inside hay; ndl is a 0-term'd string  (*hay, hay_sz       of hexadecimal characters (failure returns 0)   , *ndl, only1)     NOTE: * can be used for wildcard bytes                             example string "DEAD****BEEF"                       only1 = 1 throws fatal error if more than one                               occurrence is foundfind_bytes_stride      same as find_bytes(), but allows you to specify  (*hay, hay_sz, *ndl stride; stride is the number of bytes to   , stride, only1)   advance when searchingfind_text              find ndl inside hay; ndl is a text string  (*hay, hay_sz       (returns 0 on failure)   , *ndl, only1)     example string "scubadiver"                       only1 = 1 throws fatal error if more than one                               occurrence is foundfind_text_stride       same as find_text(), but allows you to specify  (*hay, hay_sz, *ndl stride; stride is the number of bytes to  , stride, only1)    advance when searchingovl_vram_sz            returns virtual ram size of overlay  (void *, sz)load_png               returns pointer to rgba8888 pixel data of png  (fn, int *w, int *h) if it is successfully loaded; w and h are                       propagated with its width and height as well                       ex: pix = load_png("sky.png", &width, &height);                       returns 0 if file doesn't existint_array(num, ...)    create an int array containing `num` elements                       array32 = int_array(4, 10, 20, 30, 40);                       array32[0] is now 10, [1] is 20, and so onnew_string(..., 0)     combines multiple strings and returns a pointer                       to the result, which you can free() if you want                       the list you provide must end with 0                       ex: new_string("build-", codec, ".z64", 0);loadfile(              load a file, returning a pointer to its raw  char *fn, int *sz   data, or 0 if it doesn't exist; if `optional`   , bool optional)   is `true`, no error will be thrown if file does                       not exist; `sz` will be set to size of file (in                       bytes), or if you don't need that, pass 0tsv_col_row(char *tsv  returns pointer to string inside tsv, beneath  , char *col         column `col` and in row `row` (row 0 is first  , int  row)        row where names are contained)directory functions:dir_exists(char *)     returns 1 if directory of given name exists,                       returns 0 otherwisedir_enter(char *)      enter a directory (folder)                       NOTE: directory is created if it doesn't existdir_enter_file(char *) enter the directory of provided filedir_leave(void)        leave last-entered directorydir_mkname             make a compliant directory name; str can be 0  (int, *str)         if you want only a number for the folder namedir_use_style(char *)  set style used by dir_mkname (default is "pre")                       valid options:                          "pre"  : uses form "%d - %s"                          "preX" : uses form "0x%X - %s"                          "post" : uses form "%s (%d)"                          "postX" : uses form "%s (0x%X)"file_exists(char *)    returns non-zero if file of given name exists,                       returns 0 otherwisestruct rom functions:.new(char *)           allocate a rom structure and load rom file.free(void)            free a rom structure.raw(ofs)              get pointer to raw data at offset `ofs` in rom.save(char *)          save rom to disk using specified filename.align(int)            align injected files such that their injection                       offset is a multiple of the value you provide;                       in retail roms, alignment is 0x1000 for every                       file except the overlays, boot, dmadata, the                       audio files, and link_animetion [sic] (it is                       0x10 for all of these); the value you provide                       must be a multiple of 16 (0x10); to maximize                       space savings, inject files with smaller                       alignment requirements first.compress(fmt, mb)     compress rom using specified algorithm                       valid options: "yaz", "lzo", "ucl", "aplib"                       NOTE: to use another codec, patch your rom;                       mb is the number of mb to cap the compressed                       rom to; 32 is standard for OoT and MM.seek(u32)             go to offset within rom.seek_cur(adv)         go forward adv bytes in rom                       NOTE: use a negative value to travel backwards.tell(void)            get offset within rom.size(void)            get size of rom.inject(fn, comp)      inject file into rom                       NOTE: if comp is non-zero, file is compressible                       NOTE: returns pointer to injected data, or 0                       NOTE: if name is formatted like "*.ext", it                             will auto-detect a file by extension; for                             example, "*.zobj" to inject whatever zobj                             it can find.inject_dma            inject file into rom, over known dma index  (fn, comp, idx)     (file-size must match file being overwritten).inject_png            loads PNG, converts to N64 format, and injects  (fn, fmt, bpp, comp) into rom fmt and bpp use the n64texconv enums                       NOTE: if comp is non-zero, file is compressible.inject_raw            inject raw data into rom  (*raw, sz, comp)    NOTE: if comp is non-zero, file is compressible                       NOTE: returns pointer to injected data, or 0                       NOTE: sz is number of bytes, raw points to them.inject_raw_dma        inject raw data into rom, over known dma index  (*raw, sz, idx, cmp) (sz must match entry being overwritten).file_start(void)      get start offset of data injected with inject()                       NOTE: will be 0 if inject() failed.file_end(void)        get end offset of data injected with inject()                       NOTE: will be 0 if inject() failed.file(void)            get pointer to data of most recently injected;                       NOTE: will be 0 if inject() failed.file_sz(void)         get size of injected data                       NOTE: will be 0 if inject() failed.file_dma(void)        get dma index of data injected with inject()                       NOTE: will be -1 if inject failed.extract               extract raw data to a file  (fn, start, end).extract_png           converts raw texture data to rgba8888, saves  (fn, buf*, tex, pal as PNG; buf can be a prealloc'd block that you   w, h, fmt, bpp)    can guarantee is large enough to intermediately                       store the converted texture, or 0 to tell the                       function to alloc its own; fmt and bpp must be                       as they are defined by the n64texconv enums.dma(start, num)       specify start of dmadata, and number of entries                     * every entry is by default marked as readonly,                       and dma_queue() must be used to mark specific                       entries as writable                     * no entry is queued for compression at first,                       and dma_compress() must be used to selectively                       enable compression where it is desired.dma_queue_one(idx)    mark one dma entry (by index) as writable;.dma_queue             mark dma indices as writable, between start and  (start, end)        end, inclusive (aka start <= idx <= end).dma_compress_one      set compression flag on dma entry (by index);  (idx, comp)         if (comp == 1), file is marked for compression;                       0 means no compression; other non-zero values                       are reserved for internal use only.dma_compress          set compression flag on indices between start  (start, end, comp)  and end, inclusive (aka start <= idx <= end).dma_ready(void)       call this when you're finished with the dma                       stuff; must be called before you inject data.write(void *, sz)     write and advance `sz` bytes within rom.write32(u32)          write and advance four bytes within rom.write24(int)          write and advance three bytes within rom.write16(int)          write and advance two  bytes within rom.write8(int)           write and advance one  byte within rom.read32(void)          read and advance four bytes within rom.read24(void)          read and advance three bytes within rom.read16(void)          read and advance two  bytes within rom.read8(void)           read and advance one  byte within rom.cloudpatch(ofs, fn)   patch a rom with a cloudpatch (.txt patch);                       ofs is the value to add to all the offsets in                       the patch, which is useful for applying patches                       to individual files as they are injected;                       otherwise, just use 0.rearchive             this function is for MM only; it re-encodes  (start, end, old,   the contents of an archive (a file containing   new, repack)       multiple compressed files); `old` refers to                       the old encoding (only "yaz" is supported for                       now), and `new` refers to the new encoding,                       like "ucl"; `repack` should always be true (1)                       unless you run out of space and need the lossy
                       packing hack (use false (0) in that case)
                       (it is lossy in that it zeroes data at the end of
                       the texture until it fits, so it is recommended
                       that you optimize your textures manually)
.rearchive_one         re-encode one archive, by dma index  (idx, old, new,     (MM only; see rearchive for more details)   repack)struct folder functions:.new(*ext)             allocate a folder structure and parse the                       current directory; contents can be named any                     . way you like, as long as they contain a number                        > "0 - gameplay_keep"                        > "gameplay_keep (0)"                        > "room_0.zmap"                        > etc.                     . folder/file names starting with a '.' or '_'                       are not processed                        > .trash                        > _src                        > etc.                     . items are accessed in the order specified by                       the numerical part, which can be hexadecimal as                       long as it is preceded by "0x"                     . no two folder/file names are allowed to contain                       the same number (a fatal error will be thrown)                     . if ext is 0, it creates a folder list                     . if ext is non-zero, it creates a list of files                       of the requested extension, such as "zmap"                     . it first tries to find a number at the very                       beginning (it is not allowed to be surrounded                       by quotes, parenthesis, preceded by a space,                       etc); if that fails, it uses the last number it                       detects in the name                        -> "1 - spot04"       yields index 1                        -> "En_Torch2 (51)"   yields index 51                        -> "object_link_boy"  throws fatal error.free(void)            free a folder structure.name(void)            get current folder name.index(void)           get numerical part of current folder name.next(void)            go to next folder in list;                       returns 0 when end of list is reached.count(void)           get number of items in list.remaining(void)       get number of items between current and end.max(void)             get highest index detected in liststruct conf functions:.new(*fn, *fmt)        allocate a conf structure and parse file;                       fmt should be either "table" or "list";                     * a fatal error occurs if the file doesn't exist                     * see conf section for more details.free(void)            free a conf structure.exists(*name)         returns non-zero if name exists.get_int(*name)        get integer value associated with name;                     * this function throws a fatal error if the name                       does not exist; if you are handling optional                       names, use .exists(name) to confirm it exists                       before calling this function                     * passing 0 to this function will cause it to                       return the current list item's value as an int.get_str(*name)        get pointer to string associated with name;                     * the contents of the string are read only; do                       not modify them or you will cause undefined                       behavior                     * this function throws a fatal error if the name                       does not exist; if you are handling optional                       names, use .exists(name) to confirm it exists                       before calling this function.next(void)            in the case of a table, go to next row;                       in a list, go to next item                       returns 0 when there is no next line.remaining(void)       returns non-zero if there are rows (in table),                       items (in list), remaining, 0 otherwise.name(void)            returns string of selected item name                       returns 0 at end of list                       (for use in list types only).value(void)           returns string of selected item value                       returns 0 at end of list                       (for use in list types only)conf sectionconf can load files of two formats: "table" and "list"the following information applies to both formats:you can use // to comment out the remainder of a line,or /* to comment out a specific block of text */the number of tabs or spaces between names/values doesnot matter, as all contiguous blocks of whitespace areused to determine where one name or value ends and thenext begins; the names and values can contain anythingbut whitespace (you can get around this limitation byputting quotes around them); lastly, keep in mind thatthe names are NOT cAsE-sEnSiTiVe, and as such, "vram"and "VRAM" are the samethe source code provided for each can be executed usingzzrtl; just save as .rtl and open in zzrtl; don't forgetto make sure their dependencies ("table.txt", "list.txt")are in the same directory as their respective .rtlstable noteshere is a table that you may load from a filetable.txtscene  card  music  notes             fadein0x02    off   stop  "diligent work"        20x03     on     go  "getting ocarina"      3the first row contains the names that are used to lookup the values using the .get_x() functions; the rowsthat follow contain the values themselvesthe code for parsing it would look like/**************************************** * <z64.me> zzrtl table parsing example * ****************************************//* table.txt (save in same directory as example)scene  card  music  notes             fadein0x02    off   stop  "diligent work"        20x03     on     go  "getting ocarina"      3*/intmain(int argc, char **argv){   struct conf *table;   char *card;   char *music;   char *notes;   int  scene;   int  fadein;   /* load the table */   table = table.new("table.txt", "table");   /* now parse all the rows */   while (table.remaining())   {       /* retrieve variables */       scene = table.get_int("scene");       card  = table.get_str("card");       music = table.get_str("music");       fadein = table.get_int("fadein");       notes = table.get_str("notes");             /* do something with the variables here */       printf("scene %d settings:\n", scene);       printf(" > card: %s\n", card);       printf(" > music: %s\n", music);       printf(" > fadein: %d\n", fadein);       printf(" > notes: %s\n", notes);             /* on the first pass, each variable will be whatever the *        * first value row says it should be; on the second pass, *        * it pulls from the next row; there is no third pass    */             /* go to next row */       table.next();   }   /* cleanup */   table.free();   return 0;}list noteshere is a list that you may load from a filelist.txtvram         0x80800000unknown      0x01000000"please do"  "work diligently"//optional     "output changes if you uncomment this line"each row contains a names is used to look up the valueto its right using the .get_x() functions;the code for parsing it would look like/*************************************** * <z64.me> zzrtl list parsing example * ***************************************//* list.txt (save in same directory as example)vram         0x80800000unknown      0x01000000"please do"  "work diligently"//optional     "output changes if you uncomment this line"*/intmain(int argc, char **argv){   struct conf *list;   char *optional;   char *pleasedo;   int  vram;   int  unknown;   /* load the list */   list = list.new("list.txt", "list");   /* retrieve variables */   vram     = list.get_int("vram");   unknown  = list.get_int("unknown");   pleasedo = list.get_str("please do");     /* how to do optional variables */   if (list.exists("optional"))       optional = list.get_str("optional");   else       optional = 0;   /* do something with the variables here */   printf("vram:         0x%X\n", vram);   printf("unknown:      0x%08X\n", unknown);   printf("'please do': '%s'\n", pleasedo);   if (optional)       printf("optional:    '%s'\n", optional);   /* cleanup */   list.free();   return 0;}migrating a zzromtool project tree to zzrtlfirst off, if you are taking advantage of zzromtool'sbuilt-in table expansion, you are going to need to either: (a) make everything fit within the original    limits for each table (b) create your own table expansion mod and    update the sample build script as neededmisc, system, shader, patch, repoint.tsv > this stuff is all deprecated, in favor of modifying  it in the rom directly; should you wish to reimplement  it in your own build script, the option is there > externalizing some files, like Link's overlay, does  have its benefits; it was left out of the example  build script for the sake of simplicity, but here is  a guide to adding this particular functionality to  the sample build script:  https://github.com/z64me/zzrtl/compare/master...oot-link-catroute.txt > remove the '#' character from the first row > any remaining '#' comments should be changed to //scenein the sample build script... > change "unk_a" to "unk-a:" > change "unk_b" to "unk-b:" > change "shader" to "shader:"note: > save and restrict are not used, but you could add  support for them with some assembly editing and by  updating the build scriptIf you read this far, chances are you don't even need a manual. ;) |