random taunt sound when kill enemies and objects?

rafhot

Member
how can i make my characters play random sounds ( around 10 variations of taunts for each player character) when they kill enemies but without do it too often?

also i want to do some shouts for my characters when they break stuff on the screen but not everytime

any idea how to do it?
 
If you only want to play random sounds without animation change, didhitscript can do the trick.
For 'without do it too often', hmmm.... a randomized value check might work
 
Or have one of the random sound files have no actual sound in it. So it will give the impression that the character is not saying stuff too often (although he is, you just can´t listen!).
 
lol, sorry was just surprised bloodbane's answer.  Thou shame on me I didn't really answer the question...

rafhot to change the randomness, you edit the random values in the script.  OR as mersox suggested, simply declare silent .wav files.  or add them them more than once.

Sorry can't help further with that, I think there is a topic elsewhere discussing random values etc. thou

 
I started implementing similar ideas to reproduce what Raven's Software did in X-Men Legends and Marvel Ultimate Alliance games.

What you can consider in addition to basic randomness :

- adding a cooldown variable to ensure characters do not throw a line just after (or worse, while) throwing a line
- checking if character just killed the last enemy so as to throw a "victory" type line
- checking if seeing ennemies for the first time in a while so as to throw a "to battle" type line.
 
thank you guys, i already use the randsound and other random stuff shouts like sleep animation, low health checks when player use fall animations and such. but when kill enemies and objects i have no clue how to do yet

@picollo
I started implementing similar ideas to reproduce what Raven's Software did in X-Men Legends and Marvel Ultimate Alliance games.
this exactly what i want try to do into my game, care to share what you have?

thanks
 
I've already written a library that does all this, soun0005. Moreover it auto catalogs the sounds by groups, so you don't have to go around making lists. It also optionally plays said sounds in true stereo based on screen location.

IOW, you just put a set of sounds into the folder like so:

5_0
5_1
5_2
5_3

Where "5" is "battle cry when knocking someone down" and _0 is just an index. Then you just fire the script and tell it to play group 5.  The script will auto detect how many "5_X" sounds are there and play one. It also has a fallback mode to the main sounds folder for a generic set of male/female/machine/etc in case an entity does not have any "5_X' sounds, meaning you can use a default group of generics for male/female/whatever... and will fall back from THAT into the sounds folder with no distinction at all for a non nondescript generic.

