Login x
User Name:
Password:
Social Links Facebook Twitter YouTube Steam RSS News Feeds
Watch MODSonair

Members Online

»
0 Active | 258 Guests
Online:

LATEST FORUM THREADS

»
New BF2 Mod
BF2 General

Tutorials

»
Level Scripting Tutorial 3
Versions: You must be logged in to view history.
rich_is_bored offers part 2 in scriptting tutorials. In this tutorial we will take the mechanical arm from the last tutorial as well as some new pieces and create a machine.
Level Scripting Tutorial 3

Introduction

Welcome to the third and last of my scripting tutorials. Well, that's probably not entirely true. Maybe I'll figure something else out and it will be worth writing about.

Anyway, In this tutorial we will take the mechanical arm from the last tutorial as well as some new pieces and create a machine. It's a pretty simple machine and it isn't perfect. But I wasn't making eye candy to begin with.

Advanced: Creating a Machine

Just like in the previous tutorials I am streamlining the process. I am providing you will everything you will need.

The zip is linked to below.

Download this file

Planning Your Project

The first thing to do is to plan. You need to know what you're trying to accomplish and how to do it.

One thing that is necessary is an idea. So here is the point where I am going to trust you...

You see, I decided it would be easier to just show you it in action than draw out a bunch of diagrams. This means that everything needed including the script is included in this zip file. Of course in order to learn anything you're going to rename, move, or delete the script after you've seen what we are going to do.

So, this means your going to run the map and observe the machine running through its cycle. So...

Extract the zip to [Your Doom 3 Directory]base. Fire up doom, run the map rich_scripting_tutorial_3. After it loads and starts up
you'll see these crazy robotic arms moving around and doing all kinds of weird nonsense. As you can see, I didn't do a good job of planning. Yeah, I'm not proud of it but it'll work for this tutorial.

As you can see, the robotic clasp picks up a canister and the welding gun will meet up with it and fire. Next the clasp will place the canister back and the sequence will repeat with the second canister.

Now you should have a pretty good idea what we will be trying to accomplish. But, before we start scripting away I need to give you a good idea how the parts come together to form arms and such.

grabarm.png

And here are all the parts of the clasp. From here on out we will just refer to this as the grab arm. You should be familiar with it already (Previous tutorial, Hint, Hint).

It is also a good idea to come up with a naming convention when we are working with several parts. This will make it easier to tell what is where. I am going to name these parts from the top down.

Here are the names for the grab arm components from top to bottom. We will also be forming a child parent tree. The items at the bottom will be parented to the items above it. Now take into consideration that the fingers will all be parented to the finger joint a.k.a. $GrabArm_Base3.

$GrabArm_Base1
$GrabArm_Swivel1
$GrabArm_Base2
$GrabArm_Swivel2
$GrabArm_Base3
$GrabArm_Finger1
$GrabArm_Finger2
$GrabArm_Finger3


sparkarm.png

It's the same deal here. I will name the parts from top to bottom. Again the items at the bottom will be child objects to the items above.

$SparkArm_Base1
$SparkArm_Swivel1
$SparkArm_Base2
$SparkArm_Swivel2
$SparkArm_Base3
$SparkArm_Gun1


We'll need a name for both canisters as well. We can name them from left to right to keep things simple. You all read from left to right don't you?

$Can1
$Can2


Nutz 'n' Bolts: Screwing around in the Map Editor

After you have planned... umm yeah, you'll fire up the editor and begin putting parts into place. It's not over yet though; you'll still need to run through the motions to figure out where everything goes and what you'll need to make it work.

Go ahead and load up rich_scripting_tutorial_3.map in the editor. You'll see that the parts are laid out in the editor similar to the diagram below.

layout.png

Of course in the editor you'll see several entities that are not displayed here. All of these are speakers and particle generators except for three. See if you can find them.

Hint: Take a look at the base of the grab arm (where it attaches to the machine) and to the left, directly above each canister.

Guess what these are for? Well, the grab arm needs to move to each canister and then back to its original position. These entities act as markers so the arm will know where to go. Basically they are three func_statics with the following names.

$Can_Pos1
$Can_Pos2
$Arm_Pos1


It's pretty straight forward. They're named from left to right again.

