rich_is_bored@Posted: Sat Aug 07, 2004 5:40 pm :
Level Scripting Tutorial 2

Introduction

Welcome to the second in a series of three Scripting Tutorials.

In the last tutorial I broke down scripting to the most basic elements. I explained the concept of programming and how a computer interprets code. I also included a list of commands thats syntax and function are known. And finally I walked you through creating a simple spinning box.

Now you should already have a pretty good idea of how to script, if not program in general. You now know how to make a spinning box but who wants to put something dumb like that in their levels. Not me, and we are not going to continue where the other tutorial left off.

In this tutorial we will begin making a mechanical arm. To save you the time and trouble of manually creating these moving parts I have included everything you will need in the zip in the link below. I am sparing you the trouble of learning a 3D modeling package which by the way is not easy when you are a complete newbie like myself.

FILE IS NO LONGER AVAILABLE

Eventually, I should get around to the third installment of these tutorials where we will take the knowledge and quite possibly the mechanical arm from this tutorial and create an assembly line. Um... it might take awhile for me to finish the advanced tutorial.

Creating Objects: Modeling Package VS. D3Radient (Part 1)

This will probably end up turning in to some big debate as to which method to use. Some may find creating objects in a 3rd party modeling package easier while others will think D3Radient is the way to go. Here is a list of pros and cons to each method.

If this all sounds like chinese to you now just keep reading and I'll get into this more at the end of the tutorial.

Intermediate: Creating a Mechanical Arm

Before you can run you have to learn to walk. We were crawling around in the last tutorial and hopefully by the end of this one you should be walking around on two feet.

I am trying to streamline this tutorial so that we can jump right into scripting. So, extract the zip to [Your Doom 3 Directory]\base and make sure you allow it to extract to the subfolders. You will have a precompiled map, all the separate pieces of the arm, and the appropriate material file. Please excuse the poor texturing as I didn't feel it was nessecary to model I high poly version and create a normalmap.

Now let me explain what I have already done for you.

I have created a simple map. It is one room with 6 func_movers, a light, and a player starting point. This map uses the "same name" method so make sure you name and place your script appropriately. The "model" key/value pairs of all six func_movers have been set to the appropriate models in the model directory. The func_movers were moved and rotated to the positions which they should be bound.

Note: You do not have to model 3D objects in external programs. You can create these from within D3Radient however there will be slight differences. I go into detail about the changes nessecary at the end of this tutorial.

The only thing I didn't do for you was give you the script itself. You'll be writing that up as we go.

So let's get to making a script so you can see this cool arm and start moving it.

First open editpad... or notepad if your stubborn. We are going to save a basic script just so we can load the map in the background. Copy the following into your text editor.

Code:
////////////////////////////////////////////////////
//
//   Setup binds and times etc...
//
////////////////////////////////////////////////////

void setup_objects()
{
}

////////////////////////////////////////////////////
//
//   Mechanical Movement...
//
////////////////////////////////////////////////////

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

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


Now save this code as rich_scripting_tutorial_2.script. You did remeber that we're going to save this script to the maps folder right? Good, now we have a basic script that runs but does nothing visual.

So... Load Doom 3 and type "map rich_scripting_tutorial_2" in the console. Switch to windowed mode so we can ALT + TAB between the game and text editor.

What you should see is a simple square room with a mechanical arm hanging from the ceiling. The first thing we will need to do is attatch all these objects together so that they are in a child-parent relationship.

Let me explain child-parent relationships real quick.

Do you remember in the last tutorial how we attatched a light to the cube and watched how the light inhereted all the movements of the cube? That was a child-parent relationship. The light was a child to the cube. The cube was a parent to the light.

So how is this going to play out in this tutorial? Well this arm is composed of several pieces which all move independantly. Here are the pieces and the names I assigned each entity in the editor.

  1. The base of the arm. (arm_base)
  2. The shaft of the arm. (arm_shaft)
  3. The rotating cuff of the arm. (finger_joint)
  4. The fingers of the arm. (finger_1...2...3)

If I were to rotate the base of the arm, I would expect all the parts to rotate with it. If I were to bend the shaft of the arm, I would expect all the parts except the base to move with it. If I were to rotate the cuff, I would expect the fingers to rotate with it. And the fingers... well they have nothing attached to them at least yet. We'll attatch things to the fingers in the next tutorial.

So we need to add some bind commands to our setup_objects function. Add this code.

Code:
   $arm_shaft.bind($arm_base);
   $finger_joint.bind($arm_shaft);
   $finger_1.bind($finger_joint);
   $finger_2.bind($finger_joint);
   $finger_3.bind($finger_joint);


Now the pieces are bound and I could move the entire arm as one piece just by moving the base. Let's create a test funciton to do so.

Add the following code under the mechanical movements section.

Code:
void rotate_base_90_CW ()
{
   $arm_base.rotateOnce('0 90 0');
   sys.print ("rotating base 90 degrees CW\n");
   sys.waitFor($arm_base);
}


This function will tell the base to rotate once 90 degrees clockwise. Add a call to rotate_base_90_CW to the main function and you are ready to test. Check to make sure your code looks like this and save.

Code:
////////////////////////////////////////////////////
//
//   Setup binds and times etc...
//
////////////////////////////////////////////////////
void setup_objects()
{
   $arm_shaft.bind($arm_base);
   $finger_joint.bind($arm_shaft);
   $finger_1.bind($finger_joint);
   $finger_2.bind($finger_joint);
   $finger_3.bind($finger_joint);
}

////////////////////////////////////////////////////


//
//   Mechanical Movement...
//
////////////////////////////////////////////////////

void rotate_base_90_CW ()
{
   $arm_base.rotateOnce('0 90 0');
   sys.print ("rotating base 90 degrees CW\n");
   sys.waitFor($arm_base);
}

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

void main ()
{
   setup_objects ();
   sys.wait (5);
   rotate_base_90_CW ();
}


Now reload the map. After a five second delay the entire arm should rotate and stop.

Now we have tested the movement of the base. Let's add functions for the rest of the parts.

Add this code to the mechanical movement section.

Code:
void bend_arm_45_FW ()
{
   $arm_shaft.rotateOnce('45 0 0');
   sys.print ("bending arm 45 degrees FW\n");
   sys.waitFor($arm_shaft);
}

void rotate_fingers_1800_CW ()
{
   $finger_joint.rotateOnce('0 1800 0');
   sys.print ("rotating fingers 1800 degrees CW\n");
   sys.waitFor($finger_joint);
}

void finger_release ()
{
   $finger_1.rotateOnce('45 0 0');
   $finger_2.rotateOnce('45 0 0');
   $finger_3.rotateOnce('45 0 0');
   sys.print ("releasing finger grapple\n");
   sys.waitFor($finger_1);
   sys.waitFor($finger_2);
   sys.waitFor($finger_3);
}


Now add these calls to the main function.

Code:
bend_arm_45_FW ();
rotate_fingers_1800_CW ();
finger_release ();


Again check to see that your code looks like this and save.

Code:
////////////////////////////////////////////////////
//
//   Setup binds and times etc...
//
////////////////////////////////////////////////////
void setup_objects()
{
   $arm_shaft.bind($arm_base);
   $finger_joint.bind($arm_shaft);
   $finger_1.bind($finger_joint);
   $finger_2.bind($finger_joint);
   $finger_3.bind($finger_joint);
}

////////////////////////////////////////////////////
//
//   Mechanical Movement...
//
////////////////////////////////////////////////////

void rotate_base_90_CW ()
{
   $arm_base.rotateOnce('0 90 0');
   sys.print ("rotating base 90 degrees CW\n");
   sys.waitFor($arm_base);
}

void bend_arm_45_FW ()
{
   $arm_shaft.rotateOnce('45 0 0');
   sys.print ("bending arm 45 degrees FW\n");
   sys.waitFor($arm_shaft);
}

void rotate_fingers_1800_CW ()
{
   $finger_joint.rotateOnce('0 1800 0');
   sys.print ("rotating fingers 1800 degrees CW\n");
   sys.waitFor($finger_joint);
}

void finger_release ()
{
   $finger_1.rotateOnce('45 0 0');
   $finger_2.rotateOnce('45 0 0');
   $finger_3.rotateOnce('45 0 0');
   sys.print ("releasing finger grapple\n");
   sys.waitFor($finger_1);
   sys.waitFor($finger_2);
   sys.waitFor($finger_3);
}

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

