Advertisement
ZoriaRPG

Creating ZScript Instructions

Oct 23rd, 2018
335
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 26.18 KB | None | 0 0
  1. ////////////////////////////////////
  2. // Creating ZScript Instructions ///
  3. ////////////////////////////////////////////////////////////////////////////
  4. //! Note: A ZASM instruction may have a label of no more than 79 chars.  ///
  5. ////////////////////////////////////////////////////////////////////////////
  6.  
  7. /* VARIABLES */
  8.  
  9. To add variables to ZScript, for any of the ZS namespaces (e.g. 'Screen'), you must follow a process of
  10. adding the ZASM labels, to three files, the hooks for the instruction in the Global Symbols array,
  11. and the actual live instruction code to ffscript.cpp.
  12.  
  13. You may wish to add a function to class FFScript along the way.
  14.  
  15. /* STEPS */
  16.  
  17. //////////////////////////////////////////////////
  18. /// 0. ZASM Instruction and ZScript Identifier ///
  19. //////////////////////////////////////////////////
  20.  
  21. Before adding a new instruction, you must decide both the ZASM Label (the assembly label) that it will use.
  22. and the IDENTIFIER that the user will utilise when writing ZScript code.
  23.  
  24. For the sake of the examples (below), we'll decide that we want to give Link a custom *hat*, and we will call the variable
  25. that holds the data for his hat as `Link->Hat`, with the ZASM Label LINKHAT.
  26.  
  27. /////////////////////
  28. /// 1. ffscript.h ///
  29. /////////////////////
  30. Each new ZScript variable must have a unique ZASM register, defined in ffscript.h.
  31.  
  32. A typical entry for these, looks like this:
  33.    
  34.     [example--
  35.         #define LWPNX                0x0259
  36.     --end example]
  37.  
  38. This is the primary ZASM label for the ZScript instruction, lweapon->X, used by *Zelda.cpp*.
  39.     That means that this is the token used by ZC, when processing the stack!
  40.  
  41. To add a new instruction, either:
  42. (a)(1) Find the end of the list of instructions by seeking for `NUMVARIABLES`.
  43. (a)(2) Add a new definition above NUMVARIABLES, and addign it a value equal to
  44.     the value of the (prior instruction +1).
  45.     NOTE that these values are hexadecimal.
  46. (a)(3) Increase the value assigned to NUMVARIABLES by +1.
  47.  
  48. As an example, we'll add the new variable, Link->Hat:
  49.  
  50.     Prior to adding it, we have:
  51.    
  52.     [example--
  53.         #define NPCDATABEHAVIOUR    0x1318 
  54.         #define NUMVARIABLES        0x1319
  55.     --end example]
  56.  
  57. Here is the result after we add our new definition:
  58.  
  59.     [example--
  60.         #define NPCDATABEHAVIOUR    0x1318 
  61.         #define LINKHAT         0x1319
  62.         #define NUMVARIABLES        0x131A //Remember, these are HEX!
  63.     --end example]
  64.  
  65. --or--
  66.  
  67. (b)(1) Find an unused variable *e.g., reserved space) and change the identifier of the define
  68.     directive to the ZASM LABEL that you wish to use for your new variable.
  69.        
  70.  
  71. ////////////////////
  72. /// 2. ffasm.cpp ///
  73. ////////////////////
  74. There are two large arrays in ffasm.cpp. The first is for ZASM COMMANDS, and the second is for ZASM VARIABLES.
  75.    
  76. For ZScript variables, you will want to append to the array,`script_variable variable_list[]`
  77.  
  78. A typical entry in this table looks like this:
  79.  
  80.     [example--
  81.         { "LWPNX",             LWPNX,                0,             0 },
  82.     --end example]
  83.        
  84. The TERMINATION ENTRY in the table reads as follows:
  85.     [example--
  86.         { " ",                       -1,             0,             0 }
  87.     --end example]
  88.            
  89.  
  90.        
  91. To add your new variable:
  92. (a)(1) Duplicate the last entry in the table, PRIOR to the termination entry.
  93. (a)(2) Replace the string in the entry with a string that matches your ZASM label.
  94. (a)(3) Replace the old ZASM label , in this entry, with your new ZASm label.   
  95.     e.g., if you are adding a ZASM label of LINKHAT, your table entry will be:
  96.         [example--
  97.             { "LINKHAT",             LINKHAT,                0,             0 },
  98.         --end example]
  99. (a)(2)
  100.  
  101.  
  102.            
  103. ////////////////////////////
  104. /// 3. parser/bytecode.h ///
  105. ////////////////////////////
  106. Next, we move into the parser files, starting with bytecode.h, where the actual bytecode IDs are located.
  107.            
  108. These IDs are the literal value of each instruction in ZScript, stored in the stacks!
  109.            
  110. When ZC processes a ZScript instruction, it follows this flowchart:
  111.    
  112.     1. Read stack.
  113.     2. Match instruction to a definition in the bytecode.
  114.     3. Convert that literal to a string.
  115.     4. Match that string to a value in ffscript.h
  116.     5. The switch blocksw in ffscript.cpp execute that case value.
  117.        
  118.  
  119. To add your new variable, find the end of the bytecode, by seeking `LAST_BYTECODE`.
  120. NOTE: These values are DECIMAL, not hex.
  121.    
  122. (a)(1) Duplicate the definition prior to LAST_BYTECODE.
  123. (a)(2) Append a new define after this, with a number one higher than the prior definition.
  124. (a)(3) Increment LAST_BYTECODE by one.
  125.  
  126. Continuing our example, adding Link->Hat:
  127.    
  128. Prior to adding it, we have:
  129.    
  130.     [example--
  131.         #define NPCDATABEHAVIOUR    991
  132.         #define LAST_BYTECODE       992
  133.     --end example]
  134.  
  135. Here is the result after we add our new definition:
  136.  
  137.     [example--
  138.         #define NPCDATABEHAVIOUR    991
  139.         #define LINKHAT         992
  140.         #define LAST_BYTECODE       993 //Remember, these are DEC!
  141.     --end example]
  142.  
  143.    
  144.    
  145. //////////////////////////////
  146. /// 4. parser/bytecode.cpp ///
  147. //////////////////////////////
  148. Similar to ffasm.h, here we will be adding a case to return a string when the parser encounters a specific literal.
  149.    
  150. To add a new variable, seek the function `string VarArgument::toString()`, and then, inside the switch block `switch(ID)`,
  151. add a new case, using our ZASM label as the case value, and returning the same as a string:
  152.    
  153.  
  154.     [example--
  155.         case LINLHAT: return "LINKHAT";
  156.     --end example]
  157.  
  158. ///////////////////////////////
  159. /// 5. Global Symbols Table ///
  160. ///////////////////////////////
  161.  
  162. In the global symbols table for the namespace to which you are adding the variable--Link, in the case of
  163. our example--, we will next add a table entry into the array to convert to the correct ZASM instruction
  164. when the parser scans for tokens.
  165.    
  166. At present, these tables all exist in GlobalSymbols.cpp.
  167.  
  168. Entries in these tables typically exist in PAIRS: One for reading a variable, and one entry for writing to it.
  169. These are GETTER and SETTER entries, respectively, and a typical pair looks like this:
  170.  
  171.     [example--
  172.         { "getHat", ZVARTYPEID_FLOAT, GETTER, LINKX, 1, {  ZVARTYPEID_LINK, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} },
  173.         { "setHat", ZVARTYPEID_VOID, SETTER, LINKX, 1, {  ZVARTYPEID_LINK, ZVARTYPEID_FLOAT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} },
  174.    
  175.     --end example]
  176.        
  177.     The FIELDS for these arrays are as follows:
  178.         "string"    : This is the token that the scanner will use when compiling.
  179.                 : Variables are prefaced by a lowercase "set" or "get", then the variable
  180.                 : identifier. Thus, "getHat" and "setHat" will become Hat (read, and write).
  181.                 : To add an array format (indexed) variable, append "[]" to the string.
  182.                 : Thus, "setVar[]" or "gerVar[]"
  183.         Return Type : The return type of the variable.
  184.                 : For SETTERs, this is always ZVARTYPEID_VOID.
  185.                 : For GETTERs, you must specify the appropriate type.
  186.                 : The most common GETTER return types are ZVARTYPEID_FLOAT and ZVARTYPEID_BOOL.
  187.         Instr. Type : Defines if the instruction is a SETTER or a GETTER.
  188.                 : The third type, FUNCTION, is used for ZASM COMMANDS.
  189.         ZASM LABEL  : The ZASM label (bytecode ID) into which the parser will convert the instruction.
  190.         Num. Fields : The number of fields used by the variable.
  191.                 : For ordinary variables, this is always `1`.
  192.                 : For arrays, this is the number of indices in the array.
  193.         ARGS        : The inputs, and datatypes thereof, used by the variable, starting with its `this`.
  194.                 : In the examples above, both the SETTER and the GETTER have a `this` of Link.
  195.                 : Values of `-1` indicate no input.
  196.                 : In the examples above, the GETTER has NO args after its `this`.
  197.                 : In the examples above, the SETTER has ONE args after its `this`, with a TYPE of FLOAT.
  198.        
  199.  
  200. To add your new variable:
  201.  
  202. (a)(1) Locate the correct table. For Link, seek the array `LinkSTable[] `.
  203. (a)(2) Add a GETTER entry:
  204.     [example--
  205.         { "getHat", ZVARTYPEID_FLOAT, GETTER, LINKX, 1, {  ZVARTYPEID_LINK, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} },
  206.     --end example]
  207. (a)(3) If the new variable is both read and write, then add a SETTER entry:
  208.     [example--
  209.         { "setHat", ZVARTYPEID_VOID, GETTER, LINKX, 1, {  ZVARTYPEID_LINK, ZVARTYPEID_FLOAT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} },
  210.     --end example]
  211.  
  212.        
  213.        
  214. ///////////////////////
  215. /// 6. ffscript.cpp ///
  216. ///////////////////////
  217. Now that we have completed our set-up, we can add the actual code that we will run when the user calls the new
  218. instruction in ZScript.
  219.        
  220. For variables, in ffscript.cpp, we will be adding entries both for the GETTER, and (for r/w instructions), the SETTER
  221.     in two separate switch blocks, using CASE labels.
  222. Each case in the switch uses the ZASM label.
  223.  
  224. GETTER instructions reside inside the `switch(arg)` block of the function: `long get_register(const long arg)`
  225. All entries in this switch block must return a value to `ret`.
  226. Indexed variables (arrays)
  227.  
  228.     A typical single variable:
  229.  
  230.     [example--
  231.         case LINKX:
  232.             ret = long(Link.getX()) * 10000;
  233.             break;
  234.     --end example]
  235.        
  236.     A typical array:
  237.        
  238.     [example--
  239.         case NPCDEFENSED:
  240.         {
  241.             int a = ri->d[0] / 10000; //The INDEX that we're accessing.
  242.             ///A sanity check.
  243.             if(GuyH::loadNPC(ri->guyref, "npc->Defense[]") != SH::_NoError ||
  244.                 BC::checkBounds(a, 0, (edefLAST255), "npc->Defense[]") != SH::_NoError)
  245.                 ret = -10000;
  246.             else
  247.             ret = GuyH::getNPC()->defense[a] * 10000;
  248.             break;
  249.         }
  250.     --end example] 
  251.        
  252.     NOTE: Almost all values are multiplied, or divided by 10000, as the literal values in ZScript
  253.         are 'fixed' point types, with a factor of 10000. Thus, `1` in ZScript has a literal value
  254.         of 10000, and we must manually convert to the correct values inside ffscript.cpp.
  255.        
  256.        
  257.        
  258. SETTER instructions, likewise, reside inside the `switch(arg)` block of the function:
  259.         `void set_register(const long arg, const long value)`
  260.        
  261. For these, we always have at least one base arg passed to them as `value`.
  262. Additional args, such as for indexed variables (arrays), use ri->d[] registers (part of refInfo).
  263.  
  264. Rentries in this switch block MAY NEVER return a value!
  265.        
  266.     A typical single variable:
  267.        
  268.     [example--
  269.         case LINKX:
  270.             Link.setX(value/10000);
  271.             break;
  272.     --end example]
  273.        
  274.         A typical array:
  275.    
  276.     [example-- 
  277.         case NPCDEFENSED:
  278.         {
  279.             long a = ri->d[0] / 10000; //The index to which we are writing.
  280.             //sanity check
  281.             if(GuyH::loadNPC(ri->guyref, "npc->Defense") == SH::_NoError &&
  282.                 BC::checkBounds(a, 0, (edefLAST255), "npc->Defense") == SH::_NoError)
  283.             GuyH::getNPC()->defense[a] = vbound((value / 10000),0,255);
  284.             break;
  285.         }
  286.     --end example]
  287.    
  288. Note that ZScript array sizes are automatically sanity bounded by the parser, so there is no need to
  289.         specifically check that ri->d[n] is within the bounds of 0 and size-1.
  290.        
  291. As internal/parser ZScript arrays are not true arrays, but merely a mask for accessing data in the FORM
  292.     of an arraym we can also use specific cases to do different things:
  293.        
  294.    
  295.     [example--
  296.         case NPCDD:
  297.         {
  298.             long a = ri->d[0] / 10000; //the 'INDEX'
  299.        
  300.             if(GuyH::loadNPC(ri->guyref, "npc->Attributes") == SH::_NoError &&
  301.             BC::checkBounds(a, 0, 15, "npc->Attributes") == SH::_NoError)
  302.        
  303.             //use the index to do different things
  304.             switch(a){
  305.                 case 0: GuyH::getNPC()->dmisc1 = value / 10000; break;
  306.                 case 1: GuyH::getNPC()->dmisc2 = value / 10000; break;
  307.                 case 2: GuyH::getNPC()->dmisc3 = value / 10000; break;
  308.                 case 3: GuyH::getNPC()->dmisc4 = value / 10000; break;
  309.                 case 4: GuyH::getNPC()->dmisc5 = value / 10000; break;
  310.                 //truncated list of additional values
  311.                 default: break;
  312.             }
  313.             break;
  314.         }
  315.    
  316.     --end example]
  317.        
  318. Also noteworthy, is that there need be no direct correlation internally to what each index of your
  319. ZScript array represents. It is prefectly valid for one array to access radically different internal memory locations.
  320.        
  321.  
  322. /////////////////////
  323. /// ZASM COMMANDS ///
  324. ////////////////////////////////////////////////////
  325.  
  326.  
  327. Adding ZASM Commands (ZScript FUNCTIONS), is somewhat more complicated than adding variables, as you must manually
  328. specify the operation of data registers in the GlobalSymbols maps.
  329.  
  330. Here is a BASIC OUTLINE on the process.
  331.  
  332. //////////////////////////////////////////////////
  333. /// 0. ZASM Instruction and ZScript Identifier ///
  334. //////////////////////////////////////////////////
  335.  
  336. As with adding basic instructions, you must decide both the ZASM Label (the assembly label) that it will use.
  337. and the IDENTIFIER for the function that the user will utilise when writing ZScript code.
  338.  
  339. For the sake of the examples (below), we'll decide that we want to read the tiles in Link;s sprite.
  340.  
  341. As Link's sprites are a multi-dimensional array, and we want to access it with one instruction, we'll be making
  342. Link->GetSpriteTile(int sprite, int indx), and Link->SetSpriteTile(int sprite, int index, int tile).
  343.  
  344. The ZASM labels for these will be GETLINKSPRITETILES and SETLINKSCRIPTTILES.
  345.  
  346. /////////////////////
  347. /// 1. ffscript.h ///
  348. /////////////////////
  349.  
  350. To begin this process, we'll start in ffscript.h, inside of the enum `ASM_DEFINE`.
  351.  
  352. This enumerated list contains the ZASM Labels for ALL ZASM COMMANDS.
  353.    
  354. Note that you MUST keep these in order, and never change their order; and that you will later need to add
  355. the ZASM label to a 2D array in the SAME order as you list it in ASM_DEFINE.
  356.  
  357. TO begin, seek for `NUMCOMMANDS`.
  358.    
  359. Duplicate the entry prior to that, and replace the definition with our new ZASM Label.
  360.  
  361. If the current entry for ASM_DEFINE looks like this:
  362.    
  363.     [example--
  364.         FXZAPR,
  365.         FXZAPV,
  366.         GREYSCALER,
  367.         GREYSCALEV,
  368.            
  369.         NUMCOMMANDS           //0x013B
  370.     --end example]
  371.  
  372. It will look like *this*, after we add out new label:
  373.  
  374.     [example--
  375.         FXZAPR,
  376.         FXZAPV,
  377.         GREYSCALER,
  378.         GREYSCALEV,
  379.         GETLINKSPRITETILES,
  380.         SETLINKSPRITETILES,
  381.            
  382.         NUMCOMMANDS           //0x013B
  383.     --end example]
  384.  
  385. ///////////////////
  386. // 2. ffasm.cpp ///
  387. ///////////////////
  388.  
  389. Next, in our ASM code, we need to add the new ZASM COMMAND Label to the 2D array:
  390. `script_command command_list[NUMCOMMANDS+1]`
  391.  
  392. When adding to ( script_command command_list[NUMCOMMANDS+1] ) list, in ffasm.cpp, the ORDER of listing
  393. any new parameter MUST MATCH the order in ( ASM_DEFINE ) in file ffscript.h!
  394.  
  395. (This differs from script variables, which may be in any order.)
  396.  
  397. This 2D array is matched AGAINST ADM_DEFINE to find the numeric literal value of COMMANDS.
  398.  
  399. Here is an excerpt of this table:
  400.  
  401.     [example--
  402.         { "MULTR",               2,   0,   0,   0},
  403.         { "MULTV",               2,   0,   1,   0},
  404.         { "DIVR",                2,   0,   0,   0},
  405.         { "DIVV",                2,   0,   1,   0},
  406.         { "WAITFRAME",           0,   0,   0,   0},
  407.         { "GOTO",                1,   1,   0,   0},
  408.         { "CHECKTRIG",           0,   0,   0,   0},
  409.         { "WARP",                2,   1,   1,   0},
  410.         { "COMPARER",            2,   0,   0,   0},
  411.         { "COMPAREV",            2,   0,   1,   0},
  412.         { "GOTOTRUE",            1,   1,   0,   0},
  413.         { "GOTOFALSE",           1,   1,   0,   0},
  414.     --end example]
  415.  
  416. In this table, the first entry is a STRING of the ZASM Label.
  417. The second, is the number of commands used by its Opcode:
  418.     Unary Opcodes use `1`
  419.     Binary Opcodes use 2`
  420.     All others use `0`.
  421.        
  422. These determine if data is automatically pushed into sarg1 and sarg2.
  423.    
  424. The third and fourth values are labeled `sarg1` and `sarg2`, and /**I BELIEVE that these are
  425. used to automatically POP those registers. **/
  426.  
  427. /*This needs verification!*/
  428.  
  429. The fourth value, is labeled `more`, and is not used by anything. /*I am UNSURE of its intended use. */
  430.  
  431. Thus, you have entries consisting of:
  432.  
  433.     [example--
  434.         { "ZASM_LABEL", push/num_args, sarg1/pop1, sarg2/pop2, more},
  435.     --end example]
  436.  
  437. When adding a new instruction, it is best either to use another instruction as its basis, or:
  438. (a) If you are using only one or two parameters, you can set `args to `1` or `2`.
  439. (b) If you are using three or more args, or no args, you can set `args` to `0` and directly read the stack.
  440.        
  441. All of this depends on if you wish to create a basic Opcode, a Unary opcode, or a Binary Opcode in ByteCode.h.
  442.    
  443. In any case, we are using two args for `Link->GetSpriteTile(int sprite, int index, int tile)` and three args for
  444.     Link->SetSpriteTile(int sprite, int index, int tile). The former, also must return a value to a register
  445. for us to use.
  446.    
  447.  
  448. We'll define these in the `script_command command_list[NUMCOMMANDS+1]` array as:
  449.  
  450.     [example--
  451.         { "GETLINKSPRITETILES", 1, 0, 0, 0}, //WIll use unary opcode
  452.         { "SETLINKSPRITETILES", 0, 0, 0, 0}, //Will use Opcode
  453.     --end example]
  454.  
  455.        
  456. ///Generic Setter ROutine for basic Opcode (not for Unary or Binary opcode types)
  457.        
  458. void SetterFunction(const string& label, new Opcode* ocode, int numargs)
  459. {
  460.     Function* function = getFunction(label);
  461.        int label = function->getLabel();
  462.        vector<Opcode *> code;
  463.        Opcode *first = ocode();
  464.        first->setLabel(label);
  465.        code.push_back(first);
  466.        POP_ARGS(numargs, EXP2);
  467.        //pop pointer, and ignore it
  468.        code.push_back(new OPopRegister(new VarArgument(NUL))); //Pop its `this` to NUL.
  469.        code.push_back(new OPopRegister(new VarArgument(EXP2)));
  470.        code.push_back(new OReturn());
  471.     function->giveCode(code);
  472. }
  473.  
  474. void GetterFunction(const string& label, new Opcode ocode, int numargs)
  475. {
  476.     /////////////////////////////****************************
  477.    
  478.  
  479.  
  480. We will append them to the bottom of the list.
  481.         //Drawing
  482.  
  483. Script_Drawing.cpp
  484. add function
  485. add opcode redirect with ZASM label
  486.  
  487. GlobalSymbols.cpp
  488.  
  489. Add table entry, with proper args values. The entry name should match the ZScript instruction.
  490. Add function to bind the name in the table to the O-Register
  491.  
  492. Bytecode.cpp
  493.  
  494. Add ORegister redirect that returns the ZASM instruction
  495.  
  496. Bytecode.h
  497.  
  498. Add class ORegister entry tat returns the opcode entry in Bytecode.cpp
  499.  
  500. ffasm.cpp
  501.  
  502. Add entry to script command list, using the ZASM label
  503.  
  504. ffscript.cpp
  505.  
  506. add case statement to switch(script_command) and ensure the args value matches that in GlobalSymbols.c[[
  507.  
  508. add case entry to switch(scommand), and ensure it is in the script commands case list
  509. Both of these use the ZASM label
  510.  
  511. ffscript.h
  512. Add the ZASM label to the ASM_DEFINE table.
  513.  
  514. //Link
  515.  
  516. Link.h
  517.  
  518. Add a new public variable if needed, suc as:
  519.     int linkdointhing
  520. (or)
  521. Find a public variable to use
  522. Add an empty function set (getter, setter) with the identifier that you desire, such as
  523.     int getLinkDoingThing()
  524.     void setLinkDoingThing(int value)
  525.    
  526. Add a clear instruction in the Init function:
  527.     linkdointhing = 0;
  528.  
  529. Link.cpp
  530. Create a pair of setter/getter functions tied to the link class, such as:
  531.  
  532.     //Return the variable using a getter.
  533.     int LinkClass::getLinkDoingThing()
  534.     {
  535.         return linkdointhing;
  536.     }
  537.  
  538.     //Set the variable using a setter
  539.     void LinkClass::setLinkDoingThing(int value)
  540.     {
  541.         linkdointhing=value;
  542.        
  543.     }
  544.  
  545. ! You can constrain the min and max values written with: vbound(int value, int min, int max)
  546.  
  547.     //Set the variable using a setter
  548.     void LinkClass::setLinkDoingThing(int value)
  549.     {
  550.         linkdointhing=vbound(value,0,3);
  551.        
  552.     }
  553.    
  554. ffasm.cpp
  555. Add an entry to the ( variable_list[] ) table, and introduce your ZASM keyword:
  556.     { "LINKDOTHING", LINKDOTHING, 0, 0 },
  557.     The first value is a string, that is matched wit the assembly, to the second value, called by GlobalSymbols.cpp.
  558.  
  559. ffscript.h
  560. Define the ZASM label and give it a unique numeric value. This is used by the wordtable to look it up.
  561.     #define LINKDOTHING           0x0300
  562. If you added something new, be sure to increase the value of NUMVARIABLES.
  563.  
  564.  
  565. ffscript.cpp
  566.  
  567.  
  568. in the ( long get_register(const long arg) switch(arg) ) STATEMENT, under 'Link's Variables' add a GETTER instruction case:
  569.     case LINKDOTHING:
  570.     ret=Link.getLinkDoingThing*10000; //THis points to the LinkClass::getWarpSound() function
  571.                     //Be sure to work with the ZScript 10,000 multplier!
  572.     break;
  573.  
  574. in the ( long set_register(const long arg) switch(arg) ) STATEMENT, under 'Link's Variables' add a SETTER instruction case:
  575.     case LINKDOTHING:
  576.     Link.getLinkDoingThing(value/10000); //THis points to the LinkClass::getWarpSound() function
  577.                     //Be sure to work with the ZScript 10,000 multplier!
  578.     break;
  579.  
  580. /parser/ByteCode.h
  581. Add a new definition with a unique value using your ZASM label.
  582. This DOES NOT need to match the word table ID tat you set earlier.
  583.     #define LINKDOTHING 401
  584.    
  585. /parser/ByteCode.cpp
  586.  
  587. in ( string VarArgument::toString() switch(ID) ) add a string redirect case for the ZASM label:
  588.  
  589.     case LINKDOTHING: //We the word table looks up the ZASM instruction and finds this...
  590.         return "LINKDOTHING"; //it returns this string.
  591.        
  592. /parser/GlobalSynbols.cpp
  593. in ( static AccessorTable LinkSTable[] ) add setter/getter entries.
  594.  
  595. { "getDoThing",            ScriptParser::TYPE_FLOAT,         GETTER,       PLAYWARPSOUND,         1,      {  ScriptParser::TYPE_LINK,         -1,                               -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1                           } },
  596.    { "setDoThing",            ScriptParser::TYPE_VOID,          SETTER,       PLAYWARPSOUND,         1,      {  ScriptParser::TYPE_LINK,          ScriptParser::TYPE_FLOAT,        -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1,                           -1                           } },
  597.  
  598. The first etry on each line is te ZScript command token. The chars 'set' or 'get' in lowercase are removed, so
  599. getDoThing / setDoThing i the Link table becomes Link->DoThing in ZScript.
  600.  
  601. The second entry on eac line is the TYPE. Getters are typed by their return. Setters are void typed, but you
  602. must define the input type later.
  603. The third entry is the instruction type: SETTER, GETTER, or FUNCTION.
  604. The fourth, is the ZASM label.
  605. The fifth, is '1' unless you are creating a FUNCTION type.
  606. Following these, is a ScriptParser::Type. For Link->, this is always ScriptParser::TYPE_LINK
  607. Followin this, is the input parameters.
  608. For a return, these are always all -1.
  609. For a setter, the first is its value type (TYPE_FLOAT, or TYPE_BOOL).
  610. For a function, define each input parameter by its type.
  611.  
  612. You're done.
  613.  
  614. // Adding a Function
  615.  
  616. //From DarkDragon regarding the stack:
  617.     the ZScript calling convention is more or less equivalent to C's.
  618.     The caller first pushes the return address onto the stack, then all of the function's explicit
  619.     argument, and finally, if the function is a member function, the "this" pointer is implicitly
  620.     pushed as the last argument.
  621.  
  622.     The return value of the function is by convention stored in EXP1.
  623.  
  624.     The callee, then, before it can return, must pop all of the arguments (including the "this" pointer)
  625.     off of the stack. That's what the lines are doing that you've commented about. The ZASM instruction
  626.     uses the top 4 entries of the stack, but leaves them untouched, so ZScript pops them off, then pops
  627.     off the return address and jumps to it. You could use NUL instead of EXP2 for these pops if you wanted.
  628.  
  629.     The reason EXP2 is used as scratch space instead of EXP1 is simply to avoid accidentally tampering
  630.     with the return value of the function.
  631.  
  632. Addin a function requires some additional work, as follows:
  633.  
  634. ffasm.cpp
  635. Add a new entry at the END of the table ( script_command command_list[NUMCOMMANDS+1] ) with the following format
  636. ZASMLABEL, number_of_args_for_the_assembler, has_arg_1, has_arg_2, more (?what's this now)
  637.  
  638. These are used by the function: int set_argument(char *argbuf, ffscript **script, int com, int argument)
  639.  
  640. Note that entries often have an 'R" and a 'V', meaning Register, and Value. These are effectively, ( ) and ( ).
  641.  
  642. Keep a careful eye on the position of the function in this table, as it must match the position of their counterparts
  643.     in ( enum ASM_DEFINE ) inside ffscript.h.
  644.  
  645. ffscript.h
  646.  
  647. Add an entry into the ( enum ASM_DEFINE ) table to match each entry that you added in ffasm.cpp. |
  648. These must be in the same sequence.
  649.  
  650. ffscript.cpp
  651.  
  652. Add a function to which you wish to pair each entry that you created in ffasm.cpp/ffscript.h
  653.  
  654. ByteCode.cpp
  655.  
  656. Add a string redirect, ( string OIdentifier::toString() ) in the list after the ( switch(ID) ) statement
  657.     in ( string VarArgument::toString() )
  658.  
  659. ByteCode.h
  660.  
  661. Add a class definition, setting its identifier, public type (UnaryCode, BinaryCode, OpCode) and
  662.     set its instructions. Return it new if desired.
  663.  
  664. GlobalSymbols.cpp
  665. Insert the function into the table to which you desire to link it, based on the class to which you are assigning it.
  666.     Set its type to ScriptParser::TYPE, its use to FUNCTION, its 'va' to '0' (this is for a script class variable,
  667.     such as 'X' in 'Link->X'), its indices, its number_of_indices to -1 (these are for array script vars, such as
  668.     ComboD[]), its type/class association, then, one entry for each of its inputs by type.
  669.     Use -1 to fill in any unused inputs.
  670.  
  671. In the vector for its class (e.g. ScreenSymbols::addSymbolsCode), create a routine for it, using the existing entries as
  672. examples. This may require writing a new opcode, or you may be able to use stack registers directly, depending on how many
  673. values you need to parse, and your return types.
  674.  
  675. //Global
  676.  
  677.  
  678. //NPCs
  679.  
  680. //Weapons
  681.  
  682. //FFCs
  683.  
  684. //Items
  685.  
  686. //itemdata
  687. ref->info /The current, selected object int he struct is identified by *
  688.  
  689. /// By ZoriaRPG
  690. /// Original version, (c) 8th December, 2016
  691. /// Rev 2 (c) 14th December, 216
  692. /// Revised version (c) 23rd October, 2018
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement