Idle Ambiance

Post your example zscripts/ACS scripts/etc here.
Forum rules
The Projects forums are only for projects. If you are asking questions about a project, either find that project's thread, or start a thread in the General section instead.

Got a cool project idea but nothing else? Put it in the project ideas thread instead!

Projects for any Doom-based engine (especially 3DGE) are perfectly acceptable here too.

Please read the full rules for more details.
Hey Doomer
Posts: 283
Joined: Sat Sep 25, 2021 3:38 am

Idle Ambiance

Post by Hey Doomer »

I have seen ambient sound music tracks and it's possible to add ambiance to a sector in a map or attach to an object. Here is my attempt at a universal framework to add idle ambiance (that is, looping sounds for the most part) based on items or flats without using an AmbientSound Actor. (I'm not sure that matters, however.)

The concept is all the tech lamps make an electronic buzzing, certain areas have a distant rumbling sound, and there's a distant wind outside that bodes ill.

DECORATE:

Code: Select all

Actor IA_Sound
{
	+NOGRAVITY
	+FLOAT
	States
	{
	}
}
ZScript:

Code: Select all

class idleambiance_EventHandler : EventHandler
{
	struct item
	{
		string cname;
		string sname;
		int flags;
		double volume;
	}
	item ItemSounds[50];
	int iCounter;

	struct flat
	{
		string fname;
		int type;
		int height;
		string sname;
		int flags;
		double volume;
	}
	flat FlatSounds[50];
	int fCounter;
	
	void addItemSounds(string cname, string sname, int flags, double volume = 1.0)
	{
		ItemSounds[iCounter].cname = cname;
		ItemSounds[iCounter].sname = sname;
		ItemSounds[iCounter].flags = flags;
		ItemSounds[iCounter].volume = volume;
		iCounter++;
	}
	void addFlatSounds(string fname, int type, int height, string sname, int flags, double volume = 1.0)
	{
		FlatSounds[fCounter].fname = fname;
		FlatSounds[fCounter].type = type;
		FlatSounds[fCounter].height = height;
		FlatSounds[fCounter].sname = sname;
		FlatSounds[fCounter].flags = flags;
		FlatSounds[fCounter].volume = volume;
		fCounter++;
	}
	void LoadArrays()
	{
		iCounter = 0;
		fCounter = 0;
		int FLOOR = 0;
		int CEILING = 1;
		
		addItemSounds("Column", "buzz", CHANF_LISTENERZ | CHANF_LOOP | CHANF_NOSTOP | CHANF_OVERLAP);
		addItemSounds("TechLamp", "buzz", CHANF_LISTENERZ | CHANF_LOOP | CHANF_NOSTOP | CHANF_OVERLAP);
		addItemSounds("TechLamp2", "buzz", CHANF_LISTENERZ | CHANF_LOOP | CHANF_NOSTOP | CHANF_OVERLAP);

		addFlatSounds("F_SKY1", CEILING, 128, "outsidewind", CHANF_LOOP | CHANF_NOSTOP | CHANF_OVERLAP, 0.5);
		addFlatSounds("F_SKY2", CEILING, 128, "outsidewind", CHANF_LOOP | CHANF_NOSTOP | CHANF_OVERLAP, 0.5);
		addFlatSounds("F_SKY3", CEILING, 128, "outsidewind", CHANF_LOOP | CHANF_NOSTOP | CHANF_OVERLAP, 0.5);
		addFlatSounds("F_SKY4", CEILING, 128, "outsidewind", CHANF_LOOP | CHANF_NOSTOP | CHANF_OVERLAP, 0.5);
		addFlatSounds("FLOOR4_8", FLOOR, 64, "scifi-rumble", CHANF_LOOP | CHANF_NOSTOP | CHANF_OVERLAP);
		addFlatSounds("FLOOR5_1", FLOOR, 64, "scifi-rumble", CHANF_LOOP | CHANF_NOSTOP | CHANF_OVERLAP);
	}
	
	// returns area of sector (irregular polygon)
	float polygonArea(Sector sec)
	{
		Array<float> lineAreas;
		for (int i = 0; i < sec.Lines.Size(); i++)
		{
			int v1x = int(sec.Lines[i].V1.P.x);
			int v1y = int(sec.Lines[i].V1.P.y);

			int v2x = int(sec.Lines[i].V2.P.x);
			int v2y = int(sec.Lines[i].V2.P.y);

			float avgY = (v1y + v2y) * 0.5 * .015625;
			float widthX = (v2x - v1x) * .015625;
			lineAreas.Push(avgY * widthX);
		}
		float totArea;
		for (int i = 0; i < lineAreas.Size(); i++)
		{
			totArea += lineAreas[i];
		}
		return totArea;
	}
	