void main ()
{
   setup_objects ();
   sys.wait (5);
   rotate_base_90_CW ();
   bend_arm_45_FW ();
   rotate_fingers_1800_CW ();
   finger_release ();

}


Now again, reload the map in game and watch as the arm rotates, bends, the cuff rotates, and the fingers extend. This is getting impressive.

Now let's add some more functions so we have a little more control over the arms movement.

Add the following code to the mechanical movement section.

Code:
void rotate_base_90_CCW ()
{
   $arm_base.rotateOnce('0 -90 0');
   sys.print ("rotating base 90 degrees CCW\n");
   sys.waitFor($arm_base);
}

void bend_arm_45_BW ()
{
   $arm_shaft.rotateOnce('-45 0 0');
   sys.print ("bending arm 45 degrees BW\n");
   sys.waitFor($arm_shaft);
}

void rotate_fingers_1800_CCW ()
{
   $finger_joint.rotateOnce('0 -1800 0');
   sys.print ("rotating fingers 1800 degrees CCW\n");
   sys.waitFor($finger_joint);
}

void finger_grasp ()
{
   $finger_1.rotateOnce('-45 0 0');
   $finger_2.rotateOnce('-45 0 0');
   $finger_3.rotateOnce('-45 0 0');
   sys.print ("contracting finger grapple\n");
   sys.waitFor($finger_1);
   sys.waitFor($finger_2);
   sys.waitFor($finger_3);
}


Now be creative here and try your own combination of movements by adding, changing, and deleting function calls from the main function. Save the script and reload the map in game.

You should be able to create any kind of motion desireable. What you will notice is that the arm is not moving very fluidly. Let's change that. This time it won't take too much code.

Add these lines to the setup_objects function.

Code:
   $arm_base.time (.5);   
   $arm_shaft.time (.3);   
   $finger_joint.time (1);   
   $finger_1.time (.3);   
   $finger_2.time (.3);   
   $finger_3.time (.3);   
   $arm_base.accelTime (.3);   
   $arm_shaft.accelTime (.3);   
   $finger_joint.accelTime (.3);   
   $finger_1.accelTime (.3);   
   $finger_2.accelTime (.3);   
   $finger_3.accelTime (.3);
   $arm_base.decelTime (.3);   
   $arm_shaft.decelTime (.3);   
   $finger_joint.decelTime (.3);   
   $finger_1.decelTime (.3);   
   $finger_2.decelTime (.3);   
   $finger_3.decelTime (.3);


These lines change the speed of each part, and add an amount of acceleration and deceleration. Feel free to adjust these values and experiment.

Check your code to see that looks similar to this and save.

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

   $arm_shaft.bind($arm_base);
   $finger_joint.bind($arm_shaft);
   $finger_1.bind($finger_joint);
   $finger_2.bind($finger_joint);
   $finger_3.bind($finger_joint);
   $arm_base.time (.5);   
   $arm_shaft.time (.3);   
   $finger_joint.time (1);   
   $finger_1.time (.3);   
   $finger_2.time (.3);   
   $finger_3.time (.3);   
   $arm_base.accelTime (.3);   
   $arm_shaft.accelTime (.3);   
   $finger_joint.accelTime (.3);   
   $finger_1.accelTime (.3);   
   $finger_2.accelTime (.3);   
   $finger_3.accelTime (.3);
   $arm_base.decelTime (.3);   
   $arm_shaft.decelTime (.3);   
   $finger_joint.decelTime (.3);   
   $finger_1.decelTime (.3);   
   $finger_2.decelTime (.3);   
   $finger_3.decelTime (.3);
}



////////////////////////////////////////////////////
//
//   Mechanical Movement...
//
////////////////////////////////////////////////////

void rotate_base_90_CW ()
{
   $arm_base.rotateOnce('0 90 0');
   sys.print ("rotating base 90 degrees CW\n");
   sys.waitFor($arm_base);
}

void rotate_base_90_CCW ()
{
   $arm_base.rotateOnce('0 -90 0');
   sys.print ("rotating base 90 degrees CCW\n");
   sys.waitFor($arm_base);
}

void bend_arm_45_FW ()
{
   $arm_shaft.rotateOnce('45 0 0');

   sys.print ("bending arm 45 degrees FW\n");
   sys.waitFor($arm_shaft);
}

