QuakeC Lessons for the Experienced Newb

Discuss anything not covered by any of the other categories.
Post Reply
scar3crow
InsideQC Staff
Posts: 1054
Joined: Tue Jan 18, 2005 8:54 pm
Location: Alabama

QuakeC Lessons for the Experienced Newb

Post by scar3crow »

Wherein I prostrate my shamefully relevant ignorance of all things QuakeC to ask completely random questions about the code I see, and what is going on. It may be grandiose, it may be a tiny detail, but the hope is that in illuminating myself, it may form a small archive of random tidbits for other newbs, my nescient brethren.
...and all around me was the chaos of battle and the reek of running blood.... and for the first time in my life I knew true happiness.
scar3crow
InsideQC Staff
Posts: 1054
Joined: Tue Jan 18, 2005 8:54 pm
Location: Alabama

Post by scar3crow »

What is going on here?

Code: Select all

sound (self, CHAN_VOICE, "knight/kdeath.wav", 1, ATTN_NORM);
Why the self?
What is CHAN_VOICE explicitly and what are the other CHANs?
What is normal attenuation, is there super attenuation? Paranormal attenuation?
What is the 1 being passed for?
...and all around me was the chaos of battle and the reek of running blood.... and for the first time in my life I knew true happiness.
scar3crow
InsideQC Staff
Posts: 1054
Joined: Tue Jan 18, 2005 8:54 pm
Location: Alabama

Post by scar3crow »

Code: Select all

ThrowHead ("progs/h_knight.mdl", self.health);
		ThrowGib ("progs/gib1.mdl", self.health);
		ThrowGib ("progs/gib2.mdl", self.health);
		ThrowGib ("progs/gib3.mdl", self.health);
Why the self.health? Why is it on each line and how would it be relevant to gibs, and does it matter between ThrowGib and ThrowHead that they both mention it?
...and all around me was the chaos of battle and the reek of running blood.... and for the first time in my life I knew true happiness.
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Post by leileilol »

scar3crow wrote:What is going on here?

Code: Select all

sound (self, CHAN_VOICE, "knight/kdeath.wav", 1, ATTN_NORM);
Why the self?
What is CHAN_VOICE explicitly and what are the other CHANs?
What is normal attenuation, is there super attenuation? Paranormal attenuation?
What is the 1 being passed for?
1. so the sound emits from the knight's ass, rather than the world or his attacker.
2. so his 'ouch' noises can interrupt the growls and stuff he makes, rather than the noise of his sword. localized channels is important
3. yes. the normal attenuation is normal. The lower the attenuation value the farther it goes (ATTN_NONE (0) is the whole level). Player's death uses ATTN_NONE. Why? hell if i know, i change that to ATTN_NORM in everything I do
4. Volume. from 0 to 1. This is not the same as attenuation.
scar3crow wrote:] Why the self.health? Why is it on each line and how would it be relevant to gibs, and does it matter between ThrowGib and ThrowHead that they both mention it?
so when the more overkilled player is gibbed, the gibs fly farther regarding the negative health value of the player. it makes quad rockets very fun
i should not be here
ajay
Posts: 559
Joined: Fri Oct 29, 2004 6:44 am
Location: Swindon, UK

Post by ajay »

I very much approve of this thread. Mainly as I've been doing this for years, but have massive gaps in my knowledge. The two examples so far being cases in point...
FrikaC
Site Admin
Posts: 1026
Joined: Fri Oct 08, 2004 11:19 pm

Post by FrikaC »

scar3crow wrote:

Code: Select all

ThrowHead ("progs/h_knight.mdl", self.health);
		ThrowGib ("progs/gib1.mdl", self.health);
		ThrowGib ("progs/gib2.mdl", self.health);
		ThrowGib ("progs/gib3.mdl", self.health);
Why the self.health? Why is it on each line and how would it be relevant to gibs, and does it matter between ThrowGib and ThrowHead that they both mention it?
self.health is passed into the ThrowGib (as the parameter "dm") code to determine the velocity with which to throw the gibs. So say after damaging the entity's health is around -40, that's the minimum most characters have for gibbing.

