PDA

View Full Version : emmiting complex sounds( spk or emit_sound? )


Lulu the hero
07-19-2010, 20:23
Hi everyone!

Here is the situation:

If you play half life: opposing force or sven co-op, you'll come across "shock trooper"s. They say something like this: "may ha hmm may he he". If you check the sound files, and the senteces.txt, you'll find this:

// SHOCK TROOPER
ST_GREN0 shocktrooper/kss kyur kiml
ST_ALERT0 shocktrooper/dit dit
ST_ALERT1 shocktrooper/dit kss kss
ST_ALERT2 shocktrooper/kss dit dit kss
ST_MONST0 shocktrooper/pur thirv pur kss kss
ST_COVER0 shocktrooper/ka ga blis blis ka
ST_THROW0 shocktrooper/kss wirt ras
ST_TAUNT0 shocktrooper/kiml kiml
ST_CHARGE0 shocktrooper/mub puh mub dit dit
ST_IDLE0 shocktrooper/ku kur ku
ST_QUEST0 shocktrooper/puh pur hyu ka
ST_ANSWER0 shocktrooper/dup dup
ST_CLEAR0 shocktrooper/dup blis dup
ST_CHECK0 shocktrooper/kss kss
You cannot use emit sound here, because most of the sound files don't last for even 1/10th of a second.
Here comes the HL console:

spk "shocktrooper/mub puh mub dit dit"
And voila, here is the sound we heard.

If we use the following code, we can emit the sound to all players:

public sound_to_all(){
console_cmd(0,"spk ^"shocktrooper/mub puh mub dit dit^"");
}
The problem is, it sounds like it comes from everywhere. We could filter out the distance, so someone too far would not hear the sound at all, but all the others would still hear the sound from everywhere. We could add some parameters too for volume:

