View previous topic :: View next topic |
Author |
Message |
GiffE
Joined: 08 Oct 2006 Posts: 141 Location: USA, CT
|
Posted: Thu May 20, 2010 1:11 pm Post subject: QuakeC Code Snippets |
|
|
I'd like to start a thread where we can all post small code snippets which may be of use to others learning quakec or just save some time.
Theres a lot of little things we code which seem redundant as someone has likely done it before. You can spend a lot of time reinventing the wheel and less time working on the new fun things.
I will make a page on DP Wiki and update it with these if we see fit.
I'll start it off:
This method will play a random sound. I find I have to do this alot so why not make a method for this.
Code: | // Spike:
string(string fmt, string sub1) format_s =
{
float p;
p = strstrofs(fmt, "%s", 0);
if (p == -1)
return fmt;
return strcat(substring(fmt, 0, p), sub1, substring(fmt, p+2, -1));
};
/* randomSound
Same as sound() except takes a float cnt.
plays a random variant of the sound. for example:
randomSound(self,CHAN_BODY,"Sounds/Player/pl_step%s.wav",0.3,ATTN_IDLE,3);
plays randomly Sounds/Player/pl_step1.wav,
Sounds/Player/pl_step2.wav, or
Sounds/Player/pl_step3.wav
EXT used:
FRIK_FILE
FTE_STRINGS
*/
void(entity e, float chan, string samp, float vol, float atten, float cnt) randomSound = {
float r;
r = floor(random() * cnt) + 1;
sound(e, chan, format_s(samp,ftos(r)), vol, atten);
};
|
Extensions used:
FRIK_FILE, FTE_STRING _________________ http://www.giffe-bin.net/
Last edited by GiffE on Fri May 21, 2010 1:04 pm; edited 3 times in total |
|
Back to top |
|
 |
Mexicouger

Joined: 01 May 2010 Posts: 129
|
Posted: Thu May 20, 2010 10:12 pm Post subject: |
|
|
That's alot different than How I do my random sounds.
In the function, I make a local float r;
and then make
r= random();
then do this some where in the function:
if (r >= 0.33)
sound (self, CHAN_WEAPON, "player/beffy.wav", 1, ATTN_NORM);
else if (r >= 0.66)
sound (self, CHAN_WEAPON, "player/beffy2.wav", 1, ATTN_NORM);
else
sound (self, CHAN_WEAPON, "player/beffy3.wav", 1, ATTN_NORM);
That is how I make my random sounds. So basically.
void() myfunc =
{
local float r;
r = random();
if (r >= 0.33)
sound (self, CHAN_WEAPON, "player/beffy.wav", 1, ATTN_NORM);
else if (r >= 0.66)
sound (self, CHAN_WEAPON, "player/beffy2.wav", 1, ATTN_NORM);
else
sound (self, CHAN_WEAPON, "player/beffy3.wav", 1, ATTN_NORM);
};
That could be a function all in itself.
And then goto your real function and replace the sound with;
myfunc();
Kinda scattered, But That is it! |
|
Back to top |
|
 |
Spike
Joined: 05 Nov 2004 Posts: 944 Location: UK
|
Posted: Thu May 20, 2010 10:41 pm Post subject: |
|
|
Code: |
if (r < 0.33)
blah()
else if (r < 0.66)
blah();
else
blah();
|
would work better.
your code will use the first case 2/3rds of the time, and never the middle case.
instead, if you prefer single-lines and use frikqcc or fteqcc, you could write it as:
r=random();
sound (self, CHAN_WEAPON, ((r<0.33)?"player/beffy.wav":((r<0.66)?"player/beffy2.wav":"player/beffy3.wav")), 1, ATTN_NORM);
but that's the ?: ternary operator for you - unreadable. _________________ What's a signature? |
|
Back to top |
|
 |
