Jump to content

Photo

Basic scripting tutorial (WIP)


  • Please log in to reply
66 replies to this topic

#1 Saffith

Saffith

    IPv7 user

  • Members

Posted 18 October 2008 - 01:35 AM

This has been completed and added to the tutorial section. This version may be out of date. The latest version is here.


This tutorial covers basic use of ZScript. It is not written as a general introduction to programming. Instead, it will begin with the simplest functional scripts before moving on to more complex control flow and data manipulation in the intermediate and advanced tutorials.

You should already know how to load and use scripts. If not, that's covered in this tutorial: http://www.purezc.ne...showtopic=38376

By the end of the basic tutorial, you should know the language well enough to write useful scripts, even if only simple ones. However, this is only intended to teach the language itself. Learning how to make good use of it requires experience; it's best to write a lot of practice scripts and experiment to see how things work. Scripting requires a way of thinking that doesn't come naturally to most people, and you won't learn that just by reading a few tutorials.

It's important not rush through this. Each section builds on the ones before; if you move on before you're ready, it'll just make things more difficult.

 

Comments and style


A few things need to be mentioned before getting into actual scripting.

Comments are notes in the script that are ignored by the compiler. They exist only for the sake of human readers. A comment begins with two consecutive slashes and lasts for the rest of the line.
// This is a comment. The line below is not.
int x=5;
int y=10; // This is a comment, but the first part of the line is not.
When you write scripts, it's generally a good idea to add comments to clarify what you're trying to do. They can also be used to temporarily remove code for debugging, but you shouldn't need to worry about that for a while. This tutorial will use comments extensively in code examples to explain what they're doing.

Whitespace is a collective term for spaces, tabs, and line breaks. The compiler doesn't care what you use for whitespace; any combination of the three is equivalent. The only exception is comments; a comment always ends at the end of a line. There are places where whitespace is required, places where it is optional, and places where it is forbidden. These are not really worth going into, as they're pretty intuitive. In general, as long as a human reader wouldn't be confused, the compiler won't, either.

To illustrate, here are three snippets of code that differ only in whitespace:
while (true) {
    Link -> X += 5;
    Waitframe ();
}
while(true)
{
    Link->X+=5;
    Waitframe();
}
while(true){Link->X+=5;Waitframe();}
All three of these are identical, as far as the compiler is concerned.

Since whitespace doesn't matter to the compiler, the best way to use it is strictly a matter of opinion. There are many different ways of handling line breaks and braces. Wikipedia has an article describing several common styles: https://en.wikipedia...ki/Indent_style

Indent style is a very personal matter to many programmers and the subject of numerous flame wars. Different styles have their pros and cons, but all that really matters in the end is that you're comfortable with the style you use. However you like it, though, you should stick to it. Inconsistent spacing looks sloppy and is hard to read, much like English with no punctuation. It's especially important to indent properly when asking for help; if your scripts are hard to read, you'll find people much less willing to search them for errors.

Unlike whitespace, capitalization is important to the compiler. ZScript is strictly case-sensitive. If you try to use link->x instead of Link->X, your script won't work. Names you make up yourself can be capitalized any way you like; again, just be consistent with it.

Finally, a note on terminology. { and } are curly braces or just braces. [ and ] are square brackets or brackets. ( and ) are parentheses. They're all used for different purposes and are never interchangeable, so be sure not to get them confused.

 

Getting started


Generally, the first thing you should put in a script (after any instructional comments) is this line:
import "std.zh"
This tells the compiler to include the contents of the file std.zh with your script. std.zh defines lots of helpful functions and constants, and almost every non-trivial script uses it in one way or another. Although you won't actually need it for a while, it's good to get into the habit of including it. However, when using multiple scripts, std.zh (or any script file, for that matter) should only be included once. Importing the same file more than once will cause errors.

The next thing you have to do is tell the compiler what kind of script you're writing. For an FFC script, you would write this:
import "std.zh"