void bend_arm_45_BW ()
{
   $arm_shaft.rotateOnce('-45 0 0');
   sys.print ("bending arm 45 degrees BW\n");
   sys.waitFor($arm_shaft);
}

void rotate_fingers_1800_CW ()
{
   $finger_joint.rotateOnce('0 1800 0');
   sys.print ("rotating fingers 1800 degrees CW\n");
   sys.waitFor($finger_joint);
}

void rotate_fingers_1800_CCW ()
{
   $finger_joint.rotateOnce('0 -1800 0');
   sys.print ("rotating fingers 1800 degrees CCW\n");
   sys.waitFor($finger_joint);
}

void finger_release ()
{
   $finger_1.rotateOnce('45 0 0');
   $finger_2.rotateOnce('45 0 0');
   $finger_3.rotateOnce('45 0 0');
   sys.print ("releasing finger grapple\n");
   sys.waitFor($finger_1);
   sys.waitFor($finger_2);
   sys.waitFor($finger_3);
}

void finger_grasp ()
{
   $finger_1.rotateOnce('-45 0 0');
   $finger_2.rotateOnce('-45 0 0');
   $finger_3.rotateOnce('-45 0 0');
   sys.print ("contracting finger grapple\n");
   sys.waitFor($finger_1);
   sys.waitFor($finger_2);
   sys.waitFor($finger_3);
}

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

void main ()
{
   setup_objects ();
   sys.wait (5);
   rotate_base_90_CW ();
   finger_release ();
   bend_arm_45_FW ();
   rotate_fingers_1800_CW ();
}


Now the arm moves more fluid and looks realistic. You should have a fully functional mechanical arm behaving how you want it. This should provide a good reference for constructing just about anything.

Conclusion

Hey, were done! That was a lot of copying and pasting. :)

Hopefully you understand what you were doing. If not just bombard me with questions like last time and I will try to answer them.

Don't stop reading here. There is one last section that should answer most of your questions.

Creating Objects: Modeling Package VS. D3Radient (Part 2)

Some of you may have noticed that the fingers all rotate on the X axis yet, they move in different directions. How is this possible? :?

Well, there is some quirkiness related to the way you script objects depending on whether they are models or brushes.

Let's talk about some of the pros and cons listed earlier. This is pretty difficult to explain in words alone so I busted out photoshop and make some simple diagrams to help things along.

First, take a look at the picture below.

Image

This is the hand portion of the mechanical arm. It is comprised of Finger_Joint.lwo and three instances of Finger.lwo.

Notice how each instance of finger.lwo is rotated. Notice also that in each instance, the X axis is running parallel to the connecting rod. This is why I can use the command ...

Code:
finger_X.rotateOnce('45 0 0');


... on all three fingers and they will rotate away from the center of Finger_Joint.lwo.

Now, whether I use a modeling package or D3Radient to create these objects my goal is the same. I want my objects, and their axises to be oriented like the picture above before I start animating it. The problem is that the steps involved are radically different because the game treats brushes and models differently.

Model Scripting Setup

If you use a 3rd party modeling package to create your objects, you can rotate your objects into postition in D3Radient and the objects' pivot points rotate with them. You can save your map with your objects in place and immediately begin scripting their animations.


Brush Scripting Setup

If I create an object in D3Radient and make it an entity, it won't matter how I move or rotate it. The pivot point will not rotate. The Z axis for that object will always run up and down. The X axis for that object will always run east to west. The Y axis for that object will always run north to south.

The only time the pivot point actually rotates is when you rotate the objects with a script. In order to set things up like the arm in this tutorial, when you're working with brushes, you have build the objects in line with the axis you plan to use in your animation, save your map with them in that position, and then assemble the pieces using a portion of your script prior to actually animating your scene.


More on Each Methods Differences

Look at the picture below.

Image


Here is Finger.lwo. Notice that when I created this object I made certain that the X axis was running through the connecting rod. This makes certain that when the object is rotated around the X axis in a script, it rotates around the connecting rod.

There are some more tricks involved. Also notice that the X, Y, and Z axis all meet at the center of the connecting rod. This is where the origin or "center point" will be placed when the object is loaded in D3Radient. So, if I were to rotate in any other direction (not that I would want to) it would rotate around the corresponding axis where the axis runs through the object.

The origin is also the point used when you move your object. Let's say I told the finger to move to 342, 23, 975 (again, not that I would want to). The object would move until the origin was resting at 342, 23, 975.

