FAQ  •  Register  •  Login

Monsters searching player

Moderator: Inside3D Admins

<<

toneddu2000

Posts: 320

Joined: Tue Feb 24, 2009 4:39 pm

Location: Italy

Post Fri Oct 22, 2010 11:07 pm

Monsters searching player

Hi guys. I'm trying to understand if there's a simple way to add in qc a way to make monsters search ALWAYS player (not only when they "see" him). I've look at this tutorial but here explains how to make monsters roaming along the map. I'm searching for something even (I hope) simpler: I'd only like that a fiend, an ogre or a dog could always know where's player and searching him.

Thanks in advance
<<

gnounc

User avatar

Posts: 294

Joined: Mon Apr 06, 2009 6:26 am

Post Sat Oct 23, 2010 3:36 am

I'd have to look, but I think you just change the "wakes up" code in that monsters qc file. Change the circumstances to something more broad and frequent.
<<

frag.machine

User avatar

Posts: 1475

Joined: Sat Nov 25, 2006 1:49 pm

Post Sat Oct 23, 2010 4:41 pm

Open ai.qc and find this:

  Code:
float() FindTarget =
{
    local entity    client;
    local float        r;

// if the first spawnflag bit is set, the monster will only wake up on
// really seeing the player, not another monster getting angry

// spawnflags & 3 is a big hack, because zombie crucified used the first
// spawn flag prior to the ambush flag, and I forgot about it, so the second
// spawn flag works as well
    if (sight_entity_time >= time - 0.1 && !(self.spawnflags & 3) )
    {
        client = sight_entity;
        if (client.enemy == self.enemy)
            return;
    }
    else
    {
        client = checkclient ();
        if (!client)
            return FALSE;    // current check entity isn't in PVS
    }

    if (client == self.enemy)
        return FALSE;

    if (client.flags & FL_NOTARGET)
        return FALSE;
    if (client.items & IT_INVISIBILITY)
        return FALSE;

    r = range (client);
    if (r == RANGE_FAR)
        return FALSE;
       
    if (!visible (client))
        return FALSE;

    if (r == RANGE_NEAR)
    {
        if (client.show_hostile < time && !infront (client))
            return FALSE;
    }
    else if (r == RANGE_MID)
    {
        if ( /* client.show_hostile < time || */ !infront (client))
            return FALSE;
    }
   
//
// got one
//
    self.enemy = client;
    if (self.enemy.classname != "player")
    {
        self.enemy = self.enemy.enemy;
        if (self.enemy.classname != "player")
        {
            self.enemy = world;
            return FALSE;
        }
    }
   
    FoundTarget ();

    return TRUE;
};



Basically, it's a matter of removing the undesired checking steps in the function above (doesn't matter if the monster can see the player or not ? Fine, just skip these steps then). The code is self explanatory enough, I believe you can grasp the idea by yourself. Have fun.
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
<<

Chip

User avatar

Posts: 546

Joined: Wed Jan 21, 2009 9:12 am

Location: Romania

Post Sat Oct 23, 2010 5:54 pm

So you mean if you remove RANGE_, the monsters will virtually see the entire map and know exactly where you are? That's a bit scary! :shock:

This should be the same as changing the RANGE_ values to something really large. Or to add additional checks for dogs (for example), such as change

  Code:
if (r == RANGE_FAR)

to

  Code:
if (r == 90000)


Although I'm pretty sure this holds a key, too:

  Code:
    client = checkclient ();
        if (!client)
            return FALSE;    // current check entity isn't in PVS


Remove this and the PVS check will not be performed. This could be applied to some survival mod, where monsters come pouring in from every direction.
Quake 1 Mods

Fear not the dark, but what the dark hides.
<<

frag.machine

User avatar

Posts: 1475

Joined: Sat Nov 25, 2006 1:49 pm

Post Sat Oct 23, 2010 6:24 pm

Not exactly. Let's read the code, step by step:

  Code:
   
if (sight_entity_time >= time - 0.1 && !(self.spawnflags & 3) )
    {
        client = sight_entity;
        if (client.enemy == self.enemy)
            return;
    }
    else
    {
        client = checkclient ();
        if (!client)
            return FALSE;    // current check entity isn't in PVS
    }


