Fowlplay4

From Zodiac
Jump to: navigation, search

Introduction

Background

Hello, I am Jerret. I am writing this tutorial with the sole purpose to help those who are new to the language of GS2, and even Scripting/Programming in general. I was first introduced to Graal script almost 5 to 6 or so years ago in Graal's level editor, but times have changed since then and now there is GS2, the successor to GS1 used in the level editor. I owe much of my success to learning the language and how to script/program in general to people I've worked with on Zodiac such as Ruxxter_Phantom, and Yen.

Purpose

As I mentioned in the introduction this tutorial is being written for those who would like to learn the scripting language of GS2. However I don't want to bore you with this tutorial either so I'll attempt to mix in some humor to help the learning process, as well as pictures.

If you've never done any kind of scripting or programming and want to get into GS2 then I would highly recommend trying out Javascript first. Codecademy provides a decent interactive tutorial you can start with to get your feet wet. A lot of concepts in scripting/programming learned else where can be applied to GS2 and vice versa.

Getting Started

At one point you could script in the level editor and test it offline in your own environment but times have changed dramatically since then and that is no longer an option for GS2 as it requires an NPC-Server, which I'll explain later.

Feb 27th 2012 Update: I have created a Basic GS2 Emulator that will allow you to complete the first 5 parts and first challenge of this tutorial. You can access it here: http://fp4.ca/gs2emulator/

In order to learn, experiment, and have fun with GS2 you'll need at least writable access to level on a Graal server, but preferably you want to aim higher and get NC Access so you can create Weapon NPCs.

You will need to find a developing server with an owner who is willing to let you learn to script on their server. It also doesn't hurt to try and help them out in other aspects of development. I personally started out as a LAT (Level Maker) and worked my way into a scripting/general developer position.

So we've reached your first task, in this tutorial. Find yourself NC Access.

Chris (cbk1994) has created an excellent video tutorial that explains the the How-To of NC (NPC-Control) You can view it here: NC Tutorial

I'd recommend watching it before you continue on with my tutorial as I may use terms from that video, and ask you to do things that were taught in that video.

He's also created some other Graal tutorials videos as well such as Uploading Files, feel free to check them out.

Part 1: Hello World!

Well like any other tutorial the first step is teaching the Hello World!

First step is creating the Weapon NPC to place the script in, click Add in the Weapons window, give your weapon npc a name and click Apply. If done correctly you have a window open like this:

Tutorial 1-01.png

Now we can finally do some code!

If you're familiar with Java, or any kind of Programming language you know that there is a main function that is called when the program is started. In GS2's case this is our onCreated event.

function onCreated() {
  echo("Hello World!");
}

Feel free to copy and paste the above into your script window, and click Apply. If you check your RC it should read out something like this:

Weapon/GUI-script Example added/updated by fowlplay4
Hello World!

If you get an error you may have misspelled something, or have some white space that's causing some problems.

Now that we've said hello to the world, let's blow it up! Not really though we're going explain what we just scripted.

function Basically defines what the function is, these will have their own part and I'll teach you to create your own.
onCreated() The defined function that's called, this is one of Graal's many predefined event functions that are made available to you.
{ }'s The squiggly braces as I like to call them are the code that's executed by the function, they are the traffic controllers of your script.
echo("message") echo is a predefined function that allows you to output to RC, inside of the function is where you put your message.
"Hello World" This is a string, it's one of the available data-types, Graal isn't very strict at all with data types.

Related Documentation

At the end of each part in the Tutorial I plan to provide you with some extra reading that will provide another view point and even information beyond the scope of the tutorial. I would recommend you read through them or at least come back to them when you have the chance.

Johnaudi's GS2 for the Noobs Part 1

Part 2: Variables

Now that we've said Hello to the World we can finally move on to bigger and brighter things, Variables!

If you've never programmed before, you're probably wondering what a variable is. In the simplest terms, it's a container that let's you store values and other data in it.

But it's better explained in code.

function onCreated() {
  val = "Rawrrr!";
  echo(val);
}

Feel free to copy and paste the above into your script window, and click Apply. If you check your RC it should read out something like this:

Weapon/GUI-script Example added/updated by fowlplay4
Rawrrr!

As you can see the contents of 'val' was echoed to NC.

Graal is very nice when it comes to variables and storing values inside them, you don't have to declare the data type (number, text, etc.), and can change it whenever you please.

Here's an example of variables and different data types in action.