GiffE
Joined: 08 Oct 2006 Posts: 141 Location: USA, CT
|
Posted: Fri May 21, 2010 12:38 am Post subject: |
|
|
Spike wrote: | Code: |
if (r < 0.33)
blah()
else if (r < 0.66)
blah();
else
blah();
|
would work better.
your code will use the first case 2/3rds of the time, and never the middle case.
instead, if you prefer single-lines and use frikqcc or fteqcc, you could write it as:
r=random();
sound (self, CHAN_WEAPON, ((r<0.33)?"player/beffy.wav" (r<0.66)?"player/beffy2.wav":"player/beffy3.wav")), 1, ATTN_NORM);
but that's the ?: ternary operator for you - unreadable. |
Really? I was always told by all my cs professors that with a random number function that returns from 0.0 to 0.9999999, you can do:
floor(random() * 3) + 0; where 3 = the number of numbers it can fall between, and 0 = the starting value.
0.3333 * 3 = 0.9999 so floor it = 0
0.6666 * 3 = 1.9999 floor it = 1
0.9999 * 3 = 2.9997 floor it = 2
Any value between these produce the same result due to the floor.
And by adding anything it simply shifts the results so I can effectively choose any starting value, in my case 1.
Test it:
Code: | float zeros;
float ones;
float twos;
float i;
float r;
zeros = ones = twos = 0;
for(i=0;i<1000;i++) {
r = floor(random() * 3);
switch(r) {
case 0: zeros++; break;
case 1: ones++; break;
case 2: twos++; break;
}
}
print("0: ", ftos(zeros), " (", ftos(zeros/i),")\n");
print("1: ", ftos(ones), " (", ftos(ones/i),")\n");
print("2: ", ftos(twos), " (", ftos(twos/i),")\n");
|
This produces the result of:
Quote: |
0: 341 (0.341000)
1: 324 (0.324000)
2: 335 (0.335000)
|
And i'd say that is damn close to 1 third.
I use this method instead of all the if/else's because it allows me to pass in any number of sound files to choose from, so if there's 4, 10, 100 different sounds for the same one it will always work.
EDIT:
I had believed Spikes post was directed towards me, which it clearly wasn't. Miscommunication on my behalf, however there's my attempt at explaining random numbers using the method I use... _________________ http://www.giffe-bin.net/
Last edited by GiffE on Fri May 21, 2010 2:00 am; edited 1 time in total |
|
Back to top |
|
 |
Sajt
Joined: 16 Oct 2004 Posts: 1026
|
Posted: Fri May 21, 2010 1:17 am Post subject: |
|
|
This:
Code: | local float r;
r = random();
if (r < 0.33)
a;
else if (r < 0.66)
b;
else
c; |
is slightly briefer and more readable than this:
Code: | local float r;
r = floor(random() * 3);
if (r == 0)
a;
else if (r == 1)
b;
else
c; |
(This latter method is usually only used if you have 5+ cases.) Not that I'm saying it's wrong. Probably 50% of QC coders do do it this way all the time. But the first method is no less fine. edit: And people don't always use switch statements because they're not a standard QCC feature (I think only FTEQCC supports them) and you can't always trust FTEQCC to work with non-standard features (although I think switch statements are fine).
Also, I need to react to the enormous puke of code in your first post. What you did there is fun for the sake of it, but a complete waste of time to the practical coder and also comparatively very hard to understand. _________________ F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe. |
|
Back to top |
|
 |