We aren't interested in the sounds and special effects yet. We need to get this puppy moving before we think about what sounds or special effects to use.

Playing God: Scripting it to Life

This would be the part where you delete, rename, move, or in other words, get rid of the script. Unless you wanna steal my work thief!

So, start up your favorite text editor editpad... What?! You haven't downloaded editpad yet?! Ah, forget it. Stick to whatever you're using. If you haven't changed yet you never will. Although I was thinking about working on a colored text filter specifically for doom 3 scripting. Oh well.

Alright. We are definitely going to need some comments in this code so we don't get all confused.

So start out with a simple script like this.

Code:
////////////////////////////////////////////////////
//
// Setup binds, etc...
//
////////////////////////////////////////////////////
void setup_objects()
{

// SparkArm Binds

// GrabArm Binds

}

////////////////////////////////////////////////////
//
// Part Movement...
//
////////////////////////////////////////////////////

////////////////////////////////////////////////////
//
// MAIN
//
////////////////////////////////////////////////////

void main ()
{
setup_objects ();
sys.wait(3);
}


You should already know what's coming next. That's right. We need to setup our binds. Let's take care of the spark arm. You should know where this goes by now.

Hint: We are setting up objects right?

Code:
// SparkArm Binds

$SparkArm_Gun1.bind($SparkArm_Base3);
$SparkArm_Base3.bind($SparkArm_Swivel2);
$SparkArm_Swivel2.bind($SparkArm_Base2);
$SparkArm_Base2.bind($SparkArm_Swivel1);
$SparkArm_Swivel1.bind($SparkArm_Base1);


And from here we setup our binds for the grab arm.

Code:
// GrabArm Binds

$GrabArm_Finger1.bind($GrabArm_Base3);
$GrabArm_Finger2.bind($GrabArm_Base3);
$GrabArm_Finger3.bind($GrabArm_Base3);
$GrabArm_Base3.bind($GrabArm_Swivel2);
$GrabArm_Swivel2.bind($GrabArm_Base2);
$GrabArm_Base2.bind($GrabArm_Swivel1);
$GrabArm_Swivel1.bind($GrabArm_Base1);


Now, we are ready to move some stuff. Let's setup a motion for the grab arm first since it's the more difficult of the two.

We aren't interested in covering the entire motion at first. In fact, we will only write enough code to grasp the first canister and move it into position. We are breaking the cycle into each component. (Remember talking about that from the first tutorial?)

First we will give this motion a name. Hmmm?. GrabCanister sounds good. (Pretty self explanatory huh?)

So let's make a function like this.

Code:
void GrabCanister()
{
}


Now, I'll explain what needs to happen on each line and you type up the code.

Move GrabArm_Base1 to Can_Pos1.
Wait for GrabArm_Base1 to finish it's movement.
Rotate GrabArm_Finger1 once 45 degrees on the X axis.
Rotate GrabArm_Finger2 once 45 degrees on the X axis.
Rotate GrabArm_Finger3 once 45 degrees on the X axis.
Move Can1 up 30.
Wait for Can1 to finish it's movement.
Rotate GrabArm_Finger1 once -35 degrees on the X axis.
Rotate GrabArm_Finger2 once -35 degrees on the X axis.
Rotate GrabArm_Finger3 once -35 degrees on the X axis.
Wait for Finger1 to finish it's movement. All three fingers should finish at the same time.
Bind Can1 to GrabArm_Base3.
Rotate GrabArm_Base3 once 360 degrees on the Y axis.
Wait for GrabArm_Base3 to finish it's movement.
Rotate GrabArm_Base2 once 90 degrees on the Y axis.
Wait for GrabArm_Base2 to finish it's movement.
Rotate GrabArm_Swivel2 once 90 degrees on the X axis.
Wait for GrabArm_Swivel2 to finish it's movement.
Move GrabArm_Base1 to Arm_Pos1.
Rotate GrabArm_Base2 once -90 on the Y axis.
Wait for GrabArm_Base2 to finish it's movement.

Now here is the code below. Yeah you could've just cheated and copied and pasted from below. But that's really lame.