The function VelocityForDamage in player.qc converts the remaining (negative) health of the character into a velocity. At -50 and above the random vector will be scaled by 0.7 making the gibs not go as far. The comment says "level 1". Below -50 and above -200 the random vector will be scaled by 2, making the gibs fly twice as far. Beyond that, which is probably only quad rocket/ telefrag damage, the gibs will go 10 times as far.

Function parameters need to be repeated for each call to the function. There's no way to omit parameters in QuakeC and ThrowGib / ThrowHead have no way of knowing what the previous passed in variable was. ThrowHead is basically a clone of ThrowGib with one important difference, instead of spawning a new bouncing entity, it converts self into something that is essentially a gib. So that when you gib a character, they literally become a head and toss out a handful of gibs. The reason for this is so that anything pointing at that particular entity doesn't break. It will still be pointing at the head.

A helpful thing to do when you see some identifier you don't understand is to search the code for it and find its definition. So in this case searching would have found the ThrowGib function in player.qc, and looking at what it does with the "dm" variable passed in would have led you down to VelocityForDamage, searching again for that function you would have found its definition also in player.qc, and reading again what it does with dm would lead you to the above information.

There's no guide for QuakeC. Everything anyone outside of id has ever learned of this language has been accomplished by searching and reading the code.
Seven
Posts: 301
Joined: Sat Oct 06, 2007 8:49 pm
Location: Germany

Post by Seven »

FrikaC wrote:There's no guide for QuakeC. Everything anyone outside of id has ever learned of this language has been accomplished by searching and reading the code.
... and fortunately all those people are gathering at inside3D.com :)
Happy to help others in need.

Thank you for your detailed description leileilol & FrikaC.
I learned a lot from it.

Last thing I dont understand is, why is the head-gib always lying/positioned on the floor like it is modelled/visible in QME. (example: soldiers head is looking upwards)
And all 3 other gibs are lying in a random position/condition.
I couldnt find the code that is responsible for this.

Kind regards,
Seven
FrikaC
Site Admin
Posts: 1026
Joined: Fri Oct 08, 2004 11:19 pm

Post by FrikaC »

Last thing I dont understand is, why is the head-gib always lying/positioned on the floor like it is modelled/visible in QME. (example: soldiers head is looking upwards)
And all 3 other gibs are lying in a random position/condition.
I couldnt find the code that is responsible for this.
There's a few other minor differences between ThrowHead and ThrowGib one is this:

ThrowGib:

Code: Select all

new.avelocity_x = random()*600;
new.avelocity_y = random()*600;
new.avelocity_z = random()*600;
ThrowHead:

Code: Select all

self.avelocity = crandom() * '0 600 0';
The ThrowGib version sets the avelocity (angular velocity) on all three elements independently: pitch (_x), yaw (_y) and roll (_z). The ThrowHead code multiplies a crandom call (which is a random number between -1 and 1) with '0 600 0'. Where the ThrowGib code will use a new random number for each component, this code only uses one random number and only applied to the _y component.

Zero times any number equals zero. So the avelocity_x and avelocity_z are set to zero, meaning that the head will never pitch or roll, only spin around the yaw.
Supa
Posts: 164
Joined: Tue Oct 26, 2004 8:10 am

Post by Supa »

Like FrikaC alluded to, knowing how to learn things on your own is something you'll really need if you're going to make it in software development. You'd have a hard time looking for any (*decent*) dev who isn't an autodidact of some level. Regarding builtins, two good starting points for finding more info would be the prvm_*.h files in the engine source (plus protocol.h for EF_* bits and others) and the archive of the old Quake Wiki included with the GUI version of FrikQCC 2.7
scar3crow wrote:what are the other CHANs?
Two things I want to note is that each sound channel isn't reserved for anything in particular - nothing will bite your head off if you play a weapon sound on CHAN_BODY, it just uses up that channel 'slot' for the duration of the sound - and that CHAN_AUTO (0) will take up the first free channel slot for that entity it can find every time you use it. I can't remember if CHAN_AUTO looks for slots incrementing from 1 or decrementing from the maximum (7 in NQ, DP's is probably higher), so you'd have to find out on your own. :)

