|Posted by metlslime on 2007/08/08 04:57:56|
|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.|
a bmodel entity must have it's nextthing greater than ltime or it will not move.
its a bit clumsy, as it tries to get the maths precise so that the train stops exactly where it needs to be even if its only a fraction of a frame away.
the ramifications of this is that ltime does not increase if self.ltime>=self.nextthink.
thus if you want a bsp object to move or spin, it MUST have a valid nextthink set.
remember that the timings are precise in that the movement covers the correct distance, rather than it arrives at the projected time. this isn't some national railway with precise time keeping. Its just trying to avoid moving through walls if you've got a low framerate.
If you have some third entity clearing everything out but the velocity, one pusher can still get blocked and ltime will not update while the other starts moving around freely.
An entire second and a half in 4 is too high for any precision issues. Are you sure its not getting blocked or anything? You're sure that you're using .ltime and not time when setting nextthink, etc?
Turns out I had forgotten to recompile with ltime and it was still using time. However, even though with ltime it was reealllly close, I still had a discrepancy of about 0.8 to 1 game unit when the two entities started from the same point.
I FIGURED IT OUT!!!!!!!
There is a latency, a lag, within a frame from one object to another when the physics are calculated. The two entities had been created several dozen entities apart in the map (about 15 min of mapping on another part of the map while I was thinking about what to do). This means that several dozen entities needed to be ran before the other entity would run, causing enough time lag for a small gap in start times.
Duplicated lagging entity. Deleted original. Placed duplicate entity back in the same spot.
And that only took me 2 months to figure out.
Wait till you see what I use it for in my new map!
An obscure bug with the monster that nobody cares about.
Basically, they don't move when scraping their heads against the top of the water volume they're in.
Anyone have a fix for this? I can trade you a fish model with a normal sized head when it dies...
A simple way is to use pointcontents to check a point above the fish's head and if it is out of the water, reset the monster's z origin to the previous frame so that it can still move horizotally, but won't move upwards into a position where it will be stuck.
This has the small chance of making a fish get stuck in a wall, but you'd have to make a very specific shape of wall and water edge for it to happen.
Bait On A Hook
Banging their heads on the surface usually occurs when they're trying to swim up to the level of an .enemy who's higher up than them. You can create a dummy entity called worm. When you want a fish to swim, stash their proper enemy in a temporary variable, and set their .enemy variable to the worm. You can then position the worm to lead them where you want - place it in the direction of the real enemy, but at an appropriate height vertically. Remember to reset .enemy once you've called the ai movement functions.
The issue was obvious really - like what happens to a scrag when it hits ceiling and you're above it.
Doing Things The Bad Way
The above post is the good way to do things. But we don't like the proper way of doing things, we want to save an entity! The bad way to do things is to instead stash the old height of the fish's enemy, move THE REAL ENEMY down, then instantly restore that enemy's position when the movement function is done. If you're breaking the rules, you should go all the way and skip the call to setorigin - that would only cause actual collsions to occur when you want to avoid that happening. God help you if the fish collides with the enemy though...
New QC article today - on field pointers. There are two - yes TWO - reasons to read today's article! One is if you'd like to learn what a field pointer is in QC and how to use them. They help you write generic code.
Even if you don't care about the technical knowledge, the article solves a practical problem: how do you code an entity which has templates? Templates here are where a mapper can set a single value on your entity and get a bunch of default values applied, and the mapper can selectively override these defaults.
As always a good read and I learned something new about function parameters. :)
I�m going to share a snippit of code from Quoth
You should one day publish that code, I imagine it would be awesome see how you organize and structure stuff. I would love to see how you implement features.
Don't be daft, I'm showing off the good bits! The rest of it is all cludged together. Bit by bit I'll try to blog the how-to behind all the good bits, so that everyone can make a mod better than Quoth.
Don't be daft... all the bad bits are me. :P
Here's the fixed death frame fish model:
It's also got some 'small' frames, if anyone wanted to make, say, a school of piranha.
oh btw, that's a great post about the field-as-arguments.
I was considering posting an awful bit of Quoth code for the sake of comparison - and the function that sprang to mind immediately was the coop removal function, which I wrote entirely myself!
More Field Pointers
So here's a more thoughtful counterpoint to the lovely beautiful code stuff above. It's a second blog post about field pointers on the surface, but it's also about the battle writing clean code and battling the technical limits. There's also an exciting cliffhanger for part III...
Since this is really a mapping forum, I'll give you guys the cuttings about how this stuff relates to maps. Yes, it is possible to overflow the stack if your triggers get too complicated, even in stock Quake. You're probably doing some serious neg!ke style map hacks if you get to that point. There's a workaround if you ever do hit the limits though: give one of your triggers a delay. The stack will be reset between the triggers which precede and follow the delayed trigger. You can think of this like giving the engine a chance to catch its breath!
Revenge Of The Field Pointers
Here's an article with two ways of fixing the problems from last time - using macros and using arrays.
I was going to go further, try and create a system where you could have an arbitrarily long chain of entities using each other without overflowing the stack. The plan was to split SUB_UseTargets in two, the first half would make a global linked list of targetted entities, and the second half would work through this list and call their use functions. If one of these use functions called SUB_UseTargets recursively, it would add the entities to the global list but then return, and let the original invocation call the use functions.
There are two problems with the plan though. One is that the order of which use functions start and complete has been changed by this transformation, which could break maps in some unanticipated way. The bigger problem can be found in this discussion:
It's possible, if maybe unlikely, for an entity to legitimately be triggered recursively. This doesn't work well with the linked list. There might be ways to fix this, possibly by letting the function recurse in these places, but I'll have to give it some more thought.
Chainlist = Findradius(origin,radius)
It is the subtle things in life that cause the most problems ...
The findradius QC command can work differently in Darkplaces compared to Fitz engines. It may not seem like much of a difference but it can cause serious problem if you are not aware of it.
The Fitz engine ignores all entities with .solid=SOLID_NOT when creating a chain list for the findradius command. This is a good thing because certain types of entities (particles, delay spawns) can be excluded from this function easily and included when needed.
Darkplaces (older versions) does not seem to have any exceptions, it will gladly find ANY entity within range and create a chain list. The problem is the findradius command will freely 'corrupt' the chain field and if you use it for anything else then those lists will start to fall apart.
I recently switched over to a chain list for my particle system because it was crazy to keep creating/deleting them all the time. So I cycle round a chain list and it works fine in Fitz. In Darkplaces the lists were getting corrupted and I did not know why and then I finally found the problem, Findradius was finding the particles (my system can use sprites or models) and changing the chain field.
It seems Preach has run into this problem (post#962) but I could not find any other forum links. Apparently there is a sv_gameplayfix_blowupfallenzombies to fix this but the naming of it is not easily recognizable as something to do with the findradius command.
I tried to find a way for Darkplaces to exclude entities from the Findradius command. I set the model field to an empty string or "null" (dp documentation) and setting the bbox and size to zero, but nothing seems to make a difference.
I assume the latest version of Darkplaces fixes this by disabling the fallenzombie gamefix, but not everyone using DP updates all the time. It certainly easy to code for this change, but it is frustrating to find out about this the hard way.
Yeah, the more experimental engines are a bit more of a hassle to keep combatible with. Perhaps we should try and create a little community config file which restores darkplaces etc. to standard quake compatibility. Then add it to quake.rc to execute between config.cfg and autoexec.cfg. Incidentally that's the best time to aply strongly recommended cvar defaults - it replaces whatever was autosaved in the config last time, but lets people who think they know what they're doing override them in the autoexec file.
In your specific predicament, I'd recommend creating an extra entity field, perhaps:
...and use that to replace your code's use of chain.
Could Also Contact LordHavoc
He's usually on the ball with these types of fixes and happy to help out.
sv_gameplayfix_blowupfallenzombies defaults to 0 in current builds (along with other such gamecode-changing settings), but the old value might linger via configs. Probably the easiest thing to do is to detect dp at load time somehow (to avoid warning messages in other engines) and just cvar_set it to 0.
(use solid_corpse instead of solid_not if you want to be able to shoot/find zombies, I guess)
but yeah, its probably better to simply use some other field like .enemy or .owner instead of .chain
So I took the idea I posted above, along with some other thoughts which have been coagulating for the past few months, and made a blog post. It's all about the engine config system, written mostly for someone who's writing a mod and wants to know what to do - and not do!
There's a nice bit of copy-paste code at the bottom for controlling darkplaces cvars, although it covers both the opting-out and opting-in cases so users may need to tweak it slightly to suit their needs.
Locals Conflicting With Func Args?
Is it possible for a local to conflict with arguments to a function? I noticed that with a (clean) progs106, the SpawnMeatSpray function (maybe more) takes two vectors, org and vel; but in the function itself has a local named org. SpawnMeatSpray uses org only when calling setorigin and it seems to be using the argument org, not the local (assuming, can't check atm).
Qc + Locals
arguments ARE locals.
dupe defs are ignored.
initialising a dupe is an error (vanilla qc initialisers make it a constant).
qc doesn't support scoped locals, other than to the function. unlike C+Java+etc, blocks don't have private locals, and locals are still valid beyond the end of the block that they were defined in.
Website copyright © 2002-2021 John Fitzgibbons. All posts are copyright their respective authors.