A more efficient way to do these switches?

Sun Oct 31, 2021 8:41 am

I'm trying to make a situation where the player can go on a hunt through a map for some floor switches. If he stands on a switch, the switch lowers, a door opens in a monster teleport store and the monster teleports to near the player. There are nine different switches throughout the map. Each one has four lines around it. When the player crosses the lines, he is fully on the switch and the switch activates.

The script to activate the switches does the following:
  • removes the special from the switch lines,
  • lowers the switch by 4 units (putting it 2 units below the floor - it start 2 units above)
  • Opens the remote monster door
  • Makes a switch sound at a map spot placed on the switch (the switch sectors themselves move silently)

The switch lines and the switch sectors use the same tags. I would also have had the map spots use the same tags as well but I has already used those numbers elsewhere and I didn't want to reconfigure stuff.

Anyway, that was all simple enough. It's just a 4 line script that takes arguments for the different switches - so only one script was needed and each switch was set to activate the appropriate tags via the line arguments that ran the script. We'll call that Phase 1 of the map. Phase 1 worked well and did everything I wanted nice and efficiently.

But then I had a "brainwave" - later on in the map, the player does something which ramps up the activity in the map - basically a boss fight phase where all hell is let loose. So I thought it might be good if any switches that had not yet been found got activated and released their captive enemies. We'll call that Phase 2.

The problem is, if a switch has already been activated in Phase 1, it mustn't be activated again in Phase 2 because that will lower it's floor further (putting it 6 units below the surrounding floor) and, of course, I also want to remove the special from any switches the the player has not activated personally in case he wanders over them and activates the switch a second time.

Still with me? ;)

So, my solution was to have a variable for each switch. If the player activates a switch during phase 1, a variable for that switch is incremented marking it as already switched. The problem is, this means nine variables (and more if I add more switches). As well as needing nine new variables, it also added a bunch of repetition to my previously simple switch script.

When Phase 2 starts, the script that does stuff associated with the start of the boss phase calls a script that checks the variables for each switch and activates the switch script for any that have not already been activated.

It all works as intended (at least as far as I can tell - I still need to test it thoroughly) but the scripting now looks very inefficient to my eye. So I wonder if any of the ZDoom Forum resident coding geniuses could take a look and suggest a more efficient way of doing it?

For info, currently the switches have line and sector tags 210-218 inclusive and map spot tids of 22 to 30 inclusive. The remote door numbers are a little less straight forward and have tags of the odd numbers from 47 to 63 inclusive (all just a function of how things were put together as I made the map). If I add additional switches, they are unlikely to fit this pattern because tags and tids have now been taken by other elements in the map.

Anyway, here are the relevant scripts:

The switch script (run by the player crossing lines in Phase 1).
Code:

int FloorSwitch210
;
int FloorSwitch211;
int FloorSwitch212;
int FloorSwitch213;
int FloorSwitch214;
int FloorSwitch215;
int FloorSwitch216;
int FloorSwitch217;
int FloorSwitch218;

