Difference between revisions of "VC Arrays"

From GTAMods Wiki
Jump to navigation Jump to search
 
Line 1: Line 1:
 
 
=Arrays in Vice City=
 
=Arrays in Vice City=
  
Line 8: Line 7:
 
  DEFINE ARRAY $my_array size 2 type INTEGER
 
  DEFINE ARRAY $my_array size 2 type INTEGER
 
  // Integer arrays were also used for storing ingame objects.
 
  // Integer arrays were also used for storing ingame objects.
 
+
 
  :label_my_code_0
 
  :label_my_code_0
 
  0004: $my_array_index = 0
 
  0004: $my_array_index = 0
Line 29: Line 28:
 
       $my_array = $my_array_data_0
 
       $my_array = $my_array_data_0
 
  0051: return
 
  0051: return
 
+
 
  :label_my_array_get_1
 
  :label_my_array_get_1
 
  00D6: if 0
 
  00D6: if 0
Line 36: Line 35:
 
       $my_array = $my_array_data_1
 
       $my_array = $my_array_data_1
 
  0051: return
 
  0051: return
 
+
 
  :label_my_array_get_2
 
  :label_my_array_get_2
 
  0051: return
 
  0051: return
 
+
 
  :label_my_array_set_0
 
  :label_my_array_set_0
 
  00D6: if 0
 
  00D6: if 0
Line 46: Line 45:
 
       $my_array_data_0 = $my_array
 
       $my_array_data_0 = $my_array
 
  0051: return
 
  0051: return
 
+
 
  :label_my_array_set_1
 
  :label_my_array_set_1
 
  00D6: if 0
 
  00D6: if 0
Line 53: Line 52:
 
       $my_array_data_1 = $my_array
 
       $my_array_data_1 = $my_array
 
  0051: return
 
  0051: return
 
+
 
  :label_my_array_set_2
 
  :label_my_array_set_2
 
  0051: return
 
  0051: return
 
+
 
  :label_my_code_1
 
  :label_my_code_1
 
  0050: gosub ££label_my_array_get_0
 
  0050: gosub ££label_my_array_get_0
Line 68: Line 67:
 
This method of array is still most notably used in PatrickW's Marina Carpark Mod.
 
This method of array is still most notably used in PatrickW's Marina Carpark Mod.
  
 +
The second method of simulating arrays is CyQ's method.  This uses one exploit of the SCM scripting engine in that parameters can be (in almost every OpCode, alot of the defining OpCodes are strangely limited) variables.  It also uses the fact that an address, once compiled, is merely an offset from the start of the file (or mission).  CyQ arrays calculate the address of a piece of code, store it in a variable then jump to the contents of that variable.
 +
 +
Note:  This method requires detailed SCM knowledge to use due to the byte counting and files including this can (reputably) not be decompiled properly (at least by MB).  A basic example which you can use to make arrays is explained below:
  
  :label
+
To retrieve data.  $var0 - $var2 are the globals where the data is stored.  0@ is the local variable we will work on in the script.
  0006:  0@ =  10   //these are the values we want to return from the array
+
 
 +
  :getlabel
 +
  008B:  0@ =  $var0   //these are the values we want to return from the array
 
  0051:  reutrn
 
  0051:  reutrn
  0006:  0@ =  78   //the space that the 0006 and the 0051 opcodes take up in total is 9 bytes because:
+
  008B:  0@ =  $var1   //the space that the 008B and the 0051 opcodes take up in total is 10 bytes because:
  0051:  return    //opcode(2 bytes) + ptype(1 byte) + var(2 bytes) + ptype(1 byte) + smallint(1 byte) + opcode(2 bytes) = 9
+
  0051:  return    //opcode(2 bytes) + ptype(1 byte) + localvar(2 bytes) + ptype(1 byte) + var(2 bytes) + opcode(2 bytes) = 10
  0006:  0@ =  36
+
  008B:  0@ =  $var2
 
  0051:  return
 
  0051:  return
 
   
 
   
 
  <Here is where the code will start>
 
  <Here is where the code will start>
 
  008B:  1@ = $index    //if we want the second value then $index = 1 (because for the first value $index = 0)
 
  008B:  1@ = $index    //if we want the second value then $index = 1 (because for the first value $index = 0)
  0012:  1@ *= 9       //9 * 1 = 9 (9 because the 0006 + 0051 opcodes take up 9 bytes in this case)
+
  0012:  1@ *= 10       //10 * 1 = 10 (10 because the 008B + 0051 opcodes take up 10 bytes in this case)
  000A:  1@ +=  ££label //add the value of ££label to 1@
+
  000A:  1@ +=  ££getlabel //add the value of ££label to 1@
  0050:  gosub 1@      //gosub to ££label + 9, so 0@ returns 78