ffc script ScriptName
{
    // Script body goes here
}
This part is pretty straightforward. The phrase ffc script indicates that you're creating, obviously, an FFC script. That's followed by the script's name, which is, in this case, ScriptName. There are three types of scripts you can create:





ffc script ScriptName // An FFC script
global script ScriptName // A global script
item script ScriptName // An item script
Script names are made up of letters, numbers, and underscores ( _ ). The first character cannot be a number, and the name must not be a language keyword (like script, int, or return). Spaces are not allowed in script names.

Valid Names:
  • CustomBoss2
  • makelinkdostuff
  • This_is_a__stupid_name
Invalid Names:
  • RefillHP&MP // Contains an illegal character (&)
  • int // "int" is a ZScript keyword
  • 3Hearts // The first character is a numbe.
  • ^__^ // Contains illegal characters (^)
The braces and everything in between form the block of code that makes up the script's body. Everything in between those braces is part of the script, i.e.:
 





ffc script BraceExample
{ // The opening brace of the script
    // The body of the script
} // The closing brace of the script
That's all you need to define a script, but there's one more thing you have to add before it will work.
 
ffc script ScriptName
{
    void run()
    {
        // Code goes here
    }
}
This defines the run() function. What exactly this means will have to wait. For now, just remember that the body of void run() is what the game will actually run.

A bit about the different types of scripts.

An FFC script is one that can be attached to a freeform combo. Normally, these will run when Link enters the screen (either before or after the screen scrolls, depending on the "Run Script at Screen Init" flag). It is also possible for a script to set up an FFC to run a script on demand, but this is a fairly advanced technique.

An item script can be attached to an item to run either when the item is picked up or when it is used. Any item script can be used in either way, but almost every script is specifically intended for one use or the other. Item scripts only run for a single frame, so they're commonly used in conjunction with FFC and global scripts to perform actions over time.

A global script is one that is run by the game itself. There are four global scripts. The Active script runs every time the quest is played and can run indefinitely. That's almost always the one you're interested in, but, for the sake of completeness, here are the others. The Init script runs when the quest is started for the first time, and the Continue script runs when it's reloaded after saving and quitting. The Exit script runs whenever Link dies, the game is won, or Game > End Game (F6) is used. The Init, Continue, and Exit scripts can only run for one frame each, so they're not useful for gameplay purposes. You can't load a script into the Init slot manually; instead, to create an Init script, the script must be named Init.

 

Pointers and variables


Pointers represent game objects, such as Link, FFCs, enemies, or the current screen. Variables represent properties of those objects, such as their HP, position, CSet, or tile. (These aren't really accurate definitions of the terms, but they'll do for now.)

For now, we'll only look at these special pointers:
  • Link - Represents Link
  • this - Represents the FFC or itemdata running the script; this isn't defined in global scripts
  • Screen - Represents the current screen
  • Game - Represents the game itself
Each of these pointers has a number of variables. These are accessed using an arrow. For example, Link->HP represents Link's current HP, and this->CSet is the CSet of the FFC running the script.

Variables can be one of two types of data, but there are three different words to identify them.

One type of data is numbers. Numbers are identified with the terms int (short for "integer") or float (short for "floating-point number"). The reason there are two terms will be explained shortly. Numbers go to four decimal places and have a range of -214748.3648 to 214748.3647.

The other data type is bool. Bools have only two possible values: true and false. They represent data you would think of in terms of "yes or no." For example, Link->InputA, which indicates whether the A button is pressed, is a bool. Either the button is pressed (in which case the value is true) or it isn't (false).

The value of a variable is changed with an equals sign. Changing a variable's value is called assignment. An assignment statement must end with a semicolon.
Link->HP = 16; // Set Link's HP to 16 (one full heart)
Link->InputB = true; // Press the B button
Link = 32; // ERROR: You can't assign numbers to pointers directly;
  //you have to set their variables. It doesn't make sense to set Link himself to 32.

