Oh, honestly, I think you're off the hook there. I know about best intentions and all but if someone is leveraging a bug or a hack in your mod that you haven't documented and that breaks in the next version - so sorry, but oh well.
That's not an unreasonable position to take. Use the documented features only or risk getting burned. That's totally fair.
And, really, I'd rather have the freedom that the hacks provide rather than mod authors going through the work to lock everything down.
Yeah Preach - You Shouldn't Worry About It
because the person who is making the dodgy hacked map has a copy of the original progs he was using anyway, so if a later version breaks the hack then the player/mapper just has to roll back his version.
And you guys have catered for that by releasing the individual parts of quoth, upgrade by upgrade...
Defending Against Hacks
It's reassuring to hear that, I'll worry less about people hacking. As a future warning, don't hack anything to do with path_corners in quoth, they don't work like they used to in quake, and they are going to change...
Even so, I'm gonna post how you do it anyway, because at the bottom there are two alternate applications of the ideas. And also because the second way in here is a really cool trick that I've never seen anyone post about before.
So if you do want to defend against a hack, what can you do? Well, to my knowledge there are three ways of defending against things, from the very specific to the very general. Even if you don't think you'd want to actively prevent a hack in your code, you might find some useful information at the bottom of the post about making entities more friendly to modification while maintaining sensible defaults.
If you are concerned about somebody putting an unhelpful value in one specific fields for a specific entity, then the way to prevent it is simply to set that field during the spawn function to a correct value. For example, if you have a monster which gets enraged after firing 10 missile attacks, and you count the shots fired so far in self.shotcount, you probably don't want people to be able to set .shotcount to 10 so that the monster is enraged straight away, so you can add
self.shotcount = 0;
in the spawnfunction. Although it sounds like a trivial thing there, you can prevent people from giving your entity a use function(assuming it normally lacks one) with
self.use = SUB_Null;
You could even preempt people making your entity shootable and killable by forcing
self.takedamage = 0;
self.th_die = SUB_Null;
...although some people might call that paranoid. This method is in a sense exclusive, you chose which fields you are going to prevent being set. If you start doing too much of this stuff, you should instead look at the third suggestion.
The second idea is one I've never really used because the idea only just came to me after discovering a light.exe feature. Rather than preventing people from custom-setting one field in a particular entity, this one lets you prevent a person setting the field in ANY entites. A good example of something that might warrant this protection is .super_damage_finished . The super_damage_finished field makes an attacking entity do quad damage so long as the map time is less than its super_damage_finished value. It's a bit of an ugly hack using that to get monsters with deadly weapons.
The fix is to rename the field to begin with an underscore, like _super_damage_finished. Any field which starts with an underscore gets stripped from an entity as it is loaded by the engine. This is intended so that light tools could read extra fields on lights, which had sensible names preceeded by underscores. These fields then wouldn't cause warnings if the qc omitted their definition. What we are doing is flipping that, creating a field which is only used by the qc and never from the map, rather than always by the map(via tools) and never in the qc.
For those of you who are c++/java fluent, I've come to think of this trick as creating public and private fields on entities(with respect to the map loading).
Defending Against Long Posts
If you want to go further in the other direction, protecting almost all of the fields on a specific class of entity, then there is a pattern you can use in your spawn-function:
void() func_protected =
local entity template;
template = self;
// we spawn a new entity with all fields blank
self = spawn();
self.classname = "func_protected";
//at this point you copy across all the fields you do want to inherit from the mapper
self.model = template.model;
self.health = template.health;
//then you perform the setup on self as you would expect, eg:
//finally, get rid of the template, since it is no longer needed
This gives you complete control on what can be set on your entity.
Although you may not see the need to do this for the reason of protecting an entity, there is a related construction which is more useful. Suppose you have a mod where several "rounds" of a game are played without the map restarting, but you want to reset the arena between rounds. How do you handle resetting something like a breakable wall, which may or may not have been destroyed during the round?
Method 1 would be to have a reset function which desperately tries to reset to zero all of the fields which might have been changed during the previous round on the wall. If it was destroyed, then the model field has probably been cleared, so you will need to store that information somewhere else, and you'll need to recall it's starting health from .max_health, and there are tons of things that could go wrong.
Method 2 is to use adapt the func_protected example above. The original entity placed by the mapper remains entire unchanging for the whole game, and we call this the "template". We split the above spawn function into two parts:
- the bit which precaches all the resources, which will run at worldspawn
- the bit which makes a new entity, copies the required info from the template, and sets it up
The latter function is called every time a new round starts, after the entity from the previous round has been removed. You should of course delete the line which removes the template from this version of the function!
(for c++/java people, this is a quake kinda way for doing the factory paradigm)
Finally, the flip side to the first method of protecting things(one field for a particular entity) is how to make a field customisable while still having a sensible default. Here are some methods for making the health of a shootable func_crate alterable (default:45), from the most common to the most bizzare:
self.health = 45;
This just takes the case that the mapper has set nothing, and makes it 45. We could fairly easily improve this to also perform a sanity check for negative health:
if(self.health <= 0)
self.health = 45;
We might instead decide to add whatever value of self.health is set by the mapper to 45.
self.health = self.health + 45;
This will still maintain the default at 45, but it's probably less sensible than the above methods in this case, as it would be confusing. There might be cases other than health where it would be a more sensible way.
WTF, You Double Agent!
First you lead us to the dark side of the progs, now you advertise methods of preventing the use of hacks... I can't map without them!
But yeah, mod/version conflicts are a potential problem indeed. Take the differences in model/precache handling in Quoth 1 and 2 for example. I had to come up with a crude way of progs detection in my 768 map in order to make the backpacks in the end arena appear correctly in each version.
Didn't You Understood ?
Preach is working for an antivirus program provider company: those guys are hackers one day, and the other they sell you the latest update of their tool... swindler !!!
is it possible to teleport weapons in ID1?
Didn't stop the Reaperbot... impossible CHEATAR!
I have a map file for quake that I have created with Hammer. I would like to continue working on this map using the QuakeED editor. Is there a tool to convert the map file to the right format?
Do You Mean
.map? there's an export to .map option in hammer.
The exported map is in a different format. Aguirres tools can handle it but other editors can't I guess.
Valve 220 Texture Data
It's a pain in the nuts.
Export to .map and use a notepad++ find / replace function?
Probably a long shot though.
possibly try using aguire's map converter utility? if you pass the .map through without actually doing anything, maybe it'll strip out the extraneous data when it parses the file?
Between the two and it wouldn't work - not only is there more data, but its also rearranged, and alot of it is single numbers.
Convmap might be worth a shot, yeah, otherwise I'd suggest just continuing with WC for now.
Func_door - Ignore Enroach?
Is there a way to get a func_door to close regardless of what it's hitting? Say I want 2 doors to crush anything passing between them - at the moment, the one door immediately retreats back it's starting position while the other works as normal.
Is this fixable?
is to set:
and manually retrigger to close after opening.
isn't there a "crusher" flag that prevents doors from reopening on impact?
Not For Normal Quake?
The crusher flag is called "dmg" and should prevent the door from reopening if the value is high enough. And if not, give both doors the same "team" field.
The "team" field didn't seem to work. The "dmg" is set at 10,000 so that should be high enough.
I dunno, I added a new spawnflag (SF_CRUSHER) and added a quick IF condition to the "door_blocked" function. That seemed to do it.
Necros had it right first time about the crushing behaviour, it comes from setting wait to a negative number. Quoth the source(door_blocked):
// if a door has a negative wait, it would never come back if blocked,
// so let it just squash the object to death real fast
if (self.wait >= 0)
if (self.state == STATE_DOWN)
So as long as self.wait is less that 0 the door doesn't change direction.
After several bumps in Quake modelling I won't get used to the fact a modelframe exported to dxf has a unique vertice and trianglecount.
It may be my poor knowledge of triangles and vertices but when I import this file in another editor and try to export them back to Qmle the vertices turn out higher and triangles are doubled.
I know it has something to do with triangles turned into quads and vice versa, but why doesn't these counts stay the same?
I don't add anything so that can't be the reason.
Is it the 8bit configuration, and nowadays 3Dstudio's 16 or 32bit?
Website copyright © 2002-2018 John Fitzgibbons. All posts are copyright their respective authors.