makingmonsters hunt non-player entities

Discuss programming in the QuakeC language.
Post Reply
hondobondo
Posts: 207
Joined: Tue Sep 26, 2006 2:48 am
Contact:

makingmonsters hunt non-player entities

Post by hondobondo »

say i wanted to make a MOBA type game, where two armies each hunt for the enemies totem or whatever. now they just hunt for the player. the axe of command mod will make enemies hunt for monsters that aren't = owner, but how do i make them hunt for say an entity like a turret or fortress that sits in the middle of the map (or at one end of the map)
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: makingmonsters hunt non-player entities

Post by Spike »

they go for players via the checkclient() builtin, which returns a different player 10 times a second or something stupid like that. you'd need to call some custom qc function that returns your turret or whatever instead.
hondobondo
Posts: 207
Joined: Tue Sep 26, 2006 2:48 am
Contact:

Re: makingmonsters hunt non-player entities

Post by hondobondo »

Spike wrote:they go for players via the checkclient() builtin, which returns a different player 10 times a second or something stupid like that. you'd need to call some custom qc function that returns your turret or whatever instead.
the code i use for dmsp makes them roam around looking for a player. i modified the pet_findtarget from axe of command and replaced id's findtarget to look for this turret object, but all they do is stand still
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: makingmonsters hunt non-player entities

Post by frag.machine »

You need to change FindTarget, make them look for entities with different .team values.
EDIT: spell
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
PrimalLove
Posts: 14
Joined: Sun Oct 19, 2014 2:37 am

Re: makingmonsters hunt non-player entities

Post by PrimalLove »

@hondobondo

It may be helpful if you posted some code for review to see if you made any errors. Also, not sure if you are spawning an entity model or whatever for this totem but for the record, findradius will not return SOLID_NOT solid type entities. You can get around this problem in DP with sv_gameplayfix_blowupfallenzombies cvar. It is a shot in the dark that this is the problem but thought I'd mention it.
hondobondo
Posts: 207
Joined: Tue Sep 26, 2006 2:48 am
Contact:

Re: makingmonsters hunt non-player entities

Post by hondobondo »

PrimalLove wrote:@hondobondo

It may be helpful if you posted some code for review to see if you made any errors. Also, not sure if you are spawning an entity model or whatever for this totem but for the record, findradius will not return SOLID_NOT solid type entities. You can get around this problem in DP with sv_gameplayfix_blowupfallenzombies cvar. It is a shot in the dark that this is the problem but thought I'd mention it.

Code: Select all

float() FindTarget =
{
	local entity	client;
	local float		r;
        local entity head, selected;
	local float dist;



   dist = 10000;
	selected = world;
	head = findradius(self.origin, 10000);
	while(head)
	{
		if( (head.health > 1) && (head != self) && (head != self.owner) && head.owner != self.owner)
		{
			traceline(self.origin,head.origin,TRUE,self);
			if ( (trace_fraction >= 1) && (vlen(head.origin - self.origin) < dist) && (head.owner != self.owner) && head.classname == "monster_fortress")
			{
				//selected = head;
				dist = vlen(head.origin - self.origin);
				self.enemy = head;
				FoundTarget();
				return TRUE;
			}
		}
		head = head.chain;
	}

/*
	if (selected.classname == "monster_fortress")
	{
      self.enemy = selected;
      FoundTarget ();
		return TRUE;
	}
*/

    if (self.goalentity != self.owner)
      {
        self.goalentity = self.owner;
        self.think = self.th_run;
      }
    self.ideal_yaw = vectoyaw(self.owner.origin - self.origin);
    self.nextthink = time+0.1;
    return FALSE;


};
this is the thing i'd like them to attack
from the team fortress turret

Code: Select all

void() start_monster_fortress =
{
  local entity temp;

/*
  if (deathmatch > 0)   // People won't like it in regular DM, right?
    if (self.team == 0 || teamplay == 0)
    {
//dprint("fukk!\n");
      remove(self);
      return;
    }
*/

	self.solid = SOLID_SLIDEBOX;
  self.movetype = MOVETYPE_TOSS;
  self.health = self.max_health;

  setmodel (self, "progs/aagba.mdl");
  setsize (self, '-16 -16 -20', '16 16 16');

  self.th_stand = tur_stand;
  self.th_walk = tur_walk;
  self.th_run = tur_run;
  self.th_die = tur_die;
  self.th_missile = tur_launch;
	self.classname = "monster_fortress";

  setorigin(self, self.oldorigin);
  droptofloor();
	self.takedamage = DAMAGE_AIM;

	self.ideal_yaw = self.angles * '0 1 0';
  self.view_ofs = '0 0 1';
	self.use = monster_use;

	self.flags = self.flags | FL_MONSTER;

  temp = spawn();
  temp.owner = self;
  temp.takedamage = DAMAGE_NO;
  setmodel(temp, "progs/aagtb.mdl");
  self.trigger_field = temp;
  temp.angles = self.angles;
  setorigin(temp, self.origin);
  self.ammo_cells = self.aflag;

  self.th_stand ();
};

