Author Topic: Blockland Functions + Other TorqueScript Help  (Read 3778 times)

Hello everyone. I have been trying to get into modding for Blockland lately, but I've been running into some problems. First off, some background knowledge, I am not new to programming, I have experience in Java and JavaScript (more so on Java), but not C++ or TorqueScript.

Anyways, the first major problem I ran into was getting access to all the functions that are available in the Blockland code. I was able to find an API at http://bldocs.nullable.se/html/index.html, but the problem with it is there are no explanations on what the functions do and what the parameters are/are used for for almost all of the functions listed there. I was wondering if anyone had access to a more specified and detailed API Documentation for Blockland functions, that would help me out tremendously.

Another semi-large problem I ran into, not as big as the previous one, was access to already specified names of certain variables. For example, as I was looking at some of the code for some Add-Ons, I saw references to variables such as %client that seemed to come out of nowhere. If anyone could help to explain some of these key variables to me then that would be tremendously helpful.

Thank you in advance for taking your time to help me out!

Hey there! For the variables, just post some code that's confusing you and we can explain it.

For functions, you can call dumpConsoleFunctions(); in console and it will list functions with a short description. You can also call the dump() method on any object to get a listing of its methods and fields: %obj.dump();
« Last Edit: March 20, 2015, 02:15:58 PM by Greek2me »

Another semi-large problem I ran into, not as big as the previous one, was access to already specified names of certain variables. For example, as I was looking at some of the code for some Add-Ons, I saw references to variables such as %client that seemed to come out of nowhere. If anyone could help to explain some of these key variables to me then that would be tremendously helpful.
Local variables(%) do not exist unless specified in the function.

Local variables(%) do not exist unless specified in the function.

That's what I thought, which is why I'm so confused. Here's a bit of code taken from the quests.cs file in the Server_TotalRPG mod made by Pecon7 (this function is called by an event in-game).

function fxDtsBrick::questStart(%this, %name, %description, %client)
{
   %questName = safeQuestName(%name);

   if(%client.questStarted(%questName))
   {
      %client.chatMessaage("\c6You have already started this quest! Do /quests");
      return;
   }

   $InputTarget_["Self"]   = %this;
   $InputTarget_["Player"] = %client.player;
   $InputTarget_["Client"] = %client;

   if($Server::LAN)
   {
      $InputTarget_["MiniGame"] = getMiniGameFromObject(%client);
   }
   else
   {
      if(getMiniGameFromObject(%this) == getMiniGameFromObject(%client))
         $InputTarget_["MiniGame"] = getMiniGameFromObject(%this);
      else
         $InputTarget_["MiniGame"] = 0;
   }

   %quest = new scriptObject(questObjectClass)
   {
      started = true;
      finished = false;
      name = %questName;
      displayName = %name;
      description = %description;
      chapter["START"] = "true" TAB %description;
      chapters = "START";
      currentChapter = "START";
   };

   %client.quest[%questName] = %quest;
   %client.quests = %client.quests TAB %questName;
   %client.numQuests++;

   %client.chatMessage("\c6You've started a new quest! Quest log has been updated. Do /quests for more information.");
}

What I don't understand about how this works is how is the function able to call functions and variables from the %client variable when it's only a local variable? And how is the game able to process and understand %client as the player's client?
This also brings up another question I had, which is does it matter what order you put the function parameters? In other words, could the declaration of this function be rewritten as function fxDtsBrick::questStart(%client, %this, %name, %description) or something along those lines?

%client in that case is a GameConnection object. Objects can be passed to functions just like any other values. So while %client is a local variable, the object it's referencing is in a different scope.

Yep, the order of the parameters matters. In your example, if you placed %description where %client was, %description would have the value that should've been assigned to %client.

Anyways, the first major problem I ran into was getting access to all the functions that are available in the Blockland code. I was able to find an API at http://bldocs.nullable.se/html/index.html, but the problem with it is there are no explanations on what the functions do and what the parameters are/are used for for almost all of the functions listed there. I was wondering if anyone had access to a more specified and detailed API Documentation for Blockland functions, that would help me out tremendously.
Yeah arguments of functions are often on us to figure out. Sometimes you'll get lucky and an engine function will be properly documented, but most of the ones Badspot writes aren't, and functions written in script never are. One of the usual methods would be trace(1); in the console, which causes function calls to be displayed with all the arguments until you use trace(0);, so you enable it, trigger the function you want to look at through normal means, disable it, and look through the output. The other way would be to find another add-on that does what you want to do and go read its code as an example. Some other tools worth knowing about are object.dump(); which show all the object's methods and variables, tree(); which opens a window that will allow you to explore all currently existing objects, and the ability to type in part of a function name to the console and hit tab to find functions beginning with that fragment.

