Target Leading

 

      Lets be honest now. The tutor bot can't hit moving targets. This is simply a fact. I want it to be an opinion.
      Think of it this way. You have a bot shooting straight at you, but if you strafe out of the way, he will simply miss. If you simply strafe constantly in one direction, he will NEVER hit you. This has to change.
      If you did this in a 'real' deathmatch, your opponent would counter this by shooting a little in front of you (lead you), so that by the time the shot reached you, you would be where the shot was directed. This bot doesn't do this. I'm going to make it do it.
      This tutorial is pretty short, so let's begin. Open up tutor.qc and scroll down to bot_aim_at_enemy(). It should look a little like this:


// -------------------------------------
vector() bot_aim_at_enemy =
// -------------------------------------
{
	return normalize(self.enemy.origin - self.origin);
};

        Now replace that WHOLE thing with this:

// -------------------------------------
vector() bot_aim_at_enemy =
// -------------------------------------
{
	if (self.weapon == IT_SHOTGUN || self.weapon == IT_SUPER_SHOTGUN || self.weapon == IT_LIGHTNING)
		return normalize((self.enemy.origin - self.enemy.velocity * 0.15) - self.origin);
		else return bot_lead();
};

      Now there is a bit to understand in there. The routine decides whether the bot is firing a shotgun/lightning gun or a projectile weapon. If the bot has fired a shotgun/thunderbolt, it runs the next line. Simple, eh?
      The second line is a bit complex, so I'll explain it in english. 'If the bot has just fired either shotgun or a lightning gun, then aim directly at the opponent but be a little innacurate. The faster the opponent is moving, the more innacurate it should be.'
      I stuck that bit in because I was annoyed at the way the bots always hit you with a shotgun, no matter how fast you moved.
      If the bot has fired a projectile weapon, then it calls bot_lead, and returns that position instead.
      The vector bot_lead() doesn't exist yet. Lets put it in now. Just above that routine, paste this one:

// -------------------------------------
vector () bot_lead =
// -------------------------------------
{
local vector targ_loc, dir;
local float move_fract, speedy;
local entity targ;

	targ = self.enemy;
	speedy = 1000;
	if (self.weapon == IT_GRENADE_LAUNCHER) speedy = 500;
	move_fract = vlen(targ.origin - self.origin)*1.000 / (speedy - vlen(targ.velocity)*1.000);
	targ_loc = targ.origin + targ.velocity * move_fract;
	traceline (self.origin, targ_loc, TRUE, self);

	if (trace_fraction == 1)
	{
		dir = targ_loc - self.origin;
		dir = normalize(dir);
		return dir;
	}
	else return targ.origin;
};


      Don't even attempt to understand this code. I don't understand all of it, and I wrote the thing! It's just maths which tells the bot to aim a certain amount in front of the target. The amount is worked out based on the target's velocity, the distance between the bot and the target and the velocity of the projectile. But you don't need to know any of that.
      That's it. Target leading is as simple as that to add. Now just compile, run and be shot.
      For a more complicated example of target leading, check out my ELFBOts in the STORM Quake Mod, which lead perfectly with weapons firing at many different velocities.

 


What We Learned

1. Sometimes, you just have to do maths to get good AI
2. You don't need to understand some code, just know how to use it
3. Target leading is the ultimate way of improving a bot's combat AI
4. Deathmatches are better if the bot is inaccurate with the shotguns


Author: SkinSki
Questions: skinski@storm-1.freeserve.co.uk
AI chat on ICQ: 30578982