// The variable you're setting must always be on the left side of the equals sign.
16 = Link->HP; // ERROR: The compiler thinks you're trying to change the value of the number 16

// You can also assign one variable the value of another.
Link->HP = Link->MaxHP; // Sets the value of Link's HP to the value of his MaxHP, filling Link's HP
this->X = this->X; // Set the FFC's X position to itself - this doesn't do anything, but it's legal
Link->X = Link->InputUp; // ERROR: Link->InputUp is a bool, but this->X is a number.
  // Setting a number to "true" or "false" doesn't make sense.

// Assigning one variable to another is a one-time thing.
// If one changes later on, the other won't change with it.
Link->MaxHP = 48; // Set Link's max HP to 48 (3 hearts)
Link->HP = Link->MaxHP; // Now Link's current and max HP are both 48
Link->MaxHP = 64; // Link's max HP is now 64, but his current HP is still 48
To see all of the different variables you can set, look at zscript.txt. The "class" or "namespace" tells you what pointer type something belong to. Those terms aren't meaningful in ZScript; the file is formatted the way it is to work with C++ documentation tools. The ones you should be looking at are under Link, Game, Screen, FFC (for FFC scripts only), and itemdata (for item scripts only).

As an example, one of Link's variables:
 /**
* The time, in frames, until Link regains use of his sword. -1 signifies
* a permanent loss of the sword.
*/
int SwordJinx;
The last line tells you the type and name of the variable. For now, if it has any type other than bool, int, or float, or if it has brackets or parentheses after the name, just ignore it. Those will be covered later.

The difference between int and float is that ints are whole numbers (i.e., integers), while floats can have fractional values. An FFC's CSet, for instance, is an int. There isn't, say, a CSet 4.62. This is a mostly a matter of convention; as far as the compiler is concerned, they're just different names for the same thing. However, when assigning a value to an int-type variable, it will be rounded down to an integer value.

Note also that variables will not always be the type you expect, and there are a few inconsistencies. For example, Link's X, Y, and Z coordinates are ints, but FFCs' coordinates are floats. FFCs are capable of sub-pixel positioning and movement, but Link is not.

You may notice that some variables have a note that "The effects of writing to this variable are undefined." These are meant to be read-only; you shouldn't try to change them. Assigning new values to these variables probably won't work as you expect, and even if it does, it's not guaranteed to work on every platform or in later versions.

One last note. Hexadecimal numbers can be written by prefixing them with 0x. This is mainly useful when dealing with screen numbers.
Game->ContinueScreen = 0x2F;
At this point, you know enough ZScript to write useful scripts, albeit only extremely simple ones. Again, you are strongly encouraged to write practice scripts for every new concept. Being a good scripter requires experience, and there's only one way to get it.

Here are some sample scripts using what's been covered so far. For now, FFC scripts will take effect as soon as Link walks onto the screen. If you want to delay them, you'll need to delay the appearance of the FFC (by using a warp, perhaps). Also, these will only run once. If you want to do something again and again, such as every time a button is pressed, you'll need loops, which will be covered in the intermediate tutorial.
// Using an item with this script will refill Link's HP and MP.

item script Recharge
{
    void run()
    {
        Link->HP = Link->MaxHP;
        Link->MP = Link->MaxMP;
    }
}
// This script will enable level 4 cheats. This won't work correctly if
// cheats are disabled in the quest.

item script CheatLevel4
{
    void run()
    {
        Game->Cheat = 4;
    }
}
// This script will cause the screen to shake for one second and make Link jump into the air.
// It will also disable the sword and items for as long as the screen shakes.

ffc script Earthquake
{
    void run()
    {
        // There are 60 frames in a second, so...
        Screen->Quake = 60;
        Link->Jump = 3;
        Link->SwordJinx = 60;
        Link->ItemJinx = 60;
    }
}
Also, here are a few suggestions for practice scripts. While you're not in any way required to complete these, you should be able to do so. If you can't figure out how to do these, you're probably not ready to move on. Possible answers are given in spoiler tags.
  • Write an FFC script that moves Link to the FFC's position.
    Spoiler
  • Write a script that sets Link's HP to 3 full hearts (16 HP per heart) and his MP to 3 full magic containers (32 MP per magic container).
    Spoiler
  • Write an FFC script that makes the FFC move to the left and accelerate to the right.
    Hint

    Spoiler

