News | Forum | People | FAQ | Links | Search | Register | Log in
Coding Help
This is a counterpart to the "Mapping Help" thread. If you need help with QuakeC coding, or questions about how to do some engine modification, this is the place for you! We've got a few coders here on the forum and hopefully someone knows the answer.
First | Previous | Next | Last
 
That... Is very interesting. Would have been useful to protect stuff for sure. Although if you're going to limit things in that way then you should try to provide ways to do those things explicitely. 
 
Could someone explain mechanically how Quake's monster stun effect works? Is it like Doom's where monsters have a percentage chance to be stunned, or does it go off the amount of damage cause etc? 
 
I think it happens on specific animation frames 
(i Guess You Mean The Sudden Attack Cancelling Effect) 
 
Percentage 
It's something that varies from monster to monster, and it depends on a lot of things:

Random chance
Amount of damage
Time since last attack
Skill level

Each monster has an individual function to decide what to do, I'll explain two contrasting ones:

The grunt is on the weakest end of things. The first hit it takes will always send it into pain. At that moment one of the pain animations is selected, and it's pain_finished field is set so that it can't go into pain again for a short time. The pain_finished time for grunts is barely long enough for the pain animations to complete. Amount of damage has no effect.

The shambler is on the opposite end of things. When it takes a hit, it generates a random number between 0 and 400. If the amount of damage is less than the number generated, it ignores the hit. Otherwise it goes into pain, and sets pain_finished to 2 seconds into the future.

In between these two extremes there are lots of variations. The pain_finished time is unbreakable, but after that there is usually some amount of damage which guarantees a pain animation (e.g. we see the shambler takes 400, the death knight is only 30). Nightmare skill has a global effect - the minimum gap between pain animations is 5 seconds for everything. 
 
ic, interesting. It certainly seems somewhat random but a lot less so than Doom's...

Cheers :) 
Overlaps 
As promised, the second half of yesterday's article, with a more sensible use for private and hidden fields, after introducing overlapping fields.

http://tomeofpreach.wordpress.com/2012/12/03/overlapping-fields/ 
Re: Practical Problem 
I know this is a hack, but could you not add special consideration to 'info_notnull' that when it has a 'model', you search for other entities with the same 'model', and set it's 'modelindex' the same?

So if I have a:

"classname" "info_notnull"
"origin" "# # #"
"think" "PlaceItem"
"nextthink" "0.2"
"touch" "BackpackTouch"
"model" "progs/backpack.mdl"
"modelindex" "#"


We'd look for another entity which already was 'model' 'progs/backpack.mdl', and use it's modelindex as our info_notnull's. This means the info_notnull would have to be later than an actual backpack (or whatever we were trying to copy)... but wouldn't that make the designer setting the correct modelindex irrelevent, and all he'd need to do is set a correct model? 
Modelindex 
Yeah, there's really no need to be doing anything with the modelindex if the mod supports custom model setting. Thankfully Quoth provides that with the mapobject_custom entity - which will also precache whichever model you supply it so you aren't restricted to models the mod already uses. The mapobject_custom is basically an info_notnull in every other way, so if you were to apply other hacks to it they'd work fine.

I stopped short there of saying "go ahead and use hacks", as they can cause problems, but I do still keep them in mind when designing things. For example, one of the features I've considered for Quoth is aggressive entity optimisation. This would basically be runtime consideration of which entities don't actually need a full entity slot to themselves (yet), along with a way to let entities share slots for the time being.

The path_corner is the simplest example of how this would work. Even with all the exciting extra features added to them in Quoth, you only need about half a dozen fields to store everything relevant about a path_corner. I've written code that will take those vital fields and stash them into one of four field-sets, making an entity with a "library" of 4 path_corners. The pool of library entities also doubles as the active path_corner entities, which are dynamically generated as a monster heads towards one.

So if this is all done and working, then why isn't it going into 2.2? The reason is hacks. The logic that says you only need 6 fields to store the relevant info from a path_corner breaks down if someone performs any kind of hack on the path_corner. Because there's no limits to what might be hacked, you can't predict what extra fields you'd need to store to restore the hack to working order, and the fact that potentially you'd need to store any field means there's no space to store even a second path_corner. Even if you could, dynamically generating the path_corner is equally toxic to potential hacks, as the path_corner might not exist at the vital moment the hack is to be triggered.

I can see two ways round this: one would be to create a global opt-in flag like the model optimisation flags: the flag would mean "This map is free of hacks, so go ahead and aggressively optimise it". The alternative would be a local opt-out flag on entities, meaning "don't optimise this entity, I'm performing a hack on it!". While I'd prefer the latter, I suspect it wouldn't be backwards compatible.

Some might say that surely path_corner is a safe thing to optimise, that nobody would hack. However
1) There's already a hack involving them
2) Imagine the same principle applied to unspawned monsters