GiffE
Joined: 08 Oct 2006 Posts: 141 Location: USA, CT
|
Posted: Fri May 21, 2010 1:31 am Post subject: |
|
|
Sajt wrote: | This:
[code]
(This latter method is usually only used if you have 5+ cases.) Not that I'm saying it's wrong. Probably 50% of QC coders do do it this way all the time. But the first method is no less fine. edit: And people don't always use switch statements because they're not a standard QCC feature (I think only FTEQCC supports them) and you can't always trust FTEQCC to work with non-standard features (although I think switch statements are fine).
Also, I need to react to the enormous puke of code in your first post. What you did there is fun for the sake of it, but a complete waste of time to the practical coder and also comparatively very hard to understand. |
Ouch,
I had not used a switch in my first post, only the second for the sake of testing. I never said one is better than the other. It also comes down to ones unique coding style whether one uses random()*3 or just uses the decimal, however for the method I wrote its more functional to use the first. I don't know what you mean by stuff just thrown in there, every line of it is needed.. other than possibly cutting down on the ext variable.
I did forget to hack off the else/returns (which I forgot to get rid of when I altered it slightly during posting). I removed them if it makes your eyes less sore...
I made this thread thinking you all had written small code bits, too small for a tutorial or posting on their own, but useful none the less. While they may be novelty to some, they could be fun to see, and learn how another person approaches a "problem".
Forgive me if my post sounds defensive... _________________ http://www.giffe-bin.net/ |
|
Back to top |
|
 |
Pulseczar

Joined: 12 Aug 2006 Posts: 37
|
Posted: Fri May 21, 2010 2:44 am Post subject: |
|
|
Sajt wrote: | Also, I need to react to the enormous puke of code in your first post. |
Don't hold back, man. Tell him how you really feel...
And yeah, the logic is wrong in Mexicouger's code. _________________ http://www.customtf.net/ |
|
Back to top |
|
 |
Sajt
Joined: 16 Oct 2004 Posts: 1026
|
Posted: Fri May 21, 2010 5:31 am Post subject: |
|
|
Well, GiffE, I should mention that I was the same way when I was "your age" (-ish). I didn't finish any mods because I was too busy making cool code, I guess. Anyway, to be more helpful, the first thing I would do to make randomSound clearer would probably be to make the input "filename" a printf-like pattern, like "Sounds/Player/pl_step%d.wav". Although I don't know if DP has builtins for handling that (you could always write a ton of QC code to do it!)
Hmm, sorry if I'm derailing the thread a little bit. As for cool snippets of QC, I don't really have any that are small and independent that I could post without having to explain a half-dozen other things it's interconnected with... _________________ F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe. |
|
Back to top |
|
 |
Spike
Joined: 05 Nov 2004 Posts: 944 Location: UK
|
Posted: Fri May 21, 2010 10:49 am Post subject: |
|
|
Code: |
string(string fmt, string sub1) format_s =
{
float p;
p = strstrofs(fmt, "%s", 0);
if (p == -1)
return fmt;
return strcat(substring(fmt, 0, p), sub1, substring(fmt, p+2, -1));
};
|
Just finds %s in the string and substitutes that part with the second argument. Requires FTE_STRINGS. Also requires bugfixed qcc, and some kind of multiple tempstrings _________________ What's a signature? |
|
Back to top |
|
 |
GiffE
Joined: 08 Oct 2006 Posts: 141 Location: USA, CT
|
Posted: Fri May 21, 2010 1:06 pm Post subject: |
|
|
Spike wrote: | Code: |
string(string fmt, string sub1) format_s =
{
float p;
p = strstrofs(fmt, "%s", 0);
if (p == -1)
return fmt;
return strcat(substring(fmt, 0, p), sub1, substring(fmt, p+2, -1));
};
|
Just finds %s in the string and substitutes that part with the second argument. Requires FTE_STRINGS. Also requires bugfixed qcc, and some kind of multiple tempstrings |
Very cool! Didn't think of that ! I was so focused on just parsing the string and adding a number, a simple replace makes it much easier:
Code: |
void(entity e, float chan, string samp, float vol, float atten, float cnt) randomSound = {
float r;
r = floor(random() * cnt) + 1;
sound(e, chan, format_s(samp,ftos(r)), vol, atten);
};
|
Thanks Spike! _________________ http://www.giffe-bin.net/ |
|
Back to top |
|
 |
Mexicouger

Joined: 01 May 2010 Posts: 129
|
Posted: Fri May 21, 2010 9:47 pm Post subject: |
|
|
[/quote]
And yeah, the logic is wrong in Mexicouger's code.[/quote]
...I don't quite understand how my "logic" was wrong. The code works just fine. It is just a different way of selecting a random sound effect for a function. |
|
Back to top |
|
 |
