Author Topic: ►Beginners' Guide to TorqueScript  (Read 3985 times)

A Beginner's Guide to Coding with TorqueScript. (A work in progress)
By Subpixel
TorqueScript is the coding language used by Blockland, along with any other game running the Torque engine, to create spectacular add-ons for the game. Almost everything made for the game uses TorqueScript, weather it's a client-sided or server-sided script, a weapon, even wrench events.

First off, i'd like to note some things. TorqueScript is a very powerful, very easy to learn language. TorqueScript is very similar to C++ or C#, but it's very unique. In this guide i'm not going to go too far into client scripting, since server scripting is a simpler learning curve in my opinion. This tutorial will help you get the gist of how things work in TorqueScript, for people who just want to learn how to make Add-Ons for Blockland.
Without further ado, these are some things you'll need to know.

Introduction
Let's package a simple server command. First off, go to your Add-ons folder and create a new folder. Now, normally an add-on would be in .zip format, but when we're just coding it, it's fine.
Name the folder accordingly. Since it's a server command, you could name it Server_MyScript, Script_MyScript, hell you could even name it Weapon_MyScript (kind of misleading). Let's just call it Server_MyScript.
Inside the Server_MyScript folder, create these files (with the correct name and extensions):
Quote from: Server_MyScript/
description.txt
namecheck.txt
server.cs

Variables
If you took math in grade four, you would know how a variable works.
For example: x + 2 = 5, you would know that x = 3.
To do that in TorqueScript, you can do something similiar to this:
Quote
%x = 3;
%MyMath = %x + 2;
echo(%MyMath);
You're probably confused right about now. Let's break down what just happened.
In TS there are two kinds of Variables: Local and Global.
A local variable is used by a single add-on in a package or a serverCmd.
A global variable can be used across multiple add-ons, and are commonly used for preferences.
If you open up your server preferences document (config/server/prefs.cs), you'd see a list of global variables.
Example: $Pref::Server::SuperAdminPassword = "";
Global variables are recognized by their '$' at the front, followed by their name. While badspot was making the game, he could have just called it $derpypasslol, but the preferences use a more organized system. So then what does this part mean?: "  = "" "
As you can see, that variable is not equal to a number. If you do $var = "test", that means $var is equal to a string. For example, if you were to do this:
Quote
echo($var);
that would print test into the console.
We'll look into preferences again later, but for now, let's have a looksee at local variables.
Local variables, unlike global ones, are located with their "%" tag, followed by the name.
Let's look again at our mathematics example:
Quote
%x = 3;
%MyMath = %x + 2;
echo(%MyMath);
"%x = 3;" tells the game that the variable %x is just the number 3 in disguise.
"%MyMath = %x + 2;" means simply this: %MyMath is the same as 3 plus 2.
Which, when we print it, "echo(%MyMath);", it prints 5 in the console because that's what the variable is.
Take another look at the echo function. echo(%MyMath);. Why wouldn't it just print "%MyMath" into the console? That's because there are no quotes around %MyMath, so it replaces it with whatever the variable actually means. If we were to do echo("%MyMath");, it would print "%MyMath" into the console.
« Last Edit: June 03, 2013, 10:40:36 PM by Subpixel »


another one? sou ka?

I think the chatbot tutorial should be refreshed

Making Chatbots


You've probably seen somebody in a server automatically say hi when somebody joins, or somebody just says "get server ip" in the chat, and they automatically talk back with their sentence being the ip of the server. You've probably wondered what that is, and I will explain to you about these mods called Chatbots, and how to make them.

Chatbots are very simple to make, we will first make a chatbot that will make you say "Hey dude!" after you say "Hi Chatbot". The easiest to way to make this is by packaging.

Packaging

Packaging is a very useful thing in Blockland. With packaging, you can re-modify / add on to existing functions without having to re-write all the previous data again. Packages are very simple and creating one starts like this:

Code: [Select]
package PACKAGENAME
{
     //code stuff here
};

You now see that creating packages are similar to creating functions in Blockland. But there are a few differences. Packages do not need () to surround the name of the package (as far as I know), all you need to do is type package  and then a space with the name of your package after it. Also at the end of the package, is required: a semi-colon. Semi-colons are always needed to end packages. They are not used for functions, only packages and other things that other people might explain.

