MissBubbles asked on func_ if it’s possible to create a
func_door which inflicts damage when touched – as opposed to just when it is blocked by an entity.
func_door is notoriously resistant to map hacks because its spawn function is extremely busy, which locks down lots of the traditional routes to creating a map hack. Challenge accepted!
The heart and soul of the door code is
LinkDoors, which is intended to connect adjacent doors and make them open all at once. This sets a bunch of entity fields which are needed when a door is activated – even if this door doesn’t have any siblings to connect to. As readers of the last post on logic gates may recall, entity fields cannot be set from the map editor when performing a hack, because they depend on unpredictable entity numbers. So we need to find a way to incorporate this function into our plan.
On the other hand, this might be an opportunity rather than a limitation. We can create one entity to run
LinkDoors for us, and another to actually be the solid part of the door.
LinkDoors then lets us
use the former entity to activate door movement on the latter entity. Our only restriction is that
LinkDoors will only link entities with the same
classname, so we need to develop a new entity hack idea I’ve christened Classname Masquerading.
Our first entity is the one which we will trigger to move the door. Add a point entity to the map and give it a
SUB_CalcMoveDone. This function is handy in a number hacks, because it performs a small number of side effects, before immediately running whatever function is in the
think1 field. Today’s idea is that you can put the spawn function you really want to run into
think1 and get an entity of that class, but with a classname value of
"SUB_CalcMoveDone". By varying the spawn function, we can create a variety of different entities, all masquerading as the same
The only thing we need to get out of the activator’s spawn function is to have it run
LinkDoors after a bit of a delay. Add the following keys:
"think1" "HuntTarget" "th_run" "LinkDoors"
HuntTarget schedules the function stored in
th_run to occur in 0.1 seconds. If we store
LinkDoors there, then we get exactly what we need. Now add the follow two keys, which let us trigger the entity later in the map:
"use" "door_use" "targetname" "spike"
You also need to add a button or trigger with a
spike to activate it.
The Physical Door
Now we can add the brush entity for the door – note that this hack does depend on the brush entity being loaded after the activator entity, which usually means you must create them in the editor in this order. Give this brush entity the
SUB_CalcMoveDone as well – this is the crux of the masquerade idea. Give it a key of
think1 func_wall, then quickly compile your map to check it has worked. If all went to plan, the brush entity should be visible and solid, exactly like a
func_wall. The only difference should be that when you run the
edicts command, you can see it still has a
Come back to the editor, and add the following keys to the brush entity
"speed" "100" "wait" "4" "dmg" "3" "pos2" "0 0 -100" "state" "1" "touch" "door_blocked"
These are for the most part fields that would normally be set by the
func_door spawn function, and you may need to adjust them to suit your map, e.g. my example value for
pos2 moves the door 100 units vertically down when the door opens. You must specify the distance and direction you would like the door to move instead. Also of note is the
touch function, which is non-standard, but is there to satisfy MissBubbles’ original request that the door inflict damage on any contact.
Linking Them Together
You may have tried to compile the map at this stage, and noticed it still doesn’t do anything! There’s one last thing to go. Identify the coordinates of a point which lies within the brush entity. In my test map, I chose the point
-96 -96 184. You need to add two keys to the activator entity, both of which must contain this coordinate.
"mins" "-96 -96 184" "maxs" "-96 -96 184"
This makes the
LinkDoors function believe that the activator is adjacent to the brush entity, and so they need linking. The actual position of the activator is not relevant. Compile away at this point and the hack should work.
There’s a little bit of tidying up to do still. You’ll notice errors about unprecached sounds. The way to fix these is to specify sounds for the brush entity in the keys
noise2. You will need these sounds to be precached by some other entity in your map. You may also need to add spawnflags and restore the
door_blocked function to the brush entity – without using the
func_door spawn function setting these things becomes your responsibility.
As often happens, a map hack developed to solve a specific problem has in fact opened up a wide vista of applications. Because we’ve built something that moves like a door, but is based off of a
func_wall instead, we have the opportunity to modify it further. We can add custom
th_die functions on top of making a different choice for
func_wall already comes with a
use function which we can’t override, but it’s quite an interesting one – it toggles any animated textures on the brush entity. Than’s idbase door textures could be put to use here.
The very brave might consider using something more complicated than a
func_wall with this method, it might unlock a single entity that can move in two distinct ways. And the masquerade idea has many other uses, some of which will appear in a future article.
Test map: mask.zip. This is a quick demonstration of the bare minimum hack. The sounds for the spike are chosen from those automatically precached in every map, so they’re a bit weird. At least it demonstrates how freely they can be chosen…