Code:
void GrabCanister()
{
$GrabArm_Base1.moveTo($Can_Pos1);
sys.waitFor($GrabArm_Base1);
$GrabArm_Finger1.rotateOnce('45 0 0');
$GrabArm_Finger2.rotateOnce('45 0 0');
$GrabArm_Finger3.rotateOnce('45 0 0');
Can1.move(UP, 30);
sys.waitFor($Can1);
$GrabArm_Finger1.rotateOnce('-35 0 0');
$GrabArm_Finger2.rotateOnce('-35 0 0');
$GrabArm_Finger3.rotateOnce('-35 0 0');
sys.waitFor($GrabArm_Finger1);
Can1.bind($GrabArm_Base3);
$GrabArm_Base3.rotateOnce('0 360 0');
sys.waitFor($GrabArm_Base3);
$GrabArm_Base2.rotateOnce('0 90 0');
sys.waitFor($GrabArm_Base2);
$GrabArm_Swivel2.rotateOnce('90 0 0');
sys.waitFor($GrabArm_Swivel2);
$GrabArm_Base1.moveTo($Arm_Pos1);
$GrabArm_Base2.rotateOnce('0 -90 0');
sys.waitFor($GrabArm_Base2);
}


Now add this function to the main function like this.

Code:
void main ()
{
setup_objects ();
sys.wait(3);
GrabCanister();
}


Save your script as rich_scripting_tutorial_3.script and fire up the map. You've got a
mechanical arm picking up a canister.

You know what is really interesting? When it picks up the other canister it pretty much runs through the same set of motions doesn't it? Wouldn't it save you a lot of trouble if you could just call the same function to pick up the other canister? But how?


This is where we bring parameters into the equation. You see, every function has a set of parentheses appended to the end of it. You can pass objects to the functions by placing the object's names within these parentheses. All you have to do is change the function slightly.

Let's see what objects will change in the GrabCanister function when I am picking up the second canister? Hmmm? Just two, Can1 and Can_Pos1. Everything else remains the same.

We will need to create alias names for the objects that change. These are called reference variables. We cannot use the names Can1, Can2, Can_Pos1, or Can_Pos2 in the function in order for this to work. We need to use these reference variables as aliases for the objects that are passed to the function instead. In the function we will use the names Can and CanPos.

When we call this modified form of the GrabCanister function it will look like this when we pass Can1 and Can_Pos1.

Code:
GrabCanister($Can_Pos1, $Can1);


Or when we pass Can2 and Can_Pos2 it will look like this.

Code:
GrabCanister($Can_Pos2, $Can2);


And when we declare our function we will now change the line to look like this.