Another semi-large problem I ran into, not as big as the previous one, was access to already specified names of certain variables. For example, as I was looking at some of the code for some Add-Ons, I saw references to variables such as %client that seemed to come out of nowhere. If anyone could help to explain some of these key variables to me then that would be tremendously helpful.
Not sure how much you know about variables in torque already, but since you have experience with other languages, here's an overview that may help:

In Torque, you don't need to declare or cast variable names ahead of time. Just set it to something and you're good. All variables function as the same type, so you can write "200.03" as a string then increment it as if it were a float, then concatenate the word "horse" to the end as if it were a string again. If you tried to increment it again, however, it'd go from "201.03horse" to "1", since strings that don't parse as numbers are interpreted as 0. Objects work under the same system, and are stored as ID numbers, so your player object when you spawn has a numerical ID, and YourClient.player will be set to that ID. You call methods on an object by doing 12345.doTheThing(); or %thing.doTheThing(); where 12345 and %thing are respectively the ID of the object, and a variable set to that ID. Objects can also have names and you can use those kinda interchangeably with the ID, though with exceptions. You can see that by starting a server and entering localclientconnection.dump();

The client variable is passed to the function through the fourth argument of fxDTSBrick::questStart.

In C++ this function would look more like this:

Code: [Select]
std::map<const char*, SimObject*> InputTarget_;
void fxDTSBrick::questStart(brick *this, string *name, string *description, GameConnection *client) {
    string *questName = safeQuestName(name);

    if(client->questStarted(questName))
    {
        client->chatMessage("\c6You have already started this quest! Do /quests");
        return;
    }

    InputTarget_["Self"] = (SimObject *)this;
    InputTarget_["Player"] = (SimObject *)client.player;
    InputTarget_["Client"] = (SimObject *)client;

    if(Server::LAN)
        InputTarget_["MiniGame"] = (SimObject *)getMiniGameFromObject(client);
    else
    {
        if(getMiniGameFromObject(this) == getMiniGameFromObject(client))
            InputTarget_["MiniGame"] = (SimObject *)getMiniGameFromObject(client);
        else
            InputTarget_["MiniGame"] = (SimObject *)NULL;
    }

    ScriptObject *quest = new ScriptObject;
    quest->started = true;
    quest->finished = false;
    quest->name = questName;
    quest->displayName = name;
    quest->description = description;
    quest->chapter["START"] = new string(string("true\t") + description);
    quest->chapters = new string("START");
    quest->currentChapter = quest.chapters;
    quest->setName(new string("questObjectClass"));

    client->quest[questName] = quest;
    client->quests = client.quests + string('\t') + questName;
    client->numQuests++;

    client->chatMessage("\c6You've started a new quest! Quest log has been updated. Do /quests for more information.");
}
« Last Edit: March 20, 2015, 04:21:21 PM by $trinick »

%client in that case is a GameConnection object. Objects can be passed to functions just like any other values. So while %client is a local variable, the object it's referencing is in a different scope.
How do you know when something like that is a GameConnection object or some other class? Is that the kind of information that is available with the dump() functions you mentioned earlier, or is %client always referring to a GameConnection object?

Yep, the order of the parameters matters. In your example, if you placed %description where %client was, %description would have the value that should've been assigned to %client.
What confuses me about this is in the above example, the coder was establishing a new function. Doesn't that mean he can list the parameters in any order he wants, so long as the function is called with those parameters in that order? Or is there a set order that must be followed?

In C++ this function would look more like this:

Code: [Select]
std::map<const char*, SimObject*> InputTarget_;
void fxDTSBrick::questStart(brick *this, string *name, string *description, GameConnection *client) {
    string *questName = safeQuestName(name);

    if(client->questStarted(questName))
    {
        client->chatMessage("\c6You have already started this quest! Do /quests");
        return;
    }

    InputTarget_["Self"] = (SimObject *)this;
    InputTarget_["Player"] = (SimObject *)client.player;
    InputTarget_["Client"] = (SimObject *)client;

    if(Server::LAN)
        InputTarget_["MiniGame"] = (SimObject *)getMiniGameFromObject(client);
    else
    {
        if(getMiniGameFromObject(this) == getMiniGameFromObject(client))
            InputTarget_["MiniGame"] = (SimObject *)getMiniGameFromObject(client);
        else
            InputTarget_["MiniGame"] = (SimObject *)NULL;
    }

    ScriptObject *quest = new ScriptObject;
    quest->started = true;
    quest->finished = false;
    quest->name = questName;
    quest->displayName = name;
    quest->description = description;
    quest->chapter["START"] = new string(string("true\t") + description);
    quest->chapters = new string("START");
    quest->currentChapter = quest.chapters;
    quest->setName(new string("questObjectClass"));

    client->quest[questName] = quest;
    client->quests = client.quests + string('\t') + questName;
    client->numQuests++;

    client->chatMessage("\c6You've started a new quest! Quest log has been updated. Do /quests for more information.");
}