function onCreated() {
  // Integer
  val = 1;
  // Float
  val = 3.14;
  // String
  val = "Meow :3";
  // Object Reference
  val = player;
  // Array
  // Note: We will touch on these later in this tutorial.
  val = {1, 2, 3};
}

However I would never use a variable like that without a prefix in front of it. There's a few different types of prefixes available for your use. Also note the use of //'s these are considered comments. You should always use comments to display what the code is doing. When you use //'s the script interpreter skips everything past it, so if you have a troublesome piece of code that is causing errors you can comment it out and it won't be executed.

this. Refers to the object itself, and is stored in memory.
thiso. Refers to the original object when it's called in a different scope.
temp. This is probably my favorite prefix, it allows you to use the variable and is discarded from memory after the function is complete.
player. Refers to the player object.
client. Refers to the player object's client flags.
clientr. Refers to the player object's client flags, however these flags are only read-only on the client-side.
server. Refers to the server's flags.
serverr. Refers to the server's flags, available on the client-side but like clientr flags are read-only.

Sorry if it's a little confusing right now but it'll make sense over time when you're more familiar with GScript2.

One last thing before we continue you'll notice that I use @'s and SPC's. These are for string concatenation, and it's basically piecing your variables and values together to make one complete string. Here's a few examples:

function onCreated() {
  temp.a = "My mother";
  temp.b = "bakes good";
  temp.c = "cookies.";
  // Let's make sense of this!
  temp.str = temp.a SPC temp.b SPC temp.c;
  echo(temp.str);
  // Here's another way you can do the above.
  temp.str = temp.a @ " " @ temp.b @ " " @ temp.c;
  echo(temp.str);
}

Play around with it, make a few funny sentences if you can it's really up to you. There's a guide on the Graal Bible that explains it well but it's down right now, so you can access it through the Wayback Machine [1]

Related Documentation

Johnaudi's GS2 for the Noobs Guide Part 2
Arrays Guide (fowlplay4)
Sorting Arrays (WhiteDragon)
Checking for objects in arrays (fowlplay4)
GS2 Wiki Concatenation

Part 3: Logic

If you're unfamiliar with programmed logic continue reading else skip to next paragraph, still reading? Well get familiar because you'll be doing a lot of it! It will basically allow you to control your script, and react to certain conditions.

Let's start off with a basic script

function onCreated() {
  value = 3;
  echo("value equals 1");
  echo("value equals 2");
  echo("value equals 3");
}

Feel free to run it, and you should end up with some spam on your NC, saying that value equals 1, 2, and 3. Let's fix that, by using an if statement!

function onCreated() {
  value = 3;
  if (value == 1) {
    echo("value equals 1"); 
  }
  if (value == 2) {
    echo("value equals 2");
  }
  if (value == 3) {
    echo("value equals 3");
  }
}

Now run it, and you should end up with a message on your NC, saying that value equals 3. Congratulations you just performed some successful programming logic! Now let's debrief.

if (condition) {
  // do the following
}

Let's go over the condition first, the script will only do the following if the condition results in true (or not 0 in GS2), and boolean math lets us use our variables and other values to simplify it down to either true or false.

Boolean math is quite simple, and very useful when making comparisons. Here are some common comparison operators that you will be using:

a == b    A equals B
a != b    A does not equal B
a >= b    A is greater than or equal to B
a <= b    A is less than or equal to B
a >  b    A is greater than B
a <  b    A is less than B

Here's a few examples of the above in action.

function onCreated() {
  a = 1;
  b = 2;
  if (a == b) echo("a == b");
  if (a != b) echo("a != b");
  if (a >= b) echo("a >= b");
  if (a <= b) echo("a <= b");
  if (a > b)  echo("a > b");
  if (a < b)  echo("a < b");
} 

Feel free to change the values of a and b to experiment and get acquainted with conditions.

The squiggly brackets control what is being done, and are generally used every time you use an if statement but it can be done the following way:

if (condition) echo("this works too");

However that is only good for one statement, the squiggles allow you to do multiple statements.

Now let's return to our first example with our newly scripted if statements, let's say you only want to know if it equals 3 but want to do certain script when it doesn't equal 3. There's an else for that :)

function onCreated() {
  value = 2;
  if (value == 3) {
    echo("We're so glad you're a 3, welcome!");
  } else {
    echo("We don't take kindly to " @ value @ " values around here.");
  }
}