Code:
void GrabCanister(entity CanPos, entity Can)
{


Notice that I defined the type of variables by using the keyword entity. This is because we are passing entity names to these reference variables.

And to modify the code of the function we will replace every Can1 with Can and every Can_Pos1 with CanPos. The code should look like this.

Code:
void GrabCanister(entity CanPos, entity Can, entity CanTubeSnd)
{
$GrabArm_Base1.moveTo(CanPos);
sys.waitFor($GrabArm_Base1);
$GrabArm_Finger1.rotateOnce('45 0 0');
$GrabArm_Finger2.rotateOnce('45 0 0');
$GrabArm_Finger3.rotateOnce('45 0 0');
Can.move(UP, 30);
sys.waitFor(Can);
$GrabArm_Finger1.rotateOnce('-35 0 0');
$GrabArm_Finger2.rotateOnce('-35 0 0');
$GrabArm_Finger3.rotateOnce('-35 0 0');
sys.waitFor($GrabArm_Finger1);
Can.bind($GrabArm_Base3);
$GrabArm_Base3.rotateOnce('0 360 0');
sys.waitFor($GrabArm_Base3);
$GrabArm_Base2.rotateOnce('0 90 0');
sys.waitFor($GrabArm_Base2);
$GrabArm_Swivel2.rotateOnce('90 0 0');
sys.waitFor($GrabArm_Swivel2);
$GrabArm_Base1.moveTo($Arm_Pos1);
$GrabArm_Base2.rotateOnce('0 -90 0');
sys.waitFor($GrabArm_Base2);
}


And now in the main function I will change the call to GrabCanister to look like this.

Code:
void main ()
{
setup_objects ();
sys.wait(3);
GrabCanister($Can_Pos2, $Can2);
}


Save your script and fire up the map. Now we are looking at some impressive stuff. Here you are reusing the same code to move a completely different canister.So from here we can make a function to move the place the canister back. We'll call it simply PlaceCanister.

Basically we are doing what we did above backwards. So here is the code.

Code:
void PlaceCanister(entity CanPos, entity Can)
{
$GrabArm_Base2.rotateOnce('0 90 0');
$GrabArm_Base1.moveTo(CanPos);
sys.waitFor($GrabArm_Base2);
$GrabArm_Swivel2.rotateOnce('-90 0 0');
sys.waitFor($GrabArm_Swivel2);
$GrabArm_Base3.rotateOnce('0 -360 0');
sys.waitFor($GrabArm_Base3);
Can.unbind();
$GrabArm_Finger1.rotateOnce('35 0 0');
$GrabArm_Finger2.rotateOnce('35 0 0');
$GrabArm_Finger3.rotateOnce('35 0 0');

sys.waitFor($GrabArm_Finger1);
Can.rotateTo('0 0 0');
Can.move(DOWN, 30);
sys.waitFor(Can);
$GrabArm_Finger1.rotateOnce('-45 0 0');
$GrabArm_Finger2.rotateOnce('-45 0 0');
$GrabArm_Finger3.rotateOnce('-45 0 0');
$GrabArm_Base1.moveTo($Arm_Pos1);
$GrabArm_Base2.rotateTo('0 0 0');
sys.waitFor($GrabArm_Base1);
}


There are two lines I do want you to take note of though. Notice in this function the unbind command. This is because I want to detach the canister from the mechanical arm rather than bind it. Also notice how I am not placing anything in the parentheses. This is because you can only bind an object to one other object at a time. So there is no need to tell the engine what to detach the canister from. There is only one possible object it could be detached from in the first place.

The second line to look at is this line...

Code:
$GrabArm_Base2.rotateTo('0 0 0');


The rotateTo command is used here to ensure that GrabArm_Base2 is positioned the same as it was when the map first loaded. Without this command the base of the arm would start bending in the wrong direction. Go ahead and comment it out and give it a test run if you're curious.

Now we throw a call to PlaceCanister immediately following the call to GrabCanister.

Code:
void main ()
{
setup_objects ();
sys.wait(3);
GrabCanister($Can_Pos2, $Can2);
PlaceCanister($Can_Pos2, $Can2);
}


Save the script and start up the map. It will now grab the second canister and place it back. Go ahead and add another call to both GrabCanister and PlaceCanister each pointing to the first canister instead. It should look like this.

Code:
void main ()
{
setup_objects ();
sys.wait(3);
GrabCanister($Can_Pos2, $Can2);
PlaceCanister($Can_Pos2, $Can2);
GrabCanister($Can_Pos1, $Can1);
PlaceCanister($Can_Pos1, $Can1);
}


Same deal. Save and start the map. Now it will grab the second canister, place it back, and then do the same with the first canister. Neat huh?

Now we just need to code a function to move the spark gun into position. We'll call this PosPiecesToFire. Why the crazy name? Well later we will call the spark effects function from within this function. So basically this function will position the pieces and then fire. Make sense now?

This function is pretty simple compared to the previous one. We won't be passing objects to it and its movement is simple. So here's your code.

Code:
void PosPiecesToFire ()
{
$SparkArm_Swivel2.rotateOnce('-90 0 0');
sys.waitFor($SparkArm_Swivel2);
$SparkArm_Gun1.rotateOnce('-5 0 0');
sys.waitFor($SparkArm_Gun1);
$SparkArm_Base3.rotateOnce('0 120 0');
sys.waitFor($SparkArm_Base3);
$SparkArm_Base3.rotateOnce('0 120 0');
sys.waitFor($SparkArm_Base3);
$SparkArm_Base3.rotateOnce('0 120 0');
$SparkArm_Gun1.rotateOnce('5 0 0');
$SparkArm_Swivel2.rotateOnce('90 0 0');
$SparkArm_Base3.rotateTo('0 0 0');
sys.waitFor($SparkArm_Swivel2);
}


Now change the main function to look like this.

Code:
void main ()
{
setup_objects ();
sys.wait(3);
GrabCanister($Can_Pos2, $Can2);
PosPiecesToFire();
PlaceCanister($Can_Pos2, $Can2);
GrabCanister($Can_Pos1, $Can1);
PosPiecesToFire();
PlaceCanister($Can_Pos1, $Can1);
}


Again, save the script and start up the map. Now each arm does its own thing.

Let's change something real quick. I mean we don't want this to happen once and stop right?

We're going to create a function called MechCycle that will execute forever and a day. Basically we will cut the machine movement code from main and paste it.

Then we'll place that code in a while loop. It should look like this.

Code:
void MechCycle ()
{
while (1) {
GrabCanister($Can_Pos1, $Can1, $Can1_TubeSnd);
PosPiecesToFire();
PlaceCanister($Can_Pos1, $Can1, $Can1_TubeSnd);
GrabCanister($Can_Pos2, $Can2, $Can2_TubeSnd);
PosPiecesToFire();
PlaceCanister($Can_Pos2, $Can2, $Can2_TubeSnd);
}
}


Now, we just throw a call in main so it looks like this.

Code:
void main ()
{
setup_objects ();
sys.wait(3);
MechCycle();
}


Save the script and run the map. Now the machine runs continuously.

Adding Bells, Whistles and a Light

Here is the fun part. Everything is already moving all you got to do is make it pretty. Well, I suppose it isn't going to look too pretty unless I went through the trouble of texturing my objects in the first place. Ahhh, whatever. I'm still learning modeling anyway.

Technically this part is so simple it really isn't worth documenting but hey, I'm trying to cover it all right?

Now, I'm no expert at sound type stuff and I tried really hard to find sounds that matched the action. But hey, in all honesty you should probably be creating new sounds for your work anyway. I decided I would need eight speakers. Two upward hydraulic pump sounds, one for each arm. Two downward hydraulic pump sounds again, one for each arm. Two steam type sounds for each canister being released. A spark gun sound and finally some form of ambient mechanical hum.

The ambient sound loops and the remaining sounds are all setup to sound when triggered by setting a key called s_waitfortrigger to 1. Here are the names of the sounds that need scripting.

$SparkArm_JointUp
$SparkArm_JointDown
$SparkArm_Snd1
$GrabArm_JointUp
$GrabArm_JointDown
$Can1_TubeSnd
$Can2_TubeSnd



Now because the spark arm doesn't move a significant amount the joint sounds don't need to be bound. Neither do the canister tube sounds. However, since the grab arm and the spark arm move a pretty good distance we'll bind their speakers to the moving entities.

Don't worry about the binds yet though, We'll be knocking out the sounds as well as lighting and special effects all at once.

Triggering a sound is pretty simple. Really all you have to do is perform a sys.trigger(insert speaker name here) whenever you want that particular sound to fire. There is no need to clutter your map with actual trigger entities.

Now for the spark gun. I created a func_fx, brought up the entities properties, set the fx key to fx/sparks.fx, and set the restart key to 1 so that I can trigger this effect multiple times.

Next I created a light and set the key startoff to 1. I set the shader to lights/roundfire.

Again, both the light and the func_fx are triggered using the command sys.trigger(insert light or func_fx name here).

Here is the name of the light and func_fx...

$SparkArm_Light1
$SparkArm_Fx1


So, change your binds to look like this.

Code:
void setup_objects()
{

// SparkArm Binds

$SparkArm_Fx1.bind($SparkArm_Gun1);
$SparkArm_Light1.bind($SparkArm_Gun1);
$SparkArm_Snd1.bind($SparkArm_Gun1);
$SparkArm_Gun1.bind($SparkArm_Base3);
$SparkArm_Base3.bind($SparkArm_Swivel2);
$SparkArm_Swivel2.bind($SparkArm_Base2);
$SparkArm_Base2.bind($SparkArm_Swivel1);
$SparkArm_Swivel1.bind($SparkArm_Base1);

// GrabArm Binds

$GrabArm_Finger1.bind($GrabArm_Base3);
$GrabArm_Finger2.bind($GrabArm_Base3);
$GrabArm_Finger3.bind($GrabArm_Base3);
$GrabArm_Base3.bind($GrabArm_Swivel2);
$GrabArm_Swivel2.bind($GrabArm_Base2);
$GrabArm_Base2.bind($GrabArm_Swivel1);
$GrabArm_Swivel1.bind($GrabArm_Base1);
$GrabArm_JointUp.bind($GrabArm_Swivel2);
$GrabArm_JointDown.bind($GrabArm_Swivel2);
}


Add the function FireSparkGun. Give it the following code.

Code:
void FireSparkGun ()
{
sys.trigger($SparkArm_Fx1);
sys.trigger($SparkArm_Snd1);
sys.trigger($SparkArm_Light1);
sys.wait(3);
sys.trigger($SparkArm_Light1);
}


And add another entity reference to GrabCanister and PlaceCanister for the canister tube sound to be triggered. We'll call it CanTubeSnd.

Then it's just a matter of finding the right line to insert your sound triggers into. I'll save you the trouble. Here's the code.

Code:
void GrabCanister(entity CanPos, entity Can, entity CanTubeSnd)
{
$GrabArm_Base1.moveTo(CanPos);
sys.trigger($GrabArm_JointUp);
sys.waitFor($GrabArm_Base1);
$GrabArm_Finger1.rotateOnce('45 0 0');
$GrabArm_Finger2.rotateOnce('45 0 0');
$GrabArm_Finger3.rotateOnce('45 0 0');
sys.trigger($GrabArm_JointUp);
Can.move(UP, 30);
sys.trigger(CanTubeSnd);
sys.waitFor(Can);
$GrabArm_Finger1.rotateOnce('-35 0 0');
$GrabArm_Finger2.rotateOnce('-35 0 0');
$GrabArm_Finger3.rotateOnce('-35 0 0');
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Finger1);
Can.bind($GrabArm_Base3);
$GrabArm_Base3.rotateOnce('0 360 0');
sys.trigger($GrabArm_JointUp);
sys.waitFor($GrabArm_Base3);
$GrabArm_Base2.rotateOnce('0 90 0');
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Base2);
$GrabArm_Swivel2.rotateOnce('90 0 0');
sys.trigger($GrabArm_JointUp);
sys.waitFor($GrabArm_Swivel2);
$GrabArm_Base1.moveTo($Arm_Pos1);
$GrabArm_Base2.rotateOnce('0 -90 0');
sys.trigger($GrabArm_JointUp);
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Base2);
}