IOW it will play a random "battle cry" or whatever looking in this order model->type (determined by model's throwdamage parameter)->sounds.

It's difficult to understand at first, but once set up, it's a fire and forget system. Just add or remove sound files and the the rest is automatic. See it in action here - note the random sounds in response to different events:

  • Attacking (light, medium, heavy)
  • Knock opponent down
  • Getting hurt
  • Getting hurt at low life
  • KO
  • and so on....

http://youtu.be/JossdCHwwIw

Now all that remains is how to trigger the script when you need it. Well that depends on the event. But for taunts on knockdown (or KO as you prefer) I use the didhit script. Here's what's doing the job in video above:

Code:
#include "data/scripts/vars/constants.h"	//http://www.caskeys.com/dc/?p=1314#constants
#include "data/scripts/com/bloc0002.h"		//http://www.caskeys.com/dc/?p=1314#bloc0002	
#include "data/scripts/com/soun0005.h"		//http://www.caskeys.com/dc/?p=1314#soun0005

void hit0004(void vEnt)
{
	/*
	hit0004
	Damon Vaughn Caskey
	2012_02_04
	
	Primary on hit script. Moved here from z_hit to be called by other functions.
	*/

	void    vEnt;
    void    vDef		= getlocalvar("damagetaker");
    int		iBloc		= getlocalvar("blocked");	
	int		iProj;
	int		iAIDrop;
	int		iDrop;
	int		iKnock;	
	int		iType;
	int		iAni;

	if(!vEnt)
	{
		vEnt = getlocalvar("self");
	}

	if(iBloc)																			//Attack blocked?
	{
        //bloc0002(vDef, 1);                                                              //Run block function.
    }
	else
	{
		iProj	= getentityproperty(vEnt, "projectile");								//Get projectile flag.
		iAIDrop = getentityproperty(vEnt, "aiflag", "drop");							//Get AI Drop flag.
		iAni	= getentityproperty(vEnt, "animationid");								//Get animation.

		if(!iAIDrop && !iProj && iAni != A_FOLLOW10)									//Not falling and has a sndcnt?
		{
			iDrop	= getlocalvar("drop");
			iKnock	= getentityproperty(vDef, "knockdowncount");

			if(iDrop > iKnock)															//Opponent will be knocked down?
			{
				iType = getentityproperty(vEnt, "type");

                if (iType == openborconstant("TYPE_PLAYER"))							//Player type?
                {
					soun0005(vEnt, VOIBTL, -1, 0.5, 0, 0);								//Battle cry (50%).
				}
                else
                {
                    soun0005(vEnt, VOIBTL, -1, 1, 0, 0);								//Battle cry.
                }			
			}
		}
	}
}

Pay attention to the soun005 call. Here's how it works:

soun0005 <ent>, <group>, <index>, <probability>, <sub folder>, <delay>

  • Ent: The entity to play sounds. Entities model folder will be search for sound files.
  • This is the sound group to pick a sound from (Battle cry, KO, Attack, etc.). This would the the "5" from 5_X above.
  • Sound index. This is here just in case you want to play a specific sound from a group. So if you want to always play 5_2, then you put 2 here. -1 tells the function to pick an index randomly.
  • Probability: This is a percentage chance the sound will actually play. Note here that players use their battle cry taunt on knockdown 50% of the time (keep it from getting old) and all other types play it 100%.
  • Sub folder. You can force the function to pick from a specific sub folder of sounds if you wish. Handy for certain set ups (like changing to animal sounds instead of human ones when you are riding a dragon).
  • Delay: Forced delay between sounds. Not finished, so don't bother with it.

Incidentally, a far more powerful (and if I may, that's saying something) replacement for this is also under works as the next item in my object core library - so watch for that soon.

DC

 
rafhot said:
this exactly what i want try to do into my game, care to share what you have?

I can share what I have right now, but I can't ensure you it doesn't contain bugs/flaws as I don't use this system yet myself.

Here's the functions that need to be available from character's animation script :

Code:
void rangeEvent(int rX, int rZ, int rA, int checkBehind, char type, int count){
	char engineType;
	switch(type){
		case "en":
			engineType = openborconstant("TYPE_ENEMY");
			break;
		case "obs":
			engineType = openborconstant("TYPE_OBSTACLE");
			break;
		default:
			return;
	}
	
	void vSelf = getlocalvar("self");
	int seeingEntities = getentityvar(vSelf, "seeing_" + type);
	if(seeingEntities == NULL() && findTarget01(rX, rZ, rA, checkBehind, engineType, count) != NULL()){
		int lastShout = getentityvar(vSelf, "lastShout");
		int elapsed_time = openborvariant("elapsed_time");
		if(lastShout == NULL() || lastShout != NULL() && elapsed_time > lastShout + 1000){
			//changeentityproperty(vSelf, "animation", openborconstant("ANI_freespecial1")); // Taunt animation
			char name = getentityproperty(vSelf, "defaultmodel");
			variableSound("data/chars/" + name + "/see_" + type, 1, 3);
			setentityvar(vSelf, "lastShout", elapsed_time);
			setentityvar(vSelf, "seeing_" + type, 1);
		}
	} else if(seeingEntities == 1 && findTarget01(rX+100, rZ, rA, checkBehind, engineType, 1) == NULL()){
		setentityvar(vSelf, "seeing_" +type, NULL());
	}
}

void variableSound(void path, int min, int max){
	
	int r = rand()%((max - min) + 1);
	if(r < 0) r = r * -1;
	r += min;
	
	
	playSound(path + r + ".wav");
}

void findTarget01(int Rx, int Rz,int Ra, int searchBack, char find_type, int count){
	int iECnt = openborvariant("count_entities");
	int iEnt;
	void vEnt,ani;
	void self = getlocalvar("self");
	float x = getentityproperty(self, "x");
	float z = getentityproperty(self, "z");
	float a = getentityproperty(self, "a");
	int dir=getentityproperty(self,"direction");
	int currentCount = 0;

	for(iEnt=0; iEnt<iECnt; iEnt++) {
		vEnt= getentity(iEnt);
		if(!getentityproperty(vEnt,"exists")) continue;
		if (
			getentityproperty(vEnt,"type") == openborconstant(find_type) &&
			!getentityproperty(vEnt,"dead") &&
			vEnt
		){
			if (isInRange(self,dir,vEnt,Rx,Rz,Ra,x,z,a, searchBack)){
				currentCount++;
				if(currentCount >= count) return vEnt;
			}
		}
	}
	return NULL();
}

int isBetweenRange(void self,int dir,void target,int rxMin, int rxMax, int rzMin, int rzMax, int raMin, int raMax, float x,float z,float a){
	float Tx = getentityproperty(target, "x");
	float Tz = getentityproperty(target, "z");
	float Ta = getentityproperty(target, "a");
	float Disx;
	float Disz = Tz - z;
	float Disa = Ta - a;

	if (dir==0){
		Disx = x - Tx;
	}else{
		Disx = Tx - x;
	}
	

	if(Disz < 0){
		Disz = -Disz;
	}
	if(Disa < 0){
		Disa = -Disa;
	}
	
	
	//log("\nTa = " + Ta + " ; Disa = " + Disa);
	//log("\nTx = " + Tx + " ; Disx = " + Disx);
	
	if(rxMax < rxMin){ // Is out of range
		
		if( (Disx >= rxMin || Disx < rxMax) && Disz <= rzMax && Disz >= rzMin && Disa<=raMax && Disa >= raMin) return 1;
		else return 0;
		
	} else if( Disx <= rxMax && Disx > rxMin && Disz <= rzMax && Disz >= rzMin && Disa<=raMax && Disa >= raMin){
		return 1;
	}else{
		return 0;
	}
	
}

int isInRange(void self,int dir,void target,int Rx, int Rz,int Ra,float x,float z,float a, int searchBack){
	if(searchBack) return isBetweenRange(self, dir, target, -Rx, Rx, -Rz, Rz, 0, Ra, x, z, a);
	else return isBetweenRange(self, dir, target, 0, Rx, 0, Rz, 0, Ra, x, z, a);
}

Then as of now, I put this type of call in animations such as idle or walk :

Code:
@script
	if(frame == 0) rangeEvent(700, 300, 999, 1, "en" , 3);
@end_script

This is for playing sound when seeing enemies. Here the parameters mean the event will trigger when 3 enemies will be in (X=700, Z=300, A=99) range, checking in front and behind  character's position. And it will reset when there will no longer be an enemy in this range.


As for knocking and killing shouts I use this code, in character's didhitscript :

Code:
	void vSelf = getlocalvar("self");
	void vTarget = getlocalvar("damagetaker");
	int targetType = getentityproperty(vTarget, "type");
	int dropPower = getlocalvar("drop");
	int killed = getentityproperty(vTarget, "dead");
	int knocked = getentityproperty(vTarget, "aiflag", "drop");
	
	char typeAlias;
	if(targetType == openborconstant("TYPE_ENEMY")) typeAlias = "en";
	else if(targetType == openborconstant("TYPE_OBSTACLE")) typeAlias = "obs";
	else return;

	int lastShout = getentityvar(vSelf, "lastShout");
	int elapsed_time = openborvariant("elapsed_time");
	
	if(lastShout == NULL() || lastShout != NULL() && elapsed_time > lastShout + 1000){
		char name = getentityproperty(vSelf, "defaultmodel");
		if(killed){
			if(findtarget(vSelf) != NULL()){ // Was not the last one
				variableSound("data/chars/" + name + "/killed_" + typeAlias, 1, 3);
			} else { // Killed the last one
				variableSound("data/chars/" + name + "/victory_" + typeAlias, 1, 2);
			}
			setentityvar(vSelf, "lastShout", elapsed_time);
		} else if(knocked && dropPower >= 2){
			variableSound("data/chars/" + name + "/hithard_" + typeAlias, 1, 3);
			setentityvar(vSelf, "lastShout", elapsed_time);
		}
	}

Oh yes, with the current implementation files need to be named :
- seeing enemies : see_en1.wav, see_en2.wav, see_en3.wav
- knocking enemy : hithard_en1.wav, hithard_en2.wav, hithard_en3.wav
- killing enemy : killed_en1.wav, killed_en2.wav, ...

Here's the files I use for Colossus for example.
 
very nice, i will test it too
it supports more than 3 sounds for each case?
killed 1,2,3,4,5,6,7,8?
hithard1,2,3,4,5,6,7,8...
and so on?

also inside my character folders i have to create a folder named:
see
hithard
killed
 
Right now you can adjust the number of different sounds by changing the third parameter of the variableSound calls.

eg for 8 variations :

Code:
variableSound("data/chars/" + name + "/killed", 1, 8);

You don't need to create sub folders, but yes the files (see1.wav, see2.wav, etc) need to be in character folder (and the character folder must be the same as the character model name). If you want to use subfolders it should be fairly easy to adapt the code.
 
tested picolo stuff and works perfect for what i need

i changed from 3 sounds to 50 and used 22 sound files for each and i will add more tomorrow
i want to expand this system and add a object/obstacle variation sounds for placeables used on stages

how can i set a obstacle1,2,3,4,5,6,7,8, stuff for this system?
 
Cool  :)

I edited my previous post to support obstacles variations.

With this implementation the files need to be named : see_en1.wav, see_en2.wav, .... / see_obs1.wav, see_obs2.wav, ... etc.

The fifth parameter of rangeEvent has changed :

Code:
@script
	if(frame == 0){
		rangeEvent(700, 300, 999, 1, "en" , 3); // seeing 3 enemies
		rangeEvent(700, 300, 999, 0, "obs" , 1); // seeing 1 obstacle in front
@end_script

I also added the victory condition in the didhit portion of the code. If you kill the last enemy, "victory_enX.wav" is played instead of "killed_enX.wav".
 
thanks!

the obstacle sound will be triggered when kill the obstacle like barrels and such?

im using marvel heroes mmo sounds and sometimes when you destroy obstacles hero said some fun quotes about destroy public things and colateral damage

 
Yes if files such as "killed_obs1.wav", "killed_obs2.wav", etc are present in character's folder, then they should play when you destroy obstacles.

Marvel hack'n'slash games have really fun quotes systems since X-Men Legends 1  ;D
 
i update the script now at my lunch time and the result was amazing!
this system is very addictive ehehe make the game feel very alive eheh

i want more feature creep :P

it is possible to expand the rangeevent to detect other players by character names and also npcs?

xmen legends and other games have some dialog between heroes that will be very cool in my projects too :P

 
Sure, but what type of behavior do you have in mind ? Multiple calls (each specific to one character) or an adaptative quote system ?

A character specific call will trigger and play sound only if specified character is in range.

An adapative system would require one global call (which would trigger for any character of a specified type) but the sound played will depend on  the character name.

For example if Wolverine is in range it would play "meet_wolverine1.wav", etc.
 
a specific character system for my case will be better

i will use playable characters as npc helpers too so it can happen to players and npcs
for example i have some verbal fights between hulk and the thing, the thing and human torch and so on...

 
Back
Top Bottom