Controlling repeatable switch state?

Ask about mapping, UDMF, using DoomBuilder/editor of choice, etc, here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.
Post Reply
gramps
Posts: 300
Joined: Thu Oct 18, 2018 2:16 pm

Controlling repeatable switch state?

Post by gramps »

I have a line with a switch texture and a repeatable, player-activatible special. When I flip the switch, a sound plays, the line texture changes and the special fires.

After a few seconds, the sound plays again and the texture changes back. I don't want this to happen; is there any way to set it up so the texture only changes when I activate the line, and doesn't change back after a few seconds?

Right now I'm changing the texture and playing the sound in ACS, but I'd like to get it working with animdefs.

switch OFF_TEXTURE on pic ON_TEXTURE tics 0 off pic ON_TEXTURE tics 0

That'll get the switch to stay flipped, but when you activate it again, it the texture won't change back, and the sound plays when the automatic flipping back happens. I tried adding another line, defining the same animation going in the other direction (switch ON_TEXTURE...), but it just seems to override the first line. Messing with tic count doesn't seem helpful either.

I'm sure it's something simple... how can I get the switch to stay put when I flip it?

EDIT: Discovered I could make it non-repeatable, and then set the line special up again in an ACS script. This isn't ideal, because now the line needs to have a tag for SetLineSpecial (as far as I know there's no way to get SetLineSpecial to affect the activating line, like ClearLineSpecial... tried passing 0 as first argument, didn't work).
User avatar
ReX
Posts: 1578
Joined: Tue Aug 05, 2003 10:01 am
Location: Quatto's Palace
Contact:

Re: Controlling repeatable switch state?

Post by ReX »

A hacky way to do this is to set your ACS to replicate the switch on/off action, NOT by using the switch special, but by using texture change & sound effect specials. In this way, you'll have absolute control of the texture changes, and can set the "end" texture any way you want. As this is a repeatable action, you'll also need to set the logic up so that the texture change does not occur beyond the first time the switch is used.

Give your switch linedef a LINE_ID, set it to repeatable, yada yada. Then, use the suggested scripting:

Code: Select all

#include "zcommon.acs"
script 1 OPEN 
{
	SetLineSpecial(LINE_ID,80,15,0,0,0,0);		//Light switch:Script 15
}

int switchon1;
script 15 (void)
{
If (!switchon1)
	{
		Setlinetexture (LINE_ID, SIDE_FRONT, TEXTURE_MIDDLE, "TEXTURE NAME FOR ON POSITION");
		ActivatorSound("NAME OF SWITCH SOUND",127);
		switchon = 1;
		delay(const:35*XX);		//XX is the number of seconds you want between texture changes
		Setlinetexture (LINE_ID, SIDE_FRONT, TEXTURE_MIDDLE, "TEXTURE NAME FOR OFF POSITION");
		[Perform your desired action, e.g., lowering a lift];		
	}
else
	{	If (switchon1)		//This line is optional and is included mainly for clarity. If you remove it you'll need to remove the appropriate number of curly brackets.
		{	ActivatorSound("NAME OF SWITCH SOUND",127);
			[Perform your desired action, e.g., lowering a lift];		
		}
	}
}
If you have more than one switch for which you wish to do the same sequence, simply increment the integer value (e,g, "switchon2"), give your new switch a new LINE_ID, copy & paste & change the relevant parts of the scripts above.
gramps
Posts: 300
Joined: Thu Oct 18, 2018 2:16 pm

Re: Controlling repeatable switch state?

Post by gramps »

Hmm, thanks, that looks a lot like one of my earlier attempts (except I think I went with SectorSound).

Hard-coding all this stuff seems inflexible, but some of that can be mitigated with script args...

What I've done for now is stick a bunch of data in custom UDMF fields, on the line with the switch. So the UDMF looks like this:

Code: Select all

linedef {
	v1=...; v2=...; sidefront=...;
	blocking=true; playeruse=true;
	special=80; // ACS_Execute
	id=1;
	
	arg0str="lights on";
	
	user_light_things=2;
	user_dark_things=1;
	user_light_sector_1=1;
	user_light_sector_2=3;
	user_volumetric_sector_1=3;
}
Then I wrote a little script that'll iterate over UDMF user fields named like foo_1, foo_2, foo_3, calling a named script and passing each value to it (we don't have first-class functions, right?).

Code: Select all

function void IterateLineUDMFInt(int tag, str field, str scriptname, int a, int b) {
	int i = 0;
	int sid = GetLineUDMFInt(tag, strparam(s:"user_", s:field, s:"_", i:++i));
	while (sid > 0) {
		ACS_NamedExecuteAlways(scriptname, 0, sid, a, b);
		sid = GetLineUDMFInt(tag, strparam(s:"user_", s:field, s:"_", i:++i));
	}
}
Then the rest of my code looks like this:

Code: Select all

script "flicker" (int sid) {
	Light_Stop(sid);
	Light_Strobe(sid, 96, 80, 1, 3);
}

script "fade" (int sid) {
	Light_Stop(sid);
	Light_ChangeToValue(sid, 96);
	Light_Fade(sid, 128, 30);
}

script "haze" (int sid, int value) {
	Sector_SetFade(sid, value, value, value);
}

script "dim" (int sid) {
	Light_Stop(sid);
	Light_ChangeToValue(sid, 64);
}

script "lights on" (void) {
	ACS_NamedTerminate("lights off", 0);
	SetLineSpecial(1, ACS_NamedExecute, "lights off");
	
	Thing_Activate(GetLineUDMFInt(1, "user_light_things"));
	Thing_Deactivate(GetLineUDMFInt(1, "user_dark_things"));
	IterateLineUDMFInt(1, "light_sector", "flicker", 0, 0);
	
	delay(30);
	
	IterateLineUDMFInt(1, "light_sector", "fade", 0, 0);
	IterateLineUDMFInt(1, "volumetric_sector", "haze", 255, 0);
	
}

script "lights off" (void) { 
	ACS_NamedTerminate("lights on", 0);
	SetLineSpecial(1, ACS_NamedExecute, "lights on");
	
	Thing_Activate(GetLineUDMFInt(1, "user_dark_things"));
	Thing_Deactivate(GetLineUDMFInt(1, "user_light_things"));
	
	IterateLineUDMFInt(1, "volumetric_sector", "haze", 0, 0);
	IterateLineUDMFInt(1, "light_sector", "dim", 0, 0);
}
The huge glaring problem here is "lights on" has some warmup time -- a flicker and then a fade -- so "lights off" needs to terminate it. That's enough to pretty much kill any chance of reuse (I can't have "lights off" kill the "lights on" happening in another room).

I guess I'm mainly trying to figure out how to achieve some level of encapsulation/reuse at this point (although it would still be great if there were some kind of "switches stay put" line flag).
Post Reply

Return to “Mapping”