Here, we check if there's a hint by other entity about an enemy. Basically, somebody is pointing, during some time (sight_entity_time) a potential enemy (sight_entity). If that's the case, the monster will accept that, otherwise a call to checkclient() will return a client (IIRC, every call cycles thru all clients, so monsters in coop won't all get mad at the same player). Note that checkclient() already culls out non-visible clients, so if you want to always have a valid target here, you'll need to write your own code to do so. Also, keep in mind that the returned entity in both cases MAY NOT BE A PLAYER, but instead, a monster mad at a player. We'll see this at the end of the function.

  Code:
    if (client == self.enemy)
        return FALSE;

If the returned entity is the current enemy, then there's nothing to do, we can just return and keep chasing/attacking it.
  Code:
    if (client.flags & FL_NOTARGET)
        return FALSE;
    if (client.items & IT_INVISIBILITY)
        return FALSE;


These are the tests for the "notarget" cheat and the Ring of Shadows power-up. You can disable any of this just removing this code.

  Code:
    r = range (client);
    if (r == RANGE_FAR)
        return FALSE;
       
    if (!visible (client))
        return FALSE;

    if (r == RANGE_NEAR)
    {
        if (client.show_hostile < time && !infront (client))
            return FALSE;
    }
    else if (r == RANGE_MID)
    {
        if ( /* client.show_hostile < time || */ !infront (client))
            return FALSE;
    }


Here is the test to check if the monster is too far to notice the player. If the monster must be aware of the player regardless of their positions in the map, remove entirely this.
  Code:
   
//
// got one
//
    self.enemy = client;
    if (self.enemy.classname != "player")
    {
        self.enemy = self.enemy.enemy;
        if (self.enemy.classname != "player")
        {
            self.enemy = world;
            return FALSE;
        }
    }


This code tests if the entity that we are testing is a player or actually a monster. In the later case, we change the reference to the actual player entity.

  Code:
   
    FoundTarget ();

    return TRUE;
};
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
<<

toneddu2000

Posts: 320

Joined: Tue Feb 24, 2009 4:39 pm

Location: Italy

Post Sat Oct 23, 2010 10:20 pm

Thank you guys for all your replies. I tried to remove all lines frag.machine told but, with no luck. Monsters seem stupids, even if I go closer to their noses, they stand still.
Note that checkclient() already culls out non-visible clients, so if you want to always have a valid target here, you'll need to write your own code to do so
That's exactly what I'd like to do! There was anyone who did an experiment like this to use the code? Because I've really no idea how to do it.
Thanks a lot

EDIT: I got worked. I removed some line and edited another one, like this:

  Code:

float() FindTarget =
{
   local entity   client;
   local float      r;

// if the first spawnflag bit is set, the monster will only wake up on
// really seeing the player, not another monster getting angry

// spawnflags & 3 is a big hack, because zombie crucified used the first
// spawn flag prior to the ambush flag, and I forgot about it, so the second
// spawn flag works as well
   if (sight_entity_time >= time - 0.1 && !(self.spawnflags & 3) )
   {
      client = sight_entity;
      if (client.enemy == self.enemy)
         return;
   }
   else
   {
      client = checkclient ();
      if (!client)
         return FALSE;   // current check entity isn't in PVS
   }

   if (client == self.enemy)
      return FALSE;

   if (client.flags & FL_NOTARGET)
      return FALSE;
   if (client.items & IT_INVISIBILITY)
      return FALSE;

   
   
//
// got one
//
   self.enemy = client;
   if (self.enemy.classname == "player")
   
   
   FoundTarget ();

   return TRUE;
};




now monsters seem to be alerted all the time and searching for the player. Thanks frag.machine!
<<

blubswillrule

User avatar

Posts: 68

Joined: Mon Oct 04, 2010 9:08 pm

Location: Lincoln, California

Post Wed Oct 27, 2010 3:07 am

any way to make this work with waypoints? :P
A truly rewarding experience for an AI coder: watching your ai navigate the map... makes all the time invested in the code worth it :)

Return to Artificial Intelligence

Who is online

Users browsing this forum: No registered users and 0 guests

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Icons provided by Aha Soft