Arithmetic


You're probably already be familiar with the arithmetic operations used in ZScript.
  • - Negation
  • + Addition
  • - Subtraction
  • * Multiplication
  • / Division
  • % Modulus
You may not have encountered modulus before, but it's simple enough. A % B (pronounced "A modulo B") gives you the remainder of A divided by B. For example, 23 % 5 = 3. This will be helpful later on for dealing with regular intervals - counting seconds, for instance, or determining whether Link is centered on a tile.

The standard order of operations applies: multiplication, division, and modulus are done before addition and subtraction. You can override this with parentheses; parts of expressions in parentheses are evaluated first. In programming terminology, the order of operations is called operator precedence. Operators with higher precedence are evaluated before those with lower precedence.

You assign a variable the result of an arithmetic operation the same way as a single value.
this->CSet = 1 + 1; // Set the FFC's CSet to 2
Link->MP = Link->MaxMP / 2; // Set Link's MP to 50% of the max
Link->HP = Link->HP + 8; // Add 8 to Link's current HP
this->X = 16 * ((5 + 4) / 3); // Set the FFC's X position to 48; there's no reason to do it this way, but you can
Link->HP + Link->MP = 16; // ERROR: The compiler can't figure this out;
  // arithmetic has to go on the right side of the equals sign

// You can make both numbers and variables negative. To make a variable negative,
// put the minus before the pointer.
Link->HP = Link->HP + -16; // Reduce Link's HP by adding -16 HP
this->Vx = -this->Vx; // Reverse the FFC's X movement by negating its velocity
Often, arithmetic is used to adjust a variable's current value (as in the third example above) rather than assign it a completely new value. Because this is so common, there's a shorthand way of doing it by combining the arithmetic and assignment operators. For instance, A += B is equivalent to A = A + B,
and A *= B + C is equivalent to A = A * (B + C).

Some examples:
 
Link->MP += 8; // Equivalent to Link->MP = Link->MP + 8;
this->Vx *= 1.5; // Equivalent to this->Vx = this->Vx * 1.5;
Link->HP -= Link->HP % 16; // Equivalent to Link->HP = Link->HP - (Link->HP % 16);
Link->MP -= -16; // Increase Link's MP by subtracting -16
Game->Cheat += 1; // Increase the current cheat level by 1

// Whatever operation you perform in this way, it's done last,
// regardless of the usual order of operations.
this->Vx *= this->Vy + 3; // Equivalent to this->Vx = this->Vx * (this->Vy + 3);
  // NOT this->Vx = this->Vx * this->Vy + 3;
That's all there is to using arithmetic for now, but there's a quirk in division that it's important to be aware of. Because of the way ZC handles numbers internally, the results of division are rounded down, so they won't always be what you expect. In many cases, this isn't a problem, but there are times when seemingly equivalent equations will have completely different outcomes.
 
Link->HP *= 0.5; // Reduce Link's HP by half
Link->HP /= 2; // Reduce Link's HP by half
Link->HP *= 1 / 2; // Set Link's HP to 0, because 1/2 is rounded down to 0
If you're familiar with other programming languages, you might expect that you can get the desired result by writing 1.0/2.0 instead. That's not the case; in ZScript, it makes no difference.

Once again, here are some complete sample scripts. Math is a big part of scripting, so be sure you understand how these work.
 
