QuakeC Lessons for the Experienced Newb
QuakeC Lessons for the Experienced Newb
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.
What is going on here?
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?
Code: Select all
sound (self, CHAN_VOICE, "knight/kdeath.wav", 1, ATTN_NORM);
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.
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);
...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.
1. so the sound emits from the knight's ass, rather than the world or his attacker.scar3crow wrote:What is going on here?Why the self?Code: Select all
sound (self, CHAN_VOICE, "knight/kdeath.wav", 1, ATTN_NORM);
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?
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.
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 funscar3crow 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?
i should not be here
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.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?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);
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.
... and fortunately all those people are gathering at inside3D.comFrikaC 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.
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
There's a few other minor differences between ThrowHead and ThrowGib one is this: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.
ThrowGib:
Code: Select all
new.avelocity_x = random()*600;
new.avelocity_y = random()*600;
new.avelocity_z = random()*600;
Code: Select all
self.avelocity = crandom() * '0 600 0';
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.
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
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.
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. :)scar3crow wrote:what are the other CHANs?
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.
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.leileilol wrote:Player's death uses ATTN_NONE. Why?
-
- Posts: 52
- Joined: Thu Sep 30, 2010 6:46 am
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.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?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);
I kinda did when I saidsilverjoel 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.
But yeah, it's an important thing to note and I'm glad you further called it out.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.
-
- Posts: 2126
- Joined: Sat Nov 25, 2006 1:49 pm
In some engines such as Darkplaces that remove the panning out of ATTN_NONE for music use, this becomes less useful.Supa wrote: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.leileilol wrote:Player's death uses ATTN_NONE. Why?
i should not be here
-
- Posts: 514
- Joined: Sat May 01, 2010 10:12 pm
- Contact:
Taken from defs.qc...scar3crow wrote:What is going on here?Why the self?Code: Select all
sound (self, CHAN_VOICE, "knight/kdeath.wav", 1, ATTN_NORM);
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?
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;
Code: Select all
float ATTN_NONE = 0;
float ATTN_NORM = 1;
float ATTN_IDLE = 2;
float ATTN_STATIC = 3;
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.
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.