Now, Lets say I wanted to make this same shape in D3Radient. Again, I would have to make the X axis run through the connecting rod.

I would have to open the entities properties and type in a numerical value for the origin key/value pair.

After doing this for each part I have three identical fingers. But I have to make sure they all are in line with the X axis. How am I going to make my arm look like the first picture and have all the fingers in line? :?

Well, I make the fingers in line and compile the map. Now before the player even gets the opportunity to start moving around in my map, I have to quickly move these fingers into their correct positions with a portion of my script.

This requires I adjust the time of each finger so the objects move incredibly fast. Then I can move and rotate them into postition. Then set all those time values to the values I intend to use during animation. Finally, I can begin animating them.

That pretty much sums it up. Don't get it? Post your questions here please. I want to make this the equivalent of a "scripting for dummies" book. :D



Prime@Posted: Sat Aug 07, 2004 7:12 pm :
:D

*applauds at your series*

Very well done .. I'm not such a total newbie at scripting ( as I've messed with D3's weapons a ton of times cause its the only thing I know how to do ) but this seems like a short shot for me :).

Great work.



Hell Byte@Posted: Wed Aug 11, 2004 5:04 am :
Hm, so where do tell the editor to look for the material file for the model?



BNA!@Posted: Wed Aug 11, 2004 6:29 am :
syphlitix wrote:
Hm, so where do tell the editor to look for the material file for the model?


You assign the surface name in LightWave.



Hell Byte@Posted: Wed Aug 11, 2004 6:31 am :
Hm, im not using lightwave, just doing a conversion. The converter writes the material data to the actual .lwo file i think, would this not work?



BNA!@Posted: Wed Aug 11, 2004 6:38 am :
syphlitix wrote:
Hm, im not using lightwave, just doing a conversion. The converter writes the material data to the actual .lwo file i think, would this not work?


It's only a surface name, no material data or such - the surface name is just the same as a shader name with full path like:
"textures/base/wall/wall1"



Hell Byte@Posted: Wed Aug 11, 2004 7:04 am :
Ah, ok. Ill check my plugin, maybe the material didnt get imported along with the obj.

Thanks though!



ismodred@Posted: Wed Aug 11, 2004 11:09 pm :
hmmm the models aren't working for me.

i extracted to the doom3/base/
so i have

doom3/base/maps/rich_scripting_tutorial_2.cm
doom3/base/maps/rich_scripting_tutorial_2.map
doom3/base/maps/rich_scripting_tutorial_2.proc

doom3/base/models/rich_scripting_tutorials_arm_base.lwo
doom3/base/models/rich_scripting_tutorials_arm_shaft.lwo
doom3/base/models/rich_scripting_tutorials_finger.lwo
doom3/base/models/rich_scripting_tutorials_finger_joint.lwo
doom3/base/models/rich_scripting_tutorials_grey.tga

doom3/base/materials/rich_scripting_tutorials.mtr


and added
doom3/base/maps/rich_scripting_tutorial_2.script


i open the editor and load the .map file

all of the arm parts are represented as black blocks.
if i load the map, they are still just black blocks. they rotate and all, but just blocks.

possible reasons? solutions?


edit.... goofy freaking program. erased all extracted files.. then re-extracted.. no difference.

closed out d3, restarted and it all worked right.

goofy!!



wviperw@Posted: Sat Aug 14, 2004 10:49 pm :
Rich: As much as I liked your tut, I think it breaks D3 MP. The .zip file included with the tut puts a "rich_scripting_tutorials.mtr" file in the main "materials" directory. It seems that whenever this .mtr file is in that directory, it royally screws up MP (especially through ASE). When it gets to "connecting to server" it will kick me back to Windows. As soon as I either removed your .mtr file, or moved it into a subfolder (e.g. - "materials\rich\..."), it fixed it.

Could somebody please confirm this on their D3 install?



rich_is_bored@Posted: Mon Aug 23, 2004 1:58 am :
I hope that's not the case but even if it is it's nothing that deleting the tutorial won't fix right? :?

Anyway, I'd put time into fixing the problem but I'm really pre-occupied with the aftermath of hurricane Charley. If you can confirm the problem, I'll work on the issue when things settle down here.

On a side note, I've changed the link above... again. :(

