Esempio n. 1
0
//==========================================
// AI_AddNode_Door
// Drop a node at each side of the door
// and force them to link. Only typical
// doors are covered.
//==========================================
int AI_AddNode_Door( edict_t *ent )
{
	edict_t		*other;
	vec3_t		mins, maxs;
	vec3_t		forward, right, up;
	vec3_t		door_origin;

	if (ent->flags & FL_TEAMSLAVE)
		return INVALID;		//only team master will drop the nodes

	//make box formed by all team members boxes
	VectorCopy (ent->absmin, mins);
	VectorCopy (ent->absmax, maxs);

	for (other = ent->teamchain ; other ; other=other->teamchain)
	{
		AddPointToBounds (other->absmin, mins, maxs);
		AddPointToBounds (other->absmax, mins, maxs);
	}

	door_origin[0] = (maxs[0] - mins[0]) / 2 + mins[0];
	door_origin[1] = (maxs[1] - mins[1]) / 2 + mins[1];
	door_origin[2] = (maxs[2] - mins[2]) / 2 + mins[2];

	//now find the crossing angle
	AngleVectors( ent->s.angles, forward, right, up );
	VectorNormalize( right );

	//add node
	nodes[nav.num_nodes].flags = 0;
	VectorMA( door_origin, 32, right, nodes[nav.num_nodes].origin);
	AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL );
	nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
#ifdef SHOW_JUMPAD_GUESS
	AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, "models/powerups/health/mega_sphere.md3" );
#endif
	nav.num_nodes++;

	//add node 2
	nodes[nav.num_nodes].flags = 0;
	VectorMA( door_origin, -32, right, nodes[nav.num_nodes].origin);
	AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL );
	nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
#ifdef SHOW_JUMPAD_GUESS
	AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, "models/powerups/health/mega_sphere.md3" );
