PDA

View Full Version : Regarding arrays



pkmnfrk
11-14-2008, 03:47 AM
const int numQuests = 1;
bool questGotten[numQuests];
bool questCompleted[numQuests];
bool questRewarded[numQuests];
int questGotStrings[numQuests] = {1};
int questCompleteStrings[numQuests] = {2};


Pass 1: Parsing
Pass 2: Preprocessing
line 2: syntax error, unexpected IDENTIFIER, expecting NUMBER, on token numQuests
tmp, line 1: Error P01 : Failure to parse imported file quest.z.

So, we can't use constants to declare arrays? That seems... annoying. Is this a bug, or just something that hasn't been thought of yet?

PS: I seem to recall at one point support for strings in ZScript. Am I insane? Now, I can't find any reference to this...

Edit for good measure:


* And finally, the additions of arrays to the scripting engine! Took a lot of work, but they're in. Now, each running script has the option via the global Declare() function to allocate for itself a block of memory. This block of memory is used as a scratch space for declaring and using arrays. One block is continually persistent as a 'global' memory and is used by default when an ffc or item script doesn't declare a piece of memory. Also included is a new section of memory in save files that allows you to store whatever miscellaneous data you like. ( jman2050, 2008-03-04 11:27:42 )

How does one use Declare()? Is this a function (it's not in zscript.txt)? Or, a construct of some sort (it's not on the wiki)? Or... what? I'm trying to make my arrays save, but it's not going very good right now.

Joe123
11-14-2008, 04:20 AM
We're not allowed variable sized arrays.
I don't think anyone actually worked out what Declare()'s meant to do.
There's a bug with saving arrays currently.

And I believe (though I may be wrong cause I never used it) that you can make a string like this:

int newstring = "I'm a string";
But there's currently no real purpose for it.

pkmnfrk
11-14-2008, 04:29 AM
We're not allowed variable sized arrays.

Well, yes. But, it's a constant. See your thread (http://www.armageddongames.net/forums/showthread.php?t=104302)


I don't think anyone actually worked out what Declare()'s meant to do.

I would like to hear something official about this. I added it to my script as is ("Declare()"), and it accepted it... and, I haven't seen any difference.



There's a bug with saving arrays currently.

Curses.


And I believe (though I may be wrong cause I never used it) that you can make a string like this:

int newstring = "I'm a string";
But there's currently no real purpose for it.

Hmm. Your form didn't work, but this did:


int test[10] = "Testing?";

Interestingly, this does have some use (manually drawing a string via tiles, etc), although, not much. If we had multi-dimensional arrays, we could do something like:


int test[3][20] = { "Quest 1", "Quest 2", "Quest 3" };

Which would be awesome. But, we can't :( Not directly, anyway...


int test[60] = "Quest 1 Quest 2 Quest 3 ";

CaRmAgE
11-14-2008, 11:41 AM
Well, yes. But, it's a constant.

The point is the size of a static array needs to be determined during compile time for allocating memory purposes, just like all other static variables. Thus, you can't use variables at all to define array size, even constant ones; while you may view "numQuests" as a constant value, the compiler sees just another variable.

The only way you could possibly use variables to initialize an array's size is by creating an array that determines it's size at run time (dynamic arrays). But since...


We're not allowed variable sized arrays.

...in other words, dynamic arrays, using variables to set an array's size isn't possible right now. Sorry.

pkmnfrk
11-14-2008, 02:22 PM
Interestingly, this does have some use (manually drawing a string via tiles, etc), although, not much.

I take this back. They have zero use as implemented.


int charWidth[96] = {5,3,7,7};

int string_buf[255];

const int string_tile = 14300;

global script onStart {
void run() {
string_buf = "#!#";
while(true) {
drawString(string_tile, 2, 3, 0, 0);
Waitframe();
}
}
}