It seems that I'm never going to find a permanent place to host these damn tutorial files.



Strife@Posted: Tue Aug 24, 2004 2:44 am :
ismodred wrote:
edit.... goofy freaking program. erased all extracted files.. then re-extracted.. no difference.

closed out d3, restarted and it all worked right.

goofy!!


The same exact thing happened to me. Is there something that causes this, as this would become a pain in the arse if I have to do the same thing every time for similar procedures.



rich_is_bored@Posted: Tue Aug 24, 2004 5:24 am :
Are you guys extracting the files with Doom 3 running in the background?

It's the only thing I can think of as Doom 3 has to load the custom content before it can display it.



SonicClang@Posted: Sat Sep 04, 2004 5:08 pm :
I'm getting black blocks instead of models as well.

I exctracted to base\maps\script2\... and kept file structure intact from the .zip file. The wall texture "grey.tga" shows up just fine, but no models.



SonicClang@Posted: Sat Sep 04, 2004 5:12 pm :
Easy fix...

I just have to insert "maps/script2/" in front of the path you already typed in for the path of the model. Now when I reload the map in the editor it shows up correctly.

Still all black though. Is there also a path for the textures of the models?



SonicClang@Posted: Sat Sep 04, 2004 6:11 pm :
Ok Rich,

A couple problems with my script.

1) The arm does the first few movements, but then doesn't retract. It gets all the way to unlreleasing the grapple, but doesn't come back to the beginning. I've even copied all your text into my script file and it still doesn't come bak.

2) No matter what it doesn't seem as though adjusting the .time and the .accelTime numbers does anything. The arm still flails around very jumpy and I can't smooth it out. When it spins the finger joint around 1800 degrees, that movment is very jumpy, and then goes directly into opening the fingers. I'd like to have a nice smooth accel time and have it spin for 5 seconds. So I put this in the script:

$finger_joint.time (5);
and
$finger_joint.accelTime (3);

As far as I can tell that should force the whole movment of the joint to last 5 seconds, with a 3 second accel time. Well, it's still lasting 1 second instead of 5.

3) Maybe you cover this in the third tut, but how do I put a pause between movements? I'm a mechanical engineer, and I've never seen a machine go from one movement to the next so quickly. I understand this is just a tutorial, but is there a way to pause before going on? If this is in your next tutorial just tell to read that, which I will anyway right now :D I really am learning a lot by typing all this code in.

And still the models are all black.

EDIT: Ok, I realized my error with the .time and .accelTime numbers. I put them under the main section instead of the setup section. MY BAD!!! :D



DCBKNC1701@Posted: Sat Sep 04, 2004 6:17 pm :
to pause,you put wait( 3 ); for example,which would make a wait of 3



SonicClang@Posted: Sat Sep 04, 2004 6:28 pm :
Ok I think I figured out everything I had a question on in my last post. Except for the models still being black.

I guess I didn't realize I had to call the reverse actions at the end of the code. Strange that wasn't shown in the tut. I must have missed something, I'll read it again.



rich_is_bored@Posted: Sat Sep 04, 2004 6:40 pm :
If you noticed, almost this entire tutorial tries to step away from the traditional "step by step" method. The goal here is to get you to start thinking about how you'd write up the script yourself.

Anyway, if you want to add pauses by using the wait command then just insert it wherever you think there should be a pause.

For example...

Code:
void main ()
{
   setup_objects ();
   sys.wait (5);
   rotate_base_90_CW ();
   bend_arm_45_FW ();
   rotate_fingers_1800_CW ();
   finger_release ();

}


becomes...

Code:
void main ()
{
   setup_objects ();
   sys.wait (5);
   rotate_base_90_CW ();
   sys.wait (5);
   bend_arm_45_FW ();
   sys.wait (5);
   rotate_fingers_1800_CW ();
   sys.wait (5);
   finger_release ();
}



SonicClang@Posted: Sat Sep 04, 2004 6:46 pm :
Rich, I've already started playing around with the code. I know what you mean about creating code by myself. I'm playing around with pauses, acceltime and all that stuff. I'm going to try creating some stuff myself after playing around with the existing code.

I'll wait a little longer next time before posting stupid questions! :D



rich_is_bored@Posted: Tue Oct 18, 2005 7:48 am :
Link updated...

http://www.pcgamemods.com/mod/6920.html