#endif
	//add links in both directions
	AI_AddLink( nav.num_nodes, nav.num_nodes-1, LINK_MOVE );
	AI_AddLink( nav.num_nodes-1, nav.num_nodes, LINK_MOVE );

	nav.num_nodes++;
	return nav.num_nodes-1;
}
Esempio n. 2
0
/*
* AI_AddNode_Platform_FindLowerLinkableCandidate
* helper to AI_AddNode_Platform
*/
static int AI_AddNode_Platform_FindLowerLinkableCandidate( edict_t *ent )
{
	trace_t	trace;
	float plat_dist;
	float platlip;
	int numtries = 0, maxtries = 10;
	int candidate;
	vec3_t candidate_origin, virtualorigin;
	float mindist = 0;

	if( ent->flags & FL_TEAMSLAVE )
		return NODE_INVALID;

	plat_dist = ent->moveinfo.start_origin[2] - ent->moveinfo.end_origin[2];
	platlip = ( ent->r.maxs[2] - ent->r.mins[2] ) - plat_dist;

	//find a good candidate for lower
	candidate_origin[0] = ( ent->r.maxs[0] - ent->r.mins[0] ) / 2 + ent->r.mins[0];
	candidate_origin[1] = ( ent->r.maxs[1] - ent->r.mins[1] ) / 2 + ent->r.mins[1];
	candidate_origin[2] = ent->r.mins[2] + platlip;

	//try to find the closer reachable node to the bottom of the plat
	do
	{
		candidate = AI_FindClosestNode( candidate_origin, mindist, NODE_DENSITY * 2, NODE_ALL );
		if( candidate != NODE_INVALID )
		{
			mindist = DistanceFast( candidate_origin, nodes[candidate].origin );

			//check to see if it would be valid
			if( fabs( candidate_origin[2] - nodes[candidate].origin[2] )
			   < ( fabs( platlip ) + AI_JUMPABLE_HEIGHT ) )
			{
				//put at linkable candidate height
				virtualorigin[0] = candidate_origin[0];
				virtualorigin[1] = candidate_origin[1];
				virtualorigin[2] = nodes[candidate].origin[2];

				G_Trace( &trace, virtualorigin, vec3_origin, vec3_origin, nodes[candidate].origin, ent, MASK_NODESOLID );
				//trace = gi.trace( virtualorigin, vec3_origin, vec3_origin, nodes[candidate].origin, ent, MASK_NODESOLID );
				if( trace.fraction == 1.0 && !trace.startsolid )
				{
#ifdef SHOW_JUMPAD_GUESS
					AI_JumpadGuess_ShowPoint( virtualorigin, "models/objects/grenade/tris.md2" );
#endif
					return candidate;
				}
			}
		}
	}
	while( candidate != NODE_INVALID && numtries++ < maxtries );

	return NODE_INVALID;
}
Esempio n. 3
0
//==========================================
// AI_PredictJumpadDestity
// Make a guess on where a jumpad will send
// the player.
//==========================================
qboolean AI_PredictJumpadDestity( edict_t *ent, vec3_t out )
{
	int		i;
	edict_t *target;
	trace_t	trace;
	vec3_t	pad_origin, v1, v2;
	float	htime, vtime, tmpfloat, player_factor;	//player movement guess
	vec3_t	floor_target_origin, target_origin;
	vec3_t	floor_dist_vec, floor_movedir;

	VectorClear( out );

	if( !ent->target )	//jabot092
		return false;

	// get target entity
	target = G_Find ( NULL, FOFS(targetname), ent->target );
	if (!target)
		return false;

	// find pad origin
	VectorCopy( ent->maxs, v1 );
	VectorCopy( ent->mins, v2 );
	pad_origin[0] = (v1[0] - v2[0]) / 2 + v2[0];
	pad_origin[1] = (v1[1] - v2[1]) / 2 + v2[1];
	pad_origin[2] = ent->maxs[2];

	//make a projection 'on floor' of target origin
	VectorCopy( target->s.origin, target_origin );
	VectorCopy( target->s.origin, floor_target_origin );
	floor_target_origin[2] = pad_origin[2];	//put at pad's height

	//make a guess on how player movement will affect the trajectory
	tmpfloat = AI_Distance( pad_origin, floor_target_origin );
	htime = sqrt ((tmpfloat));
	vtime = sqrt ((target->s.origin[2] - pad_origin[2]));
	if(!vtime) return false;
	htime *= 4;vtime *= 4;
	if( htime > vtime )
		htime = vtime;
	player_factor = vtime - htime;

	// find distance vector, on floor, from pad_origin to target origin.
	for ( i=0 ; i<3 ; i++ )
		floor_dist_vec[i] = floor_target_origin[i] - pad_origin[i];

	// movement direction on floor
	VectorCopy( floor_dist_vec, floor_movedir );
	VectorNormalize( floor_movedir );

	// move both target origin and target origin on floor by player movement factor.
	VectorMA ( target_origin, player_factor, floor_movedir, target_origin);
	VectorMA ( floor_target_origin, player_factor, floor_movedir, floor_target_origin);

	// move target origin on floor by floor distance, and add another player factor step to it
	VectorMA ( floor_target_origin, 1, floor_dist_vec, floor_target_origin);
	VectorMA ( floor_target_origin, player_factor, floor_movedir, floor_target_origin);

#ifdef SHOW_JUMPAD_GUESS
	// this is our top of the curve point, and the original target
	AI_JumpadGuess_ShowPoint( target_origin, "models/powerups/health/mega_sphere.md3" );
	AI_JumpadGuess_ShowPoint( target->s.origin, "models/powerups/health/large_cross.md3" );
#endif

	//trace from target origin to endPoint.
//	trap_Trace ( &trace, target_origin, tv(-15, -15, -8), tv(15, 15, 8), floor_target_origin, NULL, MASK_NODESOLID);
	trace = gi.trace(  target_origin, tv(-15, -15, -8), tv(15, 15, 8), floor_target_origin, NULL, MASK_NODESOLID);
	if (trace.fraction == 1.0 && trace.startsolid || trace.allsolid && trace.startsolid){
//		G_Printf("JUMPAD LAND: ERROR: trace was in solid.\n"); //started inside solid (target should never be inside solid, this is a mapper error)
		return false;
	} else if ( trace.fraction == 1.0 ) {
		
		//didn't find solid. Extend Down (I have to improve this part)
		vec3_t	target_origin2, extended_endpoint, extend_dist_vec;
		
		VectorCopy( floor_target_origin, target_origin2 );
		for ( i=0 ; i<3 ; i++ )
			extend_dist_vec[i] = floor_target_origin[i] - target_origin[i];
		
		VectorMA ( target_origin2, 1, extend_dist_vec, extended_endpoint);
		//repeat tracing
//		trap_Trace ( &trace, target_origin2, tv(-15, -15, -8), tv(15, 15, 8), extended_endpoint, NULL, MASK_NODESOLID);
		trace = gi.trace(  target_origin2, tv(-15, -15, -8), tv(15, 15, 8), extended_endpoint, NULL, MASK_NODESOLID);
		if ( trace.fraction == 1.0 )
			return false;//still didn't find solid
	}
	
#ifdef SHOW_JUMPAD_GUESS
	// destiny found
	AI_JumpadGuess_ShowPoint( trace.endpos, "models/powerups/health/mega_sphere.md3" );
#endif

	VectorCopy ( trace.endpos, out );
	return true;
}
Esempio n. 4
0
/*
* AI_AddNode_Teleporter
* Drop two nodes, one at trigger and other
* at target entity
*/
static int AI_AddNode_Teleporter( edict_t *ent )
{
	vec3_t v1, v2;
	edict_t	*dest;

	if( nav.num_nodes + 1 > MAX_NODES )
		return NODE_INVALID;

	dest = G_Find( NULL, FOFS( targetname ), ent->target );
	if( !dest )
		return NODE_INVALID;

	// NODE_TELEPORTER_IN
	nodes[nav.num_nodes].flags = ( NODEFLAGS_TELEPORTER_IN|NODEFLAGS_SERVERLINK|NODEFLAGS_REACHATTOUCH );

	if( !strcmp( ent->classname, "misc_teleporter" ) ) //jabot092(2)
	{
		nodes[nav.num_nodes].origin[0] = ent->s.origin[0];
		nodes[nav.num_nodes].origin[1] = ent->s.origin[1];
		nodes[nav.num_nodes].origin[2] = ent->s.origin[2]+16;
	}
	else
	{
		VectorCopy( ent->r.maxs, v1 );
		VectorCopy( ent->r.mins, v2 );
		nodes[nav.num_nodes].origin[0] = ( v1[0] - v2[0] ) / 2 + v2[0];
		nodes[nav.num_nodes].origin[1] = ( v1[1] - v2[1] ) / 2 + v2[1];
		nodes[nav.num_nodes].origin[2] = ent->r.mins[2]+32;
	}

	nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, ent );
