What this does allows you to pass arrays through functions in a script. As of 2.53 and IIRC even now, this is the only way you can have variables changed by functions persist after the function ends. Especially helpful for enemies where you need several variables that need to persist after being changed by functions.
That makes no difference here. The array pointer that you pass to a function would still be invalid, as it is global and not properly constructed in an extant save slot. You can do that freely with local arrays, but with any global variable, if you add it after saving when playing the quest, then the quest cannot access it. This applies to all variables, not only arrays.
While you can pass a global pointer to a function by reference, you can also reference it without passing it, as it is global.
int arr[16];
void foo(int ptr)
{
ptr[3] = 96;
}
ffc script t
{
void run()
{
foo(arr);
}
}
ffc script f2
{
void run()
{
arr[3] = 96;
}
}
//The array 'arr' is global, so you do not need to worry about it not being in scope.
You can pass an array pointer to a function so that a function outside of the local array scope can read it, but again, those are local arrays. If you see this error on a global variable or array, then you are using a save slot where global variables have already been allocated, and once they are allocated, if you add more, those will not be allocated, and ZASM will not know what to do with references to them.
You do not however, need a new save file. You need only a clean/blank save slot in your save file, from which to test the quest after adding the new global variables. There are only two instances where a global array can have a pointer of 0. One of them is when you do this, and have save data that does not include the array. The other, is when you intentionally write the pointer to 0, or an otherwise invalid or inactive pointer.
e.g.
int myarray[16] = {1,2,3};
global script foo
{
void run()
{
myarray = 0; //this is legal, because the pointer is INT, but it will corrupt the pointer.
//Access to myarray[] will after this point, be invalid, and will generate an error.
//Technically, there is a known valid pointer for this array type, but it is not intended to be used in a literal manner like that.
}
}
Changing array pointers is dangerous, and should never be done with literals, as the actual literal pointer value is not guaranteed to be identical from one version to another. Assign by reference OTOH, is valid.
int myarray[16] = {1,2,3};
global script foo
{
void run()
{
int newarray = myarray; //Assign an array pointer known to be valid to a new array.
newarray[1] = 6; //myarray[1] is now 6
}
}
You can also use IsValidArray(ptr) to validate arrays as of 2.53.1, recent builds, and 2.55 recent builds.
int myarray[16] = {1,2,3};
global script foo
{
void run()
{
myarray = 0; //this is legal, because the pointer is INT, but it will corrupt the pointer.
//Access to myarray[] will after this point, be invalid, and will generate an error.
//Technically, there is a known valid pointer for this array type, but it is not intended to be used in a literal manner like that.
}
}
Note that you can only assign arrays to their same type, unless you use an explicit cast.
P.S. never use an identifier of array or string. These are reserved.
e.g. never declare something like int array[5]; or something like char32 string[12];
These will give you headaches in the future. If you need a generic pointer, use ptr and buf.
Future real arrays will use array as a keyword for their type, and future real strings (like C++ string) will use string for their type.
These will be moderately incompatible with old ZScript arrays, but will be multidimensional, an you wlll be able to specify a function to expect an array or a string pointer as an argument.
In C, you can have:
void foo(int *ptr)
This will fail if you pass a normal integer, and will only accept a pointer, which is a distinction that ZScript lacks. In order to do this without breaking extant scripts, the new array and string types will use a token to mark them as a distinct pointer type. That is a olly way down the pipe, but it is worth mentioning for people who declare things like int array[]. If you do this, at some point, it will break an become illegal.
P.P.S. ZScript does know to properly evaluate function parameters when you specify char32 as a type. If you have a set of functions fuch as:
void foo(char32 ptr)
{
ptr[5] = '\0';
}
void foo (int a)
{
a = 6;
}
char32 buf[]="test";
int b = 2;
int c = buf;
char32 d = buf;
//call
foo(buf); //typematch to the string
foo(b); //typematch to the variable b
foo(c); //Ambiguous
foo(d); //Typematches to the string buf.
An argument typed to char32 tries to match a char32 string first, then it will try matching to int. , so when you pass char32 as an argument, if you have a function set up to expect char32, then ZScript will call that function. If you do not, then it defaults to int. You can pass char32 to int.
P.P.P.S.
I am extremely paranoid about array or string bugs in 2.55, so, the first thing that I did, was to test the script that the OP posted by compiling and running it. It was fine. It's usually wise to test an issue before giving out erroneous information on how to try to bypass it. Ignoring errors or trying to circumvent them is a doomed ship.