View previous topic :: View next topic |
Author |
Message |
ajay

Joined: 29 Oct 2004 Posts: 295 Location: Swindon, UK
|
Posted: Fri Jul 22, 2005 7:46 pm Post subject: monsters fighting each other |
|
|
Oh boy this is irritating me, and i've hung off posting about it for ages; mostly 'cos I really thought I knew enough by now to work it out for myself.
I want 2 types of monsters fight each other on sight - like they would on seeing the player. I can get an individual monster (e.g. one of a type) but groups of two types just don't work.
It's the kind of thing I would have guessed had a relative simple solution; but it doesn't appear to. I've tinkered (and I'm missing out what i've tried, cos firstly, I'm slightly embaressed byt what I've gone through,a nd secondly, there's too many to list!) all over ai.qc and even fight.qc, but to no avail.
I would really appreciated some nudging in the right direction, it's kind of crucial to my mod.
cheers
ajay _________________ my site |
|
Back to top |
|
 |
Sajt
Joined: 16 Oct 2004 Posts: 1026
|
Posted: Fri Jul 22, 2005 9:13 pm Post subject: |
|
|
I haven't really ever looked at the Quake AI code to much extent, but I think the function you're looking for is FindTarget. Be warned however that monsters sighting monsters will be slower than monsters sighting players, because vs players they can use a fast PVS solution, but the Quake builtins don't have a function to check for anything other than clients by PVS. Therefore you must use find() or findradius() (the sighting players code used checkclient()).
checkclient will return a client in the current PVS of 'self'. If there is more than one client in the PVS, it will cycle through them each time it is called, or each frame, or every 0.1 seconds or something (not sure), so every time you call checkclient() you will get the next player in the PVS.
Instead of that you will probably have to do something such as
ent = findradius (self, 1024);
while (ent != world)
{
if ((ent.flags & FL_MONSTER || ent.classname == "player") && ent.classname != self.classname)
{
// traceline for line of sight, check dot-product for FOV/facing, whatever else you want to do
// if true, set the target or whatever the ai does
}
ent = ent.chain;
}
You can change the 1024 to a higher number for a longer-range vision, but it may be slower. The MAIN thing to remember when using findradius like this is to call it as sparsely as possible, and try not to have 10 guys calling it at once. Perhaps make them check for opponents every 0.2 - 0.5 seconds or so. And try to spread out think times by setting the initial thinktime with an additional random factor. This may take some modifications to the AI code though, because I think currently AI is tied to animation (i.e. animation calls ai_stand() which calls FindTarget if there is no enemy). Perhaps you could make only every other stand frame, and every other walk frame, etc, call ai_stand/ai_walk.
Not sure if that helped at all... _________________ F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe.
Last edited by Sajt on Sat Jul 23, 2005 7:07 am; edited 1 time in total |
|
Back to top |
|
 |
Spike
Joined: 05 Nov 2004 Posts: 944 Location: UK
|
Posted: Fri Jul 22, 2005 9:15 pm Post subject: |
|
|
Monsters 'look' for enemies via the checkclient builtin. They only check it once, and it cycles through one, one client per frame.
Which means that coop gives slightly slower monsters.
That means you can't just test to see if it's a monster that you've got, because it'll only check client slots.
you'll have to use a findradius instead. Don't use classnames to identify things and it should run fast enough, but you might have to make them even slower at noticing, to help the cpu a bit. Seeing other monsters isn't as important as seeing the player.
It's somewhere in ai.qc, look for the checkclient. Enjoy. |
|
Back to top |
|
 |
Urre

