News | Forum | People | FAQ | Links | Search | Register | Log in
Mapping Help
This is the place to ask about mapping problems, techniques, and bug fixing, and pretty much anything else you want to do in the level editor.

For questions about coding, check out the Coding Help thread: https://www.celephais.net/board/view_thread.php?id=60097
First | Previous | Next | Last
On How It Works (the Nth In A Series Of Overly Long Posts By Preach) 
I think it's about time there was a good post on why that particular info_notnull trick works, because it's a bit complicated why you move the classname to the use field to make it work.

What is a classname?

The classname field is a qc field which stores a string. From the point of view of the QC, it isn't any different to the message field. There is only one thing which is special about classname, which happens when the map starts.

When the engine loads a map, one of the last things it does is load the list of entities, which looks a little like this:

...
{
"classname" "misc_fireball"
"delay" "15"
"target" "drawtrap"
"targetname" "draw"
"origin" "-352 -1168 160"
"use" "trigger_once"
"model" "*2"
}
...

You can see that all the fields you enter are stored as pairs of keys and values. What the quake engine does for each one of those entries is:
1. Creates a new entity with all of it's fields set to 0.
2. Fills in any of the fields listed in between the {...} with the value given.
3. Sets the "self" entity in the QC code to be this newly formed entity.
4. (this is the important bit) Searches for a function in the qc code with the same name as the classname of the entity, and then runs that function.

The function with the same name as an entity's classname is usually called the class "spawn function". There is technically nothing special about the QC in a "spawn function" - any valid function name is allowed as a classname. But usually "spawn functions" are designed to do important things to "self", like making it solid, giving it an appropriate model, and starting the ai functions in the case of a monster.

What is the use field?
In the example misc_fireball entity above we see the use key has been added. It looks like the use key follows the same format as the classname key, but this is misleading. In QC, use describes a function, not a string. When the quake engine carries out step 2 on the use key, it looks for a function whose name matches that string. Once it finds that function, it stores the function location for the QC and discards the string.

In the (very contrived) example entity I have invented above, use is set to "trigger_once". We are used to trigger_once being a classname, but as we learnt above classnames are always the name of a function. So when we trigger the event "draw", the QC finds every entity with a targetname of "draw". It then calls the function stored in use.

In this case, this gives the entity all the properties of a trigger_once, on top of whatever fields were filled out when it became a misc_fireball.

The thing to remember is that running the function doesn't change it's classname to trigger_once. Sometimes the classname matters (see http://www.celephais.net/board/view_thread.php?id=4&start=6068&end=6068 for the classic example). However, I can assure you that trigger_once is not like that, the classname is never checked once the entity is spawned. So the hack is in fact safe.


What is an info_notnull?
So why are all the hacks obsessed with info_notnull? Well, it's because info_notnull is an entirely empty "spawn function", it does nothing to the entity at all. One of the challenges of making entity hacks is finding a function which does just enough. If you make the classname "trigger_multiple" then it does all the work of making a trigger for you. But that function also overwrites any custom value for use or th_die(a function like use, but called when you kill an entity). Sometimes doing nothing is exactly what you want, in which case you choose info_notnull.

Bringing it all back home
So using all that knowledge, we create a brush based entity with these fields:
{
"classname" "info_notnull" //do nothing on spawn
"use" "trigger_once" //do what the spawn function for trigger once does once we fire the event
"target" "spawn01" //the event which makes use happen
"targetname" "newevent" //what the trigger sets off
}


Hope that was enlightening.

ps: The difference between classname and use is why mutliple-spawning entities in hipnotic/quoth/quake-mods always have two fields you need to fill out: spawnclassname and spawnfunction. The former is a string which is copied to classname, the latter is a function field which is called to replicate the engine function of looking up the classname function. You could of course mess with the program by setting the spawnfunction to monster_ogre and the spawnclassname to monster_shambler

Extra Credit Assignment: describe what you would see if you did set "spawnfunction" "monster_ogre" and "spawnclassname" "monster_shambler". Creating a test map to find out is cheating... 
First | Previous | Next | Last
You must be logged in to post in this thread.
Website copyright © 2002-2024 John Fitzgibbons. All posts are copyright their respective authors.