void PlaceCanister(entity CanPos, entity Can, entity CanTubeSnd)
{
$GrabArm_Base2.rotateOnce('0 90 0');
sys.trigger($GrabArm_JointUp);
$GrabArm_Base1.moveTo(CanPos);
sys.waitFor($GrabArm_Base2);
$GrabArm_Swivel2.rotateOnce('-90 0 0');
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Swivel2);
$GrabArm_Base3.rotateOnce('0 -360 0');
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Base3);
Can.unbind();
$GrabArm_Finger1.rotateOnce('35 0 0');
$GrabArm_Finger2.rotateOnce('35 0 0');
$GrabArm_Finger3.rotateOnce('35 0 0');
sys.trigger($GrabArm_JointUp);
sys.waitFor($GrabArm_Finger1);
Can.rotateTo('0 0 0');
Can.move(DOWN, 30);
sys.trigger(CanTubeSnd);
sys.waitFor(Can);
$GrabArm_Finger1.rotateOnce('-45 0 0');
$GrabArm_Finger2.rotateOnce('-45 0 0');
$GrabArm_Finger3.rotateOnce('-45 0 0');
$GrabArm_Base1.moveTo($Arm_Pos1);
$GrabArm_Base2.rotateTo('0 0 0');
sys.trigger($GrabArm_JointUp);
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Base1);
}


