Unofficial Tribes 2 Coding FAQ
Unofficial Tribes 2 Coding FAQ
Table of Contents
Basics
What do I need to get started?
Where are the scripting files?
What are the *.dso files in the directories with my scripts?
What language are the scripts written in?
How do I test my modifications?
How do I get a log of any errors my modifications generate?
Coding Structure
What are all the semicolons for?
What are the \$ and % symbols in the scripts?
What is the syntax for switch and switch\$ statments?
What is the syntax for if statments?
How does the ?: conditional operator work?
How does string concantenation work?
How do I write a simple function?
How do you write a datablock function?
How does datablock inheritance work?
What does the Parent keyword do?
What are packages and how do I use them?
Coding Specifics
Which projectiles are fired by which gun?
Which vehicles are derived from which datablocks?
How can I make different armour classes use different beacons?
How do I make INSERT OBJECT NAME cloak?
How do I add items or take away items from a player's inventory?
How do I add a new deployable?
How do I change the sound of INSERT ANYTHING?
How do I get characters or words from a string? (UPDATED)
Mini-HOWTO: Vectors (NEW)
Sources & Links
What does the INSERT FUNCTION NAME function do?
Where can I go to talk with other coders about Tribes 2 scripting?
Where can I get general Tribes2 questions answered?
Where can I learn about using the map editor?
LEGAL BS - This FAQ comes with no garuntees on the accuracy of the informaiton provided. We are not to be held accountable if information found here causes your Tribes 2 version to become corrupt, your computer catches fire or your dog catches a rare twitching illness, etc. etc.
Basics
What do I need to get started?
Obviously, you need a working copy of Tribes 2. If you have been messing with your script files in the base directory you should reinstall and apply the latest patch. Make sure you patch your game BEFORE you start editing. You need a zip program like WinZip (www.winzip.com) to extract the scripts. Also, you need a good plain text editor with search and replace features. The ability to search through multiple files at once will save you tons of time. Personally, I use EditPlus 2 (www.editplus.com). Others have suggested UltraEdit32 (www.ultraedit.com) and Microsoft Visual Studio. David Dunscombe is working on a Tribes2 Code IDE. Beta versions can be found at http://tribes.barrysworld.net/ide/.
Where are the scripting files?
The scripts are located inside the scripts.vl2 file in your \Tribes2GameData.ase directory. All *.vl2 files are actually regular zip files with a renamed extension. You can use WinZip to open them. To get started, make a directory called whatever you want your mod to be names in your \Tribes2GameData directory. I will call the directory MyMod for the purpose of this FAQ. Now extract the scripts.vl2 file into the \Tribes2GameDataMyMod directory. Now your ready to get started.
Note: I recommend that beggingin coders have two mod directories, one to serve as a test bed for modifications, and another with finalized code.
What are the *.dso files in the directories with my scripts?
A *.dso file is the compiled version of the corresponding *.cs file. If you want to distribute modifications without showing people your code, you can distribute the .dso file instead of the .cs file. Rumor has it that Dynamix will be switching to a one .dso file system for easier distribution. But, of course, in the interest of learning I suggest that we make our *.cs code available.
What language are the scripts written in?
The scripts are not written in any existing programming language. They are written in a scripting language created by Dynamix (the developers). Therefore, there are no books you can buy to learn more about this specific language. The language does have a syntax that roughly resembles C, so if you learn more C you should have an easier time editing the scripts.
How do I test my modifications?
Create a shortcut to the Tribes2.exe file located in your \Tribes2GameData directory and place it wherever you want. Right-click on the shortcut and go to "Properties". Edit the "Target" line so that it has "-nologin -mod MyMod" at the end. Replace MyMod with the name of the directory you created in \Tribes2GameData. My target line looks like this (I put my scripts in a directory called "Bryan"):
C:\DynamixTribes2GameDataTribes2.exe -nologin -mod Bryan
Now double-click the shortcut and the game will run using your mod.
How do I get a log of any errors my modifications generate?
You have to edit your console_start.cs file in your \Tribes2GameData directory to enable logging. Goto around line 135 and find the part that says:
else if ( \$arg $= "-mod" && $hasNextArg ) { setModPaths( \$nextArg ); \$i += 2; }
All you have to do is add a line after \$i += 2; that says:
setLogMode(1);
Any messages will be outputted to consolelog.cs in your \Tribes2GameData directory. You can safely leave this file modified and it shouldn't heart anything.
Coding Structure
What are datablocks?
The Tribes 2 scripting language stores information in datablocks. Datablocks are used to describe everything from weapons to vehicles to sounds to particles to weather etc. etc. etc. Datablocks use C style brackets ( { and } )to enclose their data. In every datablock you will see a bunch of lines that look like this:
Property = Blah;
Each of those properties is used by the game engine to determine how that entity acts.
For example, in disc.cs the \Tribes2GameDataMyModweapons directory, examine the line:
shapeFile = "weapon_disc.dts";
This tells the game engine that the model of the disc launcher is weapon_disc.dts. Changing this to something like "weapon_chaingun.dts" would make the disc launcher look like a chaingun in the game, but it would still act like a disc launcher in every other way.
Datablocks all have a class and a name. Here is a sample of normal datablock syntax:
datablock ClassName(DatablockName) { };
If a datablock is inherited from another datablock the format changes to:
datablock ClassName(DatablockName) : ParentDatablockName { };
What are all the semicolons for?
Much like the C or C++ programming languages, the Tribes 2 scripting language requires that all commands end with a semicolon. The syntax is:
statement;
Forgetting a semicolon is probably the most common cause of errors in a newbie's script.
How do I declare a variable?
You are not required to declare variables in the Tribes 2 scripting language before you use them. You can start assigning them values.
What are the \$ and % symbols in the scripts?
When a percent sign (%) is used before a variable name, the variable is defined or accessed locally (exists only in that function). When a variable name is preceded by a dollar sign (\$), the variable is defined or accessed globally (visible to all functions). If anyone has further information on how these work, please let me know.
Thanks to Robert Tockley for confirmation of this info.
What is the syntax for switch and switch\$ statements?
Tribes2 switch statements act much like C switch statements except for one major difference. Since the Tribes2 scripting language does not have variable types, you must use switch to compare numerical data and switch\$ to compare strings. They are the switch equivalents of == and $= (see below). Here are some samples I pulled from various *.cs files:
From ChatGui.cs, this handles IRC commands: switch\$(%command) { case "PING": IRCClient::onPing(%prefix,%params); case "PONG": IRCClient::onPong(%prefix,%params); // Removed other cases for length default: return false; } From LaunchLanGui.cs this handles the Launch menu: switch(%id) { case 0: LaunchGame(); case 1: // Start Training Mission LaunchTraining(); case 2: LaunchNews(); // Removed other cases for length case 12: LaunchCredits(); }
What is the syntax for if statements?
If statments use the same syntax as the C programming language. A few samples are below:
if (myvar == 3) echo( "Myvar is 3." ); if (name \$= "Bob" || name $= "Joe") { echo( "Your name is either Joe or Bob." ); } if (name \$= "Fred") { echo( "Hi, Fred!" '); } else { echo( "Hey!! Your not Fred!" ); }
Check below for a list of operators you can use in an if statement (comparison operators).
What operators are available?
The following operators are available in the Tribes 2 scripting language:
= Assignment operator ?: Conditional operator Numeric Assignment Operators += Addition assignment operator -= Subtraction assignment operator *= Multiplication assignment operator /= Division assignment operator (Untested) ++ Increment operator -- Decrement operator String Assignment Operators @ Concatenation operator Numeric Comparison Operators == Equal to != Not equal to > Greater than < Less than >= Greater or equal to <= Less or equal to String Comparison Operators \$= Equal to !\$= Not equal to Logical Operators && Logical AND operator || Logical OR operator ! Logical negation operator
How does the ?: conditional operator work?
Exactly like it does in C (getting tired of hearing that?). Here is the syntax:
testExpr ? trueExpr : falseExpr
Here is an easy example to get you started:
3 < 2 ? "Shazbot!" : "Of course!! 3 is NOT less than 2"
How does string concatenation work?
Concatenation is just a big fancy l33t programmer's word for combining strings together. In the Tribes2 scripting languages, this is done with @. Here are some examples:
"Hello" @ " " @ "World" turns into "Hello World"
"Shaz" @ "bot" @ "!" turns into "Shazbot!"
%name @ " is l33t." turns into "ZOD is l33t." (Assuming %name = "ZOD")
How do I write a simple function?
In the scripting language, functions use the following syntax:
function MyFunction(%arg1, %arg2) { // Do Some Stuff }
Pretty easy, eh?
How do you write a datablock function?
This is most easily illustrated as an example, so here is a simple one:
datablock MyDatablock { mass = 1; // Many property definitions would follow } MyDatablock::MyFunction(%obj, %arg) { echo( "You passed me: ", %arg ); }
The arguments need a bit of explaining. When you call a datablock's function with the dot operator, the datablock is automatically sent to the function as the first argument. In this example, within the MyFunction function, the variable %obj would reference a datablock. For this reason, it is common practice to declare datablock functions with the first variable as %obj.
How does datablock inheritance work?
Note: When talking about inheritance, the item that is inherited from is called the parent and the item that is doing the inheriting is called the child.
When one datablock is derived from another datablock, it inherits all properties and functions from its parent. This means that if you derive a new datablock from an old one and don't override any values in the new datablock, the datablocks will be exactly the same. In reality, when you derive a new datablock from the parent, you will want to override some properties or functions. In the case of properties, you do this by simply placing lines inside the new datablock's braces that define the new data. In the case of functions you declare them exactly as if the new datablock was like any other datablock. Remember, when you derive a datablock from the parent, nothing about the parent changes in any way.
What does the Parent keyword do?
When dealing with a child datablock, you can use the Parent keyword to call a function of the datablock's parent from within the child's code. In the following example, ShapeBaseData is a child of GameBaseData:
function GameBaseData::foo() { echo("GameBase foo"); } function ShapeBaseData::foo() { echo("ShapeBase foo"); Parent::foo(); }
Then, using the foo() function of a GameBaseData object would echo:
GameBase foo
While using the foo function of a ShapeBaseData object would echo:
GameBase foo
ShapeBase foo
How do I comment my scripts?
Anything after a "//" on a line is a comment and is ignored by the game. Simply place a "//" at the start of a line and put your comment after that. You can also put a comment after a statement:
DoSomething(); // This code does XYZ
How do color codes work?
Color codes in Tribes2 scripts are made up of four values, and can be expressed as deciamls. Below is a line from the disc.cs script:
colors[0] = "0.7 0.8 1.0 1.0";
The first three numbers are the red, green and blue (RGB) values for that color. If you have ever used a paint program like Photoshop or Paint Shop Pro you should be familiar with RGB codes. In this case the RGB values range from 0 to 1, which equates to 0 to 255. For example a value of 0.5 is about equivalent to 128 in a paint program. Many people have e-mailed me to confirm that the fourth value is the alpha setting. Thanks to those who contributed this useful information.
What are packages and how do I use them?
Packages are nifty little pieces of code that you can activate and deactivate at run time. The game uses these primarily for the various game types (CTF, Capture and Hold, Defend and Destroy, etc.). You can use them for whatever you want. When a package is activated, its functions override that of the origianal object. A single package can override the functions of multiple other objects. To activae a package you use the syntax:
activatePackage(PackageName);
To deactivate a package you use the syntax:
deactivatePackage(PackageName);
Here is a simple example:
function foo() { echo("Normal foo"); } package MyPackage { function foo() { echo("MyPackage foo"); } };
So with that example, if the package was not activated, the function foo would echo:
Normal foo
But if you activate the package, the function foo would echo:
MyPackage foo
Within a package's function, the Parent keyword refers to the original object. So, building on our original example, if the MyPackage code had read:
package MyPackage { function foo() { echo("MyPackage foo"); Parent::foo; } };
Then (while the package was active) the function foo would echo:
MyPackage foo
Normal foo
You can also activate multiple packages, and they take precedence in the order in which they are activated. A package that is activated most recently is the one who's functions will execute. So building on the code we have been using, if I had the following package:
package AnotherPackage { function foo() { echo ("AnotherPackage foo"); Parent::foo(); } };
Then, after running the following commands:
activatePackage(MyPackage);
activatePackage(AnotherPackage);
The foo function would output:
AnotherPackage foo
MyPackage foo
Normal foo
Coding Specifics and Mini HOWTOs
Which projectiles are fired by which gun?
These are the ones that have been found so far:
ELFProjectile - Elf gun EnergyProjectile - Blaster GrenadeProjectile - Grenade Launcher GrenadeProjectile - Mortar SeekerProjectile - Missile Launcher LinearFlareProjectile - Plasma Gun SniperProjectile - Laser Rifle TargetProjectile - Targeting Laser LinearProjectile - Disc Launcher TracerProjectile - Chaingun ShockLanceProjectile - ShockLance
Which vehicles are derived from which datablocks?
ScoutVehicle - Wildcat Grav Cycle AssaultVehicle - Beowulf Assault Vehicle MobileBaseVehicle - Jericho MPB ScoutFlyer - Shrike Scout Flier BomberFlyer - Thundersword Bomber HAPCFlyer - Havok Heavy Transport Flier
How can I make different armour classes use different beacons?
All of this code for beacons is in item.cs. First, you must rename the function Beacon::onUse to something like Beacon::onDeploy. This is so that if you still want at least one armour class to use the standard beacons you can call that function. If you do not want to use the standard beacons in any way, you can comment out Beacon::onUse.
Now you must write your own Beacon::onUse code. The code will simply execute the correct beacon function for the armour class of the player. Here is the code:
function Beacon::onUse(%data, %obj) { %obj.getDataBlock().onBeacon(%obj); }
What this code will do is if a player is using LightMaleHumanArmor, it will run the function LightMaleHumanArmor::onBeacon. If the player is using MediumMaleHumanArmor, it will run MediumMaleHumanArmor::onBeacon. Get the idea?
Now, all you have to do is write the actual onBeacon functions for each armour class. Below are two samples. The first one (Light armour) simply deploys a normal beacon (assuming you renamed onUse to onDeploy in the first step. The second one is there to give you a nifty idea on all the things you can do with this (but it may not work as-is).
function LightMaleHumanArmor::onBeacon(%obj, %data) { Beacon::onDeploy(%data, %obj); } function MediumMaleHumanArmor::onBeacon(%obj, %data) { SatchelCharge::onUse(%data, %obj); }
Thanks to ZOD and CrazyBrett for the info.
How do I make INSERT OBJECT NAME cloak?
First off, I'm not sure what this will work for beyond vehicles and players. If someone tries to use it to cloak something else (ie. turrets), be sure to let me know so I can add the info.
To cloak something you must make two function calls. First, you should use the setPassiveJammed function, which makes the player not show up on the sensor network, and not targeted by turrets. Second, you use the setCloaked function to actually make it disappear. Assuming the object you want to cloak is %obj, you could do the following:
%obj.setCloaked(true); %obj.setPassiveJammed(true);
We are not quite sure what the isCloaked function does. I believe it just returns weather or not an object is cloaked.
Thanks to ZOD for the info.
How do I add items or take away items from a player's inventory?
Use the incInventory and decInventory. Examples:
%player.incInventory(%gren, 1) // Add one grenade to player's inventory %player.decInventory(%ammo, 1) // Subtract one unit of ammo from player's inventory
How do I add a new deployable?
You need to include at least 3 new datablocks.
One derived from StaticShapeData to represent the physical deployed object.
One derived from ItemData to represent the pack when it's dropped or thrown.
One derived from ShapeBaseImageData to represent the pack when it's carried in your inventory.
The easiest way to do this is to make copies of existing deployables, like the pulse sensor. Rename the new blocks and change the relevant variables in each (including the models you wish to use).
Now you need to set the team maximum for this deployable. Add an entry to \$TeamDeployableMax in deployables.cs.
You also need to allow one or more armors to carry the item. In player.cs, add entries to "max" in the player datablocks.
Finally, you need to make it available at the inventory. Open inventoryHud.cs and add an entry to \$InvPack. Add a corresponding entry to $NameToInv.
This should give you the BASIC stuff required to deploy the object. In order to make it do something interesting, you probably need to override some functions from the StaticShapeData datablock.
Thanks to CrazyBrett for this information.
How do I add a weapon?
Adding a weapon consists of two major steps. First, you must create the script file detailing all of your weapons (and its projectiles, ammo, sound, explosions etc.) properties. Then, you must edit the rest of the script files to include your new weapon.
I'm assuming that you can handle the first step on you own. To get started, simply open up an existing weapon's file, replace the name of the weapon with that of your new weapon within the file and save it under a new name. You shoulden't change any of the lines with filenames because you don't have new models and sounds for your weapon, you will just use the old ones.
Now that you have this set up, you can move on to editing the extra scripts. Here is a list of scripts that need to be edited and what you need to edit in them.
controlDefaults.cs - Locate the area of the file labeled DIRECT WEAPON SELECTION FUNCTIONS. Add a function for your weapon in the following format:
function useYourGun( %val ) { if ( %val ) use( YourGun ); }
Now add a line in clientCmdSetDefaultVehicleKeys in the block of passengerKeys.copyBind functions for weapons.
hud.cs - Add a case to clientCmdSetWeaponsHudActive using the same format as the other cases. This sets the rectile for the gun. You will want to use an existing weapon's ret_*.png file, so take your pick of what rectile you like.
OptionsDlg.cs - In the middle of the file is a huge section of a bunch of \$Remap stuff. Add a block for your weapon in there. Use this format:
\$RemapName[$RemapCount] = "Your Gun"; \$RemapCmd[$RemapCount] = "useYourGun"; \$RemapCount++;
What that does is tell the options box that lets you choose your keys to have an entry that displays "Your Gun". If you bind that to a key the \$RemapCmd line tells it to bind to the useYourGun function (which we added to controlDefaults.cs).
inventory.cs - Add a case for your new weapon in ShapeBase::hasAmmo. Add lines for your weapon and its ammunition in ShapeBase::clearInventory. Add lines to give the player your weapon and ammunition in serverCmdGiveAll.
inventoryHud.cs - Add your weapon as next available item (10 if you haven't added any other weapons) in the \$InvWeapon array, this adds your weapon to the favorites list. Then, add your wepean to the \$NameToInv array (or is it hash?) in the same format that the other weapons use. The format for this entry is:
\$NameToInv["StringAddedToInvWeapon"] = "YourWeapon";
Continue by adding cases in buyFavorites and buyDeployableFavorites so that when a player buys your gun, they also get ammunition.
player.cs - Set the maximum amount each armour class can carry of your weapon and its ammunition. For the weapon if you set it as 1 that means that the armour class can carry that weapon, if you set it as 0 then that armour class cannot carry your weapon. These lines will look like:
max[YourGun] = 1;
max[YourAmmo] = 200;
You will add two lines for each armour class (one for the weapon, one for the chaingun) totalling six added lines. Also add your ammo type to the \$ammoType array as the next available item (6 if you haven't added any others). Look for lines like:
\$ammoType[5] = "ChaingunAmmo";
Add your entry at the end of that block (be sure to use the next available index number).
Finally, go to the Armor::applyConcussion function and add an "if" line for your weapon. Use this format:
if( %weaps[8] = %player.getInventory("YourGun") > 0 ) %numWeapons++;
weapons.cs - Locate the code near the very top with a bunch of entries like this:
\$WeaponsHudData[3, bitmapName] = "gui/hud_disc.png"; \$WeaponsHudData[3, itemDataName] = "Disc"; \$WeaponsHudData[3, ammoDataName] = "DiscAmmo";
Add an entry for your weapon at the end replacing the number with the next avaialable interger (11 if you haven't added anything here before). The first line is the GUI icon for your weapon, you should use an existing one unless you created your own image. Now increment the \$WeaponsHudCount variable by one in the lines following those blocks. Right below that is a block of \$AmmoIncrement settings. Add your ammunition to the end of the list and for a value use something from a similar weapon (I'm not sure what the values do exactly). Right below that are a bunch of exec functions. Add your script file to the list in the same format:
exec("scripts/weapons/yourfilename.cs");
packs\ammopack.cs - Add your ammo type to the \$AmmoItem array at the top as the next available index (7 if you haven't added any others). Also, right below that is a line setting \$numAmmoItems. Increase the number in that line by one. Later in the file, edit the AmmoPack datablock and add a line that looks like the following: max[YourAmmo] = 15;
Replace YourAmmo with your ammo object and replace 50 with half of whatever you want the limit on that ammunition to be when the ammo pack is active. This value is multiplied times 2 to get the maximum number of ammo a player can carry while the ammo pack is active.
Now fire the game up and cross your fingers. Let me know if this works for you or if I missed anything.
Note: Look for a full tutorial on this topic from ZOD coming soon.
Thanks to {MA} Sword for much of this info.
How do I change the sound of INSERT ANYTHING?
Changing the sound of anything in the game can be accomplished by editing the filename property of an AudioProfile datablock. For example, if you want to make the plasma rifle sound like the disc launcher you would find the following code in plasma.cs:
datablock AudioProfile(PlasmaFireSound) { filename = "fx/weapons/plasma_rifle_fire.wav"; description = AudioDefault3d; preload = true; effect = PlasmaFireEffect; };
And change it to:
datablock AudioProfile(PlasmaFireSound) { filename = "fx/weapons/spinfusor_fire.wav"; description = AudioDefault3d; preload = true; effect = PlasmaFireEffect; };
Also, it is worth noting that all of the wave files are in the audio.vl2 file.
How do I get characters or words from a string? (UPDATED)
getSubStr - Returns a character or group of characters getWord - Returns one word getWords - Returns one or more words firstWord - Returns the first word restWords - Returns all words except the first word
If I left any off, please let me know.
These are fairly self-explanitory but here are some examples:
%sting = 'I love Tribes 2!'; getSubStr(%string, 0, 1); // Returns 'I' getSubStr(%string, 4, 8); // Returns 've Tribe' getWord(%string, 0); // Returns 'I' getWord(%string, 2); // Returns 'Tribes' getWords(%string, 0, 2); // Returns 'I love Tribes 2!' getWords(%string, 1, 1); // Returns 'love' firstWord(%string); // Returns 'I' restWords(%string); // Returns 'love Tribes 2!'
Thanks to MorphGuppie for much of this info.
Mini-HOWTO: Vectors
All vector info is complements of CrazyBrett and Xetrov.
Diagrams coming when I get a chance to make them or some nice person sends some in. =)
What are vectors? (NEW)
A vector is simply a set of numbers. In general, they can have any number of numbers, and they can represent all kinds of stuff. They're used a lot in 3D calculations, in which case they represent dimensions in 3D space. Vectors of this kind always have 3 numbers. You can picture a vector as an arrow that has the specified dimensions. For example, the vector [25 30 2] would be represented by an arrow that is 25 units "wide" in the X direction, 30 units "long" in the Y direction, and 2 units "high" in the Z direction.
What do vectors represent?
In 3D stuff, vectors are typically used for 2 things: position and velocity. As a position, a vector represents a location in 3D space relative to some fixed origin [0 0 0]. Saying that a player is at position [1 2 3] means that they're 1 unit away from the origin in the X direction, 2 units away in the Y direction, and 3 units away in the Z direction. Imagine the vector arrow starting at the origin and ending at the location of the player.
Vectors are also used to represent the velocity of an object. The velocity vector describes both the SPEED and DIRECTION of the object. Take our player from above (at position [1 2 3]), and suppose he's moving with velocity [0 0 1]. Assuming the Z direction is up, this means he's moving straight up at a speed of "1". Imagine a vector arrow starting at the player, pointing in the direction he's moving. The direction is given by wherever the "arrow" of the vector is pointing. The speed is given by the LENGTH of that arrow. A more complicated example is the velocity vector [3 4 0]. In this case, the direction of the velocity (arrow) is diagonal in the XY plane, and the speed (arrow length) can be found with the pythagorean theorem: sqrt(x^2 + y^2 + z^2) = sqrt(3^2 + 4^2 + 0^2) = sqrt(25) = 5. So the speed of this velocity is "5". Note that two different vectors can represent the same direction with different speeds: [1 1 1] and [5 5 5] both point in the same direction (imagine the arrows), but they have different lengths, and hence different speeds.
What is normalizing a vector?
Normalizing a vector simply means adjusting it so that its length becomes 1, but it keeps pointing in the same direction. For example, consider the vector [1 2 3]. The length of this vector is sqrt(1^2 + 2^2 + 3^2) = 3.74166, approximately. To normalize the vector, we divide each dimension by this length, and get this vector [0.26726 0.53452 0.80178]. Notice that the length of this vector is 1, and it points in the same direction as the original.
In Tribes 2, normalizing a vector is done with the VectorNormalize function. It works like this:
%vec = VectorNormalize(%vec);
What is vector addition?
Adding two vectors simply sums each corresponding pair of values. Hence [1 2 3] + [50 60 70] = [51 62 73]. Think about adding two vectors like this. Without changing their orientations, take both arrows, and place the tail of arrow #2 against the head of arrow #1. Draw a new arrow from the tail of arrow #1 to the head of arrow #2.
In Tribes 2, vectors are added using the vectorAdd function. Example:
%vec1 = "1 2 3"; %vec2 = "10 20 30"; %newVec = vectorAdd(%vec1, %vec2); // %newVec will equal "11 22 33"
What is scaling a vector?
Scaling a vector simply means multiplying all its dimensions by some number. Conceptually, this adjusts the length of the arrow, but not its directions. Scaling the vector [1 2 3] by 2 results in [2 4 6], which points in the same direction but is twice as long as the original. Indeed, normalizing (above) is defined as scaling a vector by the inverse of its length.
In Tribes 2 coding, vectors are scaled using the VectorScale function. Example:
%vec = VectorScale(%vec, 2); // Doubles the length of %vec
What is a dot product?
The dot product is one of two ways to "multiply" two vectors together. The result of a dot product is a SINGLE NUMBER, not a vector. The dot product is the sum of the products of the corresponding pairs of values in the two vectors. In other words, if you have two vectors [1 2 3] and [4 5 6], their dot product is (1*4 + 2*5 + 3*6) = (4 + 10 + 18) = 32.
What is this good for? Dot products are good ways of comparing how "similar" the directions of two vectors are. If two vectors point in the exact same direction, their dot product is simply the product of the lengths of the vectors. If two vectors are exactly perpendicular, their dot products will be zero. Somewhere in between will produce dot products along the spectrum.
In Tribes 2 coding, you can get the dot product of two vectors by using the VectorDot function:
%vec1 = "1 2 3"; %vec2 = "3 2 1"; %dotProduct = VectorDot(%vec1, %vec2);
Anyone figure out what %dotProduct would be equal to? Doing the math... (1*3 + 2*2 + 3*1) = (3 + 4 + 3) = 10. If you got it right step up and recieve your cookie.
What is a cross product?
The cross product is another way to "multiply" vectors. The result of a cross product operation is a new vector. The new vector points in a direction which is PERPENDICULAR to the original two vectors. Given two vectors [x1 y1 z1] and [x2 y2 z2], the cross product is [(y1*z2 - z1*y2) (x1*z2 - z1*x2) (x1*y2 - y1*x2)].
What is this good for? Cross products are extremely useful for finding a "normal vector" to two surface vectors (NOTE: This is different from Normalizing a vector, which refers to the length). If you have two vectors which describe the angle of a sloped surface, you can use the cross product to calculate a vector which is perpendicular (normal) to that surface (to orient deployables, for example). Also, the cross product is useful for comparing how "different" the directions of two vectors are. If two vectors point in completely perpendicular directions, the length of the cross product will be equal to the product of the lengths of the original vectors. If two vectors point in exactly the same direction, their cross product will be [0 0 0]. Anywhere in between will yield a cross product with a length in that spectrum.
You can obtain the cross product of a vector using the VectorCross function in Tribes 2 coding.
Sources & Links
What does the INSERT FUNCTION NAME function do?
There are way to many functions to cover in this FAQ. To get started, you should always look at the header for the function. To find the header of a particular function go to http://www.planettribes.com/depot/downloads/t2commands.asp and use the search engine. If the header doesn't help you get an idea of what is going on, you should browse the code of that function. Sometimes the functions have comments that will help you. If all else fails, ask someone if they know.
Where can I go to talk with other coders about Tribes 2 scripting?
Try the forums at www.planettribes.com, in the coding section. A lot of helpful people hang out there.
Where can I get general Tribes2 questions answered?
The best source of general Tribes2 information is the PlanetTribes' Tribes 2 FAQ.
Where can I learn about using the map editor?
While using the map editor is beyond the scope of this FAQ, here are some links to point you in the right direction:
Using the Tribes 2 Mission Editor - http://sierrastudios.com/games/tribes2/memanual.html Falcon's Tribes 2 Mapping HOWTO - http://web.lemuria.org/T2beta/Mapping/
SPECIAL THANKS TO:
Dynamix and Sierra for producing and delivering a great game.
The users of the PlanetTribes Coding Forum for getting me interested in coding.
Rypht for putting together the list of projectiles.
ZOD for his excellent weapon making tutorial (which I borrowed the logging code from).
Yardik for helping countless people with their coding problems.
CrazyBrett for his knowledgable contributions to the forums.
Robert Tockley for the information he submitted.
Sean "x" McCarthy for his suggestion of using MSVC as an editor.
Viking for his help in the forums.
David Dunscombe for his IDE.
Founder for his assistance in the #T2modding channel.
{MA} Sword for his information on how to add a weapon. His website is at http://www.crosswinds.net/~sword003/.