Most mappers are familiar with the idea of “logic gates”. These are a way to get more complex behaviour out of triggers in maps, allowing you to ask if one event OR another has been fired before activating another event, along with one event AND another, and IF…ELSE constructions. Usually these are created out of spikeshooters, doors and shootable triggers in a box hidden outside the main map. The doors are designed so that the shots from the spikeshooters can hit the triggers only if the right logical conditions are met in the map.
I’m going to describe a variation on this system, with two goals in mind. One is response time – the system should react immediately to being triggered, and to having its logical state updated. The other is to give the gate two targetnames – one which opens the gate, and the other which closes it. This differs from the usual set-up where a single targetname toggles the switches in the gate open and closed. Our first example won’t have any logic like AND, OR, etc, it will just be a gate which only relays a trigger when open.
Important note: This entry was updated on 21/02/2016 to fix an important issue with the original article. The paragraphs which have been changed are highlighted in this colour.
We’ll start by making the most complex entity – the gate itself. Create a 32 unit cube brush, and give it the classname “
InitTrigger“. Then add the following keys, which will be explained below:
The classname starts things off by running the
InitTrigger function. This sets the entity’s model up. The “nextthink”, “think” and “max_health” functions work together on the second frame to call the code inside the
multi_wait function. This makes our gate solid, and allows it to be damaged with 1 health remaining. We then add a “th_die” key so that when the trigger is shot and killed,
demon1_die6 runs. This code comes from the death sequence of a fiend, and is chosen because it makes entities non-solid.
The next two fields are using the trick from the trigger_damagethreshold hack. The “armortype” is calculated so that an attack must do more than 20 hp in one go in order to decrease the gate’s health (and so kill it, since it has 1 hp total). The “armorvalue” is set large enough that the gate’s armour never depletes, no matter how many times it is used. We can now fully understand what the “th_die” setting does for our gate: when hit by an attack which does more than 20 damage, the gate becomes non-solid. We will see that this closes the gate.
The two fields that follow complement this set-up. “th_pain” is set to
SUB_UseTargets, which is the function that triggers an entity’s targets. The “target” key names the entities which will be triggered when the gate goes into pain. Two surprising facts about damage in Quake matter here. One is that entities which have died from an attack do not go into pain from that attack. Attacks above 20 damage do not trigger the targets, because we saw above they will kill the gate. On the other hand, attacks that do zero hp because the armour absorbed all the damage do cause pain. Conclusion: the gate will activate its targets when hit for 20 or less damage.
Lastly we give the gate a “targetname”, and set
multi_wait to be its “use” function. We already saw that
multi_wait makes our entity solid and gives it 1 hp. This conveniently reverses both of the effects of damaging the gate for more than 20 HP – being dead and non-solid. So this is our means of opening the gate.
Phew, so having explained how all the various fields fit together, we can summarise the various ways that our gate reacts. When targetted by another trigger, it becomes solid and has its hit-point restored. When hit for more than 20 damage, it loses its hit-point and becomes non-solid. When hit for 20 or less damage, it fires the event called “output_gate”. The crucial thing to notice here is that you can’t hit the gate for any amount of damage if it isn’t solid, so switching between solid and non-solid toggles the relay!
Our mission now is just to create entities which can hit it for two different amount of damage. We’re going to use the player’s axe attack to inflict a non-killing attack of 20 hp. Because the axe is a hitscan attack, it will take effect instantly, but won’t persist to the next frame. Unfortunately the axe attack of the player requires the combination of two separate functions,
W_Attack (which aims the attack) and
W_FireAxe (which performs the attack), so we need to add two entities. Start by creating the following entity:
Now duplicate this entity, and on the copy change
W_FireAxe. This is the only part of our setup which relies on order of entities, we need the W_Attack one to be earlier in the entity list. The nice thing about the two being essentially identical is that if they come out in the wrong order, we can just swap which one has
Normally the “v_angle” would set the direction that the axe attacks, but we haven’t actually bothered to set that. This means the info_notnull fires due north, so place the pair of them immediately to the south of the gate.. It’s important to know that the axe traces its attack from 16 units above the origin of the info_notnull, so place them below the midpoint of your gate. For reasons I don’t fully grasp, they also doesn’t work from inside the gate, be sure to place them just outside instead.
We need a further info_notnull to deal lethal damage to the gate, and this one is going to use the player’s lightning attack instead. Use these keys:
We’re using the infinite ammo trick here to ensure the lightning never runs out of juice. Hackers who have used the player’s lightning before may remember how hard it was to get the lightning to go in the direction you wanted. Worry not today, because we don’t care! Just bury the info_notnull inside the gate and it will strike in whichever direction it fires. Unlike the axe, this works just fine.
And that’s it. Build a test map with a couple of buttons which target “open_gate” and “close_gate”, a trigger_multiple which targets “query_gate”, and a door with targetname “output_gate”. Then give it a test, and if all is well you’ll be able to open the door with the trigger, but only when the gate is triggered open. It’s also worth verifying that opening or closing the gate multiple times has no ill effect, and trying to work out why that is.
Make sure you check out part two of the logic gates map hack where I describe how to build AND gates, OR gates, and IF-ELSE pairs, along with a .map file with complete examples to use.