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
 
C++ is fine and gets far more flack than it deserves.

C# is far superior however. FAR superior.

I guess it would help to know what specifically you're trying to code and for what platform. 
 
C++ does get treated unfairly - google Erik Naggum's usenet rants sometime for a hilarious example - but I wouldn't call it "fine".

I don't really want to get into a flamewar over C++'s fucked up design: I'm just going to note that there are plenty of better languages to choose from. 
 
at the same time, i always learnt best by doing. it's more frustrating, but it sticks better.

i've tried reading some lit on c++ but they annoy the hell out of me. i'd rather they just give me the syntax for it and give me a brief overview of how to put it in the code instead of going into all the long winded crap about stuff i never remember anyway.

otoh, the more i look at this code, the more i feel it needs to be rewritten almost from scratch. there are some things in here which i don't like at all.

ie: instead of treating ships and missiles as inheriting from the same class, they are completely different classes, and neither of them can 'see' the other.

ideally, i would have liked to override the basic 'update' function of a base entity class for specific ones (ie: for missiles and ships) and then be able to call it by just iterating down one big list of entities and calling the same function.

instead, i'm trying to hack my way around it by making a static function in a new class so that i can call it from inside one class that normally can't see the other class.

also, for, apparently no reason, missiles aren't instanciated objects, but are regular structs which is also causing other problems.

i'm going back to school next week, so i'll probably ask these questions to my instructors instead and see what they think... 
Heh 
the title for the above post should have read "that may be true, but" 
If This Is Your First C++ Program... 
you should entirely expect to have to throw it away and start again.

(Or your 10th or 100th, to be fair: "build one to throw away" is a long standing slogan of software engineering). 
 
The problem is that hardly anyone ever does that. :) That's where horrible feature bloated abominations are born. 
Unarmed Ogre 
I've been stuggling to make an Ogre variant and I'm having troubles with ai/fight/ogreb.

Basically the fat cunt keeps trying to go to th_missile when he has no grenades (crash). I must be missing something obvious here but I don't know what.

The error returned is on his run sequence (has all his own functions) but if I replace his th_missile linking it to eg.melee then I'm ok, except it takes him ages to close the distance because he's swinging chainsaws about.

NULL function

Basically I don't want him to ever th_missile - but looking over ai and other monsters sheds no light - dogs / knights / fiends all use ai_run without problem.

I'm going in circles, it seems. If anyone can shed any light on this I'd appreciate it. 
C++ For C Programmers 
http://www.4p8.com/eric.brasseur/cppcen.html

I find that documents called "X For C Programmers" tend to hit the spot. This is mainly for necros. 
Ijed 
OgreCheckAttack sets their attack state to AS_MISSILE, which leads to ai_run calling ai_run_missile, which leads to self.th_missile.. which leads to the crash.

You'll need to comment out the monster_ogre/OgreCheckAttack lines in CheckAnyAttack (so they'll use CheckAttack instead) and make sure you don't give them a .th_missile, else CheckAttack will convienently call self.th_missile for you. :) 
An Ogre By Another Name 
Have you tried changing the classname from monster_ogre to, for example, monster_ogre_unarmed? I have a feeling that might make it work.

The reason why is hidden in fight.qc and ai.qc. fight.qc is the place to start, have a look at the two functions CheckAttack and OgreCheckAttack. The former is the generic function for any monster, and it's careful enough to check whether self.th_missile is set or not before deciding to make a missile attack. OgreCheckAttack is more presumptive, it knows that an ogre has a missile attack and so goes straight ahead with setting AS_MISSILE.

This is all quite deceptive, as OgreCheckAttack never explicitly uses th_missile - it just sets AS_MISSILE and lets ai.qc do the th_missile part. ai.qc is also the place to find out how the game chooses between CheckAttack and OgreCheckAttack. The function that decides is called CheckAnyAttack, and as you can see it decides based on the classname. So if you give your melee ogres a different classname then it should use CheckAttack only, which is safe to use without th_missile set.


The downside to this method is that, like with monster_ogre_marksman, your ogres will be able to infight with each other. So you could just make the check in CheckAnyAttack more stringent:

if (self.classname == "monster_ogre" && self.th_missile)
return OgreCheckAttack ();

For neatness of code, this way is probably better, as it means you can have a single spawnfunction for both grenadiers and berserkers. This is good code sharing, as any change you make to an ogre you probably want to make for both of them.