Modifying a function

The whole reason we want to create a package, is to modify the chat function so we can make ourselves say
"Hey Dude!" after we've said "Hi Chatbot". To do this, we just define the function we want to modify in the package. What we want to modify is clientCmdChatMessage.

That function is the function that is called after we've typed all of our stuff and press ENTER. The clientCmdChatMessage function has quite a few arguments, some of which even I am not familiar with, but all you need to be familiar with is 2 arguments. Here is the function labeled below:

Code: [Select]
function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
{
      //code here
}

What we need to memorize is %name and %msg. If you already know what a variable is, then it should be obvious to you. clientCmdChatMessage is called everytime someone chats. Each variable is always changed every time someone chats. %name is the name of the user who just sent a message, and %msg is the message that they typed. To implement the function into our package, refer to the code down here:

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          //code here
    }
};

Parenting

Packages do not only exist for re-modifying functions. They also exist so that we can turn them on and off anytime we like. Packages are useful for torque programmers because whenever we wish to remodify a function, some might not use packages, and once they remodify that function, all the previous data is lost unless they enter it back in. If clientCmdChatMessage was modified without packages, then your chatting system would be broken and you would have to restart Blockland.

The code we have right now is in a package thankfully to me, and we are telling Blockland to remodify the function clientCmdChatMessage. But no, that is not all. We have not entered any code in there yet, so Blockland thinks we want clientCmdChatMessage to do practically nothing. So we have to type in a special little command that will enter all the previous data we've had. That command is called: Parent. And this is how we use it:

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          parent::clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    }
};

Using that command will re-enter all the previous data that already existed in our function back in. Now we can apply any changes to this function after the Parent command.

If Statements

If statements exist to execute code when a certain thing happens. If statements are only executed once, but now that we can remodify the clientCmdChatMessage function, any if statement in there will be checked everytime somebody chats.

So guess what we will need to put in the if statement? Come on just guess and come back when you think you've got it.


Have you got it? If not then :[. The answer is we will need our if statement to check if our player is saying "Hi Chatbot". If you've got it then high-five. Unfortunately, we cannot just enter it in like that on our code, we need to enter it in by Torque's laws of syntax.

A way to use if statements to see if the player is saying "Hi Chatbot", is by this:

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          parent::clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
          if(%msg $= "Hey Chatbot!")
          {
                 //code here
          }
    }
};

Much is to be explained here. Every if statement needs an operator of some sort. the operator I used was $=. I will present a list of operators below, and what they do:

  • == if Value Variable is equal to
  • != if Value Variable is NOT equal to
  • $= if String Variable is equal to
  • && Used to connect 2 operators together. The if statement will run if both of them return true
  • || Used to connect 2 operators together. The if statement will run if 1 or the other returns true

There are probably more operators out there but i'm tired so I'll stop it here for tonight.

The reason I used $= in our code, is because %msg always returns a string, and $= is used for connecting strings. Only use == when you are connecting values.

So basically, when Blockland looks over the code, it sees our package, then makes our package, then it sees that we want to re-define the function clientCmdChatMessage, so it does that for us, and then it sees the parent command, so we just told it to write in all the previous data that was in it before we defined it, then it sees the if statement, and understands to execute any code when a message that any player sent is equal to "Hey Chatbot!".

Don't you feel pretty accomplished for getting this far? So do I. But there is 1 slight problem. If a message that ANY player sent is equal to "Hey Chatbot!". We probably don't want that, and we only want the if statement to run if WE said that line. So all we need to do is add in another operator in our if statement and add a little command:

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          parent::clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
          if(%msg $= "Hey Chatbot!" && %name $= $Pref::Player::Netname)
          {
                 //code here
          }
    }
};

As explained before, the && is used to connect 2 operators. So when the console looks at the if statement, it will check if the message that a player sent is equal to "Hey Chatbot", and it will check to see if the name of the player who sent that message is also equal to the name of $Pref::Player::Netname. $Pref::Player::Netname is the same as the username you set on Blockland when you first registered. Everytime you change your username, $Pref::Player::Netname is changed with it also.

