Read-only archive of the Armageddon Games Forums Archive (2000–2026) · About this archive

Zelda Classic 2.11 Beta 12.9

57 replies · 8,802 views · Started 04 September 2006

Get It HERE!
FULL WINDOWS BUILD
FULL LINUX BUILD(new)

This is called 12.9 because we KNOW this will be a buggy beta. We'll save the 13 designation for when most of the major bugs have been caught and fixed.

What's new? Lots of stuff. Mostly, the scripting language has been vastly matured since the last iteratrion. Look at the next post for a tutorial on ZCScript, the C compiler for the scripting language.

Also of note is two things: First, items. When editing items, you'll notice several new options. The explanation of the item attributes is as follows:

Class Number: What type of item this is. Determines ifit's aword, a shield, an arrow, etc. Don't change this unless you know what you're doing.
Class Level: A number from 1-8 representing the level of that particular item class. For example, 1 would refer to the wooden sword, while 3 would refer to the magical sword.
Counter: In the save file, there are now 32 all-purpose counters that can be used for counting just aout anything. however, you can't use said counters except for those already defined. There are currently 7 counters defined, and the number from 0-31 specifies which one. -1 means that no counter is referenced. 0 is life. 1 is rupees. 2 is bombs. 3 is arrows. 4 is magic. 5 is keys, and 6 is super bombs. (For counters 1 and 4, check dcounter next to the amount. For the others, leave it unchecked)
Increase amount: Increase the amount of the specified counter by a certain amount. For example, an item with a counter of 1 and an increase amount of 30 would increase your rupees by 30 when picked up.
Full Max: The absolute maximum that the item can increase the maximum of the counter to. For example, a heart container will have a value of 256, which is 16 hearts (one heart is 16 HP), which means that a heart container cannot increase the heart count to above 16.
+Max: The amount to increase the maximum counter by. For a heart container, this is 16, representing one heart. Note that the increase amount for a heart container is also 16. Yes, you can increase the active counter AND the maximum counter at the same time 😊
Keep Item when Collected: specifies whether you keep an item in your inventory when collected. For example, a sword and a shield would have this checked. A rupee and a heart would not.

This is the start of making fully custom items. The next step is giving items scripts, and that may possibly be in the next beta 😊 Also note that you now have 255 items to edit. The remaining items besides the defaults are identified by z### (where ### is the item number)

The second major new thing is the SFX. Now he SFX are stored in the quest file. You now have 127 sounds to work with. Just go to the SFX Data dialog in the quest menu to import sound effects and to listen to current sound effects. Keep in mind that saving an old quest in beta 13 will cause it to take on the sound effects of the current sfx.dat file. Of course, that's of little consequence since only the included SFX file is compatible with this version.

besides the ZScript tutorial below, that should be it. Have fun, and remember:

BACK UP YOUR QUESTS OR DIE. ALSO, BACK UP YOUR SAVE FILE AS WELL, JUST IN CASE. THAT IS ALL

By DarkDragon:

The ZScript compiler is now available as an alternate way of scripting freeform combos and items. To access this new compile, go to Tools->Compile ZScript in ZQ.

Each quest now has an associated ZScript buffer. This buffer is saved with the quest. Enter a script by hand or load the contents of a file, then hit Compile to launch the ZScript compiler.

ZScript is a language heavily based off of C, with some modifications to accomodate ZC features. Consider, for instance, our first ZScript example:


int distancesq(int x1, int x2, int y1, int y2)
{
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}

The above should compile happily. Notice that the above looks just like a normal C global function declaration; and in fact is just that in ZScript as well. I've declared a function of return type int, which takes in four int parameters.
The current built-in simple types for ZScript and int, float, bool, and void. Both int and float are provided for the sake of convenience, but both simply mean fixed-point number with 4 digits of decimal point precision.
The function above returns the square distance between (x1,y1) and (x2,y2). ZScript supports most of C's math and logic operators, and enforces the correct precedence.

You'll notice the above snippet doesn't actually DO anything when compiled; that's because we've just declared a global function, and not an actual script. Let's look at the next example:


int distancesq(int x1, int x2, int y1, int y2)
{
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}

ffc script followlink {
int x;
int y;

void run() {
while(true)
{
x = this->X;
y = this->Y;
int dist = distancesq(Link->X, this->X, Link->Y, this->Y);
this->Vx = (Link->X - x)*Abs((Link->X-x))/dist;
this->Vy = (Link->Y - y)*Abs((Link->Y-y))/dist;
Waitframe();
}
}
}