+
  0050:  gosub 1@      //gosub to ££label + 10, so 0@ returns $var1 (the variable numbers match their array index).
 +
<Here is where your processing happens>
 +
 
 +
To store data.
 +
 
 +
:setlabel
 +
0088:  $var0 =  0@  //these are the values we want to store to the array.
 +
0051:  reutrn
 +
0088:  $var1 =  0@
 +
0051:  return
 +
0088:  $var2 =  0@
 +
0051:  return
 +
 +
<Here is where your processing happens>
 +
008B:  1@ = $index 
 +
0012:  1@ *= 10   
 +
000A:  1@ +=  ££setlabel
 +
0050:  gosub 1@    // Same as before only we save the data not retrieve it.
 +
<Here is where the code will end>

Revision as of 02:29, 15 December 2005

Arrays in Vice City

There are currently three methods of creating arrays. The first one (Barton Waterduck's method) has been largely depricated now due to the fact that, although simple to use in his builders (using psuedo commands), the generated code was large and complicated.

Example of array code in the builder (note: this feature was introduced about v1.3):

DEFINE ARRAY $my_array size 2 type INTEGER
// Integer arrays were also used for storing ingame objects.

:label_my_code_0
0004: $my_array_index = 0

:label_my_code_1
GET_ARRAY $my_array
// Get the data from the array at position $my_array_index.
// Do whatever with it.
$my_array += 1
SET_ARRAY $my_array
$my_array += 1
0002: jump ££label_my_code_1

Example of this code compiled and decomplied:

:label_my_array_get_0
00D6: if 0
        $my_array_index == 0
004D: jump_if_false ££label_my_array_get_1
      $my_array = $my_array_data_0
0051: return

:label_my_array_get_1
00D6: if 0
        $my_array_index == 1
004D: jump_if_false ££label_my_array_get_2
      $my_array = $my_array_data_1
0051: return

:label_my_array_get_2
0051: return

:label_my_array_set_0
00D6: if 0
        $my_array_index == 0
004D: jump_if_false ££label_my_array_get_1
      $my_array_data_0 = $my_array
0051: return

:label_my_array_set_1
00D6: if 0
        $my_array_index == 1
004D: jump_if_false ££label_my_array_get_2
      $my_array_data_1 = $my_array
0051: return

:label_my_array_set_2
0051: return

:label_my_code_1
0050: gosub ££label_my_array_get_0
// Get the data from the array at position $my_array_index.
// Do whatever with it.
$my_array += 1
0050: gosub ££label_my_array_get_1
$my_array += 1
0002: jump ££label_my_code_1

This method of array is still most notably used in PatrickW's Marina Carpark Mod.

The second method of simulating arrays is CyQ's method. This uses one exploit of the SCM scripting engine in that parameters can be (in almost every OpCode, alot of the defining OpCodes are strangely limited) variables. It also uses the fact that an address, once compiled, is merely an offset from the start of the file (or mission). CyQ arrays calculate the address of a piece of code, store it in a variable then jump to the contents of that variable.

Note: This method requires detailed SCM knowledge to use due to the byte counting and files including this can (reputably) not be decompiled properly (at least by MB). A basic example which you can use to make arrays is explained below:

To retrieve data. $var0 - $var2 are the globals where the data is stored. 0@ is the local variable we will work on in the script.

:getlabel
008B:  0@ =  $var0   //these are the values we want to return from the array
0051:  reutrn
008B:  0@ =  $var1   //the space that the 008B and the 0051 opcodes take up in total is 10 bytes because:
0051:  return     //opcode(2 bytes) + ptype(1 byte) + localvar(2 bytes) + ptype(1 byte) + var(2 bytes) + opcode(2 bytes) = 10
008B:  0@ =  $var2
0051:  return

<Here is where the code will start>
008B:  1@ = $index    //if we want the second value then $index = 1 (because for the first value $index = 0)
0012:  1@ *= 10        //10 * 1 = 10 (10 because the 008B + 0051 opcodes take up 10 bytes in this case)
000A:  1@ +=  ££getlabel //add the value of ££label to 1@
0050:  gosub 1@       //gosub to ££label + 10, so 0@ returns $var1 (the variable numbers match their array index).
<Here is where your processing happens>

To store data.

:setlabel
0088:  $var0 =  0@   //these are the values we want to store to the array.
0051:  reutrn
0088:  $var1 =  0@ 
0051:  return
0088:  $var2 =  0@
0051:  return

<Here is where your processing happens>
008B:  1@ = $index  
0012:  1@ *= 10     
000A:  1@ +=  ££setlabel 
0050:  gosub 1@     // Same as before only we save the data not retrieve it.
<Here is where the code will end>