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
 
it's just to do with the math involved to calculate the throwing vector.

because the lavaball moves so slowly (300u/s), if you jump toward chthon, you'd be behind him by the time the projectile would hit you.

i would assume that v1.01 of the progs didn't have chthon's forward projection targetting code. 
Iterative AI And Tracking 
The algorithm is:

1) work out the time it would take to hit the current player position
2) predict where the player will be at that time
3) set the target position to be that spot

There's a logical flaw in this scheme. The time it will take the projectile to reach the new spot will be different to the time it takes to reach the current spot, so there's no guarantee that the new aiming vector will be any better. This would not be significant with a fast projectile, as the two travel times would likely be very similar, and the size of the player's hitbox is a large enough margin of error.

However, the slower the projectile moves the worse the situation gets, compounding the problem necros describes. Moving towards the origin of the shot combines these two problems, and I'll try to give an example of the worst case. The player is moving towards chthon from 600 units away (2 seconds of flight time). We imagine that the player is moving at just over 300 u/s (the player's top speed is somewhere around 400 u/s). This means that in two seconds time, the player would be just behind the knuckle that the rock is thrown from. The projectile is then thrown directly backwards and misses completely.

We realise that this target point is stupid for a few reasons:
� The player will likely not run straight at chthon for two seconds
� More importantly, the player cannot run through the solid body
� Even more importantly, the rock will sail past the target point before even a fraction of a second passes. Even if the player could and did continue exactly to the predicted spot the shot would still miss!

This last problem is something we can fix with iteration! The idea is that we want to calculate a point where the time the rock will take to reach it roughly matches the time the player would take to reach it. If the player is running towards Chthon then this point will be roughly halfway between the two. The iteration is based on
� Taking the current target point
� Calculating the time to strike that
� Calculating a new target point from the predicted position the player would be in at that time
� Feeding the new target point into the top.

In our worst case scenario we described, we'd start with a target point of the player himself. Then we'd get the point right next to the knuckle with a very short flight time, so our third point would be very near to the player, but a bit closer to Chthon than point 1. After a bit of ping-pong of points that are too near to each end, we should work into the middle.

This is quite nice, and I like iteration in AI because you can do one iteration in each animation frame leading up to the shot. It creats an interesting, slightly unpredictable thought process which keeps taking on updates as the world changes. It's worth noting that this actually offers better prediction in other cases as well.

An alternate method for a more reliable forwards-travelling shot would be this: Take the offset of the new target point from the player, a vector called o.

Apply the following equation:

o = o - (o * v_forward)* v_forward;

This removes the component of o in the direction Chthon is facing. Finally, make the target point equal to the player's origin + o. Not as elegant, but perhaps slightly easier. 
<-- Chthon Lavaball 
that is... fucking cool, man. 
Heh 
I wondered why, when I go to hit the button that if I moved a step backwards and then over and than towards him as I stepped on the button I was almost always ensured not to be hit, perhaps I should have looked at him once or twice. 
 
if the original chthon fight hadn't been so gimmicky, it would have been a cool trick akin to shambler dancing or nails + fiends.
it's sad that you barely even have to look at chthon to defeat him. :\

yes, i am bitter. it's a great model and texture. yet, so poorly used. :(
the same could be said for shub. 
 
killable Chthons are en vogue lately. 
Probably A Silly Question... 
when multiple entities a touching another entity with a .touch function, each entity runs the .touch with itself as other right? 
Touching 
Yeah, although you have to be careful with entities that aren't moving. For example, monsters at rest inside a trigger don't generate touch events, since the monster only checks for collision when moving, and the trigger never does. This is where force_retouch is required. All entities use the same code for checking collisions though, and it is a combination of descending recursively down the tree of nodes intersecting the 'self' entity, along with a for loop to test all the entities within the current node. 
 
thanks yet again, preach :)

i was thinking maybe i should go through all your posts in this thread and make like a 'preach's guide to arcane quake facts' :P 
Well 
I do have a fun fact about that fun fact: it implies that in a multiple collision, the order that the collisions are resolved is essentially unpredictable - they depend on the location of the entities within the bsp tree that comprises the level.

Speculation: it might be possible to exploit this to glean some information about the bsp tree from QC - using force_retouch with a trigger and some point entities spawned in a region. Knowing that one point is in a leaf higher up the tree(or further left) than another may not be incredibly useful though... 
Path_corner Weirdness... 
void() movetarget_f =
{
if (!self.targetname)
objerror ("monster_movetarget: no targetname");

self.solid = SOLID_TRIGGER;
self.touch = t_movetarget;
setsize (self, '-8 -8 -8', '8 8 8');

};

void() path_corner =
{
movetarget_f();
};


quoted is the path_corner entity. unlike every other entity, path_corner defer's it's setup code in another function.
as i'm passing by, i frown at it, comment out movetarget_f and just paste the code into the path_corner function and grin at my cleverness.

suddenly, none of the path_corners work anymore. so i o_O and put it back the way it was. of course, i'm left with the question of why? it's just an entity with a touch function. 
Path_corner 
I couldn't reproduce this - the monsters seemed to follow their usual paths when this was the only change made to the vanilla source code. Any chance that something else changed at the same time? 
 