Run the script above, and you should find that they don't take too kindly to 2 values around here. You'll also notice that we used an else statement which is one of if's cousins!

Else can also be used in conjunction with if like the following:

function onCreated() {
  value = 2;
  if (value == 3) {
    echo("We're so glad you're a 3, welcome!");
  } else if (value == 2) {
    echo("We love you 2, you're so awesome!");
  } else {
    echo("We don't take kindly to " @ value @ " values around here.");
  }
}

Now your script loves your value of 2 :)

Finally you aren't limited to just checking one value at a time in a condition statement, you can check multiple things using the following conditional operators.

a && b    A and B are both true then statement is true
a || b    A or B are true then statement is true

Here's a little example of them in action.

function onCreated() {
  a = 4;
  b = 1;
  if (a == 4 && b == 1) {
    echo("Grawrrrr");
  }
}

However for readability it's generally better to do the following.

function onCreated() {
  a = 4;
  b = 1;
  if (a == 4) {
    if (b == 1) {
      echo("Grawrrrr");
    }
  }
}

For the sake of readability and to make it easier for others to help you, you should only make multiple comparisons in the same statement if they're related. I.e: Checking X and Y coordinates.

I'd recommend you spend some time playing around with the examples, and get comfortable with them before you continue. Even if you don't get comfortable with them you can always refer back to this section when you're confused.

Related Documentation

GS2 Wiki If Statements

Part 4: Math

Was this your favorite subject in school? Well it doesn't really matter because you'll be doing it anyway! But don't fret it's not that big of a deal in programming because you will most likely be dealing with simple math unless you decide to undertake complicated tasks involving numbers.

Let's get our basic script ready.

function onCreated() {
  a = 2;
  b = 4;
  c = 0;
  echo("Result: " @ c);
}

Run it and it should say that the Result is 0 or it will be blank. Let's do some addition!

function onCreated() {
  a = 2;
  b = 4;
  c = a + b;
  echo("Result: " @ c);
}

After running it you should get a result of 6 right? Congratulations, you just added a and b together, now let's go over other operators like the addition symbol that you can use!

+  Addition
-  Subtraction
/  Division
*  Multiplication
^  Exponents
%  Mod (Gives you the remainder of a division I.e: 5 % 2 = 1)

There's also shortcuts you can take to do math.

Don't forget you aren't limited to just adding variables together you can use numbers instead but it's just easier and can save you time in the future if you declare a variable for a number instead of having it hard coded into a math expression.

function onCreated() {
  a = 2;
  b = 4;
  a += b;
  echo("Result: " @ a);
}

Like in our example above the result is 6 again and we used a new type of assignment operator!

a += b        is basically the same as doing
a = a + b

You can do that with every operator I listed above, generally for script readability purposes I only use them with + and -.

Here's a mini challenge! Alter the variable values of a and b so the script tells you that you're super awesome at math. Remember to follow through the script and do the math in your head so you aren't just guessing.

function onCreated() {
  a = 1;
  b = 2;
  a = a - b;
  a = a + 4;
  b += a;
  if (a == 7 && b == 10) {
    echo("You're super awesome at math dawg.");
  } else {
    echo("You aren't quite there yet.");
  }
}

Done yet? Oh well you can play around with that till you get it. If you want the answers run this script but at least try to get it.

function onCreated() {
  echo("a: " @ (2 ^ 6 - 2) % 7);
  echo("b: " @ (3 ^ 2 + 4) % 5);
}

Much like the Logic section above I recommend you experiment with the examples above until you feel comfortable enough to proceed.

Related Documentation

Modulus and Ternary Operators (fowlplay4)

Part 5: Functions

Welcome to the most functional part of the tutorial! Now you're probably wondering what a function is, because you have only been using onCreated since the start of this tutorial.

A function can be an event that is invoked by a certain condition (such as a player entering the level, or a player chatting), or it can be a scripted procedure that you want your script to perform, and return a value when it's done if required.

Let's take a look at a couple different function events available to you on the server-side. (Client-side is explained further into the tutorial)

function onCreated() {
  // Invoked when the script is updated, or when created obviously.
}

function onPlayerEnters() {
  // Invoked when a player enters the level.
} 
 
function onPlayerTouchsMe() {
  // Invoked when a player touchs the npc, that contains this script.
}

function onPlayerChats() {
  // Invoked when a player chats.
}

Those above are some of the most common events that you will work with, it's important to remember that the per-defined onPlayer event functions allow you to access the player variables like so:

