It's kind of gimmicky and the 'mapping establishment' may frown down on this sort of thing, but if executed well, it can be nice. Some of you may remember a speedmap I did during one of the expos that had this in there. That was probably a good example of how NOT to do it.
I guess the first thing I should answer and get out of the way is the simple question "How is this possible?". Well, the interesting thing about Quake is that all the fields that exist on an entity are completely exposed to the mapper, although you may not realize it. There's a certain set of accepted fields you're "supposed" to fill in, but things like "think", "nextthink" and so forth are open to you, and you can make them point to any function you want. There's even a handy "info_notnull" entity that can be a blank template for whatever you want to make.
You obviously can't make entirely new code, but you can manipulate the existing code in various ways to produce things like player-model enemies, super monsters of all kinds and so on. Doing these may require "a programmer" to find the events you need to chain together, but once the store is given up (as in this tutorial), the floodgates are opened.
To get a killable Chthon we'll basically be creating 'a new monster' with map entities. So let's get to it.
In Quake, monsters and every other map entity have "a spawn function", this is the function called by Quake when loading the map and specified in the map as the "classname" field. Familiar spawn functions to you may be "info_player_start" and "monster_soldier". The former has really no code attached to it, the player just finds this blank entity and spawns there in single player.
The latter on the other hand has a bunch of code that defines the parameters of a grunt monster. Things like health, the weapon, the animation functions it will use and so forth. The key point here is that all that function, monster_soldier really 'does' is setup fields on an entity. You may have remembered me just saying that all fields in QuakeC are exposed to the mapper. You may now sense where this is going.
We can basically write our own 'spawn functions' from within the map. As all it does is configure the fields of an entity. A word of warning though, if you get too carried away with this you can break your map with a ton of mods, as most mods latch into these spawn functions to set up new fields that never existed before in Quake. For our little SP map however, this is not a concern.
How we create this new spawn function is by abusing an "info_notnull" entity. This entity, like the info_player_start entity previously mentioned, has no setup function at all. It's blank except for the fields you define.
So let's create an info_notnull on our map. This will be the spawn location of our chthon, so it'd probably be wise to locate in some lava somewhere. You should probably also activate the "Not In Deathmatch" spawnflag in case you want to support deathmatch mode in your map (otherwise "our" Chthon would appear in DM and would likely crash the server because "his counterpart" won't (I'll get to this later)).
Next we need to fill in the other fields of info_notnull Chthon. So add these fields as I present them. Adding fields is different in each map editor. I primarily use Worldcraft. To add fields in this editor, turn off "Smart Edit" and use the add button. I'll be presenting the fields as quoted name and value pairs, as would be seen inside a .map file. Under WorldCraft, don't include the quotes.
Code: Select all
"nextthink" "0.01"
"think" "boss_awake"
The think field of an entity tells Quake which function to run when the game time passes the nextthink field on an entity. By setting nextthink to 0.01 and think to boss_awake we're basically calling boss_awake 10 milliseconds after the map load. Calling this function is a needed step to get our Chthon set up and looking like Chthon.
Code: Select all
"targetname" "my_boss"
For example when you walk through an invisible trigger on a map, you will cause the game to search for all entities that have a field "targetname" that matches the "target" of the trigger. For each of the entities it finds, it will run the function .use() function for that entity. That differs from entity to entity, monsters awake when used, trigger_teleports and trigger_hurts toggle on and off, lights toggle on and off and so on.
Unfortunately for us, our blank info_notnull has no use function. But fear not, that's where the next field comes in
Code: Select all
"use" "walkmonster_start_go"
Code: Select all
"armorvalue" "2997"
"armortype" "1"
The "armortype" field indicates how good the armor is, the percentage of damage it actually blocks. The best armor the player can get, red armor, has an armortype of "0.8", it blocks 80% of the damage dealt to the player. You'll notice I put a 1 in this field, this means 100% of all damage is blocked, that means before you can do damage to the health of the creature, you must completely wear away all his armor. Et viola, we can give our Chthon 2997 armor, so that his final "health" is 2998 to 3000 hitpoints.
This trick works for all monsters, try it out, and when you're done making super duper shamblers, we'll continue..
Code: Select all
"th_run" "boss_missile1"
"th_walk" "boss_missile1"
"th_stand" "boss_missile1"
"th_missile" "boss_missile1"
Code: Select all
"th_pain" "plat_hit_bottom"
"noise1" "boss1/pain.wav"
So we kinda need a different pain reaction. The easy solution is to use another obscure function, plat_hit_bottom as our pain. Plat Hit Bottom does little but play a sound file, in this case, specified by the noise1 field on the entity.
So hidden here is our next super secret mega awesome map trick: You can make triggered sounds in Quake maps simply by targeting a notnull who's "use" field is plat_hit_bottom and who's "noise1" field is the sound you want to play. Unforunately, the sound needs to be precached first, so you're rather resticted in what sounds you can play with this method - only player or door, monster or item sounds of things that already exist on the level.
Anyway, getting back to our Chthon, we're nearly done, bear with me just a bit longer.
Code: Select all
"th_die" "boss_death1"
Alright We're done with the info_notnull, however we're not completely done. We'll need to set up a trigger to force Quake to call our Chthon's use. You can use a button or an invisible trigger_once or whatever. Take note, Chthon will work before it is activated, but he won't be killable until it's pressed, so you may want to make it a bit challenging before the player activates it, or you may want to trigger it right away. Just don't trigger it immediately, before that 10 ms delay we talking about for "think".
Next we'll need actual monster_chthon on the level so Quake will precache all of chthon's sounds and models. You can just stick it in the level somewhere, you don't need to activate it, or even make it accessible to the player in any way, it's just so the precaches in the monster_chthon function get called.
Well, that's it. I hope you learned something about mapping and QuakeC and I hope you found this in some ways valuable.