Page 1 of 1

Controlling repeatable switch state?

PostPosted: Wed Nov 21, 2018 3:39 am
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).

Re: Controlling repeatable switch state?

PostPosted: Thu Nov 22, 2018 8:15 am
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 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)
      ActivatorSound("NAME OF SWITCH SOUND",127);
      switchon = 1;
      delay(const:35*XX);      //XX is the number of seconds you want between texture changes
      [Perform your desired action, e.g., lowering a lift];      
   {   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.

Re: Controlling repeatable switch state?

PostPosted: Thu Nov 22, 2018 1:18 pm
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 allExpand view
linedef {
   v1=...; v2=...; sidefront=...;
   blocking=true; playeruse=true;
   special=80; // ACS_Execute
   arg0str="lights on";

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_Strobe(sid, 96, 80, 1, 3);

script "fade" (int 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_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);
   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).