// This script reduces Link's current HP and MP by 25%.
ffc script SeventyFive
{
    void run()
    {
        Link->HP *= 0.75;
        Link->MP *= 0.75;
    }
}
// This script will make the FFC aim at Link, but accelerate in the opposite direction.
ffc script VeerAway
{
    void run()
    {
        // Dividing by 60 means it will take one second to reach Link's position -
        // or it would, if it weren't accelerating away
        this->Vx = (Link->X - this->X) / 60;
        this->Vy = (Link->Y - this->Y) / 60;

        // Acceleration can be unintutive; you may want to try this one out.
        // The acceleration is based on the negative of the velocity, so if it
        // starts out moving up and left, it'll accelerate down and right.
        this->Ax = -this->Vx / 150;
        this->Ay = -this->Vy / 150;
    }
}
// This script disables Link's sword for one second for every full heart and
// disables items for one second for every full magic container.
ffc script ProportionateDisability
{
    void run()
    {
        // 16 HP in a heart, 60 frames in a second
        Link->SwordJinx = (Link->HP / 16) * 60;

        // And 32 MP in a magic container
        Link->ItemJinx = (Link->MP / 32) * 60;
    }
}
And a couple more practice exercises:
  • Write a script that moves Link one tile (16 pixels) down and right.
    Spoiler
  • Make an item that reduces Link's MP by 25% and increases his HP by 1 for every 2 MP taken. Think it through; this is simpler than it sounds.
    Hint

    Spoiler
Character limit reached. Continued here.
  • Avaro, TheLegend_njf, PolikMaster and 1 other like this

#2 ShadowTiger

ShadowTiger

    The Doctor Is In

  • Members

Posted 18 October 2008 - 01:39 PM

I love it. I absolutely love it. (But then again, I am inclined to love great strides in progress. icon_razz.gif Yours is just particularly well written progress. icon_blah.gif )