	// add idle ambient sounds
	override void WorldLoaded(WorldEvent e)
	{
		LoadArrays();
		
		int FLOOR = 0;
		int CEILING = 1;
		TexMan texture;

		for(int i = 0; i < Level.Sectors.Size(); i++)
		{
			textureid floorid = Level.Sectors[i].GetTexture(FLOOR);
			textureid ceilingid = Level.Sectors[i].GetTexture(CEILING);

			SecPlane ceilingplane = Level.Sectors[i].CeilingPlane;
			SecPlane floorplane = Level.Sectors[i].FloorPlane;

			int ceilingZ = int(ceilingplane.ZAtPoint((Level.Sectors[i].CenterSpot.x, Level.Sectors[i].CenterSpot.y)));
			int floorZ = int(floorplane.ZAtPoint((Level.Sectors[i].CenterSpot.x, Level.Sectors[i].CenterSpot.y)));
			int centerheight = ceilingZ - floorZ;

			for (int ii = 0; ii < fCounter; ii++)
			{
				string flat = FlatSounds[ii].type == CEILING ? texture.GetName(ceilingid) : texture.GetName(floorid);
				if (FlatSounds[ii].fname == flat && centerheight > FlatSounds[ii].height)
				{
					float pArea = polygonArea(Level.Sectors[i]);
					if (pArea > 64)
					{
						console.printf("Adding %s to %s", FlatSounds[ii].sname, FlatSounds[ii].fname);
						vector3 v3 = (Level.Sectors[i].CenterSpot.x, Level.Sectors[i].CenterSpot.y, floorZ);
						Actor ptr = Actor.Spawn("IA_Sound", v3);
						if (ptr)
						{
							console.printf(ptr.getSpecies());
							ptr.A_StartSound(FlatSounds[ii].sname, CHAN_AUTO, FlatSounds[ii].flags, FlatSounds[ii].volume);
						}
					}
					break;
				}
			}
		}
	}

	override void WorldThingSpawned(WorldEvent e)
	{
		if (e.thing)
		{
			for (int i = 0; i < iCounter; i++)
			{
				if (ItemSounds[i].cname == e.thing.GetSpecies())
				{
					console.printf("Adding %s to %s", ItemSounds[i].sname, ItemSounds[i].cname);
					Actor ptr = e.thing.Spawn("IA_Sound", e.thing.pos);
					if (ptr)
					{
						console.printf(ptr.getSpecies());
						ptr.A_StartSound(ItemSounds[i].sname, CHAN_AUTO, ItemSounds[i].flags, ItemSounds[i].volume);
					}
				}
				break;
			}
		}
	}
}
How this works is simple enough. Two structure arrays define what sound goes to what: ItemSounds that are added when an item spawns and FlatSounds that are added when WorldLoaded fires.

The item sound spawner is somewhat simpler. For now the only item sound is an electronic humming noise. When an item spawns, it loops through the ItemSounds array, matches the actor species, and spawns an IA_Sound actor that returns an Actor ptr. That ptr starts the sound in the array. This isn't attached to the originator, so it's only good for stationary objects such as lamps.

The flat sound spawner has a few more parameters to consider, since sectors often vary in size and shape depending on their purpose. The script loops through all the sectors and for each ceiling and floor flat also loops through the FlatSounds array. When it finds a match it also checks that height exceeds the defined height to add the sound. It also checks the sector area with an arbitrary size of at least 1 square map unit. This makes sure there aren't multiple overlapping sounds for tiny sectors created solely for lighting effects, for example. Other than that it works the same as item sounds.

The sounds aren't fancy. I've added short looping sound effects for outside wind and a "scifi" rumbling, but of course they can be anything that sets a tone or gets under your skin. My intention is to add a universal element of ambiance independent of map design.

I've set this up so all sounds loop, but that doesn't have to be the case; flags can be set differently in the LoadArrays function. An inventory pickup item, for example, may have an option of playing an "ambient" sound once using this method. I haven't tried that, and there are probably more effective ways of accomplishing that.
User avatar
BROS_ETT_311
Posts: 219
Joined: Fri Nov 03, 2017 6:05 pm

Re: Idle Ambiance

Post by BROS_ETT_311 »

At this rate, you could almost construct your own Zscriptified BD level enhancement system...not that I would suggest that (except I kind of am :wink: ).
User avatar
madsnark
Posts: 8
Joined: Tue Jun 12, 2018 9:15 am

Re: Idle Ambiance

Post by madsnark »

script doesn't seem to work with animated flats

also IA_Sound actors are spawned only for the first ItemSound in the array and not for the others
Last edited by madsnark on Mon Jan 17, 2022 12:45 pm, edited 3 times in total.
Hey Doomer
Posts: 283
Joined: Sat Sep 25, 2021 3:38 am

Re: Idle Ambiance

Post by Hey Doomer »

madsnark wrote:script doesn't seem to work with animated flats
It should if the flat name is what's on the map definition. It doesn't check these for any changes in-game.
User avatar
McTed
Posts: 9
Joined: Sat Apr 23, 2022 9:32 am

Re: Idle Ambiance

Post by McTed »

I managed to get animated textures to play sounds however like madsnark I can't techpillar and lamps on E1M1 to play more than the first sound called for items

Download
https://cdn.discordapp.com/attachments/ ... bience.pk3

Future edit: A break was in the wrong place
Last edited by McTed on Sat Apr 30, 2022 5:19 am, edited 1 time in total.

Return to “Script Library”