Using/Adding all Hknight magic attack animations [TUT]

Discuss programming in the QuakeC language.
Post Reply
Seven
Posts: 301
Joined: Sat Oct 06, 2007 8:49 pm
Location: Germany

Using/Adding all Hknight magic attack animations [TUT]

Post by Seven »

Hello,

First of all: I wish you all a Happy and healthy new year.

I always asked myself, why ID1 did not use all 3 magic attack animations for the Hellknight.
The animations look very nice and are available/present in the model.
It is a pity that only "hknight_magiccXX" is used.

So I searched for a way to make use of all of them (randomly).

I know, my QC skills are not good, so I am sure there are other ways to do it.
If this topic has already been discussed before, I am sorry for disturbing.

1.) Open "hknight.qc"
Search for "monster_hell_knight ()" function (at the bottom) of the file.
Replace the line

Code: Select all

self.th_missile = hknight_magicc1;
with

Code: Select all

self.th_missile = hknight_random_magic;		// adds random magic attack animation
//  self.th_missile = hknight_magicc1;
2.) Add this new function directly before "monster_hell_knight ()":

Code: Select all

void() hknight_random_magic =		// adds random magic attack animation
{						// in original ID1, only "hknight_magiccxx" is used
local float zufall;
	zufall = random();
		if (zufall > 0.66)
			self.th_missile = hknight_magica1;
		else if (zufall < 0.34)
			self.th_missile = hknight_magicb1;
		else
			self.th_missile = hknight_magicc1;	
};
3.) Add this line (quite at the beginning of hknight.qc) below the frame declarations:

Code: Select all

void() hknight_random_magic;
4.) Now, to make EACH magic attack a random animation, we need to add 3 more lines.
At the end of each magic attack animation sequence, we need to call "hknight_random_magic ()" again.
So add the call after all 3 magic atack animations:

Code: Select all

...
void()	hknight_magica14 =[	$magica14,	hknight_run1	] {ai_face();
hknight_random_magic();};

Code: Select all

...
void()	hknight_magicb13 =[	$magicb13,	hknight_run1] {ai_face();
hknight_random_magic();};

Code: Select all

...
void()	hknight_magicc11 =[	$magicc11,	hknight_run1] {hknight_shot(3);
hknight_random_magic();};
That is it.
Now each individual hknight in a map will use random magic-attack-animation, until he is dead.

Sorry again, if this is an old topic.


=====================================

Small addon:

If you use DarkPlaces and want to make the hellknight visually charging its magic attack,
you can make use of the dpextensions feature: DP_ENT_COLORMOD

Just an example for 1st magic attack:

Code: Select all

void()	hknight_magicb1 =[	$magicb1,	hknight_magicb2	] {ai_face();
self.colormod = '1.5 1 1';};
void()	hknight_magicb2 =[	$magicb2,	hknight_magicb3	] {ai_face();
self.colormod = '2 1 1';};
void()	hknight_magicb3 =[	$magicb3,	hknight_magicb4	] {ai_face();
self.colormod = '2.5 1 1';};
void()	hknight_magicb4 =[	$magicb4,	hknight_magicb5	] {ai_face();
self.colormod = '3 1 1';};
void()	hknight_magicb5 =[	$magicb5,	hknight_magicb6	] {ai_face();
self.colormod = '3.5 1 1';};
void()	hknight_magicb6 =[	$magicb6,	hknight_magicb7	] {ai_face();
self.colormod = '4 1 1';};
void()	hknight_magicb7 =[	$magicb7,	hknight_magicb8	] {hknight_shot(-2);};
void()	hknight_magicb8 =[	$magicb8,	hknight_magicb9	] {hknight_shot(-1);};
void()	hknight_magicb9 =[	$magicb9,	hknight_magicb10] {hknight_shot(0);};
void()	hknight_magicb10 =[	$magicb10,	hknight_magicb11] {hknight_shot(1);};
void()	hknight_magicb11 =[	$magicb11,	hknight_magicb12] {hknight_shot(2);};
void()	hknight_magicb12 =[	$magicb12,	hknight_magicb13] {hknight_shot(3);
self.colormod = '2 1 1';};
void()	hknight_magicb13 =[	$magicb13,	hknight_run1] {ai_face();
self.colormod = '1 1 1';
hknight_random_magic();};
Do this for all 3 magic-attack-animations if you want.
This will make his body slowly rise glowing red, before he shoots his missiles and turn normal again after his attack.
It looks really nice in-game.