The take-home message is this: Map hackers of the world, you are being considered, but you make it hard on us! 
Is That So? 
The mapobject_custom is basically an info_notnull in every other way, so if you were to apply other hacks to it they'd work fine.

Applying the "give the player a DBS" fields from my info_notnull to my mapobject_custom made the backpack model not appear.

{
"classname" "mapobject_custom"
"origin" "320 184 -244"
"model" "progs/backpack.mdl"
"skin" "14"
"think" "InitTrigger"
"touch" "BackpackTouch"
"items" "2"
"netname" "Double-barreled Shotgun"
"nextthink" "0.2"
"targetname" "pack_dbs"
InitTrigger 
InitTrigger is to blame there, it intentionally hides the model of whatever it is run on, so that you can't see triggers. 
I See. 
Any way around it? 
 
the flag would mean "This map is free of hacks, so go ahead and aggressively optimise it"

this isn't that bad an idea... like setting a strict doctype. 
Two Replies In One 
onetruepurple: try swapping the classname and the think.

necros: yeah, I think it's what will have to happen. Maybe you can have the local opt-out flag as well. Opt-in flag means: "I will let you know when I'm hacking", opt-out means: "This is a place I am hacking" 
What Else 
Other than a missing precache, causes Quake to crash without error?

Dusting off my coding skills and this has me stumped.

No errors in the compile either.. although I am running FTEQCC. It's definitely something I've done recently though. 
Difficult 
Best advice I can offer is call traceon() in the worldspawn function, then run with -condebug on. You'll get a massive log file, but you probably only need the last few lines to find out what runs immediately before the crash. Otherwise, maybe try a few different engines, darkplaces will often tell you something that other engines don't. 
 
infinite while loop? had that a few times 
Ijed 
Another crasher: whatever's happening on e2m2 when you pass the front gate without shooting both buttons on easy skill. 
Thanks! 
Will get this figured out. 
Overlapping Fields 
Preach,

So recently, I treat QuakeC as if it were an OO language in that I ALWAYS create new .variables for all entities.
I do this mainly for readability/clarity reasons after getting burned when trying to make sense of some older code that was using things like t_width and lip all over the place.

Of course, now every entity has like an extra 100 variables attached to it. While it's unlikely to really impact the code much (it's not like we're lacking memory or processing power here) it does bug me a little in that it's not really the right thing to do for this language.

So... would the proper course of action be to declare a handful of invisible fields:

internal_float1__ ... internal_float10__
internal_vector1__ ... internal_vector5__
etc...
and then overlap the same fields with unique names? 
Yeah, I Guess 
It could work, but you've got to be really careful that you're never overlapping fields that will cause problems. You don't need to give them names like internal_ etc, you can just pick one name as the original and overlap the others on that.

Doing this kind of overlapping in monster code might be safest. Make sure each monster has its own QC file, and define the overlapped field name at the top of the monster's own QC file. Then you can make sure all use of these fields is localized to functions in the one QC file. To be doubly sure, instead of using the "var" keyword to overlap, use a #DEFINE macro to give the field its name, and then undefine it at the bottom of the file. Then you only need to watch out for other QC files calling your functions (and map-hacks).

What would be really nice would be a sort of QC++ compiler which creates the idea of a "class". It would let you subclass entities, have functions that only accept particular classes of entity, and prevent you accessing entity members which aren't defined for that class (or parent classes) at compile time. Then the compiler would overlap private fields for you safely.

This isn't quite as crazy as it sounds, the original C++ compilers were source code transformers which output C code and then called a C compiler to build it. A fun project for someone who wants to learn Lexers and Parsers... 
Wah 
After rolling back everything - models, sounds, code, maps I still got the crash on map load.

So I open up the map and clean out the values I'd added to control the enemy in question, and that solved it.

pose 0
skin -1
cnt 0

One of those was the guilty party I'm assuming the skin value - I was using -1 as 'random'.

(this is about a crash I mentioned earlier in the thread, thought it might be of passing interest) 
Yeah 
I can imagine how that might cause a crash, yeah. Setting fields to zero in a map should do nothing at all, fields are zeroed to begin with. The -1 on the skin might do it though! The engine probably uses -1 as an offset into the skins array, and reads some random memory just before the site of the model data. If you still want to live dangerously and use -1 as the "random skin signifier", you can probably do it just by altering your QC a little - handle the -1 case and randomly select a skin before any call to setmodel. 
 
With a skin of -1, MSG_WriteByte will coerce the value to a unsigned char, which I think gives it a value of 255? Then the client gets the 255 and and uses that index to look up the gltexture in an array. This array access is probably out of bounds, causing the crash. 
Aha 
So when I cleaned up the code and put setmodel / setskin in the right places it broke...

I had to delete a lot of stuff, but I don't see it as wasted time - now I can build it much quicker and better.

It's for an undead enemy that 'hatches' from dead marine corpses - the unlucky guy's own skeletal and muscular structure, minus the skin. 
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.