Next we'll modify PosPiecesToFire so it calls FireSparkGun and triggers its own speakers. Again here's the code.

Code:
void PosPiecesToFire ()
{
$SparkArm_Swivel2.rotateOnce('-90 0 0');
sys.trigger($SparkArm_JointUp);
sys.waitFor($SparkArm_Swivel2);
$SparkArm_Gun1.rotateOnce('-5 0 0');
sys.trigger($SparkArm_JointUp);
sys.waitFor($SparkArm_Gun1);
FireSparkGun();
$SparkArm_Base3.rotateOnce('0 120 0');
sys.trigger($SparkArm_JointDown);
sys.waitFor($SparkArm_Base3);
FireSparkGun();
$SparkArm_Base3.rotateOnce('0 120 0');
sys.trigger($SparkArm_JointDown);
sys.waitFor($SparkArm_Base3);
FireSparkGun();
$SparkArm_Base3.rotateOnce('0 120 0');
sys.trigger($SparkArm_JointDown);
$SparkArm_Gun1.rotateOnce('5 0 0');
sys.trigger($SparkArm_JointDown);
$SparkArm_Swivel2.rotateOnce('90 0 0');
sys.trigger($SparkArm_JointDown);
$SparkArm_Base3.rotateTo('0 0 0');
sys.waitFor($SparkArm_Swivel2);
}