#ifdef SHOW_JUMPAD_GUESS
	AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL );
#endif

	//put into ents table
	nav.navigableEnts[nav.num_navigableEnts].ent = ent;
	nav.navigableEnts[nav.num_navigableEnts].node = nav.num_nodes;
	nav.num_navigableEnts++;

	nav.num_nodes++;

	//NODE_TELEPORTER_OUT
	nodes[nav.num_nodes].flags = ( NODEFLAGS_TELEPORTER_OUT|NODEFLAGS_SERVERLINK );
	VectorCopy( dest->s.origin, nodes[nav.num_nodes].origin );
	if( ent->spawnflags & 1 )  // droptofloor
		nodes[nav.num_nodes].flags |= NODEFLAGS_FLOAT;
	else
		AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL );

	nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, ent );
#ifdef SHOW_JUMPAD_GUESS
	AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL );
#endif

	//put into ents table
	nav.navigableEnts[nav.num_navigableEnts].ent = ent;
	nav.navigableEnts[nav.num_navigableEnts].node = nav.num_nodes;
	nav.num_navigableEnts++;

	// link from teleport_in
	AI_AddLink( nav.num_nodes-1, nav.num_nodes, LINK_TELEPORT );

	nav.num_nodes++;
	return nav.num_nodes -1;
}
Esempio n. 5
0
/*
* AI_AddNode_Platform
* drop two nodes one at top, one at bottom
*/
static int AI_AddNode_Platform( edict_t *ent )
{
	float plat_dist;
	float platlip;
	int candidate;
	vec3_t lorg;

	if( nav.num_nodes + 2 > MAX_NODES )
		return NODE_INVALID;

	if( ent->flags & FL_TEAMSLAVE )
		return NODE_INVALID; // only team master will drop the nodes

	plat_dist = ent->moveinfo.start_origin[2] - ent->moveinfo.end_origin[2];
	platlip = ( ent->r.maxs[2] - ent->r.mins[2] ) - plat_dist;

	//make a guess on lower plat position
	candidate = AI_AddNode_Platform_FindLowerLinkableCandidate( ent );
	if( candidate != NODE_INVALID )
	{                    //base lower on cadidate's height
		lorg[0] = ( ent->r.maxs[0] - ent->r.mins[0] ) / 2 + ent->r.mins[0];
		lorg[1] = ( ent->r.maxs[1] - ent->r.mins[1] ) / 2 + ent->r.mins[1];
		lorg[2] = nodes[candidate].origin[2];

	}
	else
	{
		lorg[0] = ( ent->r.maxs[0] - ent->r.mins[0] ) / 2 + ent->r.mins[0];
		lorg[1] = ( ent->r.maxs[1] - ent->r.mins[1] ) / 2 + ent->r.mins[1];
		lorg[2] = ent->r.mins[2] + platlip + 16;
	}

	// Upper node
	nodes[nav.num_nodes].flags = ( NODEFLAGS_PLATFORM|NODEFLAGS_SERVERLINK|NODEFLAGS_FLOAT );
	nodes[nav.num_nodes].origin[0] = lorg[0];
	nodes[nav.num_nodes].origin[1] = lorg[1];
	nodes[nav.num_nodes].origin[2] = lorg[2] + plat_dist;
#ifdef SHOW_JUMPAD_GUESS
	AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL );
#endif
	nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );

	//put into ents table
	nav.navigableEnts[nav.num_navigableEnts].ent = ent;
	nav.navigableEnts[nav.num_navigableEnts].node = nav.num_nodes;
	nav.num_navigableEnts++;

	nav.num_nodes++;

	// Lower node
	nodes[nav.num_nodes].flags = ( NODEFLAGS_PLATFORM|NODEFLAGS_SERVERLINK|NODEFLAGS_FLOAT );
	nodes[nav.num_nodes].origin[0] = lorg[0];
	nodes[nav.num_nodes].origin[1] = lorg[1];
	nodes[nav.num_nodes].origin[2] = lorg[2] + 16;
#ifdef SHOW_JUMPAD_GUESS
	AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL );
#endif
	nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );

	//put into ents table
	nav.navigableEnts[nav.num_navigableEnts].ent = ent;
	nav.navigableEnts[nav.num_navigableEnts].node = nav.num_nodes;
	nav.num_navigableEnts++;

	// link lower to upper
	AI_AddLink( nav.num_nodes, nav.num_nodes-1, LINK_PLATFORM );

	//next
	nav.num_nodes++;
	return nav.num_nodes-1;
}
Esempio n. 6
0
/*
* AI_AddNode_Door
* Drop a node at each side of the door
* and force them to link. Only typical
* doors are covered.
*/
static int AI_AddNode_Door( edict_t *ent )
{
	edict_t	*other;
	vec3_t mins, maxs;
	vec3_t door_origin, movedir, moveangles;
	vec3_t moveaxis[3];
	vec3_t MOVEDIR_UP = { 0, 0, 1 };
	float nodeOffset = NODE_DENSITY * 0.75f;
	int i, j;
	int dropped[4];

	if( ent->flags & FL_TEAMSLAVE )
		return NODE_INVALID; // only team master will drop the nodes

	for( i = 0; i < 4; i++ )
		dropped[i] = NODE_INVALID;

	//make box formed by all team members boxes
	VectorCopy( ent->r.absmin, mins );
	VectorCopy( ent->r.absmax, maxs );

	for( other = ent->teamchain; other; other = other->teamchain )
	{
		AddPointToBounds( other->r.absmin, mins, maxs );
		AddPointToBounds( other->r.absmax, mins, maxs );
	}

	for( i = 0; i < 3; i++ )
		door_origin[i] = ( maxs[i] + mins[i] ) * 0.5;

	VectorSubtract( ent->moveinfo.end_origin, ent->moveinfo.start_origin, movedir );
	VectorNormalizeFast( movedir );
	VecToAngles( movedir, moveangles );

	AnglesToAxis( moveangles, moveaxis );

	//add nodes in "side" direction

	nodes[nav.num_nodes].flags = 0;
	VectorMA( door_origin, nodeOffset, moveaxis[1], nodes[nav.num_nodes].origin );
#ifdef SHOW_JUMPAD_GUESS
	AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL );
#endif
	if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) )
	{
		nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
		dropped[0] = nav.num_nodes;
		nav.num_nodes++;
	}

	nodes[nav.num_nodes].flags = 0;
	VectorMA( door_origin, -nodeOffset, moveaxis[1], nodes[nav.num_nodes].origin );
#ifdef SHOW_JUMPAD_GUESS
	AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL );
#endif
	if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) )
	{
		nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
		dropped[1] = nav.num_nodes;
		nav.num_nodes++;
	}

	// if moving in the Y axis drop also in the other crossing direction and hope the
	// bad ones are inhibited by a solid
	if( DotProduct( MOVEDIR_UP, moveaxis[0] ) > 0.8 || DotProduct( MOVEDIR_UP, moveaxis[0] ) < -0.8 )
	{
		nodes[nav.num_nodes].flags = 0;
		VectorMA( door_origin, nodeOffset, moveaxis[2], nodes[nav.num_nodes].origin );
#ifdef SHOW_JUMPAD_GUESS
		AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL );
#endif
		if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) )
		{
			nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
			dropped[2] = nav.num_nodes;
			nav.num_nodes++;
		}

		nodes[nav.num_nodes].flags = 0;
		VectorMA( door_origin, -nodeOffset, moveaxis[2], nodes[nav.num_nodes].origin );
#ifdef SHOW_JUMPAD_GUESS
		AI_JumpadGuess_ShowPoint( nodes[nav.num_nodes].origin, PATH_AMMO_BOX_MODEL );
#endif
		if( AI_DropNodeOriginToFloor( nodes[nav.num_nodes].origin, NULL ) )
		{
			nodes[nav.num_nodes].flags |= AI_FlagsForNode( nodes[nav.num_nodes].origin, NULL );
			dropped[3] = nav.num_nodes;
			nav.num_nodes++;
		}
	}

	// link those we dropped
	for( i = 0; i < 4; i++ )
	{
		if( dropped[i] == NODE_INVALID )
			continue;

		//put into ents table
		nav.navigableEnts[nav.num_navigableEnts].ent = ent;
		nav.navigableEnts[nav.num_navigableEnts].node = dropped[i];
		nav.num_navigableEnts++;

		for( j = 0; j < 4; j++ )
		{
			if( dropped[j] == NODE_INVALID )
				continue;

			AI_AddLink( dropped[i], dropped[j], LINK_MOVE|LINK_DOOR );
		}
	}

	return nav.num_nodes-1;
}