Joined: 05 Nov 2004 Posts: 1073 Location: Sweden
|
Posted: Fri Jul 22, 2005 9:53 pm Post subject: |
|
|
I'm going to attempt getting grunts to attack enforcers, and enforcers to attack grunts, on sight, based on regular progs106.
First, in ai.qc, just above the FindTarget function, ctrl+v this little bit of code:
Code: | .entity last_check;
entity(string match) checktarget =
{
self.last_check = find(self.last_check, classname, match);
if (self.last_check)
traceline(self.origin, self.last_check.origin, TRUE, self);
if (trace_fraction == 1)
return self.last_check;
}; |
Then go to line 371, which is inside the FindTarget function, a line which says:
Code: | client = checkclient (); |
Now, remove that line, and type this in, letter by letter (HAH!):
Code: | if (self.classname == "monster_army")
client = checktarget ("monster_enforcer");
else if (self.classname == "monster_enforcer")
client = checktarget ("monster_army");
if (!client)
client = checkclient (); |
I should note that this will make them look for eachother as effectively as they look for multiple players in coop (slow), and it can get especially slow (performance-wise) if there are a lot of these specific monsters. If it gets too slow, you might want to add a findradius check of 1000 units (that's as far as they can see according to the range check code a bit further down in the FindTarget function) before the traceline in the checktarget function I told you to add. They will with this code also prefer their "hate" target before the player. If you want to change that, add the checkclient part above the monster checks.
I should also note that I just made this up, completely untested (haven't even tried compiling), and might include spelling errors and/or faulty use of builtins, but I hope you can figure those parts out. _________________ Look out for Twigboy |
|
Back to top |
|
 |
Urre

Joined: 05 Nov 2004 Posts: 1073 Location: Sweden
|
Posted: Fri Jul 22, 2005 9:55 pm Post subject: |
|
|
Haha, just noticed people posted while I was away typing...
/me reads other people's posts now _________________ Look out for Twigboy |
|
Back to top |
|
 |
Urre

Joined: 05 Nov 2004 Posts: 1073 Location: Sweden
|
Posted: Fri Jul 22, 2005 10:00 pm Post subject: |
|
|
Both Sajt and Spike have very valid points, the stuff I did was really just a quick hack, it's probably way too slow to actually use, but like I said, haven't tried it, so I don't really know. _________________ Look out for Twigboy |
|
Back to top |
|
 |
ajay

Joined: 29 Oct 2004 Posts: 295 Location: Swindon, UK
|
Posted: Sat Jul 23, 2005 7:35 pm Post subject: |
|
|
Thanks for all your replies. I'm still struggling a little. I've tried your suggestion Urre, but it didn't work, they stood looking blankly at each other
I'm struggling a little with your suggestion Sajt, it makes sense and apears similar to the find_monster stuff at AI-cafe. Incidently I tried that and it works fine for just one protagonist, but as soon as you put mroe than one in, it just stops. (which is strange, because when I was playing with Raptors2, I can remember getting multiple raptors of one type to go hunting others... mmm, by using the Ai-cafe stuff - see at bottom)
I'm a little stuck Sajt by knowing also how to randomise the looking so that they're not all looking at once - yes I know, it's a wonder I get anything coded at all
Thanks anyway everyone for your help.
ai-cafe code:
Quote: |
local entity beast;
if (self.classname == "monster_whatever")
{
if (self.enemy)
return FALSE;
beast = findradius(self.origin, 2000);
while(beast)
{
if ( (beast.flags & FL_MONSTER) && visible(beast) && beast != self && beast.health > 0)
self.enemy = beast;
beast = beast.chain;
}
if (!self.enemy)
return FALSE;
FoundTarget();
return TRUE;
} |
_________________ my site |
|
Back to top |
|
 |
Urre

Joined: 05 Nov 2004 Posts: 1073 Location: Sweden
|
Posted: Sun Jul 24, 2005 12:50 am Post subject: |
|
|
I got curious as to why it didn't work, so I went and coded it, and noticed I had forgot to check further down in FindTarget, so here's the solution (yes, it works with this, I tried):
Inside FindTarget, scroll down to the comment that says:
Just below that, add this:
Code: | if (self.classname == "monster_army")
if (self.enemy.classname == "monster_enforcer")
{
FoundTarget ();
return TRUE;
}
if (self.classname == "monster_enforcer")
if (self.enemy.classname == "monster_army")
{
FoundTarget ();
return TRUE;
} |
Enjoy!
EDIT: I should note that this is a continuation of the code I posted previously, this alone won't work, you need to smack 'em both in. _________________ Look out for Twigboy |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2004 phpBB Group
|