Finally, we'll modify MechCycle to compensate for the new reference variable CanTubeSnd. Here's the code.

Code:
void MechCycle ()
{
while (1) {
GrabCanister($Can_Pos1, $Can1, $Can1_TubeSnd);
PosPiecesToFire();
PlaceCanister($Can_Pos1, $Can1, $Can1_TubeSnd);
GrabCanister($Can_Pos2, $Can2, $Can2_TubeSnd);
PosPiecesToFire();
PlaceCanister($Can_Pos2, $Can2, $Can2_TubeSnd);
}
}


And just to make you have to scroll down for an hour here is your final script.

Man its long isn't it?

Code:
////////////////////////////////////////////////////
//
// Setup binds and times etc...
//
////////////////////////////////////////////////////
void setup_objects()
{

// SparkArm Binds

$SparkArm_Fx1.bind($SparkArm_Gun1);
$SparkArm_Light1.bind($SparkArm_Gun1);
$SparkArm_Snd1.bind($SparkArm_Gun1);
$SparkArm_Gun1.bind($SparkArm_Base3);
$SparkArm_Base3.bind($SparkArm_Swivel2);
$SparkArm_Swivel2.bind($SparkArm_Base2);
$SparkArm_Base2.bind($SparkArm_Swivel1);
$SparkArm_Swivel1.bind($SparkArm_Base1);

// GrabArm Binds

$GrabArm_Finger1.bind($GrabArm_Base3);
$GrabArm_Finger2.bind($GrabArm_Base3);
$GrabArm_Finger3.bind($GrabArm_Base3);
$GrabArm_Base3.bind($GrabArm_Swivel2);
$GrabArm_Swivel2.bind($GrabArm_Base2);
$GrabArm_Base2.bind($GrabArm_Swivel1);
$GrabArm_Swivel1.bind($GrabArm_Base1);
$GrabArm_JointUp.bind($GrabArm_Swivel2);
$GrabArm_JointDown.bind($GrabArm_Swivel2);
}

////////////////////////////////////////////////////
//
// Block movement...
//
////////////////////////////////////////////////////

void FireSparkGun ()
{
sys.trigger($SparkArm_Fx1);
sys.trigger($SparkArm_Snd1);
sys.trigger($SparkArm_Light1);
sys.wait(3);
sys.trigger($SparkArm_Light1);
}

void GrabCanister(entity CanPos, entity Can, entity CanTubeSnd)
{
$GrabArm_Base1.moveTo(CanPos);
sys.trigger($GrabArm_JointUp);
sys.waitFor($GrabArm_Base1);
$GrabArm_Finger1.rotateOnce('45 0 0');
$GrabArm_Finger2.rotateOnce('45 0 0');
$GrabArm_Finger3.rotateOnce('45 0 0');
sys.trigger($GrabArm_JointUp);
Can.move(UP, 30);
sys.trigger(CanTubeSnd);
sys.waitFor(Can);
$GrabArm_Finger1.rotateOnce('-35 0 0');
$GrabArm_Finger2.rotateOnce('-35 0 0');
$GrabArm_Finger3.rotateOnce('-35 0 0');
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Finger1);
Can.bind($GrabArm_Base3);
$GrabArm_Base3.rotateOnce('0 360 0');
sys.trigger($GrabArm_JointUp);
sys.waitFor($GrabArm_Base3);
$GrabArm_Base2.rotateOnce('0 90 0');
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Base2);
$GrabArm_Swivel2.rotateOnce('90 0 0');
sys.trigger($GrabArm_JointUp);
sys.waitFor($GrabArm_Swivel2);
$GrabArm_Base1.moveTo($Arm_Pos1);
$GrabArm_Base2.rotateOnce('0 -90 0');
sys.trigger($GrabArm_JointUp);
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Base2);
}

