Flags: A flag is a check to see if something is true or not. Flags can also be called "events". The "triggeraction" command calls the flag "action<event>" where <event> is the name of the action passed by the triggeraction command. |
Commands: A command is an execution, it tells the NPC what to do. These can also be "Functions". |
Loops: A loop is a set of checks on flags that will repeat. |
Arguments: An argument is used in a command to specify a value. For example the command "showimg" has the following arguments: index, image, x, and y. For each of those (except image) a variable could be used, or a specific number/value. |
Var: "var" is short for "variable". A variable is a non-numerical entity that can have any numerical value. |
Cords: "cord" is short for "coordinate", Coordinates refer to an x,y,z location. |
Current Player: The current player is the player activating the NPC. Examples of this is when a player touches the NPC, the player doing the touching is the "current player", or if a weapon is fired, the person doing the firing is the "current player" but not the player being hit by the weapon. Important thing to remember is the "current player's" index is always 0. So if you want to only effect the current player when scripting, incorporate a players[0].var check. |
Parameters: Parameters are values that can be passed with a function which enable numerical values to be passed and calculated on the fly. |
or
if (statement){
command(s);
}
Without the {}, only the next command will be processed. Thus,
if(statement) putexplosion 1,x,y;
putexplosion 2,x,y;
will always do putexplosion 2,x,y; but only do putexplosion 1,x,y; if (statement) is true.
if(statement){
putexplosion 1,x,y;
putexplosion 2,x,y;
}
will not do anything unless statement is true.
while (statement){
command(s);
}
In this case, the command(s) will be exectued while the
statement
is true.
The difference between the two, is an if statement will only execute
its commands once, per time the statement is read.
But a while loop, will check to see if the statement is true, if it
is, execute the command(s), then check again, if its still true, it'll
execute the command(s) again.
Example usage of a while loop:
while (flag && count<5){
putexplosion 1,x,y;
count=count+1;
sleep 1;
}
In this case, an explosion will be put at x,y, then the NPC will add
1 to the variable "count", and sleep for 1 second.
After doing this 5 times, the loop will stop because the flag
"count<5"
will no longer be true. "while" loops are limited to looping
10000
times (unless you use the sleep command).
for (init-op;statement;incr-op){
command(s);
}
For loops are a fast way to count. Basically, "init-op" is the
starting value of a variable, so long as "statement" is true, the
command(s)
will be executed, then it will go to the incr-op, add that to the
init-op,
and if the flag is still true, it'll continue to exectue the
command(s).
Example usage:
for
(explox=playerx;explox<64;explox++){
if (!onwall(explox,playery)){
putexplosion 1,explox,playery;
}
if (onwall(explox,playery)){
explox=65;
}
}
What this does is, the variable "explox" will start at the player's
x cordinate, and if there is no wall at that cordinate, then it will
put
an explosion there. If explox is still less than 64, then 1 will
be added to explox, and another explosion will be placed if theres no
wall
at the cordinate explox,playery. Note that because of the speed
at
which a "for" loop, loops, then all the explosions will apear at the
same
time on screen.
Eventually, explox will be equal to 64, and the for loop will
stop.
Or, a wall will be reached, and so I set explox to 65 so the for loop
stops.
//Compu hit detection
for (i=0;i<compuscount;i++){
if
( abs ( compus[i].x-x ) <=1 && abs ( compus[i].y-y ) <=1
){
hitcompu
i,power,x,y;
}
}
That is used to check to see of all the compus (baddies) currently on the level, which one(s) are less than or equal to 1 space away from the x,y cords of the NPC. Well, as you'll learn in section 12, anything inside the "[]" is a reference to an index. All indexes start at 0, and go up from there based on how many of that particular thing (in this case compus) there are. In the for loop, "i" (my variable I'm using to check the compu's index) starts at 0, which as I just said is the lowest value for an index. Then what it does is, checks to see if the compu with an index of 0, is less than or equal to 1 space away from the x,y cord of the NPC. Then, because of the for loop, it will add 1, to the variable "i", (if still less than the amount of compus on the board), and run the check again to see if the compu with an index of 1 is less than or equal to one space away from the NPC. This will of course continue to happen until it has checked all the compu's x's and y's. This works anytime you want to check for a index, wether for compus, players, strings, or arrays.
if (statement){
command(s);
}else{
command(s);
}
The commands listed after the else are exectued when "statement" is
not true.
Example usage:
if (playertouchsme){
if (flag){
putexplosion x,y;
}else{
putexplosion playerx,playery;
}
}
In this case, if the player touches the NPC, and the flag, "flag" is
set, then the explosion will be placed at the NPC's x,y.
But if the NPC is touched and the flag is not set, then the NPC will
put the explosion at the player's x,y.
if (playertouchsme){
timeout=10;
}
if (timeout){
putexplosion 1,x,y;
}
In this case, when the NPC is touched, the timeout will be set at 10 seconds. After it has counted down to 0, an explosion will be placed at the NPC's x,y cordinate. Note: The lowest value a timeout can be set to is: .05 seconds.
if (playertouchsme){
timeout=1;
}
if (timeout){
putexplosion 1,x,y;
timeout=1;
}
What this does, is once the NPC is touched, it will set a timeout to occur in 1 second. Once that timeout is reached, an explosion will be put at the NPC's x,y; then the timeout will be set to 1 again. Because the timeout has been reset, after another second, another explosion will be put, and the timeout will be reset again.
if (playerenters||created){
timereverywhere;
}
What timereverywhere does is when player B enters the level, the NPC
will keep track of the timeouts its currently running off of from
player
A. Using "isleader" and "players[0].variable" to stop such
problems
is a bit more complicated. I'd reccomend using the
timereverywhere
method, and if there are still problems online, try to include the
following
in your scripts:
when dealing with timeouts, include "isleader", such as:
if (timeout&&isleader){
x=x+1;
}
In this case, if a timeout is reached and "isleader" is true (isleader is only true to the player that entered the level first) then the NPC will move to the right one space. This way the NPC keep's track of variables for only one player, which cuts back on the amount of glitches. Another way to fix such problems uses the following:
if (timeout){
for(i=0;i<playerscount;i++){
this.player=i;
if (this.player==0){
x=x+1;
}
}
}
This is a method I picked up from Vangel. He told me that in his experimentations with NPC's, he has found that on a client's side, a player's index will always be 0. So, when a player is online, then the NPC will move to the right one space, once per client (only visible to the client though). That way, the NPC only has to keep track of variables once per client. Admitedly, this method a bit more complicated to the beginners, but in some cases its necessary.
if (playertouchsme){
message Hello!;
sleep 3;
message;
}
In this case, if the player touches the NPC, it will display the message "Hello!", then sleep for 3 seconds. After those 3 seconds a blank message will be displayed. The following script will serve as an example of how sleep affects the NPC.
if (playertouchsme){
message Hello!;
sleep 3;
message;
}
if (washit){
message Ow!;
sleep 3;
message;
}
In this case, if the player touches the NPC, the message "Hello!" will be displayed, and the NPC will sleep for 3 seconds. Also, if the NPC is hit, it will display the message "Ow!" and sleep for 3 seconds. If you hit the NPC, then touch it, the message "Hello!" will not be displayed. That is because the NPC is sleeping, and will not accept any more commands/statements until after the sleep countdown has reached zero; even then you would have to touch it after this has occured in order to get it to say "Hello".
if (playertouchsme){
timeout=1;
}
if (timeout){
putexplosion 1,x,y;
}
I've used the example many times, so you should know the NPC will put an explosion 1 second after being touched. That script is the same as:
if (playertouchsme){
sleep 1;
putexplosion 1,x,y;
}
But the difference is, after being touched the NPC will be sleeping so it will not check for any other flags. Here's another example, consider what I used for the explanation "sleep":
if (playertouchsme){
message Hello!;
sleep 3;
message;
}
if (washit){
message Ow!;
sleep 3;
message;
}
And you know what this does, so lets alter it to use timeout.
if (playertouchsme){
message Hello!;
timeout=3;
}
if (washit){
message Ow!;
timeout=3;
}
if (timeout){
message;
}
In this case, without the "sleep" if the NPC was hit then touched, the message will be "Hello!" since that happened most recently. So when deciding weather to use "sleep" or "timeout" consider your situation and which is best for what you'd like to achieve.
if (playertouchsme &&
!thisisaflag){
set thisisaflag;
}
if (playertouchsme &&
thisisaflag){
unset thisisaflag;
}
In the above example, "playertouchsme" is a "built-in flag" these are flags that are pre-built into Graal when you start scripting. That particular flag is true if the player is touching the NPC. All built in flags are about that easy to comprehend (of course playertouchsme means the player is touching the NPC). You'll learn about built in flags in section 11. After the "playertouchsme" I have the following: "&&!thisisaflag" the "&&" and "!" are special symbols, which you'll learn more about in section 10. But for now, just understand &&! means "and not". By putting "not" in front of a flag, that means the flag is not true. So if "thisisaflag" is not true, then that means the flag is not set. You set flags using commands, and they're stored in a player's flag list. So plug in all that info, and we read the statement
if (playertouchsme && !thisisaflag)
as:
if (playertouchsme and not thisisaflag)
In plain english: the player touched the NPC and the player does not
have the flag "thisisaflag" in their flag list.
After that I included the line "set thisisaflag". That will add
the flag "thisisaflag" to the player's flag list, so when we go to the
next part of the script:
if (playertouchsme && thisisaflag){
the flag "thisisaflag" has been set in the player's flag list, so now it is true. Since it is true:
if (playertouchsme &&
!thisisaflag){
set thisisaflag;
}
will do nothing because that only happens if the player touches the
NPC and the flag "thisisaflag" is not set.
This section touched upon flags, commands, and special symbols.
If you had any problems understanding it, I suggest you read over special
symbols and commands for help.
if (playertouchsme){
myvariable=myvariable+1;
}
As you know from the flag section, " myvariable=myvariable+1"
will be executed each time the player touches the NPC. Basically
what this means is, the NPC will store the variable "myvariable" as
"myvariable+1"
each time the NPC is touched. Important Info: ALL variables start
as 0, unless assigned as something else. So the first time the
NPC
is touched, myvariable will be 0+1, or 1. The next time it's
touched
it will be 1+1, or 2. Then 2+1, or 3. And so on.
Many commands can take advantage of the use of variables. For
example:
if (playertouchsme){
myrad=4;
myx=playerx;
myy=playery;
putexplosion myrad,myx,myy;
}
Of course I go back to the old playertouchsme, then I assigned the
variables
"myrad", "myx", and "myy". Then using the putexplosion command,
which
calls for the radius of the explosion, and the x,y cordinates of the
explosion,
i used the variables I assigned just prior to the command.
Another important aspect of variables is that they can be used in place
of flags. Take the following example:
if
(playertouchsme&&myvar<4){
myvar=myvar+1;
}
if (myvar==4&&playertouchsme){
myvar=0;
message Stop that!;
}
In this case, each time the player touches the NPC, "myvar" will have 1 added to it. But if you touch the NPC four times, then "myvar" will be reset to 0, and the NPC will display the message "Stop That!". Notice how I used a variable within the "if" statement, as a flag.
Built-In Variables
You can learn about these in section 12. They are basically variables that are read from within the game. These include player's information (like a player's x,y cordinates, the amount of rupees the player has, etc), as well as the NPC's information (like it's x,y cordinates, and the amount of rupees it has taken). Built-in variables also include compu information (compu's are the "baddies" found in the level editor). But in order to read these, you have to run a for loop to check for the index of all the compus on the level at the time the NPC is executing. This will be explained in sections 12 and 14.
Scripter Assigned Variables
As I mentioned before, the "myvariable" above is something I
assigned.
The difference here is these variables start as 0 (unless assigned
otherwise)
and do not change unless the NPC tells it to change. A player
variable
(as mentioned above) will change each time the player's information
changes.
When to use what It's hard to explain when to use which type of
variable.
Take the following example:
if (playertouchsme){
myvarx=playerx;
myvary=playery;
timeout=1;
}
if (timeout){
putexplosion 1,myvarx,myvary;
}
In this example, when the timeout is reached, an explosion will be where the player was when it touched the NPC.
if (playertouchsme){
timeout=1;
}
if (timeout){
putexplosion 1,playerx,playery;
}
In this example, the explosion will be put at where ever the player currently is when the timeout is reached. This happens because player vars are updated constantly. However:
if (playertouchsme){
myvarx=playerx;
myvary=playery;
timeout=1;
}
if (timeout){
myvarx=playerx;
myvary=playery;
putexplosion 1,myvarx,myvary;
}
Because your variables were updated before the explosion was placed,
then it would put the explosion at the current playerx and playery.
A level with 2 NPC's, the first one has the following script:
if (playertouchsme){
myvariable=myvariable+1;
}
And the other NPC has the following:
if (playertouchsme){
myvariable=myvariable+5;
}
In that situation, if you touch the first NPC, "myvariable+1" will
be
executed. So the first time you touch it, its value is 1.
The
next time you touch it it'll be 2. Let's say the player touched
that
NPC 4 times. So "myvariable" is equal to 4. Then, the
player
goes and touches the other NPC. Well, that NPC would read
"myvariable"
as 4, since thats what it was set to by the other NPC, then it will add
5 to "myvariable", thus setting "myvariable" to 9. If then the
player
goes back to the first NPC and touches it, the value will now be 10.
Now consider the following situation:
NPC 1 has the following script:
if (playertouchsme){
this.myvar=this.myvar+1;
}
And NPC 2 has the following:
if (playertouchsme){
this.myvar=this.myvar+5;
}
In this example, if the player touches NPC 1 four times, then NPC 2 one time. NPC 1 still has "this.myvar" set as 4, and NPC 2 will have "this.myvar" as 5. The variables may have the same name, but because of the "this." the two NPC's can not edit or read each other's variables.
if (playerlaysitem){
take greenrupee;
if (rupees>0){
setstring
gavetofred,#v(rupees)+#v(strtofloat(#s(gavetofred)));
rupees=0;
}
}
I know a lot of that I haven't gone over yet, but I'll explain
briefly
what it does:
if the player drops a green rupee, Fred will take it, and add to the
string I set "gavetofred" the amount of rupees he has recieved.
Now on to Bob's script:
if (playertouchsme){
message You gave Fred: #v(strtofloat(#s(gavetofred))) rupees!;
}
And what this does is allow Bob to display the string that Fred set
on the player, and read the value. Lets alter it slightly to the
following:
Fred:
if (playerchats){
setstring gavetofred,#c;
}
Bob:
if (playertouchsme){
message You told Fred: "#s(gavetofred)"!;
}
In this case, what ever you say to Fred will be stored as a text
value
in the string "gavetofred" so when you go to Bob, he'll display the
same
text you said to Fred.
Now, on to the Built-in strings
These are quite similar to the player variables. The difference
being, they also have text values. For example, "#3" is the value
of the player's head file. So lets say you have the following
script:
if (playertouchsme){
message Your head file is: #3;
}
In this example, if your player has head173.gif as his head, then
when
you touch the NPC it will say:
Your head file is: head173 Note that it does not say ".gif" at the
end of the statement. That is because it only reads the value,
which
is head173, the .gif is merely a file extension. Built-in strings, like
variables, can be used within if statements. Consider the
following
example:
if
(playertouchsme&&strequals(#w,Bow)){
message You are using the Bow!;
}
In this example, if the player's string #w (which is the name of the
weapon currently selected by the Player) is the Bow, then the NPC will
say "You are using the Bow!". "strequals" will be discussed in
section
12.
Most Built-in strings can be edited as well. Here's a good
example
of when to do so.
Lets say you have a clothing changer, and he'll change the player's
gloves to whatever color they say (assuming its one of the colors in
the
color list). You'd do the following:
if (playerchats){
setcharprop #C0,#c;
}
"playerchats" is a built-in flag, that is true if the player is
saying
something, setcharprop is how you edit a player's strings, #C0 is the
player's
glove color, and #c is the string of what the player is currently
saying.
Putting all that information together that script means this: If
the player says anything, then the NPC will set their glove color to
what
the player is saying.
To sum up, built-in strings are used/read similarly to built-in
variables.
A list of the message codes and their meanings are found in section 13.
if (playertouchsme){
setstring OldSchool,1;
}
In this case, the string "OldSchool" will have a value of "1". And if you try to alter that:
if (washit){
setstring OldSchool,0;
}
Now the string has a value of 0. But with a few different commands: addstring, insertstring, replacestring, removestring, deletestring, you can add, subtract, replace, remove, and delete entirely new values to your already existing string. Lets look at some examples:
if (playertouchsme) addstring
MyString,touched;
if (washit) addstring MyString,hit;
if (waspelt) addstring MyString,pelt;
If you were to touch this NPC, then pelt it, then hit it MyString
would
look like this in your flag list: MyString=touched,pelt,hit
"touched", "pelt", and "hit" are all values for the list
"MyString".
And each value can be manipulated using it's index (remember all
indexes
start at 0). So using the same value for MyString lets mess
around
with it a bit:
if (playersays(Hi)) insertstring
MyString,0,hello;
if (wasshot) replacestring MyString,1,shot;
Here is the player talks to the NPC, then MyString will now read:
MyString=hello,touched,pelt,hit
since "hello" was inserted at index 0 (so it'll bump everything else
over
an index). If after that the player were to shoot the NPC,
MyString
would now read: MyString=hello,shot,pelt,hit. This is because
"shot"
is to replace the value of "MyString" at index 1.
The last two commands similarly, but work differently.
if (playersays(Bye)) removestring
MyString,hello;
if (playersays(Sorry)) deletestring MyString,2;
If the player were to say "Bye" and then "Sorry", MyString would be: MyString=touched,pelt. However, saying "Sorry" and then "Bye" would make it be: MyString=touched,hit. This is because "removestring" removes all occurences of the specified text within that string (in this case the specified text is "hello" and it only occurs once, which is at index 0), and deletestring removes the value of the string at the specified index, therefore decreasing the index of all following values of the string by one.
What is the point to all of this? Well lists basically make arrays outdated and cumbersome. At some point I wrote a script that had to use like 4 arrays, loads and loads of for loops to run through the arrays... hell the nightmares went on and on. Now that we can make lists, I wrote the same script using a single string, and depending on what info I was trying to extract from it, up to two for loops. If you would like to see how I made use of lists, check out section 14 and look for my "Projectile Tracking" function.
To be honest, for a more precise definition of an array you should probably ask a programmer. I was never taught the offical definition of what an array is. So I can only explain my personal understanding of what it is. An array is basically a variable that a NPC can read/edit with different values. I'm sure that's hard to understand so I'll elaborate. Before using an array, you have to set it. That command looks like this:
setarray arrayname,size;
For arrayname you can use anything that you would for any other variable (so you can use a "this." or you don't need to do the "this."). I'd reccomend naming it based on how you're going to use it. Now the "size" part is the amount of different values that variable can have. Lets say you did the following:
if (created){
setarray myarray,5;
}
What that will do is make 1 variable, "myarray", with 5 different
values.
Because you didn't set the values, they are all currently equal to 0
(just
like variables). You can access these different values through
the
use of indexes (a for loop could be used for the index, but its not
necessary).
To do it without a for loop it would look something like this:
myarray[0]=0; myarray[1]=0; etc through: myarray[4]=0
(because the first index is always 0, and I set the array to have 5
values).
You can manipulate these just like you would any variable. Take
the
following example:
if (created){
setarray myarray,3;
}
if (playertouchsme){
if (myarray[0]==0){
myarray[0]+=1;
}else{
myarray[0]=0;
myarray[1]+=1;
}
if (myarray[1]==2){
myarray[1]=0;
myarray[2]+=1;
}
if (myarray[2]==3){
message Yeah.;
}
}
This is probably longer than necessary for an example but it'll
work.
What this does is when the NPC is created it sets the array "myarray"
with
a size of 3. Then, if the player touches the NPC, it'll add 1 to
myarray[0]. If myarray[0] is equal to 1, then
it'll
reset myarray[0] to 0, and add 1 to myarray[1].
Once
myarray[1] has had 2 added to it, then it resets to 0, and adds
1 to myarray[2]. After touching the NPC a few more times, myarray[2]
will be equal to 3, and the NPC will say "Yeah." This of course
in
not really a practical use for arrays, but its an example of
how
to use them none the less.
Ha, I can't answer this to well. I have
only
used arrays once, and it was on my Tech Bow. In that weapon I had
to keep track of values of numerous arrows shot by the bow. I set
around 8-10 different arrays to keep track of an arrow's x,y location,
it's direction of travel, what it's currently doing, and what it's
attacking.
Since each arrow was at a different location, and possibly traveling in
a different direction, I had to have the NPC keep track of what was
where
in order to have the weapon display images properly, and hit the
correct
players and compus. But of course all of that could have been
simplified
by using putnpc. If you don't already know how to use arrays, you
probably don't need to bother with them.
Truthfully, probably the best use for arrays is
to shorten your scripts. For example, Stefan uses the following
array
in scripts that require movement similar to how a player moves.
// Graal Script
dirgo = {0,-1,-1,0,0,1,1,0};
//End
Then when where the script to move the npc is located, it looks like this:
// Graal Script
x+=dirgo[dir*2];
y+=dirgo[dir*2+1];
// End
So what this will do is, is when it comes time to move the NPC will move dirgo[dir] spaces on the x plane, and dirgo[dir*2] spaces on the y plane. So if the value of 'dir' is 1, then put 1 in place of dir and you see that it'd work like this:
//Graal Script
x+=dirgo[1*2] = -1;
y+=dirgo[1*2+1]= 0;
//End
Of course when 'dir'=1 then the npc is moving left, hence -1 on the x, and 0 on the y.
All of that is the same as doing:
//Graal Script
if (dir==0) y-=1;
if (dir==1) x-=1;
if (dir==2) y+=1;
if (dir==3) x+=1;
//End
As you can see, using arrays, although more complicated, did shorten the code.
If you have ever taken an Algebra, or Geometry class you should know how to read a cartisian plane. All the stuff in a level can be read by a set of x,y cordinates. A level is laid out in the following way: the upper left corner is the origin (0,0). To the right the x value increases, and down the y value increases. One "space", or "unit" is 16 pixels. So if a NPC moved to the right one, it would have traveled 16pixels. If it went down 1, thats another 16pixels. Up would be -16 pixels, and left is also -16 pixels.
Well this all seems logical, why should you care? Well, lets try something a little more complex.
if (playertouchsme){
if (!onwall(x,y)){
x=x+1;
}
}
Well you'd look at this and think well, with this script, the NPC can't be pushed on top of the bush because I used the onwall check. Well, actually that is not the case. The player can move this NPC 3 times. Remember the NPC is 2x2 in size, and you're only checking to see if there's a wall in the upperleft corner. So when it moves to the right one space, the NPC will be touching the bush. Then when you touch it again, it'll move ontop of the left half of the bush. Then touch it again, and it'll cover the bush. At that point, the upperleft corner will be onwall, thus it won't move again. Let's alter the script to see if we can make it not move on top of the bush.
if (playertouchsme){
if (!onwall(x+2,y)){
x=x+1;
}
}
This time, before moving, the NPC will check to see if 2 spaces to the right of the NPC is blocked; and if not, it'll move. Why 2? Well, the NPC is 2x2, so if you check 2 spaces to the right, it'll move one space forward, then next time it checks to see if there's a wall, it will look to the tile immeditaly next to it on the right; and then see it's a bush, thus causing a wall to be detected.
In the Image, you see your typical Graal Player. He has a head, and a shield, all of which are part of his 3x3 size. The gray squares (outlined by the light blue) are each 1x1 in size (so thats 16x16 pixels). Lets say in a NPC you were going to check if 1 space down from the player is onwall. Of course you could do:
if (onwall(playerx,playery+1))
But that would check to see if the middle gray square on the left side is onwall. Remember, all NPCs and Player's x,y cordinates are read at the top left. So, technically the above script would check to see if there's a wall 1 space down from the player, but if you're confronted with such a situation you'll probably want to check 1 down from the player's feet (since he's moving down. So that script would look like:
if (onwall(playerx+1,playery+3))
I added 1 to the player's x to center it on the player, and down 3
from
the player's y to see if the tile below the player is a wall.
Lets try something a little more complicated. If you have a NPC
weapon, and you want to see if it's image is about 1 space away from
the
player (so you can consider it as being "touched" by the NPC). So
how would that look?
for (i=0;i<playerscount;i++){
if
(abs ( playerx-imagex ) <=1 && abs ( playery-imagey ) <=1
){
hitplayer i,power,imagex,imagey;
}
}
Sure, the above COULD work. But that checks to see if the
top,left
corner of the image is less than or equal to 1 space away from the top
left corner of the player. If the image is 2x2 units in size...
that
is a VERY inaccurate hit detection. So lets pretend the image
being
shown is 2x2, lets try for something a little more accurate:
for (i=0;i<playerscount;i++){
if
(abs((playerx+1.5)-(imagex+1))<=1.5&&abs((playery+1.5)-(imagey+1))<=1.5){
hitplayer
i,power,imagex,imagey;
}
}
There, much better. What this does is center the x
cordinate
we're checking for the hit on both the image and the player, as well as
center the y value for both. And I changed the <=1 to <=1.5
since that is half the size of the player (so it can check 1.5 to the
left,
and 1.5 to the right of where I centered the hit detection).
Where
did I get those numbers? The player is 3x3, so 3/2 is 1.5, so I
had
to add 1.5 to the x value I checked, as well as the y value. And
the image is 2x2, 2/2 is 1, so I added 1 to the x and y values I
checked
for the image.
Sections referred to: 3,
6, 10, and 12
A recent experiment I did shows the exact locations checked to see
if
there is a wall when a player is moving. Such information would
be
particularly useful if you wanted to script a showcharacter NPC with
the
same onwall detection as a player. Here's how it works: when the
player is moving left or right, Graal has to check a range of tiles on
the y axis, but only one tile on the x axis. And when the player
is moving up or down, Graal checks a range of tiles on the x axis, but
only one on the y axis.
The following are 4 pictures, one for each direction the player can
face; followed by a description of the onwall detection.
Hopefully, with the aid of the pictures, are my descriptions, you can determine the best way to write your onwall detection scripts when using a showcharacter NPC.
Explosions are usually put using the "putexplosion2" command in which you specify a power, radius, x, and y for it. Most people don't know this, but the radius can be any whole number. Including 0, and negative numbers. Each time you add 1 to the radius (when using values greater than 0), a new "explo" is put, with a size of 32x32 pixels. Lets take a look at an explosion, with a radius of 1.
Function are defined blocks of code that can be called to do the same thing multiple times in your script. They are very useful, and can shorten your code A LOT. Sometimes, just by using functions you can cut down on the use of vars and flags, as well as prevent some glitches that happen when you use the same code in different parts of your script. The syntax to define a function looks like this:
function FunctionName(){ }
In place of "FunctionName" type in the name you want for your
function.
All the script to be called goes inside the "{ }".
Here's an example of a function:
function SpriteAssign(){
sprite=(sprite%8)+1;
}
What this will do, is assign the NPCs sprite to one of the walking sprites when this function is called. So if this is called once per timeout, the NPC will appear to be walking. To call the function, just type "FunctionName();". So to call the above one, in a timeout like I said, do this:
if (timeout){
SpriteAssign();
timeout=.05;
}
Pretty simple huh? Want to see some versatile functions I wrote? Check out my Pre-made Functions.
2.) I'd highly reccomend making
all pngs you use for your npc's
have dimensions divisible by 16.
That of course, is to make the
onwall
detection, or hit detection very easy.
3.) Always make sure you spell
your variables and flags
correctly.
When you hit the "test" button, Graal will still read the vars and
flags
and won't give you an error, even though you misspelled
something.
Here's a good way to make sure everything is spelt right: push "F6"
to open the editor. Look in the "this.vars" list as well
as
the "vars" list. If you see a variable you made appearing
more than once (but spelt slightly different) or it appears in the "this.var"
window as well as the "var" window, then you need to make that
one
variable either "this." or not.
4.) Know when to use if,
while, and for.
For and While loops cycle through at an exteremly fast rate, and can be
useful for those reasons.
5.) Sleep is a good command, but
keep in mind that nothing else
can happen to the NPC while it is sleeping.
6.) Know how to read/manipulate indexes; they ARE your friend.