A more efficient way to do these switches?

Ask about ACS, DECORATE, ZScript, or any other scripting questions 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.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

A more efficient way to do these switches?

Post by Enjay »

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: Select all

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: Select all

   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?
User avatar
22alpha22
Posts: 303
Joined: Fri Feb 21, 2014 5:04 pm
Graphics Processor: nVidia with Vulkan support
Location: Montana, USA

Re: A more efficient way to do these switches?

Post by 22alpha22 »

Here is a bit of simplification:

Code: Select all

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.
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: A more efficient way to do these switches?

Post by Enjay »

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?
Gez
 
 
Posts: 17835
Joined: Fri Jul 06, 2007 3:22 pm

Re: A more efficient way to do these switches?

Post by Gez »

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: Select all

int my_array[] = {  210, 211, 218, 613, 1472, 36, 101, 0 }
for (int i = 0; my_array[i] != 0; ++i)
{
    do_something(i);
}
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: A more efficient way to do these switches?

Post by Enjay »

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

Return to “Scripting”