void PlaceCanister(entity CanPos, entity Can, entity CanTubeSnd)
{
$GrabArm_Base2.rotateOnce('0 90 0');
sys.trigger($GrabArm_JointUp);
$GrabArm_Base1.moveTo(CanPos);
sys.waitFor($GrabArm_Base2);
$GrabArm_Swivel2.rotateOnce('-90 0 0');
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Swivel2);
$GrabArm_Base3.rotateOnce('0 -360 0');
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Base3);
Can.unbind();
$GrabArm_Finger1.rotateOnce('35 0 0');
$GrabArm_Finger2.rotateOnce('35 0 0');
$GrabArm_Finger3.rotateOnce('35 0 0');
sys.trigger($GrabArm_JointUp);
sys.waitFor($GrabArm_Finger1);
Can.rotateTo('0 0 0');
Can.move(DOWN, 30);
sys.trigger(CanTubeSnd);
sys.waitFor(Can);
$GrabArm_Finger1.rotateOnce('-45 0 0');
$GrabArm_Finger2.rotateOnce('-45 0 0');
$GrabArm_Finger3.rotateOnce('-45 0 0');
$GrabArm_Base1.moveTo($Arm_Pos1);
$GrabArm_Base2.rotateTo('0 0 0');
sys.trigger($GrabArm_JointUp);
sys.trigger($GrabArm_JointDown);
sys.waitFor($GrabArm_Base1);
}

void PosPiecesToFire ()
{
$SparkArm_Swivel2.rotateOnce('-90 0 0');
sys.trigger($SparkArm_JointUp);
sys.waitFor($SparkArm_Swivel2);
$SparkArm_Gun1.rotateOnce('-5 0 0');
sys.trigger($SparkArm_JointUp);
sys.waitFor($SparkArm_Gun1);
FireSparkGun();
$SparkArm_Base3.rotateOnce('0 120 0');
sys.trigger($SparkArm_JointDown);
sys.waitFor($SparkArm_Base3);
FireSparkGun();
$SparkArm_Base3.rotateOnce('0 120 0');
sys.trigger($SparkArm_JointDown);
sys.waitFor($SparkArm_Base3);
FireSparkGun();
$SparkArm_Base3.rotateOnce('0 120 0');
sys.trigger($SparkArm_JointDown);
$SparkArm_Gun1.rotateOnce('5 0 0');
sys.trigger($SparkArm_JointDown);
$SparkArm_Swivel2.rotateOnce('90 0 0');
sys.trigger($SparkArm_JointDown);
$SparkArm_Base3.rotateTo('0 0 0');
sys.waitFor($SparkArm_Swivel2);
}

void MechCycle ()
{
while (1) {
GrabCanister($Can_Pos1, $Can1, $Can1_TubeSnd);
PosPiecesToFire();
PlaceCanister($Can_Pos1, $Can1, $Can1_TubeSnd);
GrabCanister($Can_Pos2, $Can2, $Can2_TubeSnd);
PosPiecesToFire();
PlaceCanister($Can_Pos2, $Can2, $Can2_TubeSnd);
}
}


////////////////////////////////////////////////////
//
// MAIN
//
////////////////////////////////////////////////////

void main ()
{
setup_objects ();
sys.wait(3);
MechCycle();
}


Now you save your script and run the map. Ta Da! Here is the exact same script you started with... Ahem.. I mean look! All that hard work paid off!

Conclusion

That pretty much sums up what I know of scripting as a whole. I'm hoping that some of you out there will be on my level soon and we can start tackling ideas together. If not, run over this tutorial a couple of times. You should get it.

Latest Syndicated News

»
Codutility.com up and runn...
Nice, and there still using the logo and template for the screenshots, which...
Codutility.com up and runn...
dundy writes...Quote:Call of Duty modding and mapping is barly alive only a ...
Codutility.com up and runn...
Mystic writes...Quote:It seems to me the like the site is completely dead? ...
Codutility.com up and runn...
It seems to me the like the site is completely dead?

Partners & Friends

»