Making our player talk

Yes, not much more to do now! All we need to do now is call a function to make a player talk! As you've (hopefully), read in Pacnet's tutorial, we need to send a message to the server to make us talk. Here is the command we need to send:

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          parent::clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
          if(%msg $= "Hey Chatbot!" && %name $= $Pref::Player::Netname)
          {
                 commandToServer('messageSent',"Hey dude!");
          }
    }
};

And yes, that is basically it. messageSent is a command we have to put in commandToServer to tell the server we want our player to talk. So basically, all you have to do is execute this little code through the means of a small script, or a plain add-on, and then, most importantly, you must type in the console:

Code: [Select]
activatePackage(packagename);
deactivatePackage(packagename);

ActivatePackage turns your mod on, like i've said before: Packages can be enabled or disabled. DeactivatePackage turns your mod off, so the command wont work anymore.


Up next: Advanced Chatbot Tutorial

Advanced Chatbot Tutorial


So making your chatbot say something when you say a specific thing wasn't enough for you? Well, don't worry my friend! I will hope that you have read my previous Chatbot tutorial and hope you are ready for this new challenge.

I will explain before-hand what we will be covering in our tutorial. A chatbot that just says something is highly boring, to you, and to me. We need our chatbot to actually be useful for something. And for our chatbots to be useful, we will need to use input.

Input

Input is a very special thing. Input is like taking things that the user (you) enters. If you've previously read ¥ola's tutorial, then you would understand that input can be used for many things. Input is used in a function to make functions useful for working. Functions with input take the input you entered, and work some things with the input you've entered. After it's done, it usually returns a different value or string, or something different.

Input can also be used in chatbots. Which is why, today we will be making a chatbot that takes 2 numbers we've entered, and add them both, and repeat the answer back in our chat! Sounds pretty cool right? First we will need to write down a default code template for our chatbot:

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          parent::clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    }
};

Then we will add an if statement. But in this if statement, we can't just use "%msg $=". Since we are going to make our chatbot receive input from the user, we are going to have to be a little more advanced here.

getWord() Function

getWord() is a special function, as this pre-defined function has 2 arguments: the source, and the word number. The source is like the word we want the function to examine. Lets say we want our function to examine: "Hello World". For that, we would define the following string:

Code: [Select]
%word = "Hello World!";
Then we add in a getWord function

Code: [Select]
%word = "Hello World!";
getWord(%word,0);

Hm, weird. There is a second argument in the getWord function. That is the word number. The word number is typically the number of the word we want to return. if we said "getWord(%word,0);", it would return the "Hello" part of %word. That is because the word number always starts at 0, being the first word in the string/value. Saying "getWord(%word,1);", would return "World!". Why did it put the "!" you ask? Well that's because words in the getWord() function are generally scanned when they are spaced out by spaces.

Creating our Advanced Chatbot

Now that we have an OK idea on what getWord() is, we can implement it into our chatbot. We want our Chatbot to add 2 numbers from input after we've said "add (NUMBER1) and (NUMBER2)". To do that, we must first use getWord() to check if the first word we've said in our message is, "add":

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          parent::clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
          if(getWord(%msg,0) $= "add")
          {
               //code here
          }
    }
};

The current cake we have now is saying, if the first word in our message is "add", execute the code below. We also need to see if the THIRD word in our sentence is "and". We don't really have a way to check for input now. We will check for input later, but now, lets focus on the exact words. Add this:

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          parent::clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
          if(getWord(%msg,0) $= "add" && getWord(%msg,2) $= "and")
          {
               //code here
          }
    }
};

If we used "getWord(%msg,1)" in our sentence, it would check for the 2nd word. We are saving the second word for our input, and the fourth word for our input also.

Now that we have all the data in our if statement, we can move on to the easy part. We are going to set 3 variables. The first two variables will be our input variables, because with variables, we can use getWord() in them to receive input from our message. Add this:

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          parent::clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
          if(getWord(%msg,0) $= "add" && getWord(%msg,2) $= "and")
          {
               %number1 = getWord(%msg,1);
               %number2 = getWord(%msg,3);
          }
    }
};