spk "shocktrooper/(v30) mub puh mub dit dit"
I bet there is a balance paramether( what is it's letter? ), but isn't there a simpler way to do this then a lot of filtering?
I've tried the following code to make a function, though it's not working:

#include <amxmodx>

new maxplayers = 0;

public plugin_init(){
register_plugin("SoundTest","1.0","Lulu the hero");
}

//someone connects to the server
public client_connect(id){
maxplayers++;
if(!is_user_bot(id)){
spk("vox/dadada hello",random(40)+80,50);
}
}

//someone leaves the server
public client_disconnect(id){
maxplayers--;
if(!is_user_bot(id)){
spk("vox/dadada goodbye",random(40)+80,50);
}
}

public spk(sentence[],pitch,volume){
new parsed[100] = "";
new data[4] = "";
if(pitch!=100){
num_to_str(pitch,data,3);
if(equal(parsed,"")){
format(parsed,99,"p%s",data);
}else{
format(parsed,99,"%s p%s",parsed,data);
}
}
if(volume!=100){
num_to_str(volume,data,3);
if(equal(parsed,"")){
format(parsed,99,"v%s",data);
}else{
format(parsed,99,"%s v%s",parsed,data);
}
}
if(!equal(parsed,"")){
format(parsed,99,"/(%s) ",parsed);
replace(sentence,30,"/",parsed);
}
for(new i=1;i<maxplayers;i++){
if(!is_user_bot(i)){
client_cmd(i,"spk ^"%s^"",sentence);
}
}
}

Thanks everyone for your answers in advance.

fysiks
07-19-2010, 21:25
First of all, you should explain what is not working about it (which requires some debugging).

Second, your method of counting players and using that for the for loop is not good. This is how I would do it and see if it works:

-Code Removed-

Lulu the hero
07-19-2010, 21:51
public spk(sentence[],pitch,volume)
{
new parsed[100] = "";
new szTemp[7]
if(pitch != 100)
{
formatex(szTemp, charsmax(szTemp), "p%i", pitch)
add(parsed, charsmax(parsed), szTemp)
}
if(volume != 100)
{
formatex(szTemp, charsmax(szTemp), "%sv%i", volume, parsed[0] ? " " : "")
add(parsed, charsmax(parsed), szTemp)
}
if(!equal(parsed,""))
{
format(parsed,99,"/(%s) ",parsed);
replace(sentence,30,"/",parsed);
}

new iPlayers[32], iNumPlayers;
get_players(iPlayers, iNumPlayers);
for(new i=0; i < iNumPlayers; i++)
{
client_cmd(iPlayers[i],"spk ^"%s^"",sentence);
}
}

Only one error.
The code is only for a test. It would say hello to every connecting player. But it doesn't.

If I can add a balance paramether, then I can calculate a sound source's direction and volume according to the distance.

Lulu the hero
07-19-2010, 22:19
Another example of vox used for creatures is Sven Coop's robot grunt sounds. When the robogrunt sees a grenade it says:

spk "vox/(p120) dadeda emergency evacuate"

it would look like this called from the function:

spk("vox/dadeda emergency evacuate",120,100);

Oh, by the way it's dadeda and not dadada as I thought... :(

I corrected the plugin and inserted fysiks' code:

#include <amxmodx>

new maxplayers = 0;

public plugin_init(){
register_plugin("SoundTest","1.0","Lulu the hero");
register_concmd("hello","test_spk");
}

public test_spk(){
spk("vox/dadeda emergency evacuate",120,100);
}

//someone connects to the server
public client_connect(id){
maxplayers++;
if(!is_user_bot(id)){
spk("vox/dadeda hello",random(40)+80,50);
}
}

//someone leaves the server
public client_disconnect(id){
maxplayers--;
if(!is_user_bot(id)){
spk("vox/dadeda goodbye",random(40)+80,50);
}
}

public spk(sentence[],pitch,volume)
{
new parsed[100] = "";
new szTemp[7]
if(pitch != 100)
{
formatex(szTemp, charsmax(szTemp), "p%i", pitch)
add(parsed, charsmax(parsed), szTemp)
}
if(volume != 100)
{
formatex(szTemp, charsmax(szTemp), "%sv%i", volume, parsed[0] ? " " : "")
add(parsed, charsmax(parsed), szTemp)
}
if(!equal(parsed,""))
{
format(parsed,99,"/(%s) ",parsed);
replace(sentence,30,"/",parsed);
}

new iPlayers[32], iNumPlayers;
get_players(iPlayers, iNumPlayers);
for(new i=0; i < iNumPlayers; i++)
{
client_cmd(iPlayers[i],"spk ^"%s^"",sentence);
}
}


By the way, what are the parameters of spk/speak?
The ones I've found are the following(tested all the letters)

p - pitch(%) - default value is 100 - raises/lowers pitch
t - tempo(?) - default value is 0 - increasing the tempo(without the pitch increase)
e - end(%) - default value is 100 - trim the end of a sample(cut down 100-% from the end)
s - start(%) - default value is 0 - trim the beginning of a sample(cut down a % from the start)
v - volume(%) - default value is 100 - the volume of the sample

Lulu the hero
07-19-2010, 22:49
And what about fakemeta's

EngFunc_BuildSoundMsg, // void ) (edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed);

Lulu the hero
07-19-2010, 23:19
Ok, the code is corrected, but a new error appeared, which I don't know where it came from:


L 07/20/2010 - 04:15:34: replace() buffer not big enough (36>=30)
L 07/20/2010 - 04:15:34: [AMXX] Displaying debug trace (plugin "soundtest.amxx")
L 07/20/2010 - 04:15:34: [AMXX] Run time error 10: native error (native "replace")
L 07/20/2010 - 04:15:34: [AMXX] [0] soundtest.sma::spk (line 43)
L 07/20/2010 - 04:15:34: [AMXX] [1] soundtest.sma::test_spk (line 9)if I increase the number in the plugin, then it works once, then the same error with 43 as number in the 1st line. I've reset the number in the plugin to 30, then it shows 40 in the error( no working calls this time )

The code is:

#include <amxmodx>

public plugin_init(){
register_plugin("SoundTest","1.0","Lulu the hero");
register_concmd("hello","test_spk");
}

public test_spk(){
spk("vox/dadeda emergency evacuate",120,70);
}

//someone connects to the server
public client_connect(id){
if(!is_user_bot(id)){
spk("vox/dadeda hello",random(40)+80,50);
}
}

//someone leaves the server
public client_disconnect(id){
if(!is_user_bot(id)){
spk("vox/dadeda goodbye",random(40)+80,50);
}
}

public spk(sentence[],pitch,volume)
{
new parsed[100] = "";
new szTemp[7]
if(pitch != 100)
{
formatex(szTemp, charsmax(szTemp), "p%i", pitch)
add(parsed, charsmax(parsed), szTemp)
}
if(volume != 100)
{
formatex(szTemp, charsmax(szTemp), "%sv%i",(parsed[0] ? " " : ""), volume)
add(parsed, charsmax(parsed), szTemp)
}
if(!equal(parsed,""))
{
format(parsed,99,"/(%s) ",parsed);
replace(sentence,30,"/",parsed);
}

new iPlayers[32], iNumPlayers;
get_players(iPlayers, iNumPlayers);
for(new i=0; i < iNumPlayers; i++)
{
client_cmd(iPlayers[i],"spk ^"%s^"",sentence);
}
}

fysiks
07-19-2010, 23:30
For that error use replace_all() instead of replace().

Lulu the hero
07-20-2010, 00:00
Replaced it, but still not working...


L 07/20/2010 - 05:00:36: replace() buffer not big enough (37>=27)
L 07/20/2010 - 05:00:36: [AMXX] Displaying debug trace (plugin "soundtest.amxx")
L 07/20/2010 - 05:00:36: [AMXX] Run time error 10: native error (native "replace")
L 07/20/2010 - 05:00:36: [AMXX] [0] string.inc::replace_all (line 239)
L 07/20/2010 - 05:00:36: [AMXX] [1] soundtest.sma::spk (line 43)
L 07/20/2010 - 05:00:36: [AMXX] [2] soundtest.sma::test_spk (line 9)


#include <amxmodx>

public plugin_init(){
register_plugin("SoundTest","1.0","Lulu the hero");
register_concmd("hello","test_spk");
}

public test_spk(){
spk("vox/dadeda emergency evacuate",120,70);
}

//someone connects to the server
public client_connect(id){
if(!is_user_bot(id))
spk("vox/dadeda hello",random(40)+80,50);
}

//someone leaves the server
public client_disconnect(id){
if(!is_user_bot(id))
spk("vox/dadeda goodbye",random(40)+80,50);
}

public spk(sentence[],pitch,volume){
new parsed[100] = "";
new szTemp[7]
if(pitch != 100){
formatex(szTemp, charsmax(szTemp), "p%i", pitch);
add(parsed, charsmax(parsed), szTemp);
}
if(volume != 100){
formatex(szTemp, charsmax(szTemp), "%sv%i",(parsed[0] ? " " : ""), volume);
add(parsed, charsmax(parsed), szTemp);
}
if(!equal(parsed,"")){
format(parsed,99,"/(%s) ",parsed);
replace_all(sentence,30,"/",parsed);
}
new iPlayers[32], iNumPlayers;
get_players(iPlayers, iNumPlayers);
for(new i=0; i < iNumPlayers; i++)
client_cmd(iPlayers[i],"spk ^"%s^"",sentence);
}

fysiks
07-20-2010, 00:22
Ok, I figured out the problem. You can't reuse the variable "sentence" because you are trying to make it longer but is only as long as the original string that was submitted to it.

Try this:

spk(sentence[],pitch,volume)
{
new szSoundSettings[32];
new szCmd[64];
new iPos;
if(pitch != 100)
{
iPos = formatex(szSoundSettings, charsmax(szSoundSettings), "p%i", pitch)
}

if(volume != 100)
{
formatex(szSoundSettings[iPos], charsmax(szSoundSettings) - iPos, "%sv%i", szSoundSettings[0] ? " " : "", volume)
}

if(szSoundSettings[0])
{
new iSlashPos
if( (iSlashPos = contain(sentence, "/")) != -1 )
{
iPos = add(szCmd, charsmax(szCmd), sentence, iSlashPos+1)
formatex(szCmd[iPos], charsmax(szCmd) - iPos, "(%s) %s", szSoundSettings, sentence[iSlashPos+1])
}
}
else
{
copy(szCmd, charsmax(szCmd), sentence)
}

new iPlayers[32], iNumPlayers;
get_players(iPlayers, iNumPlayers);
for(new i=0; i < iNumPlayers; i++)
{
client_cmd(iPlayers[i],"spk ^"%s^"",szCmd);
}
}

Lulu the hero
07-20-2010, 00:57
Super, I am most greatful to you. Only one thing remains. How to sort out the balancing problems? Idea: make new files, like: emergency_l.wav and emergency_r.wav, but as I see spk only supports 1 channel at a time...( need to test this )

So how can a creature have a complex sound like this?

fysiks
07-20-2010, 01:03
I have no clue what you are talking about. Does this stuff only work on those two games you mentioned? I could only do a single word like "spk damage" in DOD. I remember somebody posting about this type of stuff explaining to me how it worked (the only one I remember is the "e" for ending the sound early) but I can't find it atm.

Lulu the hero
07-20-2010, 03:05
Yup, I've listed all the options above(p t s e v).

Sadly a balance cannot be set. I would like to create something like this in pseudo code:

public positioned_speak(sentence[],Float:coords[],pitch){
for(player=0;player<maxplayers;player++){
new dist=get_distance(get_coords(player),coords);
new volume=dist/(max_hearing_distance/100)
//no balance setting available
spk(sentence,pitch,volume);
}
}

Lulu the hero
07-20-2010, 03:10
Jolly good: I've found my old plugin tryings of a shock trooper sounding:


/* --------------------------
ShockTrooper for XenPets MOD
by Lulu the hero
-------------------------- */
#include <amxmodx>
#include <fun>
#include <fakemeta>
#include <xenpets>

//Model of the creature
new const model[] = "models/xenpets/strooper/strooper.mdl";
new const spark[] = "models/xenpets/strooper/shock_effect.mdl";
new const spore[] = "models/xenpets/strooper/spore.mdl";
new const roach[] = "models/xenpets/strooper/w_shock_rifle.mdl";

//Sounds of the creature
//shock trooper
new const s_blis[] = "xenpets/strooper/blis.wav";
new const s_dit[] = "xenpets/strooper/dit.wav";
new const s_dup[] = "xenpets/strooper/dup.wav";
new const s_ga[] = "xenpets/strooper/ga.wav";
new const s_hyu[] = "xenpets/strooper/hyu.wav";
new const s_ka[] = "xenpets/strooper/ka.wav";
new const s_kiml[] = "xenpets/strooper/kiml.wav";
new const s_kss[] = "xenpets/strooper/kss.wav";
new const s_ku[] = "xenpets/strooper/ku.wav";
new const s_kur[] = "xenpets/strooper/kur.wav";
new const s_kyur[] = "xenpets/strooper/kyur.wav";
new const s_mub[] = "xenpets/strooper/mub.wav";
new const s_puh[] = "xenpets/strooper/puh.wav";
new const s_pur[] = "xenpets/strooper/pur.wav";
new const s_ras[] = "xenpets/strooper/ras.wav";
new const s_thirv[] = "xenpets/strooper/thirv.wav";
new const s_wirt[] = "xenpets/strooper/wirt.wav";
new const s_fire[] = "xenpets/strooper/shock_fire.wav";
new const s_attack[] = "xenpets/strooper/shock_trooper_attack.wav";
new const s_die[4][] = {"xenpets/strooper/die1.wav","xenpets/strooper/die2.wav","xenpets/strooper/die3.wav","xenpets/strooper/die4.wav"};
new const s_pain[5][] = {"xenpets/strooper/pain1.wav","xenpets/strooper/pain2.wav","xenpets/strooper/pain3.wav","xenpets/strooper/pain4.wav","xenpets/strooper/pain5.wav"}
//shock roach
new const s2_angry[] = "xenpets/strooper/shockroach/shock_angry.wav";
new const s2_byte[] = "xenpets/strooper/shockroach/shock_byte.wav";
new const s2_die[] = "xenpets/strooper/shockroach/shock_die.wav";
new const s2_flinch[] = "xenpets/strooper/shockroach/shock_flinch.wav";
new const s2_idle[3][] = {"xenpets/strooper/shockroach/shock_idle1.wav","xenpets/strooper/shockroach/shock_idle2.wav","xenpets/strooper/shockroach/shock_idle3.wav"};
new const s2_jump[2][] = {"xenpets/strooper/shockroach/shock_jump1.wav","xenpets/strooper/shockroach/shock_jump2.wav"};
new const s2_walk[] = "xenpets/strooper/shockroach/shock_walk.wav";

//Animations
new const seq_walk = 0;
new const seq_run = 1;
new const seq_victorydance = 2;
new const seq_cover = 3;
new const seq_flinch = 4;
new const seq_lleg_flinch = 5;
new const seq_rleg_flinch = 6;
new const seq_rarm_flinch = 7;
new const seq_larm_flinch = 8;
new const seq_granade = 9;
new const seq_idle = 10;
new const seq_idle2 = 11;
new const seq_comb_idle = 12;
new const seq_frontkick = 13;
new const seq_crouch_idle = 14;
new const seq_crouch_mp5 = 16;
new const seq_stand_mp5 = 17;
new const seq_reload_mp5 = 18;
new const seq_signal_go = 19;
new const seq_signal_flank = 20;
new const seq_signal_back = 21;
new const seq_limp_walk = 23;
new const seq_limp_run = 24;
new const seq_rotate_left = 25;
new const seq_rotate_right = 26;
new const seq_die = 27;
new const seq_die_forward = 28;
new const seq_die_back = 30;

//Creature constants
new const prize = 5000;
new const maxhp = 400;

//Creature variables
new xen_id;

//----- PLUGIN INITIALIZATION -----

//Inits the plugin
public plugin_init(){
register_plugin("XenPets Creature: ShockTrooper","1.0","Lulu the hero");
}

//Precaches the files
public plugin_precache(){
new i;
//models
precache_model(model);
precache_model(spark);
precache_model(roach);
//sounds
precache_sound(s_blis);
precache_sound(s_dit);
precache_sound(s_dup);
precache_sound(s_ga);
precache_sound(s_hyu);
precache_sound(s_ka);
precache_sound(s_kiml);
precache_sound(s_kss);
precache_sound(s_ku);
precache_sound(s_kur);
precache_sound(s_kyur);
precache_sound(s_mub);
precache_sound(s_puh);
precache_sound(s_pur);
precache_sound(s_ras);
precache_sound(s_thirv);
precache_sound(s_wirt);
precache_sound(s_fire);
precache_sound(s_attack);
for(i=0;i<4;i++){
precache_sound(s_die[i]);
}
for(i=0;i<5;i++){
precache_sound(s_pain[i]);
}
precache_sound(s2_angry);
precache_sound(s2_byte);
precache_sound(s2_die);
precache_sound(s2_flinch);
for(i=0;i<3;i++){
precache_sound(s2_idle[i]);
}
for(i=0;i<2;i++){
precache_sound(s2_jump[i]);
}
precache_sound(s2_walk);
//registering the creature
xen_id = xp_register_creature("ShockTrooper",maxhp,prize);
}

//----- FORWARD HANDLERS -----

//A creature has been purchased, could be our's
public xp_creature_bought(id,type){
if(type==xen_id){
complex_cry(id,random(1))
}
}

//A creature type has been cleared at a user.
public xp_creatures_reseted(id,type){
if(type==xen_id){
//complex_cry(id,1);
}
}

//A creature has to be summoned, is it our type?
public xp_creature_summoned(id,type){
if(type==xen_id){
new strooper;
strooper = engfunc(EngFunc_CreateNamedEntity,engfunc(Eng Func_AllocString,"info_target"));
if(pev_valid(strooper)){
set_pev(strooper,pev_classname,"shock_trooper");
engfunc(EngFunc_SetModel,strooper,model);
set_pev(strooper,pev_solid,SOLID_BBOX);
set_pev(strooper,pev_movetype,MOVETYPE_STEP);
set_pev(strooper,pev_body,0);
set_pev(strooper,pev_frame,0);
set_pev(strooper,pev_sequence,seq_idle);
set_pev(strooper,pev_framerate,1.0);



new Float:point_origin[3],Float:player_origin[3];
new origin[3],origin2[3]
get_user_origin(id,origin,3);
for(new i=0;i<3;i++){
point_origin[i]=float(origin[i]);
}
get_user_origin(id,origin2,3);
for(new i=0;i<3;i++){
player_origin[i]=float(origin2[i]);
}
set_pev(strooper,pev_origin,point_origin);
xp_turn_to_player(strooper,id,seq_rotate_left ,seq_rotate_right);

new params[2];
params[0] = strooper;
params[1] = seq_idle;

set_task(1.0,"set_sequence",0,params,2);

complex_cry(id,1);
xp_start_blink(strooper,3);
return strooper;
}
}
return -1;
}

//----- MISC -----

//Plays the "which" cry sequence
public complex_cry(id,which){
new params[3];
params[0] = id;
params[1] = 0;
params[2] = which;
give_cry(params);
}

//Gives a cry of the monster - can handle more sound samples if called recursivly
public give_cry(params[]){
if(xen_id!=-1){
new id = params[0];
new phase = params[1];
new type = params[2];
switch(type){
case 0 : { //Majha hm maj he he
switch(phase){
case 0 : {
emit_sound(id,CHAN_VOICE,s_mub,1.0,ATTN_NORM, 0,PITCH_NORM);
phase++;
params[1]=phase;
set_task(0.35,"give_cry",0,params,3);
}
case 1 : {
emit_sound(id,CHAN_VOICE,s_puh,1.0,ATTN_NORM, 0,PITCH_NORM);
phase++;
params[1]=phase;
set_task(0.13,"give_cry",0,params,3);
}
case 2 : {
emit_sound(id,CHAN_VOICE,s_pur,1.0,ATTN_NORM, 0,PITCH_NORM);
phase++;
params[1]=phase;
set_task(0.1,"give_cry",0,params,3);
}
case 3 : {
emit_sound(id,CHAN_VOICE,s_puh,1.0,ATTN_NORM, 0,PITCH_NORM);
phase++;
params[1]=phase;
set_task(0.1,"give_cry",0,params,3);
}
case 4 : {
emit_sound(id,CHAN_VOICE,s_dit,1.0,ATTN_NORM, 0,PITCH_NORM);
phase++;
params[1]=phase;
set_task(0.1,"give_cry",0,params,3);
}
case 5 : {
emit_sound(id,CHAN_VOICE,s_dit,1.0,ATTN_NORM, 0,PITCH_NORM);
}
}
}
case 1 : { //Kiml kiml
switch(phase){
case 0 : {
emit_sound(id,CHAN_VOICE,s_kiml,1.0,ATTN_NORM ,0,PITCH_NORM);
phase++;
params[1]=phase;
set_task(0.4,"give_cry",0,params,3);
}
case 1 : {
emit_sound(id,CHAN_VOICE,s_kiml,1.0,ATTN_NORM ,0,PITCH_NORM);
}
}
}
}
}
}

//Sets the creature's animation phase
public set_sequence(params[]){
new ent = params[0];
new seq = params[1];
set_pev(ent,pev_frame,0);
set_pev(ent,pev_sequence,seq);
}
You'll find the "give_cry" function which was my earlier tryings of making simultean sounds emitted from a point( entity ) using emit sound. A bit buggy, but illustrates my ideas...

The sound this way is full of "holes", not like the thing spk can produce.



EDIT! Please don't correct the code, it's old, one of my first codes, I know my mistakes, but I am not working on this right now, so this code was left as is. In simpler words: don't start optimizing the sound arrays, while not answering to the question asked above in the topic.
Thank you.