Controlling repeatable switch state?

Ask about mapping, UDMF, using DoomBuilder/editor of choice, etc, here!
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.

Controlling repeatable switch state?

Postby gramps » Wed Nov 21, 2018 3:39 am

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).
gramps
 
Joined: 18 Oct 2018

Re: Controlling repeatable switch state?

Postby ReX » Thu Nov 22, 2018 8:15 am

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 allExpand view
#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.
User avatar
ReX
Title? I don't need no steenkin' title!
 
Joined: 05 Aug 2003
Location: Quatto's Palace

Re: Controlling repeatable switch state?

Postby gramps » Thu Nov 22, 2018 1:18 pm

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 allExpand view
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 allExpand view
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 allExpand view
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).
gramps
 
Joined: 18 Oct 2018


Return to Mapping

Who is online

Users browsing this forum: No registered users and 1 guest