The third solution would be to modify OgreCheckAttack to properly check for th_missile, but I don't think that's the best way to go, it could end up complicated. 
Infighting 
it's pretty easy to get around the infighting problem above when setting up a new classname. you just need to set up 'classes' (a la quoth) and modify the infighting code slightly

here's how i did it..

- add .string class; to the monster ai in defs.qc

- add self.class = "ogre"; to the different ogre classnames

- then in combat.qc under the '//react to damage' part, change this line:
if ( (self.flags & FL_MONSTER) && attacker != world)
to read this:
if ( (self.flags & FL_MONSTER) && (self.class != attacker.class) && attacker != world)

i think that was it. you can use it to group allied monster types or groups, either in the qc or simply by adding 'class' to any other monster entity (say if you had one particular battle where you wanted the monsters to focus on the player only) 
Excellent 
Thanks for all the answers, I should be able to close this issue sometime today.

I wanted to maintain the original ogres so made the new one a different classname - ogreb (berserk) already.

As to infighting, I'm thinking of modifying all Ogres to act the same as grunts. This might sound like a cheap dodge to not have to fix the issue, but I never did see the Ogres as particularly polite, and I'm a fan of chaos.

Thanks again. 
Argh 
Solved!

Turns out I was calling ogrecheckattack for the new ogres inside ai.

You live and learn. 
Monster Won't Get Killed 
While coding for a new Q1 monster I made up a little qc where I placed all args like stand walk run etc.
Having the monster standing in game all looks well, untill I try to kill the moster.
Having two monsters in game there's always one that don't die.(?!)

I hear the kill sound but the monster just goes on turning into stone to my bullits.
I have the regular death subroutine.

http://members.home.nl/gimli/Imp.qc 
 
lol...

if (random() < 0.5)
imp_die1 ();


these lines mean if random() (random number between 0 and 1) is smaller than 0.5, then it will play the animation sequence.

so half the time it will play the animation and half the time it won't. 
Well 
cll me a fool, but what should I number 0.5? 
Right 
if(me a fool)half the time < I ain't).

thanks for pointing me out. 
Impulse Command Queuing. 
impulse command queuing.

is that handled by the engine?

in ImpulseCommands there's the if statement:
if (self.attack_finished > time)
{
self.impulse = 0;
return;
}


which seems to me to mean "if attack_finished is still ticking down, do not accept ANY impulses (set to 0) and then break out of the function altogether.

yet, when you attack with say the rocket launcher and then press 8, the impulse 8 command seems to get queued up and is executed after attack_finished is done.
is there something going on behind the scenes here? i'm actually trying to stop the queuing from happening, but can't really see even where it's happening. 
Hmm 
I don't see that line in the version posted at
http://www.inside3d.com/browse.php?show=weapons.qc
I'd probably say the place to look is in W_WeaponFrame, where any call to ImpulseCommands is skipped if self.attack_finished > time. If you really wanted to block impulses, then putting self.impulse = 0 just before that return should do the trick. 
Hm... 
that's really odd. that means the if check in ImpulseCommands is completely redundant. it will never get to that point because an identical if check is done prior to even getting in that function. o.0 
Random Coding Oddities In Quake? 
Surely not!! 
Yeah, But 
Yeah, but that if() check isn't actually in the standard quake source code for ImpulseCommands, I don't know where you got it from : -p 
Fire And Switch? 
If you want to stop the queueing, then putting that the return in the if() in W_WeaponFrame would do it. If however, you want some impulses to always happen, then you need to put a separate check in, to happen before that check.

Of course, an even more intricate fix (which goes in the other direction from where you want to go) is to track what the impulses would make the weapon change to if you were not firing (setting .weapon appropriately, so the hud light shows what you will use next), and then switch to it when the player has stopped firing. Of course, there is another issue again, in that I don't think you can switch away while firing a nailgun, because the way they fire is handled differently is handled to other weapons. 
I Sorted It Out 
i just moved the self.impulse = 0 to the end of W_WeaponFrame and removed the if check with the return. i have no idea where the if check in ImpulseCommands came from but i took it out as well and it works fine after re-arranging the way firing and impulsecommands was handled. 
And I Forgot To Mention A Couple Of Things 
You should probably use else if in ImpusleCommands(), so that it can go faster, May not make that much difference these days, but it's probably a good idea to anyway.

Even more of a timesaver, though, is skipping all of the impulse checks completely if self.impulse is 0. I don't actually know when impulse gets truncated to the lower 8 bits, but I think it's before the QC sees it (and possibly it only gets sent over the network as a byte), so you don't have to check for it being anything else that resolves to 0. 
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.