Jon Cednert submitted the latest reader challenge.
I have 5 statues in a room, kindof in a circle. There’s also 5 spotlights that each points to a statue, but they are turned off by default. Whenever you walk up to any of the statues, I want its corresponding spotlight to light up, and stay on, even if you walk away from the trigger.
The only thing that could turn that first spotlight off, is by walking up to any of the other 4 statues, and light up its corresponding light.
Challenge accepted! Here’s a quick video of the map I came up with
Enough demonstration, lets hack. The map uses two existing hacks, and the interesting part is how we compose them, so I’m just going to link to previous posts for the nitty-gritty technical stuff on exactly which key does what. The download above contains the .map file as well as the .bsp so you can look at the entities in editor as we go.
First we need to break down exactly what happens for each interaction with a statue.
- light must be toggled (on)
- activation events are triggered elsewhere in the map
- statue trigger must be deactivated
- light must be toggled (off)
- deactivation events are triggered elsewhere in the map
- statue trigger must be reactivated
It’s important to remember that we can only toggle lights, so we need to be absolutely sure we trigger the light the correct number of times. We cannot afford to ever trigger the wrong light, or fire an extra trigger, or the light will go out of sync. This limits the options for solving some future problems.
The first thing we will do is use the “Respawnable trigger_once” hack for the statue triggers. If we didn’t, we would need a logic gate for each statue handling the deactivation and reactivation of the statue’s trigger, and it’s a lot simpler if the entity just automatically deactivates when touched, and can be reactivated on trigger.
Now for the big challenge. Although we separated the tasks into activation and deactivation, it’s worth remembering that each time we touch a new statue, we need to do both: activate the new statue, and deactivate the old one. Activating the statue is quite straightforward, because the trigger belongs to the statue that needs to be activated. Deactivation is not so straightforward, because we might need to deactivate ANY of the other statues, depending on which was lit. Toggling the light on any other statue would turn it on by mistake, so we can’t do something like deactivating all other statues.
The solution I’ve used in the map is to create a logic gate that stores which statue is currently active. When the reset_last_statue event fires, the logic gate triggers the entities which deactivate the last statue. Each statue’s trigger begins by firing that event, followed by running its own statue activation entities, and then finally changing the logic gate to point at the new statue.
The sequence that occurs in is very important. If you change the logic gate before you deactivate the old statue, the reset_last_statue event will reset the same statue you are trying to activate. This leaves the internal state in a mess, with one statue illuminated but a different one activated according to the logic gate (and the state of the map). To ensure that the order is correct, I’ve doubled up the triggers at each statue, and the reset_last_statue trigger fires with no
delay, while the statue activation one has a
delay of 0.1 seconds.
This does introduce a potential race condition. Suppose that an additional “new statue” is triggered in the short window between the reset of the old statue and the activation of a new one. This will cause a second reset event to be sent to the old statue, toggling the light for the old statue an extra time, leaving it switched on! In addition, both new statues will be activated, but the logic gate will only remember that the latter one needs deactivation.
In single player, you can space the statues far enough apart that this never happens. In co-op different players could stand at multiple statues simultaneously, so this ought to be guarded against. By carefully controlling the order that the entities appear in the map file, it is possible to get the events to trigger in the correct order without needing
delay on either. I hope to follow up with a map hack that can order events regardless of which sequence the entities are placed in the map, watch this space…
Other quick notes: The logic gate starts without any of the five branches selected, because none of the statues start lit up. This works fine, the first time you select a statue it still runs reset_last_statue but this has no effect, as desired. Also there are events that other parts of the map can react to, statue1_activate and statue1_reset etc. That’s it, have a play around, and come back soon for the bonus material!