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
Lazy Idea 
Adding

self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);

straight after movetogoal (d); in ai_charge is certainly a straightforward way to eliminate the wobble. What you might ask is how much difference it makes elsewhere. I mean, we're overwriting the change SV_NewChaseDir makes, and while we've identified a case where it makes an irritating change, does it sometimes make a beneficial change instead? You might imagine that on occasions when it finds a direction the monster can walk in, we may want to retain that information.

I'd argue that no, almost every time it makes no difference besides the visual glitch. My reason is that the preceding line in ai_charge is ai_face ();. This actually resets ideal_yaw in the same way our added line of code does (I straight copy-pasted it from ai_face). So any time an ai_charge is followed by another ai_charge next frame*, the information from SV_NewChaseDir is discarded without being used. Keeping it will make little to no difference.

Ah, if only they could all be one-liners...

*Here by "next frame" I mean next monster animation frame, not engine frame. 
Duh 
I guess that's kind of what ijed was getting at too. Just reset it immediately. i'm tired. :p

Will test soon. 
 
...or use walkmove? i never use the ai_charge method for exactly the reason you stated. 
 
the ijed/preach method actually makes it WORSE. the monster spins like a ballerina.

the necros method works like a charm. walkmove is all or nothing, though, so this
if ( !walkmove(self.ideal_yaw, d) )
walkmove(self.ideal_yaw, d * 0.5);

serves as a good functional compromise.

ai_charge_side uses walkmove, and now that I understand all this I really don't know why ai_charge didn't already.

Thanks, guys! 
 

do
{
����if (!walkmove_builtin(yaw, stepDist))
��������stepDist = stepDist * 0.5;
����else
��������stepCounter = stepCounter + stepDist;
} while (stepCounter < step && stepDist > 1 && stepDist < (step - stepCounter));


Preach clued me in on this gem. This will always walk as much as possible but due to some mathyness, will only every iterate a maximum of 6(?) times. 
 
actually, come to think of it, i wrapped movetogoal in a method that essentially replaced movetogoal with walkmove. call movetogoal with distance of 1, reset position back to where it was before but record the direction it moved in, then use walkmove to do the actual move with the proper distance.
this solves the problem with monsters not willingly walking inside other bboxes, even if they are non-solid (and thereby not generating touch events). 
Piroette 
I can't understand how your monster spins so much after the change I suggested, certainly when I played around with the ogre it didn't cause such a difference. I will admit that it doesn't fix the issue - in my testing I wasn't reliably replicating the glitch. Luring the ogre to a wall on a corner makes it occur regularly, both with and without the change.

However, I think I may understand better why it's happening. I don't think it's due to the failure mode of SV_NewChaseDir you spotted, because that only changes ideal_yaw, and ideal_yaw is reset before the monster is turned towards it next (barring any functions above ai_charge calling ChangeYaw).

Instead, what if all the functions are behaving correctly in isolation, but the result is strange. Imagine that the monster is essentially trapped near the player, and movetogoal succeeds in moving the monster only occasionally. On those occasions, it's likely to move the monster away from the obstructing player. Then next frame there is space for the the monster to move in the correct direction and it returns to where it was. The net result is that the monster shuffled sideways for one frame.

But tragically, this actually could cause the one frame jump in angles! The reason is that ai_face calculates the angle for the monster to face based on the relative origins of the pair. So a one frame shift in origin has a corresponding one frame shift in facing. It might be a little hard to reliably establish this is how it works though.

Replacing movetogoal with walkmove would certainly eliminate this issue, as the monster would only ever succeed in changing origin if they had moved straight towards the player, but it does mean that you're losing the ability for a monster to slip round a barely obstructing obstacle while charging. It's not about how far the monster is moving (both functions are all or nothing), it's about which directions they try.

If this is the right explanation of the glitch, then I think it boils down to: monster angle changes should result from the player moving round the monster, but not from the monster moving round the player (because the latter tends to be back and forth and glitchy). So something like:

���self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
���movetogoal (d); // done in C code...
���if(approx_equal(vectoyaw(self.enemy.origin - self.origin), self.ideal_yaw))
������ai_face ();

Prior to movetogoal, you only change the direction you'd like to walk , not your actual angles. Then after you move, you check to see if the angle is still more or less the same. If you moved straight towards the player or not at all, then it will be (in the former case I suspect it may vary slightly so this comparison should be approximate). If you shuffled sideways then it differs, and this frame you refuse to change angles. 
 