I am also inclined to say that it could use a lot of "Making this shizzle more obvious", to use the slang term for it. That means heavy, heavy use of BB Tags. For example, I would (Personally, if you don't mind?) turn this:

QUOTE

This part is pretty straightforward. The phrase ffc script indicates that you're creating, obviously, an FFC script. That's followed by the script's name.
Script names can be any combination of letters, numbers, and underscores (_), except that the first character must be a letter. The name must not contain any spaces. CustomBoss2, makelinkdostuff, and This_is_a__stupid_name are all valid script names. RefillHP&MP, 3Hearts, and ^__^ are invalid.
The braces and everything in between form the block of code that makes up the script's body. Everything in between those braces is part of the script.


Into this:

QUOTE

This part is pretty straightforward. The phrase ffc script indicates that you're creating, obviously, an FFC script. That's followed by the script's name.
  • ffc_script_yourscriptnamehere
  • item_script_yourscriptnamehere
  • global_script_yourscriptnamehere
Script names can be any combination of letters, numbers, and underscores (_), except that the first character must be a letter. The name must not contain any spaces.

Valid Names:
  • CustomBoss2
  • makelinkdostuff
  • This_is_a__stupid_name
Invalid Names:
  • RefillHP&MP // Contains an illegal character: The ampersand.
  • 3Hearts // The first character is not a letter.
  • ^__^ // The first character is not a letter.
The braces and everything in between form the block of code that makes up the script's body. Everything in between those braces is part of the script, i.e.:
QUOTE
ffc_script_braceexample
{ // The opening braces to the script.
// This is where the real meat of the script is.
} // The closing braces to the script.




But of course, someone as A-D-D- ridden as I am would be inclined to want to mark up all this stuff, so...


Also, what do you think of this: Before we go about stating syntax and all, lets describe the different types of scripts. (I.e. FFC, Global, and Item.) Because each has different qualities, so we don't want people to use this well written guide and find out that even this has supposedly somehow steered them wrong, when in fact they're still just misinformed as of yet, and are writing the right thing in the wrong area? I.e. are writing for a global script in an FFC script or something.





Oh: And here's an idea I'm toying around with. A scripting "FAQ" of sorts, which will actually handle the gray matter between scripting and what it affects. It'll handle questions such as:
  • Why hearts and magic done in increments of 16 and 32 respectively? (And then I would display a screenshot of the Link Health Meter setup in the tiles page.)
  • Why do I keep seeing "Y+8" Everywhere? (whatever it is. icon_sweat.gif ) (Because Link is capable of moving on both the lower and upper halves of a combo, as compared to being stuck to the 16x16 grid. The 8 represents half of the vertical height of the combo, which is what Link is always standing on, as Link's hitbox is 8 pixels tall.)
etc





---------




QUOTE
For now, all of these will take effect as soon as Link walks onto the screen. If you want to delay them, you'll need to set up a warp to the screen with the FFC.
This is because of the lack of a Wairframe(); in FFC Scripts, right? D:

#3 Twilight Knight

Twilight Knight

    Tell all with glee, Argon's on PureZC

  • Members
  • Real Name:Sven
  • Location:Rotterdam, NL

Posted 18 October 2008 - 03:42 PM

Awesome tutorial and good suggestion.
The tutorial is quite well written, the information is useful, I picked up a few new things thanking to it. The layout styles of ShadowTiger are better, the reader will have an easier time of picking up info.

Now finish! icon_twisted.gif

#4 Saffith

Saffith

    IPv7 user

  • Members

Posted 18 October 2008 - 04:13 PM

QUOTE(ShadowTiger @ Oct 18 2008, 02:39 PM) View Post
I love it. I absolutely love it. (But then again, I am inclined to love great strides in progress. icon_razz.gif Yours is just particularly well written progress. icon_blah.gif )
Glad to hear that. I think I have a tendency to be too terse, so I've been a bit concerned about the writing.

QUOTE
I am also inclined to say that it could use a lot of "Making this shizzle more obvious", to use the slang term for it. That means heavy, heavy use of BB Tags.
Good idea. I'll go back and add some formatting, probably after finishing up the text.

QUOTE
Also, what do you think of this: Before we go about stating syntax and all, lets describe the different types of scripts. (I.e. FFC, Global, and Item.) Because each has different qualities, so we don't want people to use this well written guide and find out that even this has supposedly somehow steered them wrong, when in fact they're still just misinformed as of yet, and are writing the right thing in the wrong area? I.e. are writing for a global script in an FFC script or something.
Yeah, that may be a better idea. I was planning to put those off a bit, but on second though, that seems unnecessary.

QUOTE
Oh: And here's an idea I'm toying around with. A scripting "FAQ" of sorts, which will actually handle the gray matter between scripting and what it affects. It'll handle questions such as:
  • Why hearts and magic done in increments of 16 and 32 respectively? (And then I would display a screenshot of the Link Health Meter setup in the tiles page.)
  • Why do I keep seeing "Y+8" Everywhere? (whatever it is. icon_sweat.gif ) (Because Link is capable of moving on both the lower and upper halves of a combo, as compared to being stuck to the 16x16 grid. The 8 represents half of the vertical height of the combo, which is what Link is always standing on, as Link's hitbox is 8 pixels tall.)
etc
Absolutely. We'll have to see what sorts of questions arise, and how many, but that'll likely warrant an entire article or two.

QUOTE
This is because of the lack of a Wairframe(); in FFC Scripts, right? D:
Yeah. I'll get to Waitframe() in the next section, then Waitframes() in the one after that. Those are a lot more useful after getting into loops, though.

QUOTE(Twilight_Knight @ Oct 18 2008, 04:42 PM) View Post

Awesome tutorial and good suggestion.
The tutorial is quite well written, the information is useful, I picked up a few new things thanking to it. The layout styles of ShadowTiger are better, the reader will have an easier time of picking up info.

Now finish! icon_twisted.gif
Thanks. I'll try and write those last two sections before Monday, at least.

#5 ShadowTiger

ShadowTiger

    The Doctor Is In

  • Members

Posted 18 October 2008 - 05:04 PM

Can I help with the BB Tags? It's kinda 'what I do' and I don't want you to have to waste your time with it.

QUOTE
Yeah. I'll get to Waitframe() in the next section, then Waitframes() in the one after that. Those are a lot more useful after getting into loops, though.
Oh butterfigs, you mean there are two different versions of it? So it wasn't an urban myth after all... ...


So yeah, I just went through a whole bunch of agonizingly painful scripting practice with someone, (Who will remain anonymous unless he/she wishes to speak up.) and found a few of the odd issues that anyone new could come up with.

For one, I think it should be stated from the get-go that you should include import "std.zh into everything you write on instinct alone, if anything. (As well as into all of those example scripts in the first post. I was following them as a guide to writing my script, and was somehow under the impression that I didn't have to put it in for simple things or something or other.)

Then, (And I don't know if this is too advanced or not.) there was the matter of having multiple parentheses around certain things. For example:
QUOTE
Waitframes((waitTime * 62));
Link->HP -= (4 * damageAmount);
if((soundid) != 0)
{
Game->PlaySound(soundid);
}
Check out the usage of the parentheses. Do I really need two parentheses around some of those lines like that instead of just ((variable) * 5); ?

Also, is that how custom variables are used? (I know I'm getting pretty much off topic, but I doubt these are entirely advanced. It's hard to make a good script without custom variables.)

#6 Saffith

Saffith

    IPv7 user

  • Members

Posted 18 October 2008 - 05:54 PM

QUOTE(ShadowTiger @ Oct 18 2008, 06:04 PM) View Post
Can I help with the BB Tags? It's kinda 'what I do' and I don't want you to have to waste your time with it.
Certainly. Much appreciated.

QUOTE
Oh butterfigs, you mean there are two different versions of it? So it wasn't an urban myth after all... ...
Yeah, but it's not a huge deal. std.zh defines Waitframes(int j), which just calls Waitframe() j times.

QUOTE
For one, I think it should be stated from the get-go that you should include import "std.zh into everything you write on instinct alone, if anything. (As well as into all of those example scripts in the first post. I was following them as a guide to writing my script, and was somehow under the impression that I didn't have to put it in for simple things or something or other.)
Couldn't hurt.

QUOTE
Then, (And I don't know if this is too advanced or not.) there was the matter of having multiple parentheses around certain things.
Hm... That may be a matter for the FAQ. I'll see what I can do in the way of notes and examples.

QUOTE
For example:
QUOTE
Waitframes((waitTime * 62));
Link->HP -= (4 * damageAmount);
if((soundid) != 0)
{
Game->PlaySound(soundid);
}

Check out the usage of the parentheses. Do I really need two parentheses around some of those lines like that instead of just ((variable) * 5); ?
If you've double parentheses, or if you've got them around a single variable or literal or an entire expression, they're unnecessary. That example can be trimmed down to this:
CODE
Waitframes(waitTime * 62);
Link->HP -= 4 * damageAmount;
if(soundid != 0)
{
    Game->PlaySound(soundid);
}


QUOTE
Also, is that how custom variables are used?
Yes, that looks fine.

QUOTE
(I know I'm getting pretty much off topic, but I doubt these are entirely advanced. It's hard to make a good script without custom variables.)
It's not that advanced, but I want to save it for the intermediate tutorial because I've seen a lot of people get confused about declaration.


#7 Elmensajero

Elmensajero

    Doyen(ne)

  • Members
  • Real Name:John
  • Location:Raleigh, North Carolina

Posted 18 October 2008 - 07:35 PM

You did a really good job with this Saffith! icon_thumbsup.gif I tried looking at it with a perspective as if I didn't already know how to use ZScript, and I can't think of anything else to add to this section of the tutorial series. Keep working on the rest of this, and I think it will be a great asset to anyone trying to learn ZScript! icon_smile.gif

#8 Saffith

Saffith

    IPv7 user

  • Members

Posted 18 October 2008 - 11:24 PM

All right, got functions in. That was harder to write than I expected, partly because it's getting to be such an enormous chunk of text. Anyway, see what you think.

#9 SpacemanDan

SpacemanDan

  • Members
  • Location:Ontario, Canada

Posted 19 October 2008 - 01:02 PM

Great work! icon_biggrin.gif This definately helped me understand some things I was struggling with.

#10 Mitchfork

Mitchfork

    no fun. not ever.

  • Members
  • Real Name:Mitch
  • Location:Alabama

Posted 19 October 2008 - 02:40 PM

I just read through the entire thing- very good, and it really takes a lot of the intimidation of scripting away (at least for me) by explaining what all the arrows and parentheses and such mean. A few thing though:
QUOTE(Saffith @ Oct 18 2008, 01:35 AM) View Post
CODE
// This script will make the FFC aim at Link, but then veer off to the left or right - not necessarily before it reaches him.
ffc script VeerAway
{
    void run()
    {
        // Dividing by 60 means it will take one second to reach Link's position - or it would, if it weren't accelerating away
        this->Vx = (Link->X - this->X) / 60;
        this->Vy = (Link->Y - this->Y) / 60;
        
        // Acceleration can be unintutive; you may want to try this one out
        this->Ax = -this->Vx / 100;
        this->Ay = -this->Vy / 250;
    }
}

CODE
// This script disables Link's sword for one second for every full heart and disables items for one second for every full magic container.
ffc script ProportionateDisability
{
    void run()
    {
        // 16 HP in a heart, 60 frames in a second
        Link->SwordJinx = Link->HP / 16 * 60;
        
        // And 32 MP in a magic container
        Link->ItemJinx = Link->MP / 32 * 60;
    }
}

The first one I have no idea what's going on. What makes the FFC veer away from Link... does anything determine the direction, or does it simply accelerate in the "easiest" direction away from Link?

The second I understand, but you might want to make it clearer about the script only running once and operating on his current health and magic- the first time I read it, I was like "Link can't use his sword after picking up a heart? icon_blink.gif"

Also, how do you tell ZScript which FFC to use? Did I miss that, or is it automatically the first (or all of them!)


#11 Saffith

Saffith

    IPv7 user

  • Members

Posted 19 October 2008 - 03:43 PM

All right, I'll try and clear those up. Thanks.

The VeerAway script bases its acceleration on the negatives of its velocity, so it'll start moving one way and accelerate in the opposite direction. It'll usually end up going left or right since the magnitude of the X acceleration is greater.

The FFC used is just whichever one(s) you assign the script to.

#12 Mitchfork

Mitchfork

    no fun. not ever.

  • Members
  • Real Name:Mitch
  • Location:Alabama

Posted 19 October 2008 - 03:52 PM

Ah, that's right. icon_doh.gif You can attach scripts to FFC's. I haven't done much with those, so you'll have to forgive my occasional lapses.

#13 Saffith

Saffith

    IPv7 user

  • Members

Posted 20 October 2008 - 12:02 AM

All right, I got constants in. I'm a bit unsure whether it's clear enough, though, and I wonder if I shouldn't move that bit about the std.zh functions to the functions section.

I decided to add a section on arrays at the end. Seems like a good time to introduce them.

ST, you don't mind if I go back and edit your additions a bit, I'm guessing?

Edited by Saffith, 20 October 2008 - 12:23 AM.


#14 ShadowTiger

ShadowTiger

    The Doctor Is In

  • Members

Posted 20 October 2008 - 06:11 AM

Team efforts go for as close to perfection as possible. Nothing is private here, I suppose.

#15 Mitchfork

Mitchfork

    no fun. not ever.

  • Members
  • Real Name:Mitch
  • Location:Alabama

Posted 20 October 2008 - 09:07 AM

Awesome. icon_thumbsup.gif Constants are cool.
QUOTE
int ComboAt(int x, int y)
* Finds the number of the combo at the given coordinates. The
* number is 0 at the top-left corner of the screen and 175
* at the bottom-right.

What does this mean? Shouldn't the coordinate for the top-right be (0,0) and bottom-left be something like (256,176)? Single numbers don't make sense, especially not odd ones.


0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users