Exemple #1
0
//==========================================
// AI_SetGoal
// set the goal //jabot092
//==========================================
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 == -1) {
		AI_SetUpMoveWander(self);
		return;
	}

	//------- ASTAR -----------
	//do this twice, 1 time randomly dropping some nodes out so bots take alternate routes.  Second time, normal.
	dropnodes = true;
	if( !AStar_GetPath( node, goal_node, self->ai->pers.moveTypesMask, &self->ai->path ) )
	{	
		dropnodes = false;
		if( !AStar_GetPath( node, goal_node, self->ai->pers.moveTypesMask, &self->ai->path ) )
		{
			AI_SetUpMoveWander(self);
			return;
		}
	}
	dropnodes = false;
	self->ai->current_node = self->ai->path.nodes[self->ai->path.numNodes];
	//-------------------------

//	if(AIDevel.debugChased && bot_showlrgoal->value)
//		G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: GOAL: new START NODE selected %d\n", self->ai->pers.netname, node);

	self->ai->next_node = self->ai->current_node; // make sure we get to the nearest node first
	self->ai->node_timeout = 0;
}
Exemple #2
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
}
Exemple #3
0
//==========================================
// AITools_ShowPlinks
// Draws lines from the current node to it's plinks nodes
//==========================================
static void AITools_ShowPlinks( edict_t *target )
{
	static unsigned int debugdrawplinks_timeout;
	int current_node;
	int plink_node;
	int i;
	nav_ents_t *goalEnt;

	if( !target || !target->r.client || !target->r.client->level.showPLinks )
		return;

	//do it
	current_node = AI_FindClosestReachableNode( target->s.origin, target, NODE_DENSITY * 3, NODE_ALL );

	// draw the axis where the node is
	if( nodes[current_node].flags & NODEFLAGS_SERVERLINK )
		AITools_DrawAxis( nodes[current_node].origin, COLOR_RGBA( 255, 25, 25, 255 ) );
	else
		AITools_DrawAxis( nodes[current_node].origin, COLOR_RGBA( 210, 250, 250, 255 ) );

	//don't draw the links every frame (flood)
	if( level.time < debugdrawplinks_timeout )
		return;
	debugdrawplinks_timeout = level.time + 4 * game.snapFrameTime;

	if( nav.editmode || !nav.loaded )
		return;

	FOREACH_GOALENT( goalEnt )
	{
		i = goalEnt->id;
		if( goalEnt->node == current_node )
		{
			if( !goalEnt->ent->classname )
				G_CenterPrintMsg( target, "no classname" );
			else
				G_CenterPrintMsg( target, "%s", goalEnt->ent->classname );
			break;
		}
	}

	// no links to draw
	if( !pLinks[current_node].numLinks )
		return;

	for( i = 0; i < pLinks[current_node].numLinks; i++ )
	{
		plink_node = pLinks[current_node].nodes[i];
		if( pLinks[current_node].moveType[i] == LINK_ROCKETJUMP )
			AITools_DrawColorLine( nodes[current_node].origin,
			nodes[plink_node].origin, COLOR_RGBA( 0xff, 0x00, 0x00, 0x80 ), 0 );
		else if( pLinks[current_node].moveType[i] == LINK_JUMP )
			AITools_DrawColorLine( nodes[current_node].origin,
			nodes[plink_node].origin, COLOR_RGBA( 0x00, 0x00, 0xff, 0x80 ), 0 );
		else
			AITools_DrawColorLine( nodes[current_node].origin,
			nodes[plink_node].origin, COLOR_RGBA( 0x00, 0xff, 0x00, 0x80 ), 0 );
	}
}
Exemple #4
0
void Cmd_deleteClosestNode_f( edict_t *ent )
{
	int node;

	if( ent && nav.num_nodes > 0 )
	{
		node = AI_FindClosestReachableNode( ent->s.origin, ent, NODE_DENSITY*3, NODE_ALL );
		AI_DeleteNode( node );
	}
}
Exemple #5
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
}
Exemple #6
0
//==========================================
// AI_CreateNodesForEntities
//
// Entities aren't saved into nodes files anymore.
// They generate and link it's nodes at map load.
//==========================================
void AI_CreateNodesForEntities ( void )
{
	edict_t *ent;
	int		node;

	nav.num_ents = 0;
	memset( nav.ents, 0, sizeof(nav_ents_t) * MAX_EDICTS );

	// Add special entities
//	for( ent = game.edicts; ent < &game.edicts[game.numentities]; ent++ )
	for( ent = g_edicts; ent < &g_edicts[game.maxentities]; ent++ )
	{
		if( !ent->classname )		
			continue;

		// platforms
		if( !strcmp( ent->classname,"func_plat" ) )
		{
			AI_AddNode_Platform( ent );
		}
		// teleporters
		else if( !strcmp( ent->classname,"trigger_teleport" ) )
		{
			AI_AddNode_Teleporter( ent );
		}
		// jump pads
		else if( !strcmp( ent->classname,"trigger_push" ) )
		{
			AI_AddNode_JumpPad( ent );
		}
		// doors
		else if( !strcmp( ent->classname,"func_door" ) )
		{
			AI_AddNode_Door( ent );
		}
	}

	// bot roams
	nav.num_broams = 0;
	memset( nav.broams, 0, sizeof(nav_broam_t) * MAX_BOT_ROAMS );

	//visit world nodes first, and put in list what we find in there
	for( node=0; node < nav.num_nodes; node++ )
	{
		if( nodes[node].flags & NODEFLAGS_BOTROAM && nav.num_broams < MAX_BOT_ROAMS)
		{
			nav.broams[nav.num_broams].node = node;
			nav.broams[nav.num_broams].weight = 0.3;
			nav.num_broams++;
		}
	}

	//now add bot roams from entities
//	for(ent = game.edicts; ent < &game.edicts[game.numentities]; ent++)
	for( ent = g_edicts; ent < &g_edicts[game.maxentities]; ent++ )
	{
		if( !ent->classname )		
			continue;

		if( !strcmp( ent->classname,"item_botroam" ) )
		{
			//if we have a available node close enough to the item, use it instead of dropping a new node
			node = AI_FindClosestReachableNode( ent->s.origin, NULL, 48, NODE_ALL );
			if( node != -1 &&
				!(nodes[node].flags & NODEFLAGS_SERVERLINK) &&
				!(nodes[node].flags & NODEFLAGS_LADDER) )
			{
				float heightdiff = 0;
				heightdiff = ent->s.origin[2] - nodes[node].origin[2];
				if( heightdiff < 0 ) heightdiff = -heightdiff;
				
				if( heightdiff < AI_STEPSIZE && nav.num_broams < MAX_BOT_ROAMS ) //near enough
				{
					nodes[node].flags |= NODEFLAGS_BOTROAM;
					//add node to botroam list
					if( ent->count )
						nav.broams[nav.num_broams].weight = ent->count * 0.01;//count is a int with a value in between 0 and 100
					else
						nav.broams[nav.num_broams].weight = 0.3; //jalfixme: add cmd to weight (dropped by console cmd, self is player)
					
					nav.broams[nav.num_broams].node = node;
					nav.num_broams++;
					continue;
				}
			}

			//drop a new node
			if( nav.num_broams < MAX_BOT_ROAMS ){
				AI_AddNode_BotRoam( ent );
			}
		}
	}

	// game items (I want all them on top of the nodes array)
	nav.num_items = 0;
	memset( nav.items, 0, sizeof(nav_item_t) * MAX_EDICTS );

//	for( ent = game.edicts; ent < &game.edicts[game.numentities]; ent++ )
	for( ent = g_edicts; ent < &g_edicts[game.maxentities]; ent++ )
	{
		int	item_index;

		if( !ent->classname || !ent->item )		
			continue;

		item_index = ITEM_INDEX( ent->item );
		if(item_index == INVALID)
			continue;
		
		//if we have a available node close enough to the item, use it
		node = AI_FindClosestReachableNode( ent->s.origin, NULL, 48, NODE_ALL );
		if( node != INVALID )
		{
			if( nodes[node].flags & NODEFLAGS_SERVERLINK ||
				nodes[node].flags & NODEFLAGS_LADDER )
				node = INVALID;
			else
			{
				float heightdiff = 0;
				heightdiff = ent->s.origin[2] - nodes[node].origin[2];
				if( heightdiff < 0 ) heightdiff = -heightdiff;
				
				if( heightdiff > AI_STEPSIZE )	//not near enough
					node = INVALID;
			}
		}
		
		//drop a new node
		if( node == INVALID )
			node = AI_AddNode_ItemNode( ent );

		if( node != INVALID )
		{
			nav.items[nav.num_items].node = node;
			nav.items[nav.num_items].ent = ent;
			nav.items[nav.num_items].item = item_index;
			nav.num_items++;
		}
	}
}
Exemple #7
0
static void AI_AddGoalEntityNode( edict_t *ent, qboolean customReach )
{
	int node = NODE_INVALID;
	int range = NODE_DENSITY * 0.75;

	if( !ent->r.inuse || !ent->classname )
		return;

	if( AI_GetGoalentForEnt( ent ) != NULL )
		return;

	if( ent->r.client )
	{
		nav.goalEnts[nav.num_goalEnts].node = NODE_INVALID;
		nav.goalEnts[nav.num_goalEnts].ent = ent;
		nav.num_goalEnts++;
		return;
	}

	//
	// Goal entities
	//

	if( nav.loaded )
		range = AI_GOAL_SR_RADIUS;

	// if we have a available node close enough to the entity, use it
	node = AI_FindClosestReachableNode( ent->s.origin, ent, range, NODE_ALL );
	if( node != NODE_INVALID )
	{
		if( nodes[node].flags & NODE_MASK_NOREUSE )
			node = NODE_INVALID;
		else
		{
			float heightdiff = fabs( ent->s.origin[2] - nodes[node].origin[2] );

			if( heightdiff > AI_STEPSIZE + 8 )  // not near enough
				node = NODE_INVALID;
		}
	}

	// link the node is spawned after the load process is done
	if( nav.loaded )
	{
		if( node == NODE_INVALID ) // (BY NOW) can not create new nodes after the initialization was done
			return;

		if( nav.debugMode && bot_showlrgoal->integer > 2 )
			G_Printf( "New Goal Entity added: %s\n", ent->classname );
	}
	else
	{
		// didn't find a node we could reuse
		if( node == NODE_INVALID )
			node = AI_AddNode_GoalEntityNode( ent );
	}

	if( node != NODE_INVALID )
	{
		nav.goalEnts[nav.num_goalEnts].node = node;
		nav.goalEnts[nav.num_goalEnts].ent = ent;
		nav.num_goalEnts++;

		if( customReach )
			nodes[node].flags |= NODEFLAGS_ENTITYREACH;
	}
}