2025-07-16 05:03 CEST

View Issue Details Jump to Notes ]
IDProjectCategoryView StatusLast Update
0000541Spring engineGeneralpublic2007-05-30 16:02
ReporterKloot 
Assigned Totvo 
PrioritynormalSeverityfeatureReproducibilityN/A
StatusresolvedResolutionfixed 
Product Version 
Target VersionFixed in Version 
Summary0000541: [patch] multiple unit sounds
DescriptionEnables units to have multiple sound-acks. For the "ok", "select",
and "arrived" categories the new limit is 8, the others default to
1 but this would be trivial to change (see the LoadSounds() calls
in UnitDefHandler.cpp). If more than one sound is available for a
category then the sample that gets played is chosen randomly.

(Note that because the GuiSound structure is also used for weapon
fire- and hit-sounds, weapons could have multiple sounds tied to
them if the LoadSound() function in CWeaponDefHandler were modified
along the same lines as CUnitDefHandler::LoadSound()).

Final remark: this patch modifies two Lua binding functions
(LuaUnitDefs::PushGuiSound() and LuaWeaponDefs::GuiSoundTable()),
so it might be a good idea if someone more knowledgeable on that
part of Spring (trepan ;)) double-checks my changes there, in
particular to the former.
TagsNo tags attached.
Checked infolog.txt for Errors
Attached Files
  • patch file icon MultipleUnitSounds.patch (31,866 bytes) 2007-05-29 22:31 -
    Index: Lua/LuaUnitDefs.cpp
    ===================================================================
    --- Lua/LuaUnitDefs.cpp	(revision 3795)
    +++ Lua/LuaUnitDefs.cpp	(working copy)
    @@ -462,23 +462,27 @@
     }
     
     
    -static void PushGuiSound(lua_State* L,
    -                         const string& name, const GuiSound& sound)
    -{
    +static void PushGuiSound(lua_State* L, const string& name, const GuiSound& sound) {
     	lua_pushstring(L, name.c_str());
     	lua_newtable(L);
    -	HSTR_PUSH_STRING(L, "name",   sound.name);
    +
    +	for (int idx = 0; idx < sound.names.size(); idx++)
    +		HSTR_PUSH_STRING(L, "name", ((GuiSound&) sound).getName(idx));
    +
     	if (CLuaHandle::GetActiveHandle()->GetUserMode()) {
    -		HSTR_PUSH_NUMBER(L, "id",   sound.id); 
    +		for (int idx = 0; idx < sound.ids.size(); idx++)
    +			HSTR_PUSH_NUMBER(L, "id", ((GuiSound&) sound).getID(idx));
     	}
    -	HSTR_PUSH_NUMBER(L, "volume", sound.volume);
    -	lua_rawset(L, -3);  
    +
    +	for (int idx = 0; idx < sound.volumes.size(); idx++)
    +		HSTR_PUSH_NUMBER(L, "volume", ((GuiSound&) sound).getVolume(idx));
    +
    +	lua_rawset(L, -3);
     }
     
     
    -static int SoundsTable(lua_State* L, const void* data)
    -{
    -	const UnitDef::SoundStruct& sounds = *((const UnitDef::SoundStruct*)data);
    +static int SoundsTable(lua_State* L, const void* data) {
    +	const UnitDef::SoundStruct& sounds = *((const UnitDef::SoundStruct*) data);
     
     	lua_newtable(L);
     	PushGuiSound(L, "select",      sounds.select);
    @@ -496,9 +500,10 @@
     }
     
     
    -static int ModelDefTable(lua_State* L, const void* data)
    -{
    -	const UnitModelDef& md = *((const UnitModelDef*)data);
    +
    +
    +static int ModelDefTable(lua_State* L, const void* data) {
    +	const UnitModelDef& md = *((const UnitModelDef*) data);
     	lua_newtable(L);
     	HSTR_PUSH_STRING(L, "path", md.modelpath);
     	HSTR_PUSH_STRING(L, "name", md.modelname);
    Index: Lua/LuaWeaponDefs.cpp
    ===================================================================
    --- Lua/LuaWeaponDefs.cpp	(revision 3795)
    +++ Lua/LuaWeaponDefs.cpp	(working copy)
    @@ -397,15 +397,17 @@
     }
     
     
    +
     static int GuiSoundTable(lua_State* L, const void* data)
     {
    -	const GuiSound& sound = *((const GuiSound*)data);
    +	const GuiSound& sound = *((const GuiSound*) data);
     	lua_newtable(L);
    -	HSTR_PUSH_STRING(L, "name",   sound.name);
    +
    +	HSTR_PUSH_STRING(L, "name", ((GuiSound&) sound).getName(0));
     	if (CLuaHandle::GetActiveHandle()->GetUserMode()) {
    -		HSTR_PUSH_NUMBER(L, "id",   sound.id);
    +		HSTR_PUSH_NUMBER(L, "id", ((GuiSound&) sound).getID(0));
     	}
    -	HSTR_PUSH_NUMBER(L, "volume", sound.volume);
    +	HSTR_PUSH_NUMBER(L, "volume", ((GuiSound&) sound).getVolume(0));
     	return 1;
     }
     
    Index: Sim/Units/Unit.cpp
    ===================================================================
    --- Sim/Units/Unit.cpp	(revision 3795)
    +++ Sim/Units/Unit.cpp	(working copy)
    @@ -758,11 +758,18 @@
     		    && (team == gu->myTeam) && !camera->InView(midPos,radius+50) && !gu->spectatingFullView) {
     			logOutput.Print("%s is being attacked",unitDef->humanName.c_str());
     			logOutput.SetLastMsgPos(pos);
    -			if (unitDef->isCommander || uh->lastDamageWarning+150<gs->frameNum) {
    -				sound->PlaySample(unitDef->sounds.underattack.id,unitDef->isCommander?4:2);
    +
    +			if (unitDef->isCommander || uh->lastDamageWarning + 150 < gs->frameNum) {
    +				int soundIdx = unitDef->sounds.underattack.getRandomIdx();
    +				if (soundIdx >= 0) {
    +					sound->PlaySample(
    +						unitDef->sounds.underattack.getID(soundIdx),
    +						unitDef->isCommander? 4: 2);
    +				}
     			}
    -			minimap->AddNotification(pos,float3(1,0.3f,0.3f),unitDef->isCommander?1:0.5f);	//todo: make compatible with new gui
     
    +			minimap->AddNotification(pos,float3(1,0.3f,0.3f),unitDef->isCommander? 1: 0.5f);	//todo: make compatible with new gui
    +
     			uh->lastDamageWarning=gs->frameNum;
     			if(unitDef->isCommander)
     				uh->lastCmdDamageWarning=gs->frameNum;
    @@ -1512,42 +1519,42 @@
     		gs->Team(team)->CommanderDied(this);
     	gs->Team(this->lineage)->LeftLineage(this);
     
    -	if(!reclaimed && !beingBuilt){
    +	if (!reclaimed && !beingBuilt) {
     		string exp;
    -		if(selfDestruct)
    -			exp=unitDef->selfDExplosion;
    +		if (selfDestruct)
    +			exp = unitDef->selfDExplosion;
     		else
    -			exp=unitDef->deathExplosion;
    +			exp = unitDef->deathExplosion;
     
    -		if(!exp.empty()){
    -			WeaponDef* wd=weaponDefHandler->GetWeapon(exp);
    -			if(wd){
    -				helper->Explosion(midPos,wd->damages,wd->areaOfEffect,wd->edgeEffectiveness,wd->explosionSpeed,this,true,wd->damages[0]>500?1:2,false,wd->explosionGenerator,0, ZeroVector, wd->id);
    +		if (!exp.empty()) {
    +			WeaponDef* wd = weaponDefHandler->GetWeapon(exp);
    +			if (wd) {
    +				helper->Explosion(
    +					midPos, wd->damages, wd->areaOfEffect, wd->edgeEffectiveness,
    +					wd->explosionSpeed, this, true, wd->damages[0] > 500? 1: 2,
    +					false, wd->explosionGenerator, 0, ZeroVector, wd->id
    +				);
     
    -				// Play explosion sound
    -				CWeaponDefHandler::LoadSound(wd->soundhit);
    -				if (wd->soundhit.id) {
    -
    -					// HACK loading code doesn't set sane defaults for explosion sounds, so we do it here
    -					if (wd->soundhit.volume == -1)
    -						wd->soundhit.volume = 5.0f;
    -
    -					sound->PlaySample(wd->soundhit.id, pos, wd->soundhit.volume);
    +				// play explosion sound
    +				if (wd->soundhit.getID(0) > 0) {
    +					// HACK: loading code doesn't set sane defaults for explosion sounds, so we do it here
    +					// NOTE: actually no longer true, loading code always ensures that sound volume != -1
    +					float volume = wd->soundhit.getVolume(0);
    +					sound->PlaySample(wd->soundhit.getID(0), pos, (volume == -1)? 5.0f: volume);
     				}
    -
    -				//logOutput.Print("Should play %s (%d)", wd->soundhit.name.c_str(), wd->soundhit.id);
     			}
     		}
    -		if(selfDestruct)
    -			recentDamage+=maxHealth*2;
     
    +		if (selfDestruct)
    +			recentDamage += maxHealth * 2;
    +
     		vector<int> args;
    -		args.push_back((int)(recentDamage/maxHealth*100));
    +		args.push_back((int) (recentDamage / maxHealth * 100));
     		args.push_back(0);
     		cob->Call(COBFN_Killed, args, &CUnitKilledCB, this, NULL);
     
     		UnBlock();
    -		delayedWreckLevel=args[1];
    +		delayedWreckLevel = args[1];
     //		featureHandler->CreateWreckage(pos,wreckName, heading, args[1],-1,true);
     	} else {
     		deathScriptFinished=true;
    @@ -1615,38 +1622,46 @@
     	//if(unitDef->tidalGenerator>0)
     	//	cob->Call(COBFN_SetSpeed, (int)(readmap->tidalStrength*3000.0f*unitDef->tidalGenerator));
     
    -	if(activated)
    +	if (activated)
     		return;
    +
     	activated = true;
    -
     	cob->Call(COBFN_Activate);
     
    -	if(unitDef->targfac){
    -		radarhandler->radarErrorSize[allyteam]/=radarhandler->targFacEffect;
    +	if (unitDef->targfac){
    +		radarhandler->radarErrorSize[allyteam] /= radarhandler->targFacEffect;
     	}
    -	if(hasRadarCapacity)
    +	if (hasRadarCapacity)
     		radarhandler->MoveUnit(this);
     
    -	if(unitDef->sounds.activate.id)
    -		sound->PlayUnitActivate(unitDef->sounds.activate.id, this, unitDef->sounds.activate.volume);
    +	int soundIdx = unitDef->sounds.activate.getRandomIdx();
    +	if (soundIdx >= 0) {
    +		sound->PlayUnitActivate(
    +			unitDef->sounds.activate.getID(soundIdx), this,
    +			unitDef->sounds.activate.getVolume(soundIdx));
    +	}
     }
     
     void CUnit::Deactivate()
     {
    -	if(!activated)
    +	if (!activated)
     		return;
    +
     	activated = false;
    -
     	cob->Call(COBFN_Deactivate);
     
    -	if(unitDef->targfac){
    -		radarhandler->radarErrorSize[allyteam]*=radarhandler->targFacEffect;
    +	if (unitDef->targfac){
    +		radarhandler->radarErrorSize[allyteam] *= radarhandler->targFacEffect;
     	}
    -	if(hasRadarCapacity)
    +	if (hasRadarCapacity)
     		radarhandler->RemoveUnit(this);
     
    -	if(unitDef->sounds.deactivate.id)
    -		sound->PlayUnitActivate(unitDef->sounds.deactivate.id, this, unitDef->sounds.deactivate.volume);
    +	int soundIdx = unitDef->sounds.deactivate.getRandomIdx();
    +	if (soundIdx >= 0) {
    +		sound->PlayUnitActivate(
    +			unitDef->sounds.deactivate.getID(soundIdx), this,
    +			unitDef->sounds.deactivate.getVolume(soundIdx));
    +	}
     }
     
     void CUnit::PushWind(float x, float z, float strength)
    Index: Sim/Units/UnitDefHandler.h
    ===================================================================
    --- Sim/Units/UnitDefHandler.h	(revision 3795)
    +++ Sim/Units/UnitDefHandler.h	(working copy)
    @@ -52,7 +52,8 @@
     
     	void AssignTechLevel(UnitDef& ud, int level);
     	
    -	void LoadSound(TdfParser &sunparser, GuiSound &gsound, std::string sunname);
    +	void LoadSounds(TdfParser&, GuiSound&, std::string, int);
    +	void LoadSound(TdfParser&, GuiSound&, std::string, int);
     
     public:
     //	void CreateBlockingLevels(UnitDef *def,std::string yardmap);
    Index: Sim/Units/COB/CobInstance.cpp
    ===================================================================
    --- Sim/Units/COB/CobInstance.cpp	(revision 3795)
    +++ Sim/Units/COB/CobInstance.cpp	(working copy)
    @@ -629,7 +629,7 @@
     				dir.Normalize();
     				unit->unitDef->sfxExplGens[type-1024]->Explosion(pos, 1, 1, unit, 0, 0, dir);
     			}
    -			else if(type&2048)  //make a weapon fire from the piece
    +			else if (type&2048)  //make a weapon fire from the piece
     			{
     				//this is very hackish and probably has a lot of side effects, but might be usefull for something
     				//float3 relDir =-unit->localmodel->GetPieceDirection(piece);
    @@ -648,12 +648,18 @@
     				unit->weapons[type-2048]->weaponPos = weaponPos;
     
     			}
    -			else if(type&4096)  //detonate weapon from piece
    -			{
    -				WeaponDef *weaponDef = unit->weapons[type-4096]->weaponDef;
    -				sound->PlaySample(weaponDef->soundhit.id,unit,weaponDef->soundhit.volume);
    -				helper->Explosion(pos,weaponDef->damages,weaponDef->areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,unit, true, 1.0f, false,weaponDef->explosionGenerator,NULL,float3(0,0,0), weaponDef->id);
    +			else if (type & 4096) {
    +				// detonate weapon from piece
    +				WeaponDef* weaponDef = unit->weapons[type - 4096]->weaponDef;
    +				if (weaponDef->soundhit.getID(0) > 0) {
    +					sound->PlaySample(weaponDef->soundhit.getID(0), unit, weaponDef->soundhit.getVolume(0));
    +				}
     
    +				helper->Explosion(
    +					pos, weaponDef->damages, weaponDef->areaOfEffect, weaponDef->edgeEffectiveness,
    +					weaponDef->explosionSpeed, unit, true, 1.0f, false, weaponDef->explosionGenerator,
    +					NULL, float3(0, 0, 0), weaponDef->id
    +				);
     			}
     			break;
     	}
    Index: Sim/Units/UnitTypes/Builder.cpp
    ===================================================================
    --- Sim/Units/UnitTypes/Builder.cpp	(revision 3795)
    +++ Sim/Units/UnitTypes/Builder.cpp	(working copy)
    @@ -573,10 +573,14 @@
     
     	std::vector<int> args;
     	args.push_back(short(h-heading));
    -	cob->Call("StartBuilding",args);
    +	cob->Call("StartBuilding", args);
     
    -	if(unitDef->sounds.build.id)
    -		sound->PlaySample(unitDef->sounds.build.id, pos, unitDef->sounds.build.volume);
    +	int soundIdx = unitDef->sounds.build.getRandomIdx();
    +	if (soundIdx >= 0) {
    +		sound->PlaySample(
    +			unitDef->sounds.build.getID(soundIdx), pos,
    +			unitDef->sounds.build.getVolume(soundIdx));
    +	}
     }
     
     
    Index: Sim/Units/UnitTypes/Factory.cpp
    ===================================================================
    --- Sim/Units/UnitTypes/Factory.cpp	(revision 3795)
    +++ Sim/Units/UnitTypes/Factory.cpp	(working copy)
    @@ -105,11 +105,14 @@
     
     			cob->Call("StartBuilding");
     
    -			if (unitDef->sounds.build.id) {
    -				sound->PlaySample(unitDef->sounds.build.id, pos, unitDef->sounds.build.volume);
    +			int soundIdx = unitDef->sounds.build.getRandomIdx();
    +			if (soundIdx >= 0) {
    +				sound->PlaySample(
    +					unitDef->sounds.build.getID(soundIdx), pos,
    +					unitDef->sounds.build.getVolume(0));
     			}
     		} else {
    -			helper->BuggerOff(buildPos-float3(0.01f,0,0.02f),radius+8);
    +			helper->BuggerOff(buildPos - float3(0.01f, 0, 0.02f), radius + 8);
     		}
     	}
     
    Index: Sim/Units/UnitDef.h
    ===================================================================
    --- Sim/Units/UnitDef.h	(revision 3795)
    +++ Sim/Units/UnitDef.h	(working copy)
    @@ -12,15 +12,61 @@
     struct WeaponDef;
     class CExplosionGenerator;
     
    -const int MAX_UNITS=5000;
    +const int MAX_UNITS = 5000;
     
    +
     struct GuiSound
     {
    -	std::string name;
    -	int id;
    -	float volume;
    +	// note: vector sizes are always equal
    +	// (vector of triples would be better)
    +	std::vector<std::string> names;
    +	std::vector<int> ids;
    +	std::vector<float> volumes;
    +
    +	// return a random sound index if more than one sound was loaded
    +	// (used for unit acknowledgements, could be called for weapons too)
    +	int getRandomIdx(void) {
    +		switch (ids.size()) {
    +			case 0: { return -1; } break;
    +			case 1: { return 0; } break;
    +			default: {
    +				return int((float(rand()) / RAND_MAX) * ids.size());
    +			} break;
    +		}
    +	}
    +
    +	// get a (loaded) sound's name for index <idx>
    +	std::string getName(int idx) {
    +		return (idx >= 0 && idx < names.size())? names[idx]: "";
    +	}
    +	// get a (loaded) sound's ID for index <idx>
    +	int getID(int idx) {
    +		return (idx >= 0 && idx < ids.size())? ids[idx]: 0;
    +	}
    +	// get a (loaded) sound's volume for index <idx>
    +	float getVolume(int idx) {
    +		return (idx >= 0 && idx < volumes.size())? volumes[idx]: 0.0f;
    +	}
    +
    +	// set a (loaded) sound's name for index <idx>
    +	void setName(int idx, std::string name) {
    +		if (idx >= 0 && idx < names.size())
    +			names[idx] = name;
    +	}
    +	// set a (loaded) sound's ID for index <idx>
    +	void setID(int idx, int ID) {
    +		if (idx >= 0 && idx < ids.size())
    +			ids[idx] = ID;
    +	}
    +	// set a (loaded) sound's volume for index <idx>
    +	void setVolume(int idx, float volume) {
    +		if (idx >= 0 && idx < volumes.size())
    +			volumes[idx] = volume;
    +	}
     };
     
    +
    +
     struct UnitModelDef
     {
     	std::string modelpath;
    Index: Sim/Units/UnitLoader.cpp
    ===================================================================
    --- Sim/Units/UnitLoader.cpp	(revision 3795)
    +++ Sim/Units/UnitLoader.cpp	(working copy)
    @@ -409,42 +409,46 @@
     	weapon->metalFireCost=weapondef->metalcost;
     	weapon->energyFireCost=weapondef->energycost;
     
    -	CWeaponDefHandler::LoadSound(weapondef->firesound);
    -	CWeaponDefHandler::LoadSound(weapondef->soundhit);
     
    -	if(weapondef->firesound.volume == -1 || weapondef->soundhit.volume == -1)  //no volume read from defenition
    -	{
    -		if(weapon->damages[0]>50){
    -			float soundVolume=sqrt(weapon->damages[0]*0.5f);
    -			if(weapondef->type=="LaserCannon")
    -				soundVolume*=0.5f;
    -			float hitSoundVolume=soundVolume;
    -			if((weapondef->type=="MissileLauncher" || weapondef->type=="StarburstLauncher") && soundVolume>100)
    -				soundVolume=10*sqrt(soundVolume);
    -			if(weapondef->firesound.volume==-1)
    -				weapondef->firesound.volume=soundVolume;
    -			soundVolume=hitSoundVolume;
    -			if(weapon->areaOfEffect>8)
    -				soundVolume*=2;
    -			if(weapondef->type=="DGun")
    -				soundVolume*=0.15f;
    -			if(weapondef->soundhit.volume==-1)
    -				weapondef->soundhit.volume=soundVolume;
    +	if (weapondef->firesound.getVolume(0) == -1 || weapondef->soundhit.getVolume(0) == -1) {
    +		// no volume (-1) read from weapon definition, set it dynamically here
    +		if (weapon->damages[0] > 50) {
    +			float soundVolume = sqrt(weapon->damages[0] * 0.5f);
    +
    +			if (weapondef->type == "LaserCannon")
    +				soundVolume *= 0.5f;
    +
    +			float hitSoundVolume = soundVolume;
    +
    +			if ((weapondef->type == "MissileLauncher" || weapondef->type == "StarburstLauncher") && soundVolume > 100)
    +				soundVolume = 10 * sqrt(soundVolume);
    +			if (weapondef->firesound.getVolume(0) == -1)
    +				weapondef->firesound.setVolume(0, soundVolume);
    +
    +			soundVolume = hitSoundVolume;
    +
    +			if (weapon->areaOfEffect > 8)
    +				soundVolume *= 2;
    +			if (weapondef->type == "DGun")
    +				soundVolume *= 0.15f;
    +			if (weapondef->soundhit.getVolume(0) == -1)
    +				weapondef->soundhit.setVolume(0, soundVolume);
     		}
    -		else
    -		{
    -			weapondef->soundhit.volume = 5.0f;
    -			weapondef->firesound.volume = 5.0f;
    +		else {
    +			weapondef->soundhit.setVolume(0, 5.0f);
    +			weapondef->firesound.setVolume(0, 5.0f);
     		}
     	}
    -	weapon->fireSoundId = weapondef->firesound.id;
    -	weapon->fireSoundVolume=weapondef->firesound.volume;
     
    -	weapon->onlyForward=weapondef->onlyForward;
    -	if(owner->unitDef->type=="Fighter" && !owner->unitDef->hoverAttack)		//fighter aircrafts have too big tolerance in ta
    -		weapon->maxAngleDif=cos(weapondef->maxAngle*0.4f/180*PI);
    +	weapon->fireSoundId = weapondef->firesound.getID(0);
    +	weapon->fireSoundVolume = weapondef->firesound.getVolume(0);
    +
    +
    +	weapon->onlyForward = weapondef->onlyForward;
    +	if (owner->unitDef->type == "Fighter" && !owner->unitDef->hoverAttack)	// fighter aircraft have too big tolerance in TA
    +		weapon->maxAngleDif = cos(weapondef->maxAngle * 0.4f / 180 * PI);
     	else
    -		weapon->maxAngleDif=cos(weapondef->maxAngle/180*PI);
    +		weapon->maxAngleDif = cos(weapondef->maxAngle / 180 * PI);
     
     	weapon->weaponNum=owner->weapons.size();
     
    Index: Sim/Units/UnitDefHandler.cpp
    ===================================================================
    --- Sim/Units/UnitDefHandler.cpp	(revision 3795)
    +++ Sim/Units/UnitDefHandler.cpp	(working copy)
    @@ -716,39 +716,66 @@
     		ud.customParams = tdfparser.GetAllValues("UNITINFO\\CustomParams");
     	}
     
    -	LoadSound(tdfparser, ud.sounds.ok, "ok1");
    -	LoadSound(tdfparser, ud.sounds.select, "select1");
    -	LoadSound(tdfparser, ud.sounds.arrived, "arrived1");
    -	LoadSound(tdfparser, ud.sounds.build, "build");
    -	LoadSound(tdfparser, ud.sounds.activate, "activate");
    -	LoadSound(tdfparser, ud.sounds.deactivate, "deactivate");
    -	LoadSound(tdfparser, ud.sounds.cant, "cant");
    -	LoadSound(tdfparser, ud.sounds.underattack, "underattack");
    +	LoadSounds(tdfparser, ud.sounds.ok, "ok", 8);					// eg. "ok1", "ok2", ...
    +	LoadSounds(tdfparser, ud.sounds.select, "select", 8);			// eg. "select1", "select2", ...
    +	LoadSounds(tdfparser, ud.sounds.arrived, "arrived", 8);			// eg. "arrived1", "arrived2", ...
    +	LoadSounds(tdfparser, ud.sounds.build, "build", 1);
    +	LoadSounds(tdfparser, ud.sounds.activate, "activate", 1);
    +	LoadSounds(tdfparser, ud.sounds.deactivate, "deactivate", 1);
    +	LoadSounds(tdfparser, ud.sounds.cant, "cant", 1);
    +	LoadSounds(tdfparser, ud.sounds.underattack, "underattack", 1);
     }
     
     
    -void CUnitDefHandler::LoadSound(TdfParser &tdfparser, GuiSound &gsound, std::string sunname)
    +
    +void CUnitDefHandler::LoadSounds(TdfParser &tdfparser, GuiSound& gsound, std::string soundName, int numSounds)
     {
    -	soundcategory.GetDef(gsound.name, "", tdfparser.SGetValueDef("", "UNITINFO\\SoundCategory")+"\\"+sunname);
    -	if(gsound.name.compare("")==0)
    -		gsound.id = 0;
    -	else
    -	{
    -		const string soundFile = "sounds/" + gsound.name + ".wav";
    +	if (numSounds > 1) {
    +		for (int i = 1; i <= numSounds; i++) {
    +			// soundnames are 1-based (eg. "ok1", "ok2", ...)
    +			// if more than one is available, so start at 1
    +			LoadSound(tdfparser, gsound, soundName, i);
    +		}
    +	} else {
    +		LoadSound(tdfparser, gsound, soundName, 0);
    +	}
    +}
    +
    +void CUnitDefHandler::LoadSound(TdfParser &tdfparser, GuiSound& gsound, std::string soundCatName, int soundNum)
    +{
    +	if (soundNum > 0) {
    +		// soundNum of 0 means this sound has no
    +		// alternates (ie. no number suffix)
    +		char buf[8];
    +		sprintf(buf, "%d", soundNum);
    +		soundCatName += buf;
    +	}
    +
    +	string soundName = "";
    +
    +	// extract the sound's actual name sans extension (eg. "kbarmsel")
    +	soundcategory.GetDef(soundName, "", tdfparser.SGetValueDef("", "UNITINFO\\SoundCategory") + "\\" + soundCatName);
    +
    +	if (soundName.compare("") != 0) {
    +		const string soundFile = "sounds/" + soundName + ".wav";
     		CFileHandler file(soundFile);
    -		if(file.FileExists()) {
    +
    +		if (file.FileExists()) {
    +			// we have a valid soundfile: store name, ID, and default volume
     			PUSH_CODE_MODE;
     			ENTER_UNSYNCED;
     			int id = sound->GetWaveId(soundFile);
     			POP_CODE_MODE;
    -			gsound.id = id;
    -		} else
    -			gsound.id = 0;
    +
    +			gsound.names.push_back(soundName);
    +			gsound.ids.push_back(id);
    +			gsound.volumes.push_back(5.0f);
    +		}
     	}
    -	gsound.volume = 5.0f;
     }
     
     
    +
     void CUnitDefHandler::ParseUnit(std::string file, int id)
     {
       try {
    Index: Sim/Projectiles/WeaponProjectile.cpp
    ===================================================================
    --- Sim/Projectiles/WeaponProjectile.cpp	(revision 3795)
    +++ Sim/Projectiles/WeaponProjectile.cpp	(working copy)
    @@ -117,15 +117,15 @@
     		
     		helper->Explosion(pos,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,weaponDef->areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,true,weaponDef->noExplode? 0.3f:1,weaponDef->noExplode || weaponDef->noSelfDamage, weaponDef->explosionGenerator,0,impactDir, weaponDef->id);
     	}
    -		
    -	if(weaponDef->soundhit.id)
    -		sound->PlaySample(weaponDef->soundhit.id,this,weaponDef->soundhit.volume);
     
    -	if(!weaponDef->noExplode)
    +	if (weaponDef->soundhit.getID(0) > 0) {
    +		sound->PlaySample(weaponDef->soundhit.getID(0), this, weaponDef->soundhit.getVolume(0));
    +	}
    +
    +	if (!weaponDef->noExplode)
     		CProjectile::Collision();
    -	else
    -	{
    -		if(TraveledRange())
    +	else {
    +		if (TraveledRange())
     			CProjectile::Collision();
     	}
     
    @@ -141,8 +141,7 @@
     
     void CWeaponProjectile::Collision(CUnit* unit)
     {
    -	if(!weaponDef->noExplode || gs->frameNum&1)
    -	{
    +	if (!weaponDef->noExplode || gs->frameNum & 1) {
     		float3 impactDir = speed;
     		impactDir.Normalize();
     
    @@ -154,14 +153,14 @@
     		helper->Explosion(pos,weaponDef->dynDamageExp>0?dynDamages:weaponDef->damages,weaponDef->areaOfEffect,weaponDef->edgeEffectiveness,weaponDef->explosionSpeed,owner,true,weaponDef->noExplode? 0.3f:1,weaponDef->noExplode,weaponDef->explosionGenerator,unit,impactDir, weaponDef->id);
     	}
     
    -	if(weaponDef->soundhit.id)
    -		sound->PlaySample(weaponDef->soundhit.id,this,weaponDef->soundhit.volume);
    +	if (weaponDef->soundhit.getID(0) > 0) {
    +		sound->PlaySample(weaponDef->soundhit.getID(0), this, weaponDef->soundhit.getVolume(0));
    +	}
     
     	if(!weaponDef->noExplode)
     		CProjectile::Collision(unit);
    -	else
    -	{
    -		if(TraveledRange())
    +	else {
    +		if (TraveledRange())
     			CProjectile::Collision();
     	}
     }
    Index: Sim/MoveTypes/groundmovetype.cpp
    ===================================================================
    --- Sim/MoveTypes/groundmovetype.cpp	(revision 3795)
    +++ Sim/MoveTypes/groundmovetype.cpp	(working copy)
    @@ -428,10 +428,14 @@
     	StartEngine();
     
     	ENTER_UNSYNCED;
    -	if(owner->team == gu->myTeam){
    -		//Play "activate" sound.
    -		if(owner->unitDef->sounds.activate.id)
    -			sound->PlayUnitActivate(owner->unitDef->sounds.activate.id, owner, owner->unitDef->sounds.activate.volume);
    +	if (owner->team == gu->myTeam) {
    +		// Play "activate" sound.
    +		int soundIdx = owner->unitDef->sounds.activate.getRandomIdx();
    +		if (soundIdx >= 0) {
    +			sound->PlayUnitActivate(
    +				owner->unitDef->sounds.activate.getID(soundIdx), owner,
    +				owner->unitDef->sounds.activate.getVolume(soundIdx));
    +		}
     	}
     	ENTER_SYNCED;
     }
    @@ -1178,11 +1182,15 @@
     
     		StopEngine();
     
    -		//Play "arrived" sound.
    +		// Play "arrived" sound.
     		ENTER_UNSYNCED;
    -		if(owner->team == gu->myTeam){
    -			if(owner->unitDef->sounds.arrived.id)
    -				sound->PlayUnitReply(owner->unitDef->sounds.arrived.id, owner, owner->unitDef->sounds.arrived.volume);
    +		if (owner->team == gu->myTeam) {
    +			int soundIdx = owner->unitDef->sounds.arrived.getRandomIdx();
    +			if (soundIdx >= 0) {
    +				sound->PlayUnitReply(
    +					owner->unitDef->sounds.arrived.getID(soundIdx), owner,
    +					owner->unitDef->sounds.arrived.getVolume(soundIdx));
    +			}
     		}
     		ENTER_SYNCED;
     
    @@ -1214,12 +1222,16 @@
     
     	//Sends a message to user.
     	ENTER_UNSYNCED;
    -	if(owner->team == gu->myTeam){
    -		//Playing "can't" sound.
    -		if(owner->unitDef->sounds.cant.id)
    -			sound->PlayUnitReply(owner->unitDef->sounds.cant.id, owner, owner->unitDef->sounds.cant.volume);
    +	if (owner->team == gu->myTeam) {
    +		// Playing "can't" sound.
    +		int soundIdx = owner->unitDef->sounds.cant.getRandomIdx();
    +		if (soundIdx >= 0) {
    +			sound->PlayUnitReply(
    +				owner->unitDef->sounds.cant.getID(soundIdx), owner,
    +				owner->unitDef->sounds.cant.getVolume(soundIdx));
    +		}
     
    -		if(owner->pos.distance(goal)>goalRadius+150){
    +		if (owner->pos.distance(goal) > goalRadius + 150) {
     			logOutput << owner->unitDef->humanName.c_str() << ": Can't reach destination!\n";
     			logOutput.SetLastMsgPos(owner->pos);
     		}
    Index: Sim/Weapons/WeaponDefHandler.cpp
    ===================================================================
    --- Sim/Weapons/WeaponDefHandler.cpp	(revision 3795)
    +++ Sim/Weapons/WeaponDefHandler.cpp	(working copy)
    @@ -56,7 +56,10 @@
     	delete[] weaponDefs;
     }
     
    -void CWeaponDefHandler::ParseTAWeapon(TdfParser *sunparser, std::string weaponname, int id)
    +
    +
    +
    +void CWeaponDefHandler::ParseTAWeapon(TdfParser* sunparser, std::string weaponname, int id)
     {
     	weaponDefs[id].name = weaponname;
     
    @@ -185,19 +188,8 @@
     
     //	logOutput.Print("%s as %s",weaponname.c_str(),weaponDefs[id].type.c_str());
     
    -	sunparser->GetDef(weaponDefs[id].firesound.name, "", weaponname + "\\soundstart");
    -	sunparser->GetDef(weaponDefs[id].soundhit.name, "", weaponname + "\\soundhit");
    -	sunparser->GetDef(weaponDefs[id].firesound.volume, "-1", weaponname + "\\soundstartvolume");
    -	sunparser->GetDef(weaponDefs[id].soundhit.volume, "-1", weaponname + "\\soundhitvolume");
     
    -	/*if(weaponDefs[id].firesound.name.find(".wav") == -1)
    -		weaponDefs[id].firesound.name = weaponDefs[id].firesound.name + ".wav";
    -	if(weaponDefs[id].soundhit.name.find(".wav") == -1)
    -		weaponDefs[id].soundhit.name = weaponDefs[id].soundhit.name + ".wav";*/
     
    -	//weaponDefs[id].firesoundVolume = 5.0f;
    -	//weaponDefs[id].soundhitVolume = 5.0f;
    -
     	weaponDefs[id].range = atof(sunparser->SGetValueDef("10", weaponname + "\\range").c_str());
     	float accuracy,sprayangle,movingAccuracy;
     	sunparser->GetDef(accuracy, "0", weaponname + "\\accuracy");
    @@ -476,34 +468,57 @@
     	weaponDefs[id].dynDamageExp = atof(sunparser->SGetValueDef("0", weaponname + "\\dynDamageExp").c_str());
     	weaponDefs[id].dynDamageMin = atof(sunparser->SGetValueDef("0", weaponname + "\\dynDamageMin").c_str());
     	weaponDefs[id].dynDamageRange = atof(sunparser->SGetValueDef("0", weaponname + "\\dynDamageRange").c_str());
    +
    +
    +	LoadSound(sunparser, weaponDefs[id].firesound, id, "firesound");
    +	LoadSound(sunparser, weaponDefs[id].soundhit, id, "soundhit");
     }
     
    -void CWeaponDefHandler::LoadSound(GuiSound &gsound)
    +
    +
    +void CWeaponDefHandler::LoadSound(TdfParser* sunparser, GuiSound& gsound, int id, string soundCat)
     {
    -	// gsound.volume = 5.0f;
    -	if (gsound.name.compare("") == 0) {
    -		gsound.id = 0;
    -		return;
    -	}
    +	string name = "";
    +	float volume = -1;
     
    -	if (gsound.name.find(".wav") == -1) {
    -		gsound.name = gsound.name + ".wav";
    +	if (soundCat == "firesound") {
    +		sunparser->GetDef(name, "", weaponDefs[id].name + "\\soundstart");
    +		sunparser->GetDef(volume, "-1", weaponDefs[id].name + "\\soundstartvolume");
    +	} else if (soundCat == "soundhit") {
    +		sunparser->GetDef(name, "", weaponDefs[id].name + "\\soundhit");
    +		sunparser->GetDef(volume, "-1", weaponDefs[id].name + "\\soundhitvolume");
     	}
     
    -	const string soundPath = "sounds/" + gsound.name;
    -	CFileHandler sfile(soundPath);
    -	if (!sfile.FileExists()) {
    -		gsound.id = 0;
    -		return;
    +	if (name != "") {
    +		// only push data if we extracted a valid name
    +		gsound.names.push_back(name);
    +		gsound.ids.push_back(0);
    +		gsound.volumes.push_back(volume);
    +
    +		if (name.find(".wav") == -1) {
    +			// .wav extension missing, add it
    +			gsound.setName(0, name + ".wav");
    +		}
    +
    +		const string soundPath = "sounds/" + gsound.getName(0);
    +		CFileHandler sfile(soundPath);
    +
    +		if (!sfile.FileExists()) {
    +			// name refers to non-existent file, return
    +			return;
    +		}
    +
    +		PUSH_CODE_MODE;
    +		ENTER_UNSYNCED;
    +		int id = sound->GetWaveId(soundPath);
    +		POP_CODE_MODE;
    +
    +		gsound.setID(0, id);
     	}
    -	PUSH_CODE_MODE;
    -	ENTER_UNSYNCED;
    -	int id = sound->GetWaveId(soundPath);
    -	POP_CODE_MODE;
    -	gsound.id = id;
     }
     
     
    +
     WeaponDef *CWeaponDefHandler::GetWeapon(const std::string weaponname2)
     {
     	std::string weaponname(StringToLower(weaponname2));
    Index: Sim/Weapons/WeaponDefHandler.h
    ===================================================================
    --- Sim/Weapons/WeaponDefHandler.h	(revision 3795)
    +++ Sim/Weapons/WeaponDefHandler.h	(working copy)
    @@ -38,12 +38,6 @@
     	std::string type;
     	std::string description;
     
    -	/*std::string sfiresound;
    -	std::string ssoundhit;
    -	int firesoundId;
    -	int soundhitId;
    -	float firesoundVolume;
    -	float soundhitVolume;*/
     	GuiSound firesound;
     	GuiSound soundhit;
     
    @@ -192,8 +186,10 @@
     	bool dynDamageInverted;
     };
     
    +
     class CExplosionGeneratorHandler;
     
    +
     class CWeaponDefHandler
     {
     public:
    @@ -204,9 +200,9 @@
     	CWeaponDefHandler();
     	~CWeaponDefHandler();
     
    -	WeaponDef *GetWeapon(const std::string weaponname);
    +	WeaponDef* GetWeapon(const std::string weaponname);
     
    -	static void LoadSound(GuiSound &gsound);
    +	void LoadSound(TdfParser*, GuiSound&, int, std::string);
     
     	DamageArray DynamicDamages(DamageArray damages, float3 startPos, float3 curPos, float range, float exp, float damageMin, bool inverted);
     
    @@ -215,6 +211,7 @@
     	float3 hs2rgb(float h, float s);
     };
     
    +
     extern CWeaponDefHandler* weaponDefHandler;
     
     
    Index: Game/SelectedUnits.cpp
    ===================================================================
    --- Game/SelectedUnits.cpp	(revision 3795)
    +++ Game/SelectedUnits.cpp	(working copy)
    @@ -324,10 +324,15 @@
     
     	SendCommand(c);
     
    -	if(!selectedUnits.empty()){
    +	if (!selectedUnits.empty()) {
     		set<CUnit*>::iterator ui = selectedUnits.begin();
    -		if((*ui)->unitDef->sounds.ok.id)
    -			sound->PlayUnitReply((*ui)->unitDef->sounds.ok.id, (*ui), (*ui)->unitDef->sounds.ok.volume, true);
    +
    +		int soundIdx = (*ui)->unitDef->sounds.ok.getRandomIdx();
    +		if (soundIdx >= 0) {
    +			sound->PlayUnitReply(
    +				(*ui)->unitDef->sounds.ok.getID(soundIdx), (*ui),
    +				(*ui)->unitDef->sounds.ok.getVolume(soundIdx), true);
    +		}
     	}
     }
     
    Index: Game/UI/MouseHandler.cpp
    ===================================================================
    --- Game/UI/MouseHandler.cpp	(revision 3795)
    +++ Game/UI/MouseHandler.cpp	(working copy)
    @@ -405,10 +405,13 @@
     					}
     				}
     			}
    -			if(addedunits==1)
    -			{
    -				if(unit->unitDef->sounds.select.id)
    -					sound->PlayUnitReply(unit->unitDef->sounds.select.id, unit, unit->unitDef->sounds.select.volume);
    +			if (addedunits == 1) {
    +				int soundIdx = unit->unitDef->sounds.select.getRandomIdx();
    +				if (soundIdx >= 0) {
    +					sound->PlayUnitReply(
    +						unit->unitDef->sounds.select.getID(soundIdx), unit,
    +						unit->unitDef->sounds.select.getVolume(soundIdx));
    +				}
     			}
     			else if(addedunits) //more than one unit selected
     				sound->PlaySample(soundMultiselID);
    @@ -452,9 +455,12 @@
     				}
     				buttons[button].lastRelease=gu->gameTime;
     
    -				if(unit->unitDef->sounds.select.id)
    -					sound->PlayUnitReply(unit->unitDef->sounds.select.id, unit,
    -					                     unit->unitDef->sounds.select.volume);
    +				int soundIdx = unit->unitDef->sounds.select.getRandomIdx();
    +				if (soundIdx >= 0) {
    +					sound->PlayUnitReply(
    +						unit->unitDef->sounds.select.getID(soundIdx), unit,
    +						unit->unitDef->sounds.select.getVolume(soundIdx));
    +				}
     			}
     		}
     	}
    Index: Game/UI/MiniMap.cpp
    ===================================================================
    --- Game/UI/MiniMap.cpp	(revision 3795)
    +++ Game/UI/MiniMap.cpp	(working copy)
    @@ -692,9 +692,11 @@
     			sound->PlaySample(mouse->soundMultiselID);
     		}
     		else if (addedunits == 1) {
    -			if (unit->unitDef->sounds.select.id) {
    -				sound->PlayUnitReply(unit->unitDef->sounds.select.id, unit,
    -														 unit->unitDef->sounds.select.volume);
    +			int soundIdx = unit->unitDef->sounds.select.getRandomIdx();
    +			if (soundIdx >= 0) {
    +				sound->PlayUnitReply(
    +					unit->unitDef->sounds.select.getID(soundIdx), unit,
    +					unit->unitDef->sounds.select.getVolume(soundIdx));
     			}
     		}
     	}
    @@ -747,9 +749,11 @@
     			}
     			bp.lastRelease = gu->gameTime;
     
    -			if (unit->unitDef->sounds.select.id) {
    -				sound->PlayUnitReply(unit->unitDef->sounds.select.id, unit,
    -														 unit->unitDef->sounds.select.volume);
    +			int soundIdx = unit->unitDef->sounds.select.getRandomIdx();
    +			if (soundIdx >= 0) {
    +				sound->PlayUnitReply(
    +					unit->unitDef->sounds.select.getID(soundIdx), unit,
    +					unit->unitDef->sounds.select.getVolume(soundIdx));
     			}
     		}
     	}
    
    patch file icon MultipleUnitSounds.patch (31,866 bytes) 2007-05-29 22:31 +

-Relationships
+Relationships

-Notes

~0000919

tvo (reporter)

Committed, thanks! (r3799)

Btw, I think it's fine if you just commit yourself in the future, the code looks good enough ;-)

I changed the GetRandomIdx function to just 'return rand() % blah.size()' instead of casting to float and casting back to int etc.
+Notes

-Issue History
Date Modified Username Field Change
2007-05-29 22:31 Kloot New Issue
2007-05-29 22:31 Kloot File Added: MultipleUnitSounds.patch
2007-05-30 16:00 tvo Status new => assigned
2007-05-30 16:00 tvo Assigned To => tvo
2007-05-30 16:02 tvo Status assigned => resolved
2007-05-30 16:02 tvo Resolution open => fixed
2007-05-30 16:02 tvo Note Added: 0000919
+Issue History