This might be a lot to ask and possibly not be able to be done, but is it possible to translate this into Java? I'm a lot more familiar with Java than I am with C++.

How do you know when something like that is a GameConnection object or some other class? Is that the kind of information that is available with the dump() functions you mentioned earlier
Indeed it is. If you were to run %client.dump(); inside that function, the information would tell you the class name and info.

is %client always referring to a GameConnection object?
%client is simply the variable name. You could (theoretically) use %client to refer to a brick, but that would be counter-intuitive. %client almost always intentionally refers to a GameConnection object.

What confuses me about this is in the above example, the coder was establishing a new function. Doesn't that mean he can list the parameters in any order he wants, so long as the function is called with those parameters in that order? Or is there a set order that must be followed?
He can list them in any order he wants, but he has to call the function with them in the listed order as Greek2me said. If he were to mix them up after defining the function, the variables would all hold the wrong info.

This might be a lot to ask and possibly not be able to be done, but is it possible to translate this into Java? I'm a lot more familiar with Java than I am with C++.
*sigh* Someone else will have to do that for you, I haven't used Java since high school AP Computer Science and never intend to use it again in the future.

If you're wondering where the order of the parameters comes from, I think this is the piece you're missing:
Code: [Select]
registerOutputEvent(fxDtsBrick, "questStart", "string 50 80 string 200 250", true);The first parameter on all methods is %this, and is the object you're calling the method on. You can call it whatever you want, %a1, %this, %object, whatever, but the first parameter to a method is the thing the method is called on. The event registration dictates the next two parameters, note the "string 50 80   string 200 250" in there. The event system wires up the boxes in the UI to the corresponding arguments, so the first box maps to the second argument and the second box maps to the third. Additional arguments would correspond in a similar function. Then the last parameter, %client, is something provided by the events system. That last argument in the registration, true, basically means "if this is set to true, then it will append the client who triggered this event to the end of the parameters when calling the method." Thus, the last argument is %client because that's where the client will be passed in. The names of all these parameters are irrelevant; the first one is the object, the following ones map to the event parameters, and the last one is the client.

If you're wondering where the order of the parameters comes from, I think this is the piece you're missing:
Code: [Select]
registerOutputEvent(fxDtsBrick, "questStart", "string 50 80 string 200 250", true);The first parameter on all methods is %this, and is the object you're calling the method on. You can call it whatever you want, %a1, %this, %object, whatever, but the first parameter to a method is the thing the method is called on. The event registration dictates the next two parameters, note the "string 50 80   string 200 250" in there. The event system wires up the boxes in the UI to the corresponding arguments, so the first box maps to the second argument and the second box maps to the third. Additional arguments would correspond in a similar function. Then the last parameter, %client, is something provided by the events system. That last argument in the registration, true, basically means "if this is set to true, then it will append the client who triggered this event to the end of the parameters when calling the method." Thus, the last argument is %client because that's where the client will be passed in. The names of all these parameters are irrelevant; the first one is the object, the following ones map to the event parameters, and the last one is the client.

That makes a lot more sense now, thank you so much!
That function, registerOutputEvent(), looks like I would be using it a lot, as well as registerInputEvent(), since I will probably be making add-ons related to events most frequently. Could you tell me more about the other possibilities of the parameters for both of those functions, so I know what my possibilities are?

...functions written in script never are [properly documented].

I dunno, I think doNothing() { } documents itself.

That makes a lot more sense now, thank you so much!
That function, registerOutputEvent(), looks like I would be using it a lot, as well as registerInputEvent(), since I will probably be making add-ons related to events most frequently. Could you tell me more about the other possibilities of the parameters for both of those functions, so I know what my possibilities are?
http://forum.blockland.us/index.php?topic=40631.0

I dunno, I think doNothing() { } documents itself.
Such a function does not exist in my installation.

Also, no, it does not document itself.
There's no reason to make a function that actually does nothing. It just takes up space. So either the person had no idea what they're doing, or it does do something (potential example: making an object specific to that add-on halt [do nothing] for a period of time) albeit with a bad name