/*QUAKED monster_tur (1 0 0) (-16 -16 -20) (16 16 16) Ambush Laser
Shoots people by spikes and lasers. 99% effective leading routine.
Health and ammo_cells can be set in map file, wait == respawn time.
*/
void() monster_fortress =
{
  local vector v1;

  precache_model ("progs/aagba.mdl");
  precache_model ("progs/aagtb.mdl");

	self.bondoflag = TECH;
//  if (!deathmatch)
    //total_monsters = total_monsters + 1;
  self.oldorigin = self.origin;
  if (!self.health)
    self.health = M5HEALTH;
  self.max_health = self.health;
  v1 = self.angles_y * '0 1 0' + '-20 0 0';
  makevectors (v1);
  self.movedir = v_forward;

  if (!self.ammo_cells)
    self.ammo_cells = 5000;
  self.aflag = self.ammo_cells;

  if (!self.wait)
    self.wait = 30;

  self.think = start_monster_fortress;
  self.nextthink = time + 0.1 + random() * 0.3;
};


PrimalLove
Posts: 14
Joined: Sun Oct 19, 2014 2:37 am

Re: makingmonsters hunt non-player entities

Post by PrimalLove »

Here are a couple of suggestions:

1. Place a few bprints in there so you can see where things are getting hung up.
2. How many of these turret monster things are you spawning? If it is like one or two per map I'd suggest not using findradius because the distance you are searching, plus the fact that all the monsters will be running this same routine you might want to consider a different method to alert them to the enemy.
3. Do any of the monsters actually have a self.owner? I ask because I see alot of additional conditions in your while statement that may just not even need to be there. If none of them do you can also get rid of the last self.goalentity stuff at the bottom of the function because its not needed. But if some of them do indeed have a self.owner then I suppose this is fine. I also question the head.owner != self.owner but I am not sure of how the rest of your mod works so I am going to assume this is a condition you need. It may not be best to put it in the first if statement tho.
4. The purpose of your while statement as I see it is to find the closest enemy possible by walking through the list of potential enemies and setting the dist each time to keep track of different locations of enemies as you walk through the list. It appears tho you are not actually using it in this way. Instead restricting it to only the one entity you hope to find? I say this because even if you have multiple turret monsters, it will return after the first one it finds. Making setting the dist afterwards rather pointless. As it is now it will just go after the first turret it finds. I'd suggest setting it to selected as you were previously and not having head.classname in your traceline condition statement. Without a bit more information about how your mod is intended to work I have nothing specifically I can point to that would lead me to think it wouldn't work other than some things I pointed out before that may be causing problems.
5. If the self.owner stuff is not needed and you only plan for them to look for one turret per map you can greatly shorten this routine up and make it much more efficient. Hard to stay for sure without a bit more info.
hondobondo
Posts: 207
Joined: Tue Sep 26, 2006 2:48 am
Contact:

Re: makingmonsters hunt non-player entities

Post by hondobondo »

ok what i wanted to do was spawn monsters that would hunt this single stationary entity and attack it like DOTA/LOL or somesuch, and the player would have to defend it. ideally there would be two entities for two different teams, but one would be fine to start
frag.machine
Posts: 2126
Joined: Sat Nov 25, 2006 1:49 pm

Re: makingmonsters hunt non-player entities

Post by frag.machine »

hondobondo wrote:ok what i wanted to do was spawn monsters that would hunt this single stationary entity and attack it like DOTA/LOL or somesuch, and the player would have to defend it. ideally there would be two entities for two different teams, but one would be fine to start
Open ai.qc, go to FindTarget. First thing you will change: you want non-player enemies, right ? Then rip this off:

Code: Select all

    if (self.enemy.classname != "player")
    {
        self.enemy = self.enemy.enemy;
        if (self.enemy.classname != "player")
        {
            self.enemy = world;
            return FALSE;
        }
    }
Add this to the very begin of this function:

Code: Select all

local entity en;
Also, you want to look for something more than players, so change this part (again in FindTarget), from:

Code: Select all

    if (sight_entity_time >= time - 0.1 && !(self.spawnflags & 3) )
    {
        client = sight_entity;
        if (client.enemy == self.enemy)	{ return FALSE; }
    }
    else
    {
        client = checkclient ();
        if (!client) { return FALSE; }
    }
To:

Code: Select all

        client = checkclient ();
        if (!client) {
           en = findradius (self.origin, 1000); // change this to whatever value you want
           if (!en) { return FALSE; } // Okay, nothing detectable nearby
           while ((en != world) & (client == world))
           {
               // you'll want something more elaborated but this is a good start point
               if ((en.team != self.team) && (en.health > 0)) { client = en; }
               else if ((en.team == self.team) && (en.enemy != world)) { client = en.enemy; }

               en = en.chain;
           }

           if (!client) { return FALSE; }
        }
Of course, for this to work the code expects that all monsters and buildings have the .team attribute correctly set. This code is untested and probably sucks because eventually all the monsters will try to attack one single target each time, so you may want to apply some smart trick at the findradius loop like randomizing enemy picking or checking the potential targets against the monster to see if attacking makes sense (for example, a dog trying to bite a building would look stupid).
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC :) (LordHavoc)
Post Reply