Also, regarding the entity parameter you need to keep in mind that you need to spawn a (temporary) entity to play a sound in the first place, you can't just play the sound at a specific origin vector. So if you just want to play a sound at vector xyz (like a music loop played at two opposite points in the level for a stereo effect) you'll need to spawn *something* at that point and pass it along as the sound origin entity - though nothing will stop you from removing it on the next server frame. Also note that DP will make the sound follow whatever entity you pass it to, which allows you to do things like playing a rocket motor loop on rockets in order to emulate the Q3 rocket flyby sound effect.
leileilol wrote:Player's death uses ATTN_NONE. Why?
It's only really important in teamplay or FFA games, as it serves as a feedback cue to help intuit where your teammates and other players are dying.
silverjoel
Posts: 52
Joined: Thu Sep 30, 2010 6:46 am

Post by silverjoel »

scar3crow wrote:

Code: Select all

ThrowHead ("progs/h_knight.mdl", self.health);
		ThrowGib ("progs/gib1.mdl", self.health);
		ThrowGib ("progs/gib2.mdl", self.health);
		ThrowGib ("progs/gib3.mdl", self.health);
Why the self.health? Why is it on each line and how would it be relevant to gibs, and does it matter between ThrowGib and ThrowHead that they both mention it?
Something that hasn't been mentioned is self becomes the ThrowHead, in this case the knight becomes h_knight.mdl, where as the ThrowGib are new entities that are spawned like when firing a rocket.
FrikaC
Site Admin
Posts: 1026
Joined: Fri Oct 08, 2004 11:19 pm

Post by FrikaC »

silverjoel wrote:Something that hasn't been mentioned is self becomes the ThrowHead, in this case the knight becomes h_knight.mdl, where as the ThrowGib are new entities that are spawned like when firing a rocket.
I kinda did when I said
ThrowHead is basically a clone of ThrowGib with one important difference, instead of spawning a new bouncing entity, it converts self into something that is essentially a gib.
But yeah, it's an important thing to note and I'm glad you further called it out.
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Post by frag.machine »

I for one welcome our elder QuakeC overlords. :D
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
leileilol
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Post by leileilol »

Supa wrote:
leileilol wrote:Player's death uses ATTN_NONE. Why?
It's only really important in teamplay or FFA games, as it serves as a feedback cue to help intuit where your teammates and other players are dying.
In some engines such as Darkplaces that remove the panning out of ATTN_NONE for music use, this becomes less useful.
i should not be here
Mexicouger
Posts: 514
Joined: Sat May 01, 2010 10:12 pm
Contact:

Post by Mexicouger »

scar3crow wrote:What is going on here?

Code: Select all

sound (self, CHAN_VOICE, "knight/kdeath.wav", 1, ATTN_NORM);
Why the self?
What is CHAN_VOICE explicitly and what are the other CHANs?
What is normal attenuation, is there super attenuation? Paranormal attenuation?
What is the 1 being passed for?
Taken from defs.qc...

Code: Select all

// sound channels
// channel 0 never willingly overrides
// other channels (1-7) allways override a playing sound on that channel
float	CHAN_AUTO		= 0;
float	CHAN_WEAPON	= 1;
float	CHAN_VOICE		= 2;
float	CHAN_ITEM		= 3;
float	CHAN_BODY		= 4;
Here is also the other attenuations, also taken from defs.qc...

Code: Select all

float	ATTN_NONE		= 0;
float	ATTN_NORM		= 1;
float	ATTN_IDLE		= 2;
float	ATTN_STATIC		= 3;
goldenboy
Posts: 924
Joined: Fri Sep 05, 2008 11:04 pm
Location: Kiel
Contact:

Post by goldenboy »

From a sound guy's perspective, the channels are like a crude mixing desk with a really poor interface.

Imagine adding constant footsteps for example, their sound will need to play on a different channel from the gunfire/grunting etc so they are not cut out during combat.

Not to mention stuff like taunts and cheers and heartbeats.
Post Reply