Ejemplo n.º 1
0
void AI_SetGoal( edict_t *self, int goal_node )
{
	int node;

	self->ai->goal_node = goal_node;
	node = AI_FindClosestReachableNode( self->s.origin, self, NODE_DENSITY * 3, NODE_ALL );

	if( node == NODE_INVALID )
	{
		AI_ClearGoal( self );
		return;
	}

	// ASTAR 
	if( !AStar_GetPath( node, goal_node, self->ai->status.moveTypesMask, &self->ai->path ) )
	{
		AI_ClearGoal( self );
		return;
	}

	self->ai->current_node = self->ai->path.nodes[self->ai->path.numNodes];

	if( nav.debugMode && bot_showlrgoal->integer > 1 )
		G_PrintChasersf( self, "%s: GOAL: new START NODE selected %d goal %d\n", self->ai->pers.netname, node, self->ai->goal_node );

	self->ai->next_node = self->ai->current_node; // make sure we get to the nearest node first
	self->ai->node_timeout = 0;
	self->ai->longRangeGoalTimeout = 0;
	self->ai->tries = 0; // Reset the count of how many times we tried this goal
}
Ejemplo n.º 2
0
void AI_NodeReached( edict_t *self )
{
	if( !AI_NewNextNode( self ) )
	{
		AI_ClearGoal( self );
	}
}
Ejemplo n.º 3
0
/*
* AI_TouchedEntity
* Some AI has touched some entity. Some entities are declared to never be reached until touched.
* See if it's one of them and declare it reached
*/
void AI_TouchedEntity( edict_t *self, edict_t *ent )
{
	int i;
	nav_ents_t *goalEnt;

	// right now we only support this on a few trigger entities (jumpads, teleporters)
	if( ent->r.solid != SOLID_TRIGGER && ent->item == NULL )
		return;

	// clear short range goal, pick a new goal ASAP
	if( ent == self->movetarget )
	{
		self->movetarget = NULL;
		self->ai->shortRangeGoalTimeout = level.time;
	}

	if( self->ai->goalEnt && ent == self->ai->goalEnt->ent )
	{
		if( nav.debugMode && bot_showlrgoal->integer > 1 )
			G_PrintChasersf( self, "REACHED entity %s\n", ent->classname ? ent->classname : "no classname" );
		AI_ClearGoal( self );
		return;
	}

	if( self->ai->next_node != NODE_INVALID &&
		( nodes[self->ai->next_node].flags & (NODEFLAGS_REACHATTOUCH|NODEFLAGS_ENTITYREACH) ) )
	{
		for( i = 0; i < nav.num_navigableEnts; i++ )
		{
			if( nav.navigableEnts[i].node == self->ai->next_node && nav.navigableEnts[i].ent == ent )
			{
				if( nav.debugMode && bot_showlrgoal->integer > 1 )
					G_PrintChasersf( self, "REACHED touch node %i with entity %s\n", self->ai->next_node, ent->classname ? ent->classname : "no classname" );

				AI_NodeReached( self );
				return;
			}
		}

		FOREACH_GOALENT( goalEnt )
		{
			i = goalEnt->id;
			if( goalEnt->node == self->ai->next_node && goalEnt->ent == ent )
			{
				if( nav.debugMode && bot_showlrgoal->integer > 1 )
					G_PrintChasersf( self, "REACHED touch node %i with entity %s\n", self->ai->next_node, ent->classname ? ent->classname : "no classname" );

				AI_NodeReached( self );
				return;
			}
		}
	}
}
Ejemplo n.º 4
0
//==========================================
// AI_ResetNavigation
// Init bot navigation. Called at first spawn & each respawn
//==========================================
void AI_ResetNavigation( edict_t *self )
{
	self->enemy = self->ai->latched_enemy = NULL;
	self->ai->state_combat_timeout = 0;

	self->ai->is_bunnyhop = false;

	self->ai->nearest_node_tries = 0;
	self->ai->longRangeGoalTimeout = 0;

	self->ai->blocked_timeout = level.time + 15000;

	self->ai->shortRangeGoalTimeout = level.time + AI_SHORT_RANGE_GOAL_DELAY;
	self->movetarget = NULL;

	AI_ClearGoal( self );
}
Ejemplo n.º 5
0
/*
* AI_ReachedEntity
* Some nodes are declared so they are never reached until the entity says so.
* This is a entity saying so.
*/
void AI_ReachedEntity( edict_t *self )
{
	nav_ents_t *goalEnt;
	edict_t *ent;

	if( ( goalEnt = AI_GetGoalentForEnt( self ) ) == NULL )
		return;

	// find all bots which have this node as goal and tell them their goal is reached
	for( ent = game.edicts + 1; PLAYERNUM( ent ) < gs.maxclients; ent++ )
	{
		if( !ent->ai || ent->ai->type == AI_INACTIVE )
			continue;

		if( ent->ai->goal_node == goalEnt->node )
			AI_ClearGoal( ent );
	}
}
Ejemplo n.º 6
0
bool AI_NewNextNode( edict_t *self ) 
{
	// reset timeout
	self->ai->node_timeout = 0;

	if( self->ai->next_node == self->ai->goal_node )
	{
		if( nav.debugMode && bot_showlrgoal->integer > 1 )
			G_PrintChasersf( self, "%s: GOAL REACHED!\n", self->ai->pers.netname );

		//if botroam, setup a timeout for it
		/*
		if( nodes[self->ai->goal_node].flags & NODEFLAGS_BOTROAM )
		{
		int i;
		for( i = 0; i < nav.num_broams; i++ ) //find the broam
		{
		if( nav.broams[i].node != self->ai->goal_node )
		continue;

		//if(AIDevel.debugChased && bot_showlrgoal->integer)
		//	G_PrintMsg (AIDevel.chaseguy, "%s: BotRoam Time Out set up for node %i\n", self->ai->pers.netname, nav.broams[i].node);
		//Com_Printf( "%s: BotRoam Time Out set up for node %i\n", self->ai->pers.netname, nav.broams[i].node);
		self->ai->status.broam_timeouts[i] = level.time + 15000;
		break;
		}
		}
		*/

		// don't let it wait too long to weight the inventory again
		AI_ClearGoal( self );

		return false; // force checking for a new long range goal
	}

	// we did not reach our goal yet. just setup next node...
	self->ai->current_node = self->ai->next_node;
	if( self->ai->path.numNodes )
		self->ai->path.numNodes--;
	self->ai->next_node = self->ai->path.nodes[self->ai->path.numNodes];

	return true;
}
Ejemplo n.º 7
0
//==========================================
// BOT_DMclass_DeadFrame
// ent is dead = run this think func
//==========================================
static void BOT_DMclass_GhostingFrame( edict_t *self )
{
	usercmd_t ucmd;

	AI_ClearGoal( self );

	self->ai->blocked_timeout = level.time + 15000;
	self->nextThink = level.time + 100;

	// wait 4 seconds after entering the level
	if( self->r.client->level.timeStamp + 4000 > level.time || !level.canSpawnEntities )
		return;

	if( self->r.client->team == TEAM_SPECTATOR )
	{
		// try to join a team
		// note that G_Teams_JoinAnyTeam is quite slow so only call it per frame
		if( !self->r.client->queueTimeStamp && self == level.think_client_entity )
			G_Teams_JoinAnyTeam( self, false );

		if( self->r.client->team == TEAM_SPECTATOR ) // couldn't join, delay the next think
			self->nextThink = level.time + 2000 + (int)( 4000 * random() );
		else
			self->nextThink = level.time + 1;
		return;
	}

	memset( &ucmd, 0, sizeof( ucmd ) );

	// set approximate ping and show values
	ucmd.serverTimeStamp = game.serverTime;
	ucmd.msec = game.frametime;
	self->r.client->r.ping = 0;

	// ask for respawn if the minimum bot respawning time passed
	if( level.time > self->deathTimeStamp + 3000 )
		ucmd.buttons = BUTTON_ATTACK;

	ClientThink( self, &ucmd, 0 );
}
Ejemplo n.º 8
0
//==========================================
// AI_Think
// think funtion for AIs
//==========================================
void AI_Think( edict_t *self )
{
	if( !self->ai || self->ai->type == AI_INACTIVE )
		return;

	if( level.spawnedTimeStamp + 5000 > game.realtime || !level.canSpawnEntities )
	{
		self->nextThink = level.time + game.snapFrameTime;
		return;
	}

	// check for being blocked
	if( !G_ISGHOSTING( self ) )
	{
		AI_CategorizePosition( self );

		if( VectorLengthFast( self->velocity ) > 37 )
			self->ai->blocked_timeout = level.time + 10000;

		// if completely stuck somewhere
		if( self->ai->blocked_timeout < level.time )
		{
			self->ai->pers.blockedTimeout( self );
			return;
		}
	}

	//update status information to feed up ai
	if( self->ai->statusUpdateTimeout <= level.time )
		AI_UpdateStatus( self );

	if( AI_NodeHasTimedOut( self ) )
		AI_ClearGoal( self );

	if( self->ai->goal_node == NODE_INVALID )
		AI_PickLongRangeGoal( self );

	//if( self == level.think_client_entity )
	AI_PickShortRangeGoal( self );

	self->ai->pers.RunFrame( self );

	// Show the path
	if( nav.debugMode && bot_showpath->integer && self->ai->goal_node != NODE_INVALID )
	{
		// only draw the path of those bots which are being chased
		edict_t *chaser;
		bool chaserFound = false;

		for( chaser = game.edicts + 1; ENTNUM( chaser ) < gs.maxclients; chaser++ )
		{
			if( chaser->r.client->resp.chase.active && chaser->r.client->resp.chase.target == ENTNUM( self ) )
			{
				AITools_DrawPath( self, self->ai->goal_node );
				chaserFound = true;
			}
		}

		if( !chaserFound && game.numBots == 1 )
			AITools_DrawPath( self, self->ai->goal_node );
	}
}
Ejemplo n.º 9
0
//==========================================
// AI_PickLongRangeGoal
//
// Evaluate the best long range goal and send the bot on
// its way. This is a good time waster, so use it sparingly.
// Do not call it for every think cycle.
//
// jal: I don't think there is any problem by calling it,
// now that we have stored the costs at the nav.costs table (I don't do it anyway)
//==========================================
void AI_PickLongRangeGoal( edict_t *self )
{
#define WEIGHT_MAXDISTANCE_FACTOR 20000.0f
#define COST_INFLUENCE	0.5f
	int i;
	float weight, bestWeight = 0.0;
	int current_node;
	float cost;
	float dist;
	nav_ents_t *goalEnt, *bestGoalEnt = NULL;

	AI_ClearGoal( self );

	if( G_ISGHOSTING( self ) )
		return;

	if( self->ai->longRangeGoalTimeout > level.time )
		return;

	if( !self->r.client->ps.pmove.stats[PM_STAT_MAXSPEED] ) {
		return;
	}

	self->ai->longRangeGoalTimeout = level.time + AI_LONG_RANGE_GOAL_DELAY + brandom( 0, 1000 );

	// look for a target
	current_node = AI_FindClosestReachableNode( self->s.origin, self, ( ( 1 + self->ai->nearest_node_tries ) * NODE_DENSITY ), NODE_ALL );
	self->ai->current_node = current_node;

	if( current_node == NODE_INVALID )
	{
		if( nav.debugMode && bot_showlrgoal->integer )
			G_PrintChasersf( self, "%s: LRGOAL: Closest node not found. Tries:%i\n", self->ai->pers.netname, self->ai->nearest_node_tries );

		self->ai->nearest_node_tries++; // extend search radius with each try
		return;
	}

	self->ai->nearest_node_tries = 0;

	// Run the list of potential goal entities
	FOREACH_GOALENT( goalEnt )
	{
		i = goalEnt->id;
		if( !goalEnt->ent )
			continue;

		if( !goalEnt->ent->r.inuse )
		{
			goalEnt->node = NODE_INVALID;
			continue;
		}

		if( goalEnt->ent->r.client )
		{
			if( G_ISGHOSTING( goalEnt->ent ) || goalEnt->ent->flags & (FL_NOTARGET|FL_BUSY) )
				goalEnt->node = NODE_INVALID;
			else
				goalEnt->node = AI_FindClosestReachableNode( goalEnt->ent->s.origin, goalEnt->ent, NODE_DENSITY, NODE_ALL );
		}

		if( goalEnt->ent->item )
		{
			if( !G_Gametype_CanPickUpItem( goalEnt->ent->item ) )
				continue;
		}

		if( goalEnt->node == NODE_INVALID )
			continue;

		weight = self->ai->status.entityWeights[i];

		if( weight <= 0.0f )
			continue;

		// don't try to find cost for too far away objects
		dist = DistanceFast( self->s.origin, goalEnt->ent->s.origin );
		if( dist > WEIGHT_MAXDISTANCE_FACTOR * weight/* || dist < AI_GOAL_SR_RADIUS*/ )
			continue;

		cost = AI_FindCost( current_node, goalEnt->node, self->ai->status.moveTypesMask );
		if( cost == NODE_INVALID )
			continue;

		cost -= brandom( 0, 2000 ); // allow random variations
		clamp_low( cost, 1 );
		weight = ( 1000 * weight ) / ( cost * COST_INFLUENCE ); // Check against cost of getting there

		if( weight > bestWeight )
		{
			bestWeight = weight;
			bestGoalEnt = goalEnt;
		}
	}

	if( bestGoalEnt )
	{
		self->ai->goalEnt = bestGoalEnt;
		AI_SetGoal( self, bestGoalEnt->node );

		if( self->ai->goalEnt != NULL && nav.debugMode && bot_showlrgoal->integer )
			G_PrintChasersf( self, "%s: selected a %s at node %d for LR goal. (weight %f)\n", self->ai->pers.netname, self->ai->goalEnt->ent->classname, self->ai->goalEnt->node, bestWeight );

		return;
	}

	if( nav.debugMode && bot_showlrgoal->integer )
		G_PrintChasersf( self, "%s: did not find a LR goal.\n", self->ai->pers.netname );

#undef WEIGHT_MAXDISTANCE_FACTOR
#undef COST_INFLUENCE
}