function onPlayerEnters() {
  this.chat = "Welcome to the level" SPC player.account @ "!";
}

You can add the script above to a level NPC, just:

1. Open the Graal level editor
2. Add a NPC by dragging it on the level
3. Open the NPC's script window by double-clicking it
4. Finally place the code inside the script window

Tutorial 5-01.png

It's important to note that if you click test, you will most likely get an error due to the usage of GS2. This is because the level editor only supports GS1 which sucks :[. You'll then have to upload your level to the server and warp to it.

You should be greeted to something like this:

Tutorial 5-02.png

We'll touch more on those invoked events, further into the tutorial when we use them in client-side scripts.

Now let's get back to why functions are so handy! Have you ever needed to do a common task over and over, and wished that you had a function to do it for you? Probably not but I know I have.

Here's a few advantages of using functions:

1. Reduces unnecessary duplicate code
2. Improves readability
3. Improves reuse-ability

Let's start with a new example, to calculate the tax for a certain item.

function onCreated() {
  // Declare Variables
  temp.price    = 10;       // Price of Item
  temp.tax_rate = 0.11;     // Taxes are recorded as a percent value (11 / 100 = 11%)
  // Calculate Taxes
  temp.taxes    = getTaxes(temp.price, temp.tax_rate);
  // Echo Tax Amount
  echo("You owe " @ temp.taxes @ " in taxes on that item.");
}

// We have to declare the getTaxes function, so that we can use it.
function getTaxes(a, b) {
  // We'll add code here soon.
  // Returns the result to the location where the function was called.
  return 0;
}

Copy and paste that into your script window and run it. You'll find that you owe nothing! That's just not true, we'll never escape the tax man, remember that line "The only certain things in life are death and taxes." let's make that apply here.

Keep the script above in tact, we'll only be editing the getTaxes function from now on.

function getTaxes(a, b) {
  temp.taxes = a * b;
  return temp.taxes;
}

This is taxes in it's simplest form, value * rate = tax amount. If you replace the getTaxes function in your script with the one above, and run the script you should get a valid tax amount.

There's just one problem though, I haven't explained the function to you yet completely. Let's have a look over a couple new sections.

