-=-=ZScript Tutorial=-=- ZScript is a new feature in Version 2.5 of Zelda Classic. While it is not required to make a good quest, you can get around various normal limitations with scripting. It may look hard at first, but it's not as hard as it seems. All you need to do is take the time to get used to it all. Basically, it's just patience and giving it a try. -=Your first script=- Well, after learning what the functions are, you should put them to use, right? Let's start with a basic script. I'll explain why I'm using certain things as wel go along, too. ;) Begin by opening the text-editing program of your choice. I prefer Notepad. Let's put something on that first line, shall we? import "std.zh" This imports the file "std.zh", which should be in the same folder as the script, into the script. This file has plenty of constants (More on that later. iIt's an advanced part of ZScript, know that.) which will help you out. Heck, without them, you can't do certain things. You don't HAVE to import this, but it makes things better for you, since you get to use more things. Note, however, that you can import other scripts into a script. Just replace "std.zh" with the name of whatever you wish to import. Okay, next line... ffc script testscript This basically tells what kind of script you're dealing with here. FFC= FreeForm Combo script (Activates upon entering the screen with the FFC the script is attached to). Item = Item script (activates upon use of the item the script is attached to). Global = Global script (Activates upon starting the quest). The name, which is testscript here, organizes your loaded scripts. Hey, easier to tell which script is which when they're named. :P { What's that? It's just a brace? ("Curly brace" to you people over in Europe.) Well, yes... These are used in *ahem* certain cases. For example, after the naming and defining of the script. Next. void run() This starts the script. Without this, the script will NEVER run. Put it here, or else. { This comes after void run(). Let's set up a basic loop, okay? We'll make the script loop for as long as it's activated. To do that, you must do... while(true) This will loop whatever comes after this until the case is found to be not true, which is the script not being active. This is one of those things that gets a { after it. So the next line is.... { Oh yes, you could also put those { things on the same line as what requires them to be in the script. It makes no difference to the script. What to do next....? Ooh, how about we check for a certain something? Hmmmm.... Why not check to see where Link is? First, let's store that value to a variable. But! Why make it a simple variable? This would be a great time to discuss Global Variables! Global Variables are Variables that, when modified, keep the last value they had when the script restarts. It also makes the entire script the its own scope. I'll explain that later. ;) So, right before void run(), put a new variable there: int LinkXNew = 0; This will create a new variable for you to use, and it's Global, because you put it before void run(). Simple enough, right? Now, let's do something for some FFCs: int loadedffc = 0; This will be used later, and I'll explain it then. Don't forget to put this right after LinkXNew! Now, for an item! int loadeditem = 0; Again, used later, put it after loadedffc. Don't worry, work with me here. ;) Now, let's begin with something new, shall we? Right after loadeditem, put: int RandomNum = 0; RandomNum? Yes, it will be random! How? I'll show you! Let's go back to the last line we did in the script, the { after while(true). Put this on the line after it: ffc loadedffc = Screen->LoadFFC(32); This will give variable loadedffc all the data that FFC #32 has. Remember, this script should be given to that same FFC, okay? Let's do an "if" statement: if(Link->X == loadedffc->X) This will only proceed if what's on the right is equal to what's on the left. Maybe now would be a good time to explain what each of these symbols mean? "=" tells the script to set whatever is on the left to whatever is on the right. Like, "Link->X = 32" would set Link's X-position to 32. He'll "warp" there automatically at that time. "==" means "is equal to". It's used mainly in if and else statements, and while loops. ">" and "<" are fairly obvious- They're "greater than" and "less than", respectively. Again, only used in if and else statements, and for and while loops. (I'd explain "for" loops, but I have yet to use a single one of them. Sorry :( ) "->" is a pointer device. They're used with pointers, like "Link", "Screen", and "Game". "This" is also a pointer, but only for FFCs. Anyways, next line: { Yep, here we go again. It's another {. Used after anything without a semicolon. Next: RandomNum = Floor(Rand(1) * 3); This is what RandomNum is for- Storing the value of a random number. It could be 1-3. Whatever number you get.... Something will happen. Next: if(RandomNum == 1) Must I explain? Of course I must! This checks to see if the randomized number is 1. If it is... { I won't explain these anymore, and instead just go on to the next line, okay? Screen->CreateItem(3); This will create the item with the specified value when this function is done. Here, the value is 3, which is Bombs. Next: int ScreenItems = Screen->NumItems(); This will give ScreenItems the value of the number of items on the screen. This will come in handy soon enough. item loadeditem = Screen->LoadItem(ScreenItems); This will basically load the last item created to the screen to loadeditem. Why? Well, the number of items on the screen is equal to the value of the item we created, since it was the last item made. Next: loadeditem->X = Link->X; This will put the item where Link is. Simple, right? } This closes the statement or loop you're in. Enough said, right? :) Now... Would you like to make that simpler? Would you rather Link just GET the item instead of the item simply appearing, where Link could walk away without ever picking it up? If so, replace all those lines in the if statement to this one line: Link->Item[3] = true; He'll simply be given the item. Simple, no? else if(RandomNum == 2) Now we're checking to see if RandomNum is equal to 2...but thanks to the "else" there, it's only if the previous "if" statement we did came back false! :) { Now how about we just skip the item-creating and just GIVE him something? while(Link->HP < Link->MaxHP) Continues only if Link's current heart status is less than the max amount he can have. { if(Link->HP > Link->MaxHP - 16) This will check to see if Link's current hearts is less than Link's Max hearts, BUT greater than 1 full heart away from it. { Link->HP = Link->MaxHP; Waitframe(); This is a failsafe so Link's HP doesn't go over his Max HP. ;) The Waitframe(); is so things can keep happening between frames. If you don't use one in a loop, Link can never move, and only the script will happen. } else Link->HP += 16; Waitframe(); Yay! We're giving Link 1 full heart as long as his current hearts do not equal his max hearts. But only if the previous statement isn't true! } } We've closed the last else statement now. Next: else if(RandomNum == 3) ....Just in case. { Now, next, we're gonna do something else. We're gonna do three things here: if(!Link->Item[52]) { Screen->CreateItem(52); int ScreenItems = Screen->NumItems(); item loadeditem = Screen->LoadItem(ScreenItems); Yes, we're creating an item again. This time, it's Hookshot. But this time, we're not giving it to Link. Instead... int loadedffc2 = 0; ffc loadedffc2 = Screen->LoadFFC(31); loadeditem->X = loadedffc2->X; This time, we're loading up a new FFC, and instead of giving Link the item, the item goes to the FFC. But how about we make it harder? Why not make it so the item hits a conveyor? The conveyor carries the item along, and if it hits a certain combo before you can get it.... Poof. Game over for the item. That's a bit advanced, so we'll cover how to do that later, okay? ;) For now, it just appears there. Next, we'll do: } if(Link->HP < Link->MaxHP) { while(Link->HP < Link->MaxHP) { if(Link->HP > Link->MaxHP - 16) { Link->HP = Link->MaxHP; Waitframe(); } else Link->HP += 16; Waitframe(); } } else if (Link->HP == Link->MaxHP) { Link->Item[28] = true; } This will give Link a new Heart Container if his HP is max when this effect is activated. The "if" copy of the while loop is so the "else" statement can be used. Without an "if", an "else" gives an error. Finally, we do this: if (Link->MaxHP > 16) { if (Link->MaxHP > 16) { if(Link->Item[58]) { if(Link->Item[58]) { Link->Item[36] = true; Link->Item[28] = false; Link->Item[28] = false; Link->Item[58] = false; Link->Item[58] = false; } } } } } This will give Link the Master Sword, but at the cost of two Heart Containers and Two Magic Containers. If he doesn't have said Containers, no Master Sword for him. *whew* I think that's enough for now. Let's see where we are... Ah, it's time to close it all up. } This closes the loop for while Link is on the first FFC. Waitframe(); } And that closes the first While loop that keeps the script running. As I said before, without the Waitframe();, infinite loop you can't escape from, unless a Waitframe(); is hit. Which would never happen if you weren't on the FFC. Now all that's left is to close the void run(); and the naming. } } And there you go, your first script. A little over-the-top, but nice anyways. Would you like a basic script? Okay, start with all that leading up to while(true). Put this afterwards: Link->X += 8; Waitframe(); } } } That will move Link 8 pixels to the right every time the script loops. ....By the way, += is a combination of "+" and "=". You could very well do the same thing as "Link->X = Link->X + 8", but why do that when you can do it easier the way I first showed you? And that concludes the Basic part of my tutorial. I'll update it every so often, so check back for more tips and some Advanced Scripting later! :D