well... i dunno but it works now...

new comment:
//deprecated. why was it even like this to begin with? (not deprecated, it stopped working when i moved this down into the path_corner function o_O) un-not-deprecated: it ended up working now. o.o 
Hmm 
Just bumping for easier location by new users (coding scares me way to much to be in here for any other reason ;) 
Self 
if you change 'self' in a think function and forget to change it back, what happens? (beyond just the operations in the same think function)
does it mess up the engine's think iteration as it goes through the list of stuff?

what about entity links? can something cause a .entity link to get broken?

i'm having some weird problem with entities randomly getting messed up but it's so random that tracking it down is proving quite annoying. 
Selfless 
The 'self' that you can access from the qc side is not used (at least in the standard source) in any of the engine code, it always begins with it's own reference to an entity passed as a parameter, and then set in the global_qc_self variable (not it's actual name in the source). So I don't think that could be your problem.

Is it possible that some of the entity links you have run through entities which are removed? The quake engine has a 'lazy remove' paired with a 'thorough spawn' function. Only 5 or 6 entity fields are cleared on removed entities, just enough that they are no longer transmitted to clients. When the entity slot is reused, the spawn builtin goes through and zeroes all of the fields.

Although it makes sense to not go to the trouble of zeroing all of that memory until necessary from a performance point of view, it can make bugs intermittent. If your code relies on a reference to an entity which has been removed, then it will more than likely perform correctly until something uses that entity slot. The trouble is now that the cause of the bug is separated from it's first effect by an unpredictable length of time, making it very hard to diagnose. 
 
i use
if (self.someEntityLink)
{
self.someEntityLink.think = SUB_Remove;
self.someEntityLink.nextthink = 0.1;
}

which i felt was pretty safe.

the problem seems to be centered around accelerating movers.
i'm still using helper entities to control velocity but it seems as if after a few minutes a helper will just become removed (when i check the helper's edict it is either free or a new entity).

however, this also happens with a custom lightning entity. the custom lightning entity spawns a chain of models to simulate the lightning effect and cleans them up when the effect is over. somehow that master entity just dies sometimes leaving the models in the game.

both of those entity's think loops seem to be solid so i can only guess something outside of their thinks are killing them. 
The Debugging Wrap 
You could put a wrapper around the remove function to try and work out exactly what is removing them. In defs.qc rename the builtin definition #15 to

void(entity e) remove_builtin = #15;


You can then define a function called remove which has extra behaviour before calling remove_builtin. I'd probably add a boolean field to the entities you want to monitor.

.float donotremove;

void(entity e) remove =
{
�if(e.donotremove)
�{
��dprint("Entity of class '");
��dprint(e.classname);
��dprint(' was removed!);
�}
�remove_builtin(e);
}

This doesn't give you much debugging information though, it still requires you to guess what just happened. It would be better to get a stack trace, but the only way to get one of those is to crash the map. I'm not sure how much of a stacktrace you get by calling error() or objerror(e). I do know that you'll get one by creating a runaway loop though, so something like:

void(entity e) remove =
{
�if(e.donotremove)
�{
��eprint(e);
��while(0){};
�}
�remove_builtin(e);
}


That ought to give you plenty of information as soon as one of these entities gets removed. Just remember to clear the donotremove flag before actually removing them! Also, it should be obvious that this kind of code shouldn't go in a release build... 
Oops 
That of course should be while(1) in the code above, so that it loops forwever rather than not at all. 
 
that's a great idea, thanks! maybe i should create a wrapper for spawn() so that donotremove is set to true by default, or do the inverse have it as 'safetoremove' defaulting to 0.
anyway, nice idea to abuse the stack trace engine feature. ^_^
it's like teaching progs new tricks but for engines. :P 
Donotremoveanything 
I was figuring you'd only apply donotremove in the spawn functions of the two entities you were trying to debug, otherwise you've got to worry about your game crashing every time a missile hits a wall and stuff! Wrapping spawn and remove is a really great trick with lots of uses, I'm really grateful to frikbot for showing me the trick of redirecting builtins. 
More Weirdness 
you know how, when you're riding a platform that's moving upward, your viewpoint sort of sinks down a bit?

currently, console prints (like bprints or stuffcmd bf) are causing the view sink effect to reset each time. every time there's a bprint, the view height resets to the standard height and starts to sink again.

i have the feeling i've fucked something up pretty badly. :P 
Oh O.o 
apparently, the bprint thing is happening in stock quake too. this must be some setting in fitzquake because it doesn't happen in aguirre's quake.

will investigate... o.0 
Uh Oh... 
 
 
i'm still unsure exactly what's causing it... if someone wouldn't mind checking this out, an easy way to test this is to bind a key to 'god' and then load up e1m1. hit the button for the first lift and let it lower.
when it starts to raise back up, repeatedly hit the key you bound to god mode. each time the screen should reset to the normal view height before sinking back down.

this happens in fitzquake and quakespasm. 
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.