Best wishes,
Seven
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by toneddu2000 »

Great tutorial Seven! Thanks a lot for sharing! Just two questions:
1) is it possible to use DP_ENT_COLORMOD with non-per-frame animations?
I explain: I use iqm and I had to rewrite the part of animation frames (I don't use the $frame convention but I use the self. frame 1, self. frame++ structure).
In this case how can I increase the "redness" of the entity during frame interpolation?
2) I'm creating a scratch qc and I can't figure out the th_.... function (for example th_missile,th_walk, and so on). I know they are the "Think actions of an entity (player/monster)" but , are they hard-coded? Should I declare the th_pain for example and then create a monster_pain function to "link" to it?

Thanks
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Seven
Posts: 301
Joined: Sat Oct 06, 2007 8:49 pm
Location: Germany

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by Seven »

Hello toneddu2000,

Yes, there are 2 ways to code animation as far as I know.
- the classic way (with $frame)
- the alternative way with a "loop"-like count, that adds "1" each loop.

I never tried it, cause I always use the "classic" way, but this *might* work:
Just an example taken out of thin air:

Code: Select all

void() test =
{
   self.frame = self.frame + 1;
   self.colormod = self.colormod + '0.5 0 0';  // this might work if colormod is handled like a regular vector, but I have my doubts
    if (self.frame == 8)
                return;    // or do whatever you want
     self.nextthink = time + 0.1;
};

Regarding your point 2.)
Lets take a look at the soldier.qc:

Code: Select all

	self.th_stand = army_stand1;
	self.th_walk = army_walk1;
	self.th_run = army_run1;
	self.th_missile = army_atk1;
	self.th_pain = army_pain;
	self.th_die = army_die;
You will find the function for ALL "self.th_"´s without a "1" at the end inside the .qc file itself.
So it is clear, that these are handled via QC.
But there are NO real functions for "self.th_"´s with a "1" at the end.
These are just animation-frame functions.
So these must be handled via engine. That is at least my understanding.
But my knowledge is poor.

I think there are much better people here at inside3d to explain the difference and how it works.
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by toneddu2000 »

for point 1: ok I'll try it, thanks. I'm not 100% sure that red glow will "fade in" and then "fade out"with that method but I could be wrong
for point 2: well, inside army_stand1 function (besides the frames function) there's the ai_stand function that (afaik) is called by ai.qc and it handles all the ai stuff

Well in the next 4 days I won't have a pc, but once back home I'll try to dig the whole question.

Thanks again Seven!!
Meadow Fun!! - my first commercial game, made with FTEQW game engine
sp4x0r
Posts: 16
Joined: Mon Jul 21, 2008 11:48 am

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by sp4x0r »