void drawString(int s_tile, int cset, int lay, int x, int y) {
int dx, dy;
dx = x;
dy = y;

int tile;


for(int i = 0; i < 255; i++) {
if(string_buf[i] < 32) {
if(string_buf[i] = 10) {
dy += 8;
dx = x;
}
} else {
tile = string_buf[i] - 32;
Screen->DrawTile(lay, dx, dy, tile + s_tile, 1, 1, cset, 1, 1, 1, 0, 0, true, 128);
dx += charWidth[tile];
}
}
}

You can't assign to string_buf in any way (other than manually assigning each element), and you can't pass arrays as parameters. For these fake string array things to be useful, you need to be able to do one or the other... I personally don't care which.

pkmnfrk
11-16-2008, 10:42 PM
Ok, I give up.

What I was trying to do (as I alluded to above) is, essentially, implement drawing strings via a "tile font" (variable width, with the widths in the charWidth[] array). But, it's impossible.

My first idea was to pass a string to drawString, but since you can't pass arrays, this is out.

My next idea was to have a global "string buffer", into which you put your string, and then drawString draws from it. But, you can't assign strings outside of a variable initializer (right?), so that limits it to... the very first string you have in the game.

My last idea was to have the draw string routine in a separate file, and include it in all the places you would use drawString. You would have to use the same array name in all these places, but at least you can draw more than one string, right?

No, you can't "import" inside a function. For the love of...

Anyone else have any ideas? Or, am I wasting large amounts of time on something that just is not possible currently?

Gleeok
11-17-2008, 02:28 AM
Don't give up!!! :P

This has actually been on my to do list for a while. I just finished upgrading my quest to 887, and would be happy to help out in getting some scripted string functions working. ...At least I think that's what you're doing. Hmm... :)

Lemme just take a look at what you've got there....


Edit1; Do ascii characters have a numerical value in ZScript, and what would they be? - EDIT3; Goddamnit. Nevermind. These are completely useless. :(

Edit2; Well here's a thought: No, you cannot pass an array in ZScript, But, you can have global arrays. What I'm getting at here is that you can have a temp_array[] and simply copy the data of a global array into that, for temorary use with a function.

Edit4; Well this is prop8 gay, but you're right, you can't initialize an array with int or const. gay.


So...What we're looking at here is having to type sentences with numbers instead of letters..blah. I'll mess with it tomorrow.

pkmnfrk
11-17-2008, 04:15 AM
Don't give up!!! :P

This has actually been on my to do list for a while. I just finished upgrading my quest to 887, and would be happy to help out in getting some scripted string functions working. ...At least I think that's what you're doing. Hmm... :)

Lemme just take a look at what you've got there....