but it does mean that you're losing the ability for a monster to slip round a barely obstructing obstacle while charging

That will rarely happen anyway though since it would need several consecutive frames for it to successfully walk around even the smallest of obstacles. 
 
oh come to think of it, i think i understand what you mean; if you have a monster charging at you and it hits an angled wall or railing or something, it can still walk towards you following the railing whereas walkmove would just stop dead. 
 
String concatenation without crazy hacked compilers: possible? I can do it by abusing the 'stuffcmd' buffer and changing the player's name, waiting a frame, getting the player's .netname and then stuffcmding it back, but this prints messages about the player's name changing. 
String Concat 
depends what you're cating. part of the problem is that even if you can hack the player's netname like that, you have to do it for every single string.
one trick (abused quite effectively in prydon gate, also in frikbot to a lesser extent) is to use writebytes for your sprints and centerprints and stuff. this can generally get close enough without visible side effects, but does mean that your strings need to be hard coded to some extent.
the last part of your message can still use writestring, so at least that part of it doesn't need to be hardcoded.

quakeworld could do something with the server's localinfo, but this does still impose a frame's delay due to localcmd. 
 
Yeah, I'm trying to create guaranteed unique targetnames, so centerprint effectively goes into the void.

Fuck it, I might as well just make them all numbers.

Here's a real contribution: I made a Notepad++ userDefineLang.xml preset for QuakeC syntax highlighting.
http://pastebin.com/G0s8mw92
it also colors quake's required globals (like self etc) and all the builtins. 
Well, That Doesn't Work 
apparently if you set something's targetname to just ftos(some_integer), it somehow changes to other numbers as you move around! 
 
ftos stores the string it creates in a shared spot in memory. if you call ftos multiple times in a frame, all strings you assigned ftos to, even if they were different numbers, will have the number of the last ftos call.
this is true for vtos as well. 
Ftos 
works in fte. :)

but yeah, in most engines, builtins that return temporary strings will overwrite the previously returned one(s), such that the old reference now refers to the new value. which is really useless.
either that or it starts complaining about stale/invalid tempstrings. including when saving games. potentially even with crash-to-console results...
as a general rule, if you have a tempstring, NEVER store it to a field or global (if you have the somewhat common frik_file engine extension, then you can use strzone for these usecases).

findfloat doesn't exist in vanilla qc (and hacking find to find a float is unreliable too, and potentially crashy), but you can use nextent to itterate over all entities manually. obviously its less efficient, but if you're really trying to avoid extensions then you won't have more than 600 ents anyway. 
Ok I'm Going To Bed 
I spawn an entity, set its targetname to self.netname, check it with an eprint, change my name, eprint it again, and the fucking targetname on the entity has changed to my new name.

I don't have a fucking clue in the world what's going on here. 
 
wait, are ALL these string fields referenced rather than copied? 
Styring References 
Lunaran: yes, it's a reference to your name string buffer. Some engines offer extensions like "zone" for allocating new buffers.

Depending on what you need to do with strings, there may be a way to do it building the string character by character at time of use. This is the way that Prydon Gate makes its menus, for example. I wrote some articles on how to organise this so it's not quite as awful as it sounds, starting at https://tomeofpreach.wordpress.com/2013/03/28/text-manipulation-in-quake-i-the-basics/ 
 
I read those. Doesn't work for my needs, unfortunately. Seems any mechanism I use to exploit that buffer trick is going to be foiled by whatever field I try to exploit to capture its result. I don't want to start exploring engine specific code, either.

A giant lookup table it is then. 
Lunaran 
Thx for the xml! 
Lookup Tables 
What you up to Lunaran? Sometimes there are ways to avoid them in QC, as they're never a pleasant task to maintain. 
 
I assumed a giant array of strings each with a unique name? 
Yep 
f.write("\\tswitch(num)\\n\\t{\\n")

for i in xrange(256):
. s = str(i)
. f.write("\\t\\tcase "+s+": return "node"+s+"";\\n")

f.write("\\t}\\n\\treturn string_null;\\n}\\n\\n")
 
 
hm. func is weird with backslashes. 
QC Math To Calc Odd / Even Number 
Has anyone run across or can post some QC that can tell weather or not a number on the positive number line is odd or even? 
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.