(disclaimer: I've been wrong so many times before, so we can assume that the trend continues with this post)

With regard to the ".th_" references, I don't think they're hard coded, pretty sure it's all in QC. My understanding is that the ".th_" part is just a naming convention. In defs.qc you have declarations like:

Code: Select all

.void()		th_stand;
.void()		th_walk;
.void()		th_run;
.void()		th_missile;
.void()		th_melee;
.void(entity attacker, float damage)		th_pain;
.void()		th_die;
So every entity will have these ".th_" functions that can be called for it. It's basically so that you can have one set of ai code for all monsters that calls th_run, th_pain, etc., without caring which particular monster the ai code is running for. The value you set is the name of any QC function you want. If you've written a function called "soldier_custom_pain()" then you can set for the soldier:

Code: Select all

self.th_pain = soldier_custom_pain;
and the ai code will run that instead whenever the soldier gets hurt, leaving other monsters' behaviour untouched. Of course if soldier_custom_pain() doesn't trigger some animations, things can look weird (e.g. the monster will stay stuck on one frame until it's told to do something else).
But there are NO real functions for "self.th_"´s with a "1" at the end.
The functions that deal with frames and animations are functions just like any other, it's just that they tend to be formatted differently for readability. Generally if there's only one animation for one type of "thought" (e.g. th_run) then the vanilla QC points to the function that triggers the first frame of that animation e.g. monstername_run1(). If there are multiple animations (e.g. th_pain, _th_death) then there is usually an unnumbered function that decides which animation gets run. If you look at the code for army_pain() you'll see that it randomly decides to call army_pain1(), army_painb1() or army_painc1(). If you were just going to have one pain animation for the soldier you could set the .th_pain value to "army_pain1" and that's all that would ever happen when you shoot the soldier.
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by goldenboy »

You can even add new th_* routines, to extend the monster ai. This is all driven from ai.qc. Sou you could make a self.th_charge, or whatever.
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by toneddu2000 »

Now I understood. Thanks a lot sp4x0r!! With the example of army_pain() instead of army_pain1 a light bulb appeared over my head!And thanks goldenboy too! I'll try to create my on th_functions imediately!

Just a noob question again: why sometimes I find function_name(); and other time I find function_name; what's the difference with () and without it? Some time ago I put () in a function, the compiler compiled everything but then quakec crashed, after removing the () the game has returned to work.
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by Spike »

() in means 'this is a function'. no () means this is a regular variable.
if there's no () then chances are its being stored in some field for later use.
so 'self.fred = foo();' calls foo, and stores the return value in self.fred.
'self.fred = foo;' on the other hand stores foo in self.fred... if they're functions you can then do 'self.fred()' to invoke 'foo()'.
which is how the ai code runs each monster without really caring which monster it is. those th_foo functions are simply nice references to the function to use when the monster needs to start running/walking/etc. just a nice and simple extra layer of indirection.
there's nothing engine-specific with them, you can add others if you update the ai to support those extras, of course.
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by toneddu2000 »

Thanks a lot Spike, kind and precise as always
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Seven
Posts: 301
Joined: Sat Oct 06, 2007 8:49 pm
Location: Germany

Post by Seven »

Dear all,

I didnt want to open a new thread, because my question is related to the above discussed topic with:
self.th_*

What I do not understand is the difference in:
self.th_pain

Why different monsters have different function-formats ?
Example:
knight:
self.th_pain = knight_pain;
void(entity attacker, float damage) knight_pain =

demon:
self.th_pain = demon1_pain;
void(entity attacker, float damage) demon1_pain =

dog:
self.th_pain = dog_pain;
void() dog_pain =


1.) Why does the dog function does not have the variables: attacker and damage, while demon has them ?
Is it inconsequent code from ID (because even in knight_pain the 2 variables are not used ! ) ?
2.) Where is the call for the monsters pain function ?
Where I could see the usage of the variables. Is it engine sided ?

Thank you for your answer.
Last edited by Seven on Sun Nov 18, 2012 12:28 pm, edited 1 time in total.
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by Spike »

this logic is pure qc, not the engine (ignoring the fact that the vm is part of the engine and that qc depends upon the vm...).
it is safe to call a qc function with more arguments than it accepts. the extra arguments are simply discarded. if the dog doesn't care who's hitting it or how much damage its taking then there is no issue with it not having any arguments specified.
the inverse is not true. never omit arguments if the function that you are calling will read/use them.
your qcc should probably warn on the assignment, but hey, qccs are basically all useless in at least one way. :)
Seven
Posts: 301
Joined: Sat Oct 06, 2007 8:49 pm
Location: Germany

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by Seven »

Thank you Spike,

I still dont know why id-software used different pain functions (without even using the arguments in most cases).
Yes, a warning is what your qcc might come up with.
I guess even id-coders are only humans... :)

What I still do not know is where the *_pain calls are ?
I dont find them in any .qc file (also not ai.qc).
I mean, a function is useless if it is never called, right ?
But the *_pain functions must be called from somewhere...
So where is it called from ? :roll:
The fact, that I do not find the calling function made me think that the engine takes care of it.

I *might* need a special/modified *_pain call function for the new spider monster I am working on,
or I must go with global .floats.
That is why I need your help to point me to the calling function.

Thank you very much.
Seven
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by Spike »

bottom of T_Damage in combat.qc
Seven
Posts: 301
Joined: Sat Oct 06, 2007 8:49 pm
Location: Germany

Re: Using/Adding all Hknight magic attack animations [TUT]

Post by Seven »

:oops: Where else should it be.. :oops:

Thank you for opening my eyes Spike. :)
Post Reply