Edit1; Do ascii characters have a numerical value in ZScript, and what would they be? - EDIT3; Goddamnit. Nevermind. These are completely useless. :(


Yup, they have standard ASCII values (http://www.cdrummond.qc.ca/cegep/informat/Professeurs/Alain/files/ascii.htm). They're not useless, see below for more thoughts.


Edit2; Well here's a thought: No, you cannot pass an array in ZScript, But, you can have global arrays. What I'm getting at here is that you can have a temp_array[] and simply copy the data of a global array into that, for temorary use with a function.


Well, no need for a global. But...


Edit4; Well this is prop8 gay, but you're right, you can't initialize an array with int or const. gay.


Or re-init an array with a string. However...


So...What we're looking at here is having to type sentences with numbers instead of letters..blah. I'll mess with it tomorrow.

My idea was to use method 2 (in my post), and have a separate utility that basically takes a list of strings, and outputs a chunk of code. Eg:

Input:

ABC
123

Output:

int string_buf[4]; //auto-sized to the largest string

void loadString(int num) {
if (num==1) {
string_buf[0] = 65; string_buf[1] = 66; string_buf[2] = 67; string_buf[3] = 0;
} else if(num==2) {
string_buf[0] = 48; string_buf[1] = 49; string_buf[2] = 50; string_buf[3] = 0;
} else {
string_buf[0] = 0;
}
}

And then, in your script file, you do this:


import "std.zh"
import "strings.zh"

//...
loadString(2);
drawString(16, 16, 2, 6);
//...

Ideally, this would become obsolete very quickly.

Edit: The only potential problem with this is that if you have a lot of strings, and a lot of scripts, this will likely fill up whatever script space we have very quickly.

Gleeok
11-17-2008, 09:40 AM
Alright, I'm pretty much finished with it. Although I still can't understand how it may be possible to convert a "string" into data read by an array in ZScript. (At least I think that's what you're doing..?) I couldn't quite figure it out without using arrays, (and they are currently very limited in use) so each string requires one array. Perhaps you can take a look at it when it's done?

..Which reminds me: Anyone wan't to post up a ripped .gif of some letters? Up to 8 pixels wide would be fantastic. :)

pkmnfrk
11-17-2008, 07:52 PM
Last things first, a font as used by drawString is one tile per character. The standard size is 8px high, with a variable width. Originally, I was going to have a maximum size of 8x8, but I then realized you can't draw a sub-tile with ZScript :'(

Anyway. A string, in any language, is just a sequence of numbers that happen to correspond to certain codes in an ASCII table, which make coherent sentences. "A" is 65, "B" is 66, "4" is 52, etc.

Internally, when assigning a string to an array, ZScript just takes the numeric value of each letter, and puts it in the appropriate slot of the array (and, adds a zero at the end to indicate that the string is done).

To work around the lack-luster support for strings in ZScript, I would write a wholly separate program that takes a bunch of strings, and creates a function which manually loads those strings into a certain buffer (for use with drawString). The program would do something like this:


print out function header
i = 1
for each line
print "case " & (i++)
j = 0
for each character in the line
what is the value of that character?
print "string_buf[ " & j++ & "] = " & the value of the character & "; "
next character
print "string_buf[" & j++ & "] = 0;\n"
print "break;\n"
next line
print out function footer

This would result in the function I posted in my last post. You'd add 'include "strings.zh"' to your script file, and away you go.

I think I should just do it, and you'll be able to see how it works...

Gleeok
11-17-2008, 11:33 PM
Oh, I get what you're doing now. I don't know that's even neccessary though. since ASCII chars already have a number value why do you need to assign them another?

I just tested this out and it works friggin great. Check it out, this was about as user freindly as I could make:


EDIT: Got it. :D



int string1[98] = "this is a test |this is only a test |if this had been an actual emergency, |you would be dead.";

int string2[25] = "abcdefghijklmnopqrstuvwxyz";


int string3[9] = {1,2,3,4,5,6,7,8,9};
int string4[9] = {1,2,3,4,5,6,7,8,9};
int string5[9] = {1,2,3,4,5,6,7,8,9};
int string6[9] = {1,2,3,4,5,6,7,8,9};
int string7[9] = {1,2,3,4,5,6,7,8,9};
int string8[9] = {1,2,3,4,5,6,7,8,9};
int string9[9] = {1,2,3,4,5,6,7,8,9};




global script test{
void run(){

while(true){

Waitframes(30);

Draw_String(1,98,0,0,6);
}
}
}

int temp[255];

void Draw_String(int string, int max_depth, int Xindent, int Yindent, int cset){

int x = Xindent; int y = Yindent;
int i; int t; int j; int k;
int tile = 520;

if(string==1){ for(i=0;i<=max_depth;i++) temp[i] = string1[i]; }
else if(string==2){ for(i=0;i<=max_depth;i++) temp[i] = string2[i]; }
else if(string==3){ for(i=0;i<=max_depth;i++) temp[i] = string3[i]; }
else if(string==4){ for(i=0;i<=max_depth;i++) temp[i] = string4[i]; }
else if(string==5){ for(i=0;i<=max_depth;i++) temp[i] = string5[i]; }
else if(string==6){ for(i=0;i<=max_depth;i++) temp[i] = string6[i]; }
else if(string==7){ for(i=0;i<=max_depth;i++) temp[i] = string7[i]; }
else if(string==8){ for(i=0;i<=max_depth;i++) temp[i] = string8[i]; }
else if(string==9){ for(i=0;i<=max_depth;i++) temp[i] = string9[i]; }

Waitframe();


for(i=0;i<=max_depth;i++){

for(k=0;k<4;k++){

for(j=0;j<=i;j++){

if(temp[j]==124){
t = tile + 32;
Screen->DrawTile(6,x,y,t,1,1,cset,1,0,0,0,0,true,128);
y+=8;x=Xindent;
}
else{
t = tile + temp[j];
Screen->DrawTile(6,x,y,t,1,1,cset,1,0,0,0,0,true,128);
x+=6;
}
}
x=Xindent;y=Yindent;
Waitframe();
}
}
}


http://i235.photobucket.com/albums/ee138/Tiamat_AD/zelda007.jpg

pkmnfrk
11-18-2008, 12:24 AM
http://zctut.com/strings.zip

This is how I done it.

The original strings are in strings.tbl. It's a plain text file, comments start with @. Certain comments are special, such as the @bufname at the top. That tells strings.exe what to call the variable.

A string is said to be everything from the start of a line to the end. If a string ends in "\", it's "escaping" the new line at the end, and allows a string to span more than one line (with an embedded new-line). Also, you can explicitly embed control codes (or, rather, you will be able to), such as "\n" for new line, or "\c" for change cset.

anyway, drag strings.tbl onto strings.exe to create strings.zh. This is a very ugly file to inspect manually. Your strings are those ugly blocks of numbers and brackets that look like something out of the IOCCC (http://www.ioccc.org/) competition. Don't worry about that.

Anyway, strings.zh defines 5 important things for your script:
* a string buffer (although, you shouldn't have to interact with this directly)
* a constant with the size of the buffer (again, it's primarily for internal use)
* a loadString(int) function, which allows you to load a string into the buffer.
* a loadString(int, int) function, which allows you to load part of a string into the buffer. The second parameter is how much to load. You can only load from the beginning to an arbitrary point.
* a stringLen(int) function, which returns the size of a string.

Combining the two last functions allows you to have, say, a block of text that slowly appears on screen.

The last file to look at is quest.z, which is the main script file. It has all the non-directly-related-to-strings stuff, such as the font-width definitions, a couple unrelated arrays, and the drawString() function.

drawString accepts 5 parameters: s_tile (the first tile in the font set, which should be ASCII 32), cset (the cset), lay (the layer), x and y (yeah).

Above this, in the onStart() script, I demonstrate how one could create a marquee (scrolling text). My intro is comprised of three strings, which slow scroll from bottom to top, one after another. As a speed optimization, it won't load and draw the string unless part of it is on screen.

Start a new game on the included quest to check it out in action.

Gleeok
11-18-2008, 12:57 AM
Wowsers. :odd: You made a seperate program to do that for you. That's pretty impressive. No wonder I couldn't make heads or tails out of what you were posting. ..Well then, carry on. :P

What's the max number of strings you can generate like that? ..And good god, how long did that take?

Looks awesome.

pkmnfrk
11-18-2008, 01:24 AM
Altogether, about three hours.

How many strings? Well, the program can do about 2 billion before it chokes, though I don't know how much ZC can handle.

I do know that obscenely long strings (500 chars+, maybe) cause ZC to barf a little in its mouth, and not do anything at all, but if you break them up like I did, it should be fine.

The main advantage of my method over yours is that I'm not relying on arrays being saved and loaded. You are. I bet your code would break if you saved, since right now arrays are borked. And, if that was fixed, then you couldn't ever change your arrays, since they're only set on a new game (in ~Init).

My way is more likely to chew up valuable room in the script buffer, but it won't break on new versions of the quest.

jman2050
11-18-2008, 02:14 AM
...I should've finished implementing strings a long time ago. Ah well, Zscripters are resourceful as always XD

pkmnfrk
11-18-2008, 02:31 AM
Your mistake was to give me an inch. Strictly speaking, none of this requires strings proper, only arrays ;)

CaRmAgE
11-18-2008, 09:23 AM
I'm sure this program will have some useful applications. Nice brainstorming, guys. :thumbsup: