Inside3D tutorials.
Created By: Iestyn
eMail: idb20@hermes.cam.ac.uk
Difficulty Scale: Medium\Hard (?)


Step 1
This section covers something not used in any tutorials so far - how to call up and use specific frames from .mdl files. It's not at all difficult, you just need to learn a bit of new syntax and you're away.

Step 1
Open up *soldier.qc* and scroll down to the army_pain() function. Edit it to look like this:
//This function is called every time a soldier is hurt.
void(entity attacker, float damage)     army_pain =
{
        local float r;
        
        //This checks if the soldier's still hurting from something else.
        if (self.pain_finished > time)
                return;

        r = random();//For choosing a random pain sequence.

        if (r < 0.2)
        {
                self.pain_finished = time + 0.6;
                army_pain1 ();
                sound (self, CHAN_VOICE, "soldier/pain1.wav", 1, ATTN_NORM);
        }
        else if (r < 0.45)//Changed this slightly
        {
                self.pain_finished = time + 1.1;
                army_painb1 ();
                sound (self, CHAN_VOICE, "soldier/pain2.wav", 1, ATTN_NORM);
        }
        //Added the next else if:
        else if (r < 0.75) //Our pain sequence occurs a fraction of the time
        {
                self.pain_finished = time + 2.0;//Time enough for 20 frames.
                army_paind1 ();//This is the new pain function we'll be writing
                sound (self, CHAN_VOICE, "soldier/pain2.wav", 1, ATTN_NORM);
        }
        else
        {
                self.pain_finished = time + 1.1;
                army_painc1 ();
                sound (self, CHAN_VOICE, "soldier/pain2.wav", 1, ATTN_NORM);
        }
};

Step 2
Now we create the animation. Put the following lines into *soldier.qc* just above army_pain() and just below the army_painc*() functions (where * is one in a sequence of numbers):
void()  army_paind1     =[      $death1,        army_paind2     ] {};//Here the soldier
void()  army_paind2     =[      $death2,        army_paind3     ] {};//decides that
void()  army_paind3     =[      $death3,        army_paind4     ] {};//he's an India
void()  army_paind4     =[      $death4,        army_paind5     ] {};//rubber ball.
void()  army_paind5     =[      $death5,        army_paind6     ] {};
void()  army_paind6     =[      $death6,        army_paind7     ] {};
void()  army_paind7     =[      $death5,        army_paind8     ] {};
void()  army_paind8     =[      $death4,        army_paind9     ] {};
void()  army_paind9     =[      $death3,        army_paind10] {};
void()  army_paind10=[  $death2,        army_paind11] {};
void()  army_paind11=[  $death1,        army_paind12] {};
void()  army_paind12=[  $painc1,        army_paind13] {};//Here, he decides
void()  army_paind13=[  $painc2,        army_paind14] {};//it wasn't such
void()  army_paind14=[  $painc3,        army_paind15] {};//a good idea ;)
void()  army_paind15=[  $painc4,        army_paind16] {};
void()  army_paind16=[  $painc5,        army_paind17] {};
void()  army_paind17=[  $painc4,        army_paind18] {};
void()  army_paind18=[  $painc3,        army_paind19] {};
void()  army_paind19=[  $painc2,        army_paind20] {};
void()  army_paind20=[  $painc1,        army_run1] {};   //Soldier gets on
                                                         //with life.

Step 3
Now, you've created the "India Soldier Rubber Ball" patch. Now, how many of you can open up another .qc file, and manage to add new frames for, say the ogre? So i thought. Read on, and you'll (hopefully) understand)

Let me explain the syntax above - the square brackets before a function definition:
        name =[framenum, nexttime, nextthink] {code};
Expands to:
        name ()
        {
                self.frame=framenum;
                self.nextthink = time + nexttime;
                self.think = nextthink
                
        };      //This text copyright Id Software. (don't wanna get in trouble!)

Step 4
Think I worked that out myself? Well, sorta, but it's right there at the top of monsters.qc ripe for exploiting. In addition to what I've done above, you could add in some extra effects during the pain sequence - you'll need to add them in in the code section {} at the end of each line. You could create your own sound effects and play them there, or have the soldier fly about a bit. Whatever you like, now you know how!

Another thing to note is that if you have created NEW animation frames (with qME or QMET for example) then you need to make sure that at the top of whichever file you're editing (e.g zombie.qc if you edited the zombie.mdl file, or dragon.qc if you created your own dragon entity - damn that Id for removing it!!) these lines are included:
$cd id1/models/THEMODEL.mdl     //Where the relevant .mdl file is
$origin 0 -6 24                         //The centre of the model's bounding box
$base base                                      //Umm...?
$skin skin                                      //Which skin from the .mdl file to use?

$frame stand1 stand2 stand3 stand4 stand5 stand6 stand7 stand8

$frame death1 death2 death3 death4 death5 death6 death7 death8
$frame death9 death10

$frame deathc1 deathc2 deathc3 deathc4 deathc5 deathc6 deathc7 deathc8
$frame deathc9 deathc10 deathc11

Step 5
The three example sequences are each animation sequences. If you create a whole new animation sequence (e.g. karate-kick) then you need to create a list like these, with all the frames of the sequence in the right order. Then, you can increment the entity's frame member like this:
                entity.frame = entity.frame + 1;

...and it'll just change to the next frame in the sequence.

Well, that's about it. If you really want to learn QC, these tutorials are great, but I'd definitely recommend just reading through the original QC files from the game. They're easy to follow, for three reasons; first QuakeC is simple compared to ANSI C; second the variables and functions have names you'll recognise; three...you all play Quake too much, so you're bound to recognise what all the functions actually do in the game.
If you have any questions or any ideas you don't quite know how to implement, drop me a line.