Yes, we are getting closer to the end. %number1 is now defined as the 2nd word in our message, and %number is defined as the 4th. Also, remember getWord() always starts at 0, 0 being the first word in the sentence. It's something with the engine, don't ask me :/.

Now we will create a variable that is the total of adding both of those variables together. Very simple:

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          parent::clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
          if(getWord(%msg,0) $= "add" && getWord(%msg,2) $= "and")
          {
               %number1 = getWord(%msg,1);
               %number2 = getWord(%msg,3);
               %total = %number1 + %number2;
          }
    }
};

%total is now the added total of %number1 and %number2. Now that we have a variable, everything else can be so simple. All we have to do is call a command to the server to make us say that variable. Also, a thing to remember. If you want to display variables in a string, then you have 2 ways: If you are trying to say just a variable and only a variable: use this:

Code: [Select]
commandToServer('messageSent',%total);
Otherwise, if you wish to display some words in your text, you can switch between displaying variable mode and string mode by using "@ to enter variable mode, and @" to exit back into word mode. An example below is this:

Code: [Select]
commandToServer('messageSent',"Your answer is "@%total@"");
If the variable %total is defined, It will make your character say:

"Your answer is (totalhere)"

So, you can just add any of those at the bottom of where we defined the %total, and it will work successfully. I personally am going to go with the other version, where it displays string. I just like it because it looks more advanced. This is our final code:

Code: [Select]
package Chatbot
{
    function clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
    {
          parent::clientCmdChatMessage(%a, %b, %c, %fmsg, %cp, %name, %cs, %msg)
          if(getWord(%msg,0) $= "add" && getWord(%msg,2) $= "and")
          {
               %number1 = getWord(%msg,1);
               %number2 = getWord(%msg,3);
               %total = %number1 + %number2;
               commandToServer('messageSent',"Your answer is "@%total@"");
          }
    }
};

Well, that's the end of our chatbot. That was really simple, right? Yes, hopefully. Now that you now how to receive input from a chatbot, you can make a chatbot that does games, such as "Guess The Number" games, or to make a chatbot subtract, MULTIPLY, or even DIVIDE your inputs! Yes, with chatbots, you can do so many things..

Up next, Creating a Chatbot Game which will never happen haha

A local variable is used by a single add-on in a package or a serverCmd.
Kono yarou, rephrase that please.

Uh, i never really finished this up but i'll post it anyways, i guess. tsforblockland.weebly.com

I seriously think every tutorial that has to do with Blockland torque is terrible.

None of them explain what a function does, or what arguments are, people just explain how you need this or that, at least explain why.

hopefully this one can.

Uh, i never really finished this up but i'll post it anyways, i guess. tsforblockland.weebly.com
The guide looks great. But I think "class = myObjectClass;" needs to look like "class = "myObjectClass";"

The guide looks great. But I think "class = myObjectClass;" needs to look like "class = "myObjectClass";"

That is not necessary at all.
To demonstrate how little TorqueScript cares, you can also do this:

"MissionCleanup".setName( "Not The MissionCleanup" );
"Not The MissionCleanup".delete();

I was not aware of that. TorqueScript really sounds like a lazy person.

Add more, pwease. :(

I'd say a lot of new scripters want to learn how to make server commands..


Client and Server Commands
Have you ever used commands such as, for example, "/buyDirt 50 500" etc.? Have you wondered how to make "slash commands"?
Before you can learn that, let us recap and discuss what a client and a server is. In Blockland, when someone is hosting a server, the Blockland server running on their computer is the Server. When you join his game, you connect to that server and you are the Client. The client in Blockland does not host the server, but joins a game.

Outside of Blockland, the Server is basically the computer hosting a database, game room, chat server such as Mumble or TeamSpeak, and can be used when multiple computers need to share information. The computers that access the database, join the game room, chat on the chat room, access files from the server are the Clients.

You may have to read this a few times to see what's going on, but if you understand, read on. Now that you know what a Client and a Server is, we can begin.
Let's put this into Blockland perspective. Everytime you chat in a server, CTRL + K, build, fire a weapon, etc. you are communicating with the server.

Communicating Client To Server

When you want to communicate with the server as a Client, you use this command in your script :
commandToServer();

Here's and example of it :

Code: [Select]
commandToServer('kill', %target);

"What is that?" you say? Let me break it down :
-commandToServer(); - This is a function (as you have learned earlier), that communicates with the server.
-'kill' - In these single quotes, I am saying that the command I want to perform is "kill".
-%target - You've learned already that this is a local variable, only usable by the function that it is in. You can think of it as I'm providing the server with extra details on my command. In this case, if I wanted my command to kill someone in the server, logically I would have to explain who should be killed, so I would want to add a variable such as %target in there.

So let's say I made this function :

Code: [Select]
function byebye(%target)
{
   commandToServer('kill', %target);
}

Now if I typed byebye("James"); in my script, it would tell the server to "kill" James.

That's basically how you communicate to the server as a client.

Receiving A Server Command
You know what? If a client uses commandToServer('kill', "fredrick55"); , then the server running default Blockland will probably not at all understand what to do. That's because you have to specify what the server has to do when someone tells it a command.

As the server-side, you must declare a function like this to handle things like that :
Code: [Select]
function serverCmdkill(%client, %target)
{
   findclientbyname(%target).player.kill();
}

In this example, findclientbyname(%target).player.kill(); is not terribly important for learning uses, but I'll break down the rest of it :

function / () / { } - You should be familiar with this, if not, read Functions above.

serverCmd - Alright, so server commands are a special type of function you can declare. If you want the server to respond to "/dig", you would use function serverCmdDig(). If you wanted the server to respond to "/buy", you would use function serverCmdBuy(). The simple idea is to keep "serverCmd" before the name of your command.

%client - Whenever you code what the server should do when it receives a certain command, you should always keep "%client" as the first argument after the first ( in the set of parentheses. The %client is a local variable you can use in the function which is basically the person who commanded the server to do something. %client is the client object but NOT the player.

%target - I skipped a comma, but whenever you have multiple arguments in a function, you insert a comma between them. Anyway, %target is an extra variable I'm using since logically I need to specify who should be killed.

When you type something like /kill Blake1, whatever spaces you type and whatever you type after a space is a new argument.

Using /kill Blake1 50 No (Let's just say the %target, %score [that i get], %displayKillMessage for example) I would be sending "kill" to the server with three arguments.

You now know how to make a client communicate with the server and specify how the server receives it.


Let's put your client / server command knowledge together so far :

Say this is my client side script :

Code: [Select]
function goodbye(%target)
{
   commandToServer('kill', %target);
}

Now say this is my server side script :

Code: [Select]
function serverCmdkill(%client, %target)
{
   if(%client.isAdmin) //By the way, these two slashes I put here are comments. Comments don't affect the script at all. This checks if the client is an admin.
   {
      findclientbyname(%target).player.kill();
   }
}

Now on the server, if I am an admin and there is a player on it called "BasonMason"..

Doing EITHER
Code: [Select]
commandToServer('kill', "BasonMason");

OR

Typing /kill BasonMason

Will do the same thing. That's right, typing a /slash command in your chat uses commandToServer(). They do the same thing.


Server to Client Commands
Alright, here I am, I'm the big old server and I want to tell the client to 'spinAround'.

So if client -> server is "commandToServer();", can you guess what server -> client is?

It's the function "commandToClient();", and it works in a similar way! Let's say I'm the server side in this script :
Code: [Select]
$Client = findclientbyname("Pacnet2013");
commandToClient($Client, 'spin');

The first argument you use in commandToClient is always the client object itself, most commonly named inside a function as "%client".
I then use the single quotes after that, simply to specify the command I want that client to perform.


Receiving a Command from the Server as a Client
Above, I used commandtoclient($client, 'spin', 1); as an example.
My client usually won't know what the heck the server wants it to do, so you also have to declare what happens in a client command declaration. It's very similar to serverCmd declarations.
This is my client side :

Code: [Select]
function clientCmdspin(%onOroff)
{
   turnleft(%onOroff); //Just a function that makes you turn around fast.
}

My argument is either 1 or 0 declared by the server, to spin or to stop spinning.


You should now know how to use client to server and server to client commands. They are a key part of Blockland. Good luck!