Sajt
Joined: 16 Oct 2004 Posts: 1026
|
Posted: Fri May 21, 2010 9:52 pm Post subject: |
|
|
Mexicouger wrote: | Code: | if (r >= 0.33)
...;
else if (r >= 0.66)
...;
else
...; |
|
The first clause has a 66% chance of occurring, the second clause 0%, and the third 33%. If you replaced ">=" with "<=", however... _________________ F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe. |
|
Back to top |
|
 |
Pulseczar

Joined: 12 Aug 2006 Posts: 37
|
Posted: Fri May 21, 2010 10:07 pm Post subject: |
|
|
Mexicouger wrote: | ...I don't quite understand how my "logic" was wrong. The code works just fine. It is just a different way of selecting a random sound effect for a function. |
Which path should be taken if r = 0.9? The second, but your code takes the first. Since code runs sequentially, it always checks the first if first, and for all values >= 0.33, it executes that first if clause. _________________ http://www.customtf.net/ |
|
Back to top |
|
 |
frag.machine

Joined: 25 Nov 2006 Posts: 728
|
Posted: Sat May 22, 2010 7:45 pm Post subject: |
|
|
Pulseczar wrote: | Mexicouger wrote: | ...I don't quite understand how my "logic" was wrong. The code works just fine. It is just a different way of selecting a random sound effect for a function. |
Which path should be taken if r = 0.9? The second, but your code takes the first. Since code runs sequentially, it always checks the first if first, and for all values >= 0.33, it executes that first if clause. |
Mexicouger,
Code: |
if (r > 0.66) // if r between 1.00 and 0.67
sound (self, CHAN_WEAPON, "player/beffy3.wav", 1, ATTN_NORM);
else if (r > 0.33) // if r between 0.66 and 0.34
sound (self, CHAN_WEAPON, "player/beffy2.wav", 1, ATTN_NORM);
else // if r between 0.33 and 0.00
sound (self, CHAN_WEAPON, "player/beffy.wav", 1, ATTN_NORM);
|
That's what your code should look to have the same chance to play all of the 3 sounds. You may not realized the error because your code always plays some sound - it's just the wrong one. _________________ frag.machine - Q2K4 Project
http://fragmachine.quakedev.com/ |
|
Back to top |
|
 |
GiffE
Joined: 08 Oct 2006 Posts: 141 Location: USA, CT
|
Posted: Sun May 30, 2010 11:06 am Post subject: |
|
|
I was playing around with the dp's file searching extensions (DP_QC_FS_SEARCH and FTE_STRINGS) a few days back. I noticed there was a random level tutorial in the qc tutorials so I figured's I'd update it with DP's extensions:
Code: |
string() RandomMap = {
string rmap;
float handle,r;
handle = search_begin("maps/*.bsp", FALSE, TRUE); //Find all Maps
r = floor(random() * search_getsize(handle)); // Choose a random index
rmap = search_getfilename(handle,r); // Get our map
search_end(handle);
return substring(rmap,5,strlen(rmap)-9); // Strip maps/ and .bsp (changelevel doesn't like those)
}; |
It searches ALL BSP's so if you have bsp in the maps directory that isn't a map it could return it... which you may have to find an a way to fix it if you use bsp's as anything but maps.
This can be used to replace the Random Level Changing Tutorial.
Getting rid of this ugliness:
Code: | local float whichmap;
whichmap = rint (random()*36 + 1);
if (whichmap == 1)
mapname = "start";
else if (whichmap == 2)
mapname = "e1m1";
...
else
mapname = "dm6"; |
I used it in combination with csqc to create a Halo: Reach style "next map vote" that I took a liking to while playing the beta:
I might try to see if I can use "WritePicture" to send a small thumbnail for each map. _________________ http://www.giffe-bin.net/ |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2004 phpBB Group
|