Scripts:Fake arrays

From OHRRPGCE-Wiki
(Redirected from Fake arrays)
Jump to navigation Jump to search

An array is a (typically variable length) list of data, such as this: [2, 5, -1]. HamsterSpeak currently doesn't natively support arrays (that's coming!) In the meantime there are two reasonable ways to 'fake' them (that is, store variable length lists): either store your array in global variables, or in slices.

The easiest way to use arrays in HamsterSpeak is to use the Scripts:Slice arrays library, which imitate Python lists.

Global variables[edit]

For basic uses, global variables are the simpler but less flexible solution. They are also faster to access.

First you need to decide which global variables you will use to store your array which does not overlap with other uses. Globals have ID numbers from 0 to 16383. For example, lets use globals starting at 1000 for an array holding the heroes that are alive. It's a good idea to use a constant defining the position so that you don't forget about it and can move as needed:

define constant(1000, array:alive heroes)

We'll also use a variable to hold the current array length:

variable(length)

Here's how to append an item X to the array:

write global(array: alive heroes + length, X)
length += 1

And here is how you access the ith item of the array, where 0 <= i < length:

hero := read global(array: alive heroes + i)

Lets loop through all heroes in the party and build the array:

variable(length, hero)
for (hero, 0, 40) do (
  if (get hero stat (hero, stat:hp) >= 1) then (
    write global(array: alive heroes + length, X)
    length += 1
  )
)

Now you can pick a random hero easily:

hero := read global(array: alive heroes + random(0, length -- 1))

Trimming values from the end of the array is as easy to reducing length. However removing from the middle of the array, sorting, or rearranging items is a pain; it's easier to use slices.

There's no need to erase the data in the globals at the end; simple forget about them (or set length := 0). Next time you call this script it overwrite the previous data.

Slices[edit]

Unlike globals, slice-based arrays can have unlimited length. You can store the data in the slice extra data or any of the other data fields, and can parent additional children to each slice to store more data.

Slice arrays[edit]

For a complete and friendly implementation of slice-based arrays, see the Scripts:Slice arrays article.

Compact slice arrays[edit]

The above Slice arrays library stores one value per slice. Here is an alternative way to store data in slices, which uses far fewer slices.

This is quite convenient if you have several pieces of data you want to store per position in the list, such as a list of enemies each of which has an NPC reference number and HP and firing cooldown values. Also, if you want to store strings then using text slices is the most reasonable method.

First, create a parent slice to hold the array.

variable(array)
array := create container

You might like to make it invisible if you'll keep it around:

set slice visible(array, false)

We'll demonstrate storing data in several data fields of a slice, up to 4 pieces of data per slice. It's easy to write a helper script to append an item to the list and set one or more pieces of data on it at the same time:

script, append data, array, data0, data1 = 0, data2 = 0, data3 = 0, begin
  variable(sl)
  sl := create container
  set parent(sl, array)
  set sort order(sl, data0)
  set slice extra(sl, extra 0, data1)
  set slice extra(sl, extra 1, data2)
  set slice extra(sl, extra 2, data3)
end

(If needed, you can easily stuff more more data into each slice, making use of the x, y, width, height, padding, etc fields.) And a helper script to read the data back out:

script, read data, sl, data num = 0, begin
  if (data num == 0) then (exit returning (get sort order(sl)))
  else if (data num == 1) then (exit returning (get slice extra(sl, extra 0)))
  else if (data num == 2) then (exit returning (get slice extra(sl, extra 1)))
  else if (data num == 3) then (exit returning (get slice extra(sl, extra 2)))
end

Let's form an array containing [(4, -2), (1, -1), (0, 0), (1, 1), (4, 2), (9, 3)]:

variable(array, ctr)
array := create container
for (ctr, -2, 3) do (
  append data(array, ctr ^ 2, ctr)
)

The appenddata script above stores the first data value in the 'sort order' field, so that sorting the array sorts in ascending order based on that value (while ignoring the others):

sort children(array)

Now the array contains [(0, 0), (1, -1), (1, 1), (4, -2), (4, 2), (9, 3)]. Let's retrieve the second item:

variable(item, i, i squared)
item := slice child(array, 1)  # index 1 is second item in array
i squared := read data(item, 0)
i := read data(item, 1)


Finally, you can make use of slice commands to reorder slices or delete from the middle of the list.

When you're done, you need to delete the array:

free slice(array)


Slices can also be saved in save games by turning on the setting in the Saved Games Settings menu.