function getTaxes(a, b) {

- getTaxes is the function name, that you use to call/invoke it.
- a is a parameter that is usable by the function.
- b is another parameter that is usable as well.

You can name your parameters anything, and I would even recommend you name them something meaningful to add clarity to your script.

But you might be wondering, well where do the values in the parameters come from. Elementary my dear chap, you pass them to it when you call it in the function. In the example it was done with this line:

temp.taxes = getTaxes(temp.price, temp.tax_rate);

The value of temp.price is placed into the 'a' parameter, and the value of temp.tax_rate is placed into the 'b' parameter.

The other foreign line would be the return command, it basically exits the function and returns whatever it's told to, and to wherever the function was called. In our current case it returns a 0. Here's a little example of some return usage.

function onCreated() {
  temp.response = sup();
  echo("(npcserver): " @ temp.response); // Would echo "(npcserver): not much dawg..."
}
 
function sup() {
  return "not much dawg jus keepin' it rael!";
}

Pretty tight, huh?

Let's update our getTaxes function with our new knowledge.

function getTaxes(price, tax_rate) {
  // Calculate Taxes Due
  temp.tax_amount = price * tax_rate;
  // Return the Tax Amount to the location where the function was called.
  return temp.tax_amount;
}

Now our script is read-able and should make sense to other coders when they look over it. Congratulations we just calculated some taxes, and learned a bit about functions! We're getting so close to our first challenge.

Related Documentation

GS2 Wiki Functions

Part 6: Basic Debugging

Let's face it you're going to encounter bugs, script errors, and plenty of other logical messes while you're scripting. I'm going to show you a couple methods and techniques that I use nearly every time I have to debug and fix a script.

Let's use this broken script I wrote just for you!

function onCreated() {
  temp.lyric = "london bridge is falling"
  echo("down!");
}

Run this is in a script window, and watch the RC for an error message you should get:

Script compiler output for Example:
error: missing semicolon at line 3: echo("down!");
Weapon/GUI-script Example added/updated by fowlplay4
down!

The error reports that it's an error on line 3 but that's a lie, it's actually on the line above it! Can you see it? As indicated by the error message it's missing a semi-colon.

function onCreated() {
  temp.lyric = "london bridge is falling";
  echo("down!");
}

So just add the semi-colon (;) and it's fixed, you'll get a down message on NC and no error.

Remember when you get script compiler errors, you should always check the first line that it lists, and work your way down from there. It's usually something simple like an open set of { }'s " "'s or a missing semi-colon.

The next tool that is extremely helpful, is the function echo. It'll allow you to trace through scripts and allow to figure out exactly where it goes wrong. Simply place it after each line of your code that you consider a checkpoint. If it's successful move the echo forward a bit and retest, repeat until you find the troublesome line of code.

You'll learn the art of debugging as you gain experience in the programming/scripting field, and may even adapt your learning to other problem solving situations. Anyway onto our first challenge! :D

Related Documentation

Debugger Script (fowlplay4)
GS2 Wiki Echo Function

Challenge 1: Calculator Functions

Well we're going to make some basic math functions for our calculator. The calculator will require 4 different basic functions, addition, subtraction, multiplication, division.

The only catch is that you have to code an if statement in the division function, so that you can't divide by 0! Instead it should return an error message stating that you can't divide by 0.

Here's the basic shell and test data for the functions.

function onCreated() {
  temp.a = 2;
  temp.b = 1;
  temp.c = 3;
  temp.a = onAdd(temp.a, temp.b);
  onResult(temp.a);  // Should display "3"
  temp.a = onSubtract(temp.a, temp.c);
  onResult(temp.a);  // Should display "0"
  temp.a = onDivide(temp.b, temp.a);
  onResult(temp.a);  // Should display "can't divide by 0 error"
  temp.a = onDivide(temp.c, temp.b + 0.5);
  onResult(temp.a);  // Should display "2"
  temp.a = onMultiply(temp.b + 1, temp.c);
  onResult(temp.a);  // Should display "6"
}

function onResult(temp.result) {
  echo("Result: " @ temp.result);
}

function onAdd(a, b) {
  return 0;
}

function onSubtract(a, b) {
  return 0;
}

function onDivide(a, b) {
  return 0;
}

function onMultiply(a, b) {
  return 0;
}

Good luck, and don't be afraid to refer back to the previous chapters, they're there to help you!

Part 7: Clientside Code

There's two sides to GScript, and they are the Server-side and the Client-side. It's very easy to separate the two in your own scripts. Here's how you'll tell what code is on the server-side and which is client-side.

/*
   Code above this point is on the server-side.
*/

//#CLIENTSIDE

/*
   Code below this point is on the client-side.
*/

The //#CLIENTSIDE separator designates the code above it as server-side, if there's no separator than it is all server-side.

It's important to remember that client-side code runs entirely on the Graal client, and code above it on the server-side is ran by the NPC-Server so you want to avoid having the server perform intensive tasks that may slow down the entire server. A good example of intensive code are the Baddies on Zodiac. We've had to do countless optimizations to it's code just so we can have hundreds them run without crashing the NPC-Server.

Now just one thing to remember before we continue. There is no such thing as //#SERVERSIDE and you should never write it in your code.

You might be wondering, why do we even have server-side code when we can have all our code on the client-side. Well it used to be like that actually, there was no server-side and players could actually open the level editor on a live server and add their own scripts to themselves which was very insecure. The server-side prevents this and opens up many possibilities such as manipulating other players and working with global data that's not accessible on client-side code.

As mentioned in the paragraph above, client-side code is very insecure and you have to plan around hackers using tools like Cheat Engine, editing the memory of the Graal client and attempting to changes values and messing around to get the script performing in their favor (I.e: Editing damage from 1 to 9999). So it's not smart to perform crucial calculations then pass them to the server and not validate them, sometimes you can't get around this though.

Now that we've been introduced to client-side, let's dive into our next topic.

Related Documentation

None.

Part 8: Basic Drawing

Alright this section is dedicated to teaching you how draw images to the screen, it's fairly simple but first let's get our basic shell that we'll be working with.

//#CLIENTSIDE

function onCreated() {
  // Script Started
  player.chat = "Grawrrr";
}

Let's paste this into our Example weapon script, and click Apply. You should get an updated message and no errors. However it's important to note that the script does nothing at the moment and we still need to login on and add the weapon script to ourself. Here's a little shortcut I use to do so, simply add this line above your client-side separator.

findplayer("yourAccountName").addweapon(this.name);

Replace yourAccountName in quotations with your account name and click apply. If you check your client you should have noticed that your character said Grawrrr which indicates success. If you are unable to achieve Grawrrr status, make sure you added the weapon to yourself and that you're logged into the client.

Now that we've attained Grawrrr status let's draw some blocks! There's a few methods to drawing simple imagery, I'll only be covering showimg and findimg. Let's start with showimg.

//#CLIENTSIDE

function onCreated() {
  // Script Started
  showimg(200, "block.png", player.x, player.y);
} 

Update your script and you should notice a block on your players coordinates, the parameters for showimg are as follows.

showimg(index, image, x, y);

index - The unique ID for the image
image - The file name of the image
x - The X coordinate where the image is drawn
y - The Y coordinate where the image is drawn

It's important to note that images with indexes from 0 to 199 will be shown to every player in the level (aka global), while every other index will only be shown on your client. It's not recommended to use the global indexes for drawing images because they work rather poorly, showing animations using global indexes is another story though.

Both findimg and showimg are valid ways to show images, but findimg is the object-oriented approach and allows you to manipulate images after they've been shown. Here's an example of findimg.

//#CLIENTSIDE

function onCreated() {
  with (findimg(200)) {
    image = "block.png";
    x = player.x;
    y = player.y;
  }
}

As you can see the code is a little bit longer and uses a with statement. The with statement allows you to set the scope of the script to the object passed to it, in our example that object is findimg(200). While in the scope of the image we can access and set it's properties directly.

Part 9: Looping / Timeouts

When you're coding systems for your server, you are most likely going to run into a situation where you need a script to constantly run. An example of that would be an image constantly moving in a circle pattern. There are two main tools to do so and they are listed below.

Basic Clientside Timeout Loop:

//#CLIENTSIDE

function onCreated() {
  setTimer(0.05);
}

function onTimeout() {
  this.ticker++;
  player.chat = this.ticker;
  setTimer(1);
}

In most cases this will be your 'go-to-loop' when you want to continuously perform a repetitive task.

Loop using Scheduled Events:

//#CLIENTSIDE

function onCreated() {
  this.scheduleevent(0.05, "Looping", 0);
}

function onLooping(ticker) {
  ticker++;
  player.chat = ticker;
  this.scheduleevent(1, "Looping", 1);
}

Scheduling events will be very handy later in your scripting travels when you want to have an event occur in a set period of time.

You should never use a loop when you can use an event instead, however sometimes the lack of an event for certain scenario will require you to, but you should avoid looping at fast rates.

It's important to note that the fastest you can get a script to "Timeout" on the client-side is 0.05 seconds which is equivalent to one frame. This is because Graal is frame-rate-capped at 20 FPS (Frames-per-second) so having your timeout operate at faster speeds than Graal's frame-rate is pointless. The server-side also has a similar restriction except that it is capped at 10 FPS which results in 0.1 being the fastest allowed timeout value.

Related Documentation

How to use for and foreach loops (cbk1994)
GS2 Wiki For Loops
GS2 Wiki While Loops

Part 11: Disabling Default Systems

Sometimes the default way just doesn't work for your situation. If you want to create a custom HUD/GUI you're going have to disable the default features on your server which is quite simple.

//#CLIENTSIDE
function onCreated() {
  // FEATURES DOCUMENTATION
  // 1 	M key (map) 
  // 2 	P key (pause) 
  // 4 	Q key (weapon select) 
  // 8 	R key (show ratings) 
  // 0x10 	S+A key combination for dropping items 
  // 0x20 	S+D key combination for switching weapons 
  // 0x40 	TAB key (if disabled then you cannot switch to the chat field with TAB) 
  // 0x80 	Display of chat text 
  // 0x100 	Display of the hearts over player heads 
  // 0x200 	Display of nicknames 
  // 0x400 	Toall/PM-icons on the minimap 
  // 0x800 	Right-click on players opens their profile 
  // 0x1000 	Emoticons (disable it if you want to do other stuff with control+keys) 
  // 0x2000 	Alt+5 for making snapshots (deprecated) 
  // 0x4000 	Alt+8/9 for zooming (deprecated) 
  // 0x8000 	Allows F2 output (savelog()/echo()) 
  // allfeatures 	All of the previously stated feature flags enabled

  // Define Features to Disable
  temp.disabled = 1 + 2;

  // Disable the Features
  enablefeatures(allfeatures - temp.disabled);
}

In our example above it will disable the Map key and Pause key. If you want to disable nicknames as well you would modify it like so:

temp.disabled = 1 + 2 + 0x200;

However enablefeatures doesn't disable the default HUD there's showstats for that.

//#CLIENTSIDE
function onCreated() {
  // STATS DOCUMENTATION
  // 1 	ASD 
  // 2 	Icons (for rupees, bombs, arrows) 
  // 4 	Rupees count 
  // 8 	Bombs count 
  // 0x10 	Arrows count 
  // 0x20 	Hearts 
  // 0x40 	Alignment (ap) bar 
  // 0x80 	Magic points (mp) bar 
  // 0x100 	Minimap (you can only hide it, you cant show it when the player presses (Alt+3) 
  // 0x200 	Inventory NPCs 
  // 0x400 	Players 
  // 0x800 	Right-click on players opens their profile 
  // allstats 	All of the previously stated stats flags enabled

  // Define Features to Disable
  temp.disabled = 1 + 2 + 4 + 8 + 0x10 + 0x20 + 0x40 + 0x80 + 0x100 + 0x200;

  // Disable the Features
  showstats(allstats - temp.disabled);
}

Works exactly the same way as enablefeatures. In the example above it disables nearly all the default GUI functionality.

In the future you might find yourself needing a way to disable default movement so you can script your own, this is quite easy.

//#CLIENTSIDE
function onCreated() {
  // Disable Movement
  disabledefmovement();
}

Can you guess how you re-enable it? I bet you do.. or you looked below.

//#CLIENTSIDE
function onCreated() {
  // Enable Movement
  enabledefmovement();
}

and that's it to disabling the most common default systems in Graal.

When disabling default systems I recommend you do it all in the same weapon script. I've created a working example of that on the Graal forums. You can find it here: [2]

Part 12: Keyboard and Mouse I/O

We've reached a point in the tutorial where I feel you've gotten skilled enough to be able to learn from example, so I'm simply going to present a little documentation and some fully functional examples to play around with.

There are a few events and ways you can track keyboard and mouse input and output. I'll cover some ways with events and then an example using a loop.

Basic Keyboard Events

onKeyPressed(keycode, key, scancode)
onWeaponFired()

Basic Keyboard Functions

keydown(keyvalue)

Key Values

0  - Up
1  - Left
2  - Down
3  - Right
4  - D (Weapon)
5  - S (Attack/Sword)
6  - A (Grab)
7  - M (Map)
8  - TAB (Chat Bar Toggle)
9  - Q (Inventory)
10 - Pause

Examples

How to use keydown(keyvalue):

//#CLIENTSIDE
function onKeyPressed() {
  if (keydown(5)) {
    player.chat = "Shishishaww!";
  }
}

How to use the parameters in onKeyPressed:

//#CLIENTSIDE
function onKeyPressed(keycode, key, scancode) {
  player.chat = "I just pressed " @ key @ " guys!!11";
}

How to use onWeaponFired, Make sure you add the weapon to yourself and select it in the Inventory:

//Fireball Weapon Example
//#CLIENTSIDE
function onWeaponFired() {
  setani("grab", "");
  shootfireball(player.dir);
  freezeplayer(0.1);
  sleep(0.1);
  setani("idle", "");
}

Using keydown in a Movement system:

//#CLIENTSIDE
function onKeyPressed() {
  setTimer(0.05);
}

function onTimeout() {
  // Loop through each directional key
  for (temp.i = 0; temp.i < 4; temp.i++) {
    // Check if the key is being held down
    if (keydown(temp.i)) {
      // Move the player in that direction
      player.x += vecx(temp.i); // VecX Documentation can be found here: http://wiki.graal.us/vecx
      player.y += vecy(temp.i); // VecY Documentation can be found here: http://wiki.graal.us/vecy
      // Moving so Set Timer to continue Looping
      // If you want to see the difference this makes remove it.
      setTimer(0.05);
    }
  }
}

Basic Mouse Events

onMouseDown(mousevalue)
onMouseUp(mousevalue)

Mouse Values

left   - Left Mouse Button
right  - Right Mouse Button
middle - Middle Mouse Button
double - Double-Left Click

Mouse Related Variables and Flags

leftmousebutton - boolean (read only)
leftmousebuttonglobal - boolean (read only)
middlemousebutton - boolean (read only)
middlemousebuttonglobal - boolean (read only)
mousebuttons - integer (read only)
mousebuttonsglobal - integer (read only)
mousepitch - float (read only)
mousescreenx - integer
mousescreeny - integer
mousewheeldelta - integer (read only)
mousex - float
mousey - float
mouseyaw - float (read only)

Examples

How to use MouseDown:

//#CLIENTSIDE
function onMouseDown(mousevalue) {
  // Check if Left Clicking
  if (mousevalue == "left") {
    // Draw Block on Mouses Position on Level
    showimg(200 + this.counter, "block.png", mousex - 1, mousey - 1);
    this.counter++;
    if (this.counter > 20) this.counter = 0;
  }
}

How to use the Mouse Variables:

//#CLIENTSIDE
function onCreated() {
  // Draw Block on Screen
  temp.img = showimg(200, "block.png", mousescreenx - 16, mousescreeny - 16);
  temp.img.layer = 4;
  setTimer(0.05);
}

function onTimeout() {
  // Update Position of Block
  with (findimg(200)) {
    x = mousescreenx;
    y = mousescreeny;
  }
  // Check if Left Mouse Button is Down
  if (leftmousebutton) {
    // Make Block Larger
    findimg(200).zoom += 0.05;
  }
  // Check if Right Mouse Button is Down
  if (rightmousebutton) {
    // Make Block Smaller
    findimg(200).zoom -= 0.05;
  }
  // Check if Middle Mouse Button is Down
  if (middlemousebutton) {
    // Rotate Block
    findimg(200).rotation += 0.05;
  }
  setTimer(0.05);
}

Challenge 2: Staff Boots

Staff Boots is one of the oldest staff tools in Graal, they basically allow you to ignore walls and walk all over them.

In this challenge you'll be creating a pair of staff boots that can be toggled with a chat command, and also allow you to change the speed of them as well.

You can read the player's chat output by using onPlayerChats:

//#CLIENTSIDE
function onPlayerChats() {
  if (player.chat == "/boots") {
    player.chat = "You used the boots command!";
  }
}

You can move the player by altering their X and Y values:

//#CLIENTSIDE
function onCreated() {
  // Warps player to random X, Y value
  player.x = random(10, 60);
  player.y = random(10, 60);
}

You'll also want to review the Keyboard I/O section.

Challenge 2 Solution

Challenge 3: Basic Custom HUD

Part 13: Intro to GUI Objects

This section is currently under-construction, view the related documentation for now.

Related Documentation

GUIControl's List
Creating Tabbed Window Panes
Understanding GUI Profiles
Preventing GUI Objects from Stealing Focus

Part 14: Client / Server Interaction

This section is currently under-construction, view the related documentation for now.

Related Documentation

Explanation of clientside/serverside; triggering serverside (cbk1994)
Triggering serverside and clientside (cbk1994)
Triggering weapons from level NPCs (cbk1994)
Triggering serverside from a level NPC (cbk1994)

Part 15: Database NPCs

This section is currently under-construction, view the related documentation for now.

Related Documentation

Database Communication

Part 16: Public Functions

This section is currently under-construction, view the related documentation for now.

Related Documentation

Public Functions (cbk1994)

Challenge 3: Basic Graal Bank

Part 17: Classes

This section is currently under-construction, view the related documentation for now.

Related Documentation

Using Classes Effectively

Part 18: File I/O

This section is currently under-construction, view the related documentation for now.

Related Documentation

Basic File I/O Examples
Quick Text Editor Example

Part 19: Intro to SQLite

cbk1994 has created a nice introduction to SQLite on the Graal Bible. You can view it here Using SQLite.

Related Documentation

Stefan Announcing SQLite Functionality
W3Schools' Guide to SQL

Part 20: Network I/O

This section is currently under-construction, view the related documentation for now.

Related Documentation

Communicating with a Webserver (cbk1994)

Conclusion

Helpful Resources

NPC Scripting Forum: http://forums.graalonline.com/forums/forumdisplay.php?f=8

GScript Wiki: http://gscript.graal.net/Index

Graal Bible Scripting Wiki: http://wiki.graal.net/index.php/Creation/Dev/GScript

Helpful Scripting Posts: http://forums.graalonline.com/forums/showpost.php?p=1624710&postcount=27

Era-Go Scripting Forum (search for GS2 Noob Guides): http://era-go.com/forum/forumdisplay.php?15-NPC-Scripting

Graalians Development Forum: http://www.graalians.com/forums/forumdisplay.php?f=43

On RC: /scripthelp <function/variable name>