Turrets:Part 3


This tutorial deals with improving the target selecting functions of the turret.

It will also deal with the limiting of a turret to firing in a 180 degree hemisphere forwards.


For this we will need a vec3_t.

Go to where you added vec3_t turloc; in g_local.h (game). Add the line below just after it

vec3_t		centerpoint;

That's the variable added. centerpoint will be set when the turret is placed (it will be straight along the horizontal line drawn through the player going forwards).

If you don't wish to add these limitations, just leave out any lines that make a reference to the variablesabove, and the commands to set them. the code does not fully depend on them


There are a few changes to make to existing functions. First off Cmd_SpawnTurret_f. The main change is setting its yaw to the same as the players (thus making it point in the same direction while keeping it level). Just add the line below, just after the line G_SetOrigin(base,ent->r.currentOrigin);

	VectorSet(base->s.apos.trBase,0,ent->s.apos.trBase[1],0);

Simple enough, don't you think?

now to createturretgun. add the following lines again just after G_SetOrigin( turret, ent->r.currentOrigin );

	
	VectorCopy(ent->s.apos.trBase,turret->s.apos.trBase);
	VectorCopy(turret->s.apos.trbase,turret->centerpoint);

Fairly simple, don't you think? All you've done so far is make the turrets spawn pointing in the same direction you were. (and store a variable we'll use later)


I decided while writing this to neaten up the think function, and I managed fairly well. Replace turret_think with the new version below

void turret_think( gentity_t *ent){

ent->nextthink=level.time+10;



if (!checktarget(ent,ent->enemy))
	turret_findenemy(ent);
if(!ent->enemy)
	return;

turret_trackenemy(ent);
if (ent->count<level.time)
	turret_fireonenemy(ent);
}

The neatening is due to all the checks being stuck in a new function. Makes life easier.

There are changes to the targeting function as well. Replace turret_findenemy with the new version below.

void turret_findenemy( gentity_t *ent){
	gentity_t *target;

	target = g_entities;

	for (; target < &g_entities[level.num_entities]; target++)
	{
		if(!checktarget(ent,target))
			continue;
		ent->enemy=target;
		return;
	}

	ent->enemy=NULL;
}

Simpler, isn't it? Now we get down to buisness. Add the code below, above all the other functions you've added.

#define RANGE 500 // change this to give the turrets a bigger range.


qboolean checktarget(gentity_t *firer,gentity_t *target){
vec3_t 		distance,forward;
trace_t         trace;
float		dot;

/*
returns qfalse if the target is not valid. returns qtrue if it is
*/

if (!target) // Do we have a target?
	return qfalse;
if (!target->inuse) // Does the target still exist?
	return qfalse;
if (target==firer) // is the target us?
	return qfalse;
if(!target->client) // is the target a bot or player?
	return qfalse;
if (target==firer->parent) // is the target the person that created the turret?
	return qfalse;
if (OnSameTeam(firer->parent, target)) // is the target one of us?
	return qfalse;

if (target->health<0) // is the target still alive?
	return qfalse;

VectorSubtract(target->r.currentOrigin,firer->r.currentOrigin,distance);
if (VectorLength(distance)>RANGE) // is the target within range?
	return qfalse;

trap_Trace (&trace, firer->s.pos.trBase, NULL, NULL, target->s.pos.trBase, firer->s.number, MASK_SHOT );
if ( trace.contents & CONTENTS_SOLID ) // can we see the target?
	return qfalse;
/*
The last two checks are done last as they require more processing power than the others.
this order is just better from a proccesing load perspective
*/

	AngleVectors (firer->centerpoint, forward, NULL, NULL);
	VectorNormalize (distance);
	dot = DotProduct (distance, forward);
	
	if (!(dot > 0.3))  //is it in front of us?
		return qfalse;

return qtrue;
}


More complex. I'd make the targeting more customizable, but currently my vector maths isn't good enough to work out how to do it. (If you feel like telling me, I'll give credit)

The main differences here are the range being put in as a macro (all references to RANGE will be replaced by 500) the addition of the trace (so it can only fire at targets it can see), and the maths at the bottom (so it can only fire at things in front of it)


Thats it. (If you got the models before this tut went up, I would get the again. i had to rotate the base through 90, as it wasn't right. it makes no real difference, just looks better)


Next part of the tutorial series
Back to the tutorials
Mail me