I've now added a script to the source file. Notice the syntax: "ffc script <name> { }". The ffc specifies that this script can be assigned to an FFC Script slot in ZQ; "item" is also a supported script type. Global scripts will be added in later betas.

You'll notice I've declared two variables in script scope: x and y. Any variables declared in the scope of a script are global variables, and accessible to all scripts; you'll see this feature used in the next example.

In addition to x and y, there is a function declared in script scope: void run(). All scripts must implement this function, as this is the function that is run when the script is started. A script may have additional functions besides run(), which may be called by you explicitly, but run() is the only one called automatically.

Inside run() you can see a while loop; while and for loops are both implemented.

You can see I use several implicit "pointers" to get at various pieces of data using dereference (->😉 notation. "this" is a pointer whose type is dependent on the type of the scripts; since currently all scripts are ffc or item scripts, "this" refers to an ffc type, which contains the ffc's position, velocity, data, etc, or an item type. Link, Screen, and Game are global pointers that encapsulate the current state of link, the screen, and the game, respectively. A full list of the available pointer types will be listed at the bottom of this tutorial.

I said earlier that int, float, bool and void were ZScript's simple types. ZScript also has complex types, ffc, item, and itemclass, which are like pointers. They are provided implicitly through "this" pointers as described above, but can also be declared explicitly, and are returned from some library functions. Like the global pointers they can be dereferenced. For instance, in the following snippet, I move the screen's second item to x=10:


item i = Screen->LoadItem(1);
i->X = 10;

In any case, back to the FFC example. The first thing I do in the while loop is set the values of x and y. Other FFCs can't read the X position of this FFC directly, since no ASM instructions can do that currently; what I can do, though, is store the current X position in a globally accessible variable, x, each frame, and this is what I do in the above example.

Next I do some more complicated math to set the current FFC's velocity to point towards link with magnitude 1; notice that I take advantage of my global function squaredist() here. Then I call a global function, Waitframe(). Global functions are like user-defined global functions, but are provided for you by the ZScript compiler. A list of all the global functions follows this tutorial.

At this point you can run the script in a sample quest: compile the above, assign "followlink" to some FFC Script slot, and assign that slot to some FF combo, save, run ZC, and that FF should now follow link.

Unlike in ASM, you can define multiple ZScripts in one source file, and in fact it is encouraged that you do so. Here is the final sample script:


int distancesq(int x1, int x2, int y1, int y2)
{
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}

ffc script followlink {
int x;
int y;

void run() {
while(true)
{
x = this->X;
y = this->Y;
int dist = distancesq(Link->X, this->X, Link->Y, this->Y);
this->Vx = (Link->X - x)*Abs((Link->X-x))/dist;
this->Vy = (Link->Y - y)*Abs((Link->Y-y))/dist;
Waitframe();
}
}
}

ffc script satellite {
void run() {
for(int i=0; true; i++)
{
this->X = followlink.x + 10*Sin(i);
this->Y = followlink.y + 10*Cos(i);
Waitframe();
}
}
}

I've added a new script, "satellite", which orbits the FFC defined above by using some trig functions. Notice that I can use the dot operator to access another script's global variables.

There's one more useful feature not used in the above examples: suppose a community member writes a very useful library of global functions or scripts, and you want to include them in your quest. No problem! Using the "import" keyword lets you add the contents of another file as if they were copied into the current file. So for instance if I moved the declaration of distancesq() into library.z, I could just do

import "library.z"

ff script followlink {
...

and it would compile the same.

One last postscript: as you can see when you're assigning script to slots, we've added three slots for "global" scripts. One of these scripts is run the first time you start a new quest. ZScript does a lot of behind-the-scenes work (you can declare a lot more than 9 variables in a script!) but as a consequence must be allowed to place a special auto-generated script, ~Init, in global slot 0. This is all done automatically - but I don't want you to be surprised when ZQ doesn't let you overwrite ~Init in the slot assignment dialog.

Here is a brief reference of what's currently implemented in the ZScript language:

Pointer types: (use -> to access)
ffc: (accessible using the "this" pointer, or explicit pointer)
float Data;
float CSet;
float Delay;
float X;
float Y;
float Vx;
float Vy;
float Ax;
float Ay;
bool wasTriggered();

link: (accessible through the global "Link" pointer)
float X;
float Y;
float Dir;
float HP;
float MaxHP;
float MaxMP;
float Action;
void Warp(int, int);
void PitWarp(int,int);
bool InputsEnabled;
bool ForcedUp;
bool ForcedDown;
bool ForcedLeft;
bool ForcedRight;
bool ForcedA;
bool ForcedB;
bool ForcedL;
bool ForcedR;
bool APressed();
bool BPressed();
bool LPressed();
bool RPressed();
bool UpPressed();
bool DownPressed();
bool LeftPressed();
bool RightPressed();
bool StartPressed();

screen: (accessible through the global "Screen" pointer)
float D[8];
float ComboC[176];
float ComboD[176];
float ComboF[176];
float ComboI[176];
float ComboT[176];
float ComboS[176];
int NumItems();
item LoadItem(int);
item CreateItem(int);

item: (accessible through the "this" pointer, or explicit pointer)
float X;
float Y;
float DrawType;
itemclass Class;
float Tile;
float CSet;
float FlashCSet;
int NumFrames;
int Frame;
float ASpeed;
float Delay;
bool Flash;
float Flip;
float Extend;

itemclass: (accessible through explicit pointer)
float Family;
float FamilyType;
float Amount;
float Max;
float MaxIncrement;
bool Keep;
float Counter;

game: (accessible through the "Game" pointer)
int GetCurScreen();
int GetCurMap();
int GetCurDMap();
int NumDeaths;
int Cheat;
float Time;
bool HasPlayed;
bool TimeValid;
float GuyCount[];
int ContinueScreen;
int ContinueDMap;
float Counter[];
float MCounter[];
float DCounter[];
float Generic[];
float Items[];
float LItems[];
float LKeys[];
float CurMapFlag[];
float GetMapFlag(int, int);
void SetMapFlag(int, int,float);
float GetScreenD(int, int);
void SetScreenD(int,int,float);
itemclass LoadItemClass(int);

Global Functions:
float Rand(float);
void Quit();
void Waitframe();
void Trace(float);
float Sin(float);
float Max(float,float);
float Min(float,float);
float Pow(float, float);
float InvPow(float,float);
int Factorial(int);
float Abs(int);
float Sqrt(float);

Lastly, all of the keywords implemented in the language:
script
float
for
bool
void
if
else
return
import
true
false
while
ffc
itemclass
item

Operators:
=
.
->
<<
>>
&
|
^
&&
||
!
~
++
--
<=
<
>=
>
!=
==
+
-
*
/
%

One last thing I forgot to put in the above tutorial:

Although the ffc and item scripts, once compiled, should be compatible with all future versions of ZQuest, [SIZE="6"]I do not guarantee the ZScript syntax will remain unchanged in future betas[/SIZE], as compilation is a fairly elaborate process with multiple steps, rendering support for multiple versions of the grammar extremely painful if not impractical.

...
.........
...........................
...holy...sh...

C?! In ZC scripting?!

Item editing?!?!

A new age of greatness has just dawned over ZC... o.o

*downloads faster than his bandwidth will allow through pure excitement*

Even though I saw it coming, I'm STILL having fits of glee. GREAT job, guys!

EDIT: In the items and Weapons/Misc data, there's a bit of what I'd call an "interface error". The fully custom entires are ordered starting with z100, with all <100 numbered entries coming AFTER 255. Not a bug per se, but still awkward (might I suggest using z090, z091, etc.?)

jman2050 wrote:Also of note is two things: First, items. When editing items, you'll notice several new options. The explanation of the item attributes is as follows:

Class Number: What type of item this is. Determines ifit's aword, a shield, an arrow, etc. Don't change this unless you know what you're doing.
Class Level: A number from 1-8 representing the level of that particular item class. For example, 1 would refer to the wooden sword, while 3 would refer to the magical sword.
Counter: In the save file, there are now 32 all-purpose counters that can be used for counting just aout anything. however, you can't use said counters except for those already defined. There are currently 7 counters defined, and the number from 0-31 specifies which one. -1 means that no counter is referenced. 0 is life. 1 is rupees. 2 is bombs. 3 is arrows. 4 is magic. 5 is keys, and 6 is super bombs. (For counters 1 and 4, check dcounter next to the amount. For the others, leave it unchecked)
Increase amount: Increase the amount of the specified counter by a certain amount. For example, an item with a counter of 1 and an increase amount of 30 would increase your rupees by 30 when picked up.
Full Max: The absolute maximum that the item can increase the maximum of the counter to. For example, a heart container will have a value of 256, which is 16 hearts (one heart is 16 HP), which means that a heart container cannot increase the heart count to above 16.
+Max: The amount to increase the maximum counter by. For a heart container, this is 16, representing one heart. Note that the increase amount for a heart container is also 16. Yes, you can increase the active counter AND the maximum counter at the same time 😊
Keep Item when Collected: specifies whether you keep an item in your inventory when collected. For example, a sword and a shield would have this checked. A rupee and a heart would not.

This is the start of making fully custom items. The next step is giving items scripts, and that may possibly be in the next beta 😊 Also note that you now have 255 items to edit. The remaining items besides the defaults are identified by z### (where ### is the item number)

I'm going to pray that this is like, options to check, uncheck, input, so on and so forth in the item/sprite editor, and NOT scripting, right?

Both. These are set in the item editor at quest creation time, but can be subsequently read or modified by item scripts.

How did you install 12.9? Since the sfx.dat file in this beta is new, you need to be sure that you installed these files AFTER you install the support files from 12d.

I absolutely love the new sfx editor. I have a quick question about it though. I heard every sound effect in the game except for the music that is played when you get the triforce piece. Where is that and can that be changed through this editor?

A few questions... First:

float ComboC[176];
float ComboD[176];
float ComboF[176];
float ComboI[176];
float ComboT[176];
float ComboS[176];
What's the difference between these?

Second (and third):

Other FFCs can't read the X position of this FFC directly, since no ASM instructions can do that currently;
I thought you could do that with LOAD1 and LOAD2... Was I mistaken about that?
If that can't be done, then is there currently any way to pass data between FFCs on the same screen without going through global variables?

Also, what's the function to play sounds? Or is it not in yet?

Finally, since I'm too lazy to try it and see, is it possible to overload functions?

ComboC - Refers to the combo cset at that screen position
ComboD - Reers to the combo reference at that position
ComboF - Refers to the normal flag at that position
ComboI - Refers to the inherent flag of the combo referenced in that poosition
ComboT - Refer's to the combo's type
ComboS - Refers to the combo's solidity data. 4 bits. bit 0 (the lowermost bit) is top-left, bit 1 is bottom-left, bit 2 is top-right, bit 3 is bottom-right.

I thought you could do that with LOAD1 and LOAD2... Was I mistaken about that?

Actually, it might be an oversight on DD's part. I'll talk to him about it.

I can't get the player to work at all. Once it does, it just crashes on sight immediately. It seems to be that ZC was broken from the process with upgrading from beta 12d. It can't be my ag.cfg, it's something else.

what does the allegro.log file say when starting up, for those who have the player crash upon startup.

To make it short, it was something to do with my save file. I deleted the Zelda Classic save file, and it is working now. Now I need to know to delete save files when a new file of Zelda Classic is released. *hits head*

what the... that shouldn't happen. At worst it should delete the save filand start anew, not crash outright O_O

Saffith wrote:A few questions...
Second (and third):I thought you could do that with LOAD1 and LOAD2... Was I mistaken about that?

The problem with LOAD1 and LOAD2 is that I don't know the slot of the script at compile time, so I can't generate ASM code to take advantage of them.

If that can't be done, then is there currently any way to pass data between FFCs on the same screen without going through global variables?

Coming in b13.

Also, what's the function to play sounds? Or is it not in yet?

An oversight on my part. Coming in b13.


Finally, since I'm too lazy to try it and see, is it possible to overload functions?

It depends what you mean by "overload functions." Yes, you can declare two functions of the same name with different type signatures, as in C.

Bitchin'. Can you trigger text with this? You could truely create dynamic text boxes if you could.

Something like:

if(Link->UpPressed())
return ("You pressed up!"😉;
else if(Link->DownPressed())
return ("You pressed down!"😉;

etc and then display that string as text on the screen (possibly with a dialog box under it).

Is there a list to what sfx number corresponds to which effect? Especially the ones over 36.
Is there a way the assign them to a specific effect?
Like in the item editor. Say for the sword it would have the sfx option :"Use sfx #"

SFX 35-127 are for your own use. SFZ 1-34 are used by ZC, but haven' been labeled yet. In a later beta perhaps.

ZQuest crashed on me when using the SFX editors' "Play" feature with custom WAV's (the ones from the WINDOWS\MEDIA folder).

Check the 12.9.1 thread for fixes. Also note, if an item cannot be picked up (the game crashes), edit it's properties in ZQ again and press OK. That should fix the problem in short order.