script 210 (int SwitchNumber, int SwitchDoor, int SwitchTid)
   {
        SetLineSpecial(SwitchNumber,0,0,0,0,0,0);              //Deactivate the other lines on this switch
        Floor_LowerByValue (SwitchNumber, 64, 4);               //Depress the switch
        Door_Open (SwitchDoor, 64);                               //Let the monster come in
        ThingSound(SwitchTid, "switches/exitbutn", 127);    //Make switch click

        if (SwitchNumber == 210)
            {
                FloorSwitch210++;
            }

        if (SwitchNumber == 211)
            {
                FloorSwitch211++;
            }

        if (SwitchNumber == 212)
            {
                FloorSwitch212++;
            }

        if (SwitchNumber == 213)
            {
                FloorSwitch213++;
            }

        if (SwitchNumber == 214)
            {
                FloorSwitch214++;
            }

        if (SwitchNumber == 215)
            {
                FloorSwitch215++;
            }

        if (SwitchNumber == 216)
            {
                FloorSwitch216++;
            }

        if (SwitchNumber == 217)
            {
                FloorSwitch217++;
            }

        if (SwitchNumber == 218)
            {
                FloorSwitch218++;
            }
   


The Phase 2 script run by the boss-start script using "ACS_NamedExecuteAlways("ActivateAllSwitches", 0, 0, 0, 0);"

Code:
   Script "ActivateAllSwitches" (void)
   {
           if (FloorSwitch210 <1)
        {
            ACS_ExecuteAlways(210, 0, 210, 47, 22);
        }

           if (FloorSwitch211 <1)
        {
            ACS_ExecuteAlways(210, 0, 211, 49, 23);
        }

           if (FloorSwitch212 <1)
        {
            ACS_ExecuteAlways(210, 0, 212, 51, 24);
        }

           if (FloorSwitch213 <1)
        {
            ACS_ExecuteAlways(210, 0, 213, 53, 25);
        }

           if (FloorSwitch214 <1)
        {
            ACS_ExecuteAlways(210, 0, 214, 55, 26);
        }

           if (FloorSwitch215 <1)
        {
            ACS_ExecuteAlways(210, 0, 215, 57, 27);
        }

           if (FloorSwitch216 <1)
        {
            ACS_ExecuteAlways(210, 0, 216, 59, 28);
        }

           if (FloorSwitch217 <1)
        {
            ACS_ExecuteAlways(210, 0, 217, 61, 29);
        }

           if (FloorSwitch218 <1)
        {
            ACS_ExecuteAlways(210, 0, 218, 63, 30);
        }
   }


So, is there a way to make that more efficient?

Re: A more efficient way to do these switches?

Sun Oct 31, 2021 9:28 am

Here is a bit of simplification:
Code:
Int FloorSwitch[9];

script 210 (int SwitchNumber, int SwitchDoor, int SwitchTid)
{
     SetLineSpecial(SwitchNumber,0,0,0,0,0,0);
     Floor_LowerByValue (SwitchNumber, 64, 4);
     Door_Open (SwitchDoor, 64);
     ThingSound(SwitchTid, "switches/exitbutn", 127);

     FloorSwitch[SwitchNumber - 210]++;
}

Script "ActivateAllSwitches" (void)
{
     For (Int I = 0; I < 9; I++)
     {
         If (FloorSwitch[I] < 1)
         { 
             ACS_ExecuteAlways(210, 0, 210 + I, 47 + (I  * 2), 22 + I);
         }
         Delay(1);  //Haven't mapped in awhile so I haven't used ACS in some time, therefore I don't know if this delay is necessary to prevent a runaway script
     }
}


EDIT:
Fixed incorrect If statement in the second script.
Last edited by 22alpha22 on Sun Oct 31, 2021 9:31 pm, edited 1 time in total.

Re: A more efficient way to do these switches?

Sun Oct 31, 2021 11:10 am

Cool, I'll try that. Thank you. I figured that there would be some way to simplify all that repetition.

By the look of it, if I add any extra switches that can't fit within the 210, 211... number sequence (because tags 219 and above have already been used elsewhere) I will have to specify them separately though, right?

Re: A more efficient way to do these switches?

Sun Oct 31, 2021 12:39 pm

By the way, you could have used sector actions instead of putting line specials all around.

Enjay wrote:By the look of it, if I add any extra switches that can't fit within the 210, 211... number sequence (because tags 219 and above have already been used elsewhere) I will have to specify them separately though, right?


The secret of programming is that there isn't any problem that cannot be solved by adding another layer of indirection.

Code:
int my_array[] = {  210, 211, 218, 613, 1472, 36, 101, 0 }
for (int i = 0; my_array[i] != 0; ++i)
{
    do_something(i);
}

Re: A more efficient way to do these switches?

Sun Oct 31, 2021 1:32 pm

OK, wrapping my head around that too - I'll get there. Thanks. :)