The idea behind Interactive Vehicle Support was simple: provide a way of interacting with things on vehicles. While Trigun included some documentation in the add-on, I felt that having a tutorial with examples might help to clear up some confusion on how to use it.
Example 1: Converti Hood1. Getting Started:Before any scripting can be done, we need to make sure we have animations to work with! In this example, we are going to see how one can update a vehicle with Interactive Vehicle Support. We will use Phydeoux's Converti, because it already has animations.
Download
Phydeoux's Converti &
Interactive Vehicle Support2. Change the server.cs File:The vehicle needs to reference the script. So, we are going to change the
server.cs, which is responsible for executing the scripts when your server starts.
Here is an example of rewriting the
server.cs:
// server.cs
// Handle Required Add-ons
%errorA = ForceRequiredAddOn("Vehicle_Jeep");
%errorB = ForceRequiredAddOn("Support_Interactive_Vehicle");
if(%errorA == $Error::AddOn_NotFound)
{
error("ERROR: Vehicle_Converti - required add-on Vehicle_Jeep not found");
%errors++;
}
// Remove Jeep from Vehicle List if Disabled
else if(%errorA == $Error::AddOn_Disabled)
JeepVehicle.uiName = "";
if(%errorB == $Error::AddOn_NotFound)
{
error("ERROR: Vehicle_Converti - required add-on Support_Interactive_Vehicle not found");
%errors++;
}
if(%errors)
return;
exec("./Converti_Explosion.cs");
exec("./Converti_FinalExplosion.cs");
exec("./Converti_Spring.cs");
exec("./Converti_Tire.cs");
exec("./Vehicle_Converti.cs");
exec("./Vehicle_ConvertiInteractive.cs");
Notice how I added "
exec("./Vehicle_ConvertiInteractive.cs");". We are going to create a new datablock in a new script file, so we can focus on what needs to be done to implement the support script.
3. Create the Vehicle_ConvertiInteractive.cs File:In a new script file, we create a datablock named "
ConvertiInteractiveVehicle" that inherits from the original vehicle datablock. Make sure to redefine the uiName to distinguish it from the original!
datablock WheeledVehicleData(ConvertiInteractiveVehicle : ConvertiVehicle)
{
uiName = "Converti - Interactive";
};
This will reference the original Converti, so we can concentrate on the changes. According to
example.txt from the Interactive Vehicle Support add-on, we can define a vehicle as interactive like this:
//- Interactive Definitions -
isInteractive = true;
iNumZones = 2;
iZone[0] = "-5 -0.5 0.2 -1.4 1.2 2.5";
iZoneScript[0] = "onLeftDoor";
iZone[1] = "1.4 -0.5 0.2 5 1.2 2.5";
iZoneScript[1] = "onRightDoor";
Since we only have only one animated part (the convertible roof), change '
iNumZones' to 1 and remove the definitions for the second zone. We also want to rename "
onLeftDoor" to something referring to the interactive zone, so let's call it "
onTop".
This is what we should have now:
//- Interactive Definitions -
isInteractive = true;
iNumZones = 1;
iZone[0] = "-5 -0.5 0.2 -1.4 1.2 2.5";
iZoneScript[0] = "onTop";
Now, we have the definition for one interactive zone. The value of '
iZone[0]' represents the coordinates used for defining the interactive zone in the form of "
minX minY minZ maxX maxY maxZ".
4. Get the Coordinates of the Interactive Zone:There are many methods of getting the coordinates. We could use a modelling program to look up the coordinates for the bounding box of each animated object if we had the source files, but we don't, so that isn't an option here.
Another way is to use Torque ShowTool. Open the model in ShowTool and, with the help of grid seen in certain viewports (anything that is not perspective view), we can determine the coordinates fairly easy. Each little box is 0.1 Torque units.
Trigun also implemented a feature which helps us get the coordinates in-game. In order to do so, we have to do the following in the console:
$Debug::InteractiveVehicles = true;
Then, if we click on the vehicle in-game, it will display the coordinates of where we clicked in the console.
Once we have the coordinates, let's add them to our code. In the end it should roughly look like this:
//- Interactive Definitions -
isInteractive = true;
iNumZones = 1;
iZone[0] = "-2 -4 1.2 2 1.4 2.5";
iZoneScript[0] = "onTop";
5. Create the Script Callback:We are still not done yet! We have defined the zone, but we have to make the whole thing work. According to
example.txt, we can define an interactive script callback like this:
function YourVehicle::onLeftDoor(%this, %obj, %client, %offset, %position, %vector)
{
%time = getSimTime();
if((%time - %obj.leftDoorTime) > 1300)
{
%obj.leftDoorTime = %time;
%obj.leftDoor = !%obj.leftDoor;
%obj.playThread(0, %obj.leftDoor ? ldOpen : ldClose);
}
return 1;
}
We need to change a few values to suit our needs. "
YourVehicle" is obviously the name of the vehicle datablock, so let's rename it to "
ConvertiInteractiveVehicle". "
onLeftDoor" should be changed to "
onTop", and every instance of "
leftDoor" should be changed to "
top".
The script comes with a feature which prevents us from disrupting the animation by adding a timeout from the moment we originally activate it. The number "
1300" is the length of the timeout in milliseconds. Normally, it should be adjusted to the length of our animation, but for the sake of simplicity, let's just keep that value. "
ldOpen" and "
ldClose" are the names of the animations we are planning to trigger. However, those must be changed to correspond with the name of the animation we want to play! Luckily for us, Phydeoux used the straightforward names of "
open" and "
close" for his animations, so let's use those.
If we changed everything correctly, we should have this:
function ConvertiInteractiveVehicle::onTop(%this, %obj, %client, %offset, %position, %vector)
{
%time = getSimTime();
if((%time - %obj.topTime) > 1300)
{
%obj.topTime = %time;
%obj.top = !%obj.top;
%obj.playThread(0, %obj.top ? open : close);
}
return 1;
}
At this point, we are pretty much done. Now, we can open and close the convertible top and use our handbrake separately! In case you are not sure if you followed this tutorial correctly, here is the complete code for reference:
datablock WheeledVehicleData(ConvertiInteractiveVehicle : ConvertiVehicle)
{
uiName = "Converti - Interactive";
//- Interactive Definitions -
isInteractive = true;
iNumZones = 1;
iZone[0] = "-2 -4 1.2 2 1.4 2.5";
iZoneScript[0] = "onTop";
};
function ConvertiInteractiveVehicle::onTop(%this, %obj, %client, %offset, %position, %vector)
{
%time = getSimTime();
if((%time - %obj.topTime) > 1300)
{
%obj.topTime = %time;
%obj.top = !%obj.top;
%obj.playThread(0, %obj.top ? open : close);
}
return 1;
}
Addendum: Vehicles may store their animations is separate .dsq files. This should be no problem, as you can simply load those animations with the help of the script. Here's an example snippet taken from the Tudor:
datablock TSShapeConstructor(TudorDts)
{
baseShape = "./tudor.dts";
sequence0 = "./root.dsq root";
sequence1 = "./bootlidopen.dsq bootlidopen";
sequence2 = "./bootlidclose.dsq bootlidclose";
sequence3 = "./bonnetlidopen.dsq bonnetlidopen";
sequence4 = "./bonnetlidclose.dsq bonnetlidclose";
sequence5 = "./ldopen.dsq ldopen";
sequence6 = "./ldclose.dsq ldclose";
sequence7 = "./rdopen.dsq rdopen";
sequence8 = "./rdclose.dsq rdclose";
};
There is a limit on how many animation threads you may have playing at any time. The current limit is 4 which means you can animate a two door car with bonnetlid and bootlid (hood and trunk). You can try getting around the problem by using AIPlayers, but be warned it is datablock intensive and should be used sparingly!
Example 2: Triggering Lights on a Police CarComing Soon!
Credits:Trigun - co-author, man behind the Interactive Support Add-On
Blocktim - proofreading and being a Swede
Spation - proofreading (not well)