Beispiel #1
0
/*
* G_TeleportPlayer
*/
void G_TeleportPlayer( edict_t *player, edict_t *dest )
{
	int i;
	vec3_t velocity;
	mat3_t axis;
	float speed;
	gclient_t *client = player->r.client;

	if( !dest ) {
		return;
	}
	if( !client ) {
		return;
	}

	// draw the teleport entering effect
	G_TeleportEffect( player, false );

	//
	// teleport the player
	//

	// from racesow - use old pmove velocity
	VectorCopy( client->old_pmove.velocity, velocity );

	velocity[2] = 0; // ignore vertical velocity
	speed = VectorLengthFast( velocity );

	AnglesToAxis( dest->s.angles, axis );
	VectorScale( &axis[AXIS_FORWARD], speed, client->ps.pmove.velocity );

	VectorCopy( dest->s.angles, client->ps.viewangles );
	VectorCopy( dest->s.origin, client->ps.pmove.origin );

	// set the delta angle
	for ( i = 0; i < 3; i++ )
		client->ps.pmove.delta_angles[i] = ANGLE2SHORT( client->ps.viewangles[i] ) - client->ucmd.angles[i];

	client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
	client->ps.pmove.pm_time = 1; // force the minimum no control delay
	player->s.teleported = true;

	// update the entity from the pmove
	VectorCopy( client->ps.viewangles, player->s.angles );
	VectorCopy( client->ps.pmove.origin, player->s.origin );
	VectorCopy( client->ps.pmove.origin, player->s.old_origin );
	VectorCopy( client->ps.pmove.origin, player->olds.origin );
	VectorCopy( client->ps.pmove.velocity, player->velocity );

	// unlink to make sure it can't possibly interfere with KillBox
	GClip_UnlinkEntity( player );

	// kill anything at the destination
	KillBox( player );

	GClip_LinkEntity( player );

	// add the teleport effect at the destination
	G_TeleportEffect( player, true );
}
static bool BOT_DMclass_FindRocket( edict_t *self, vec3_t away_from_rocket )
{
#define AI_ROCKET_DETECT_RADIUS 1000
#define AI_ROCKET_DANGER_RADIUS 200
	int i, numtargets;
	int targets[MAX_EDICTS];
	edict_t *target;
	float min_roxx_time = 1.0f;
	bool any_rocket = false;

	numtargets = GClip_FindRadius( self->s.origin, AI_ROCKET_DETECT_RADIUS, targets, MAX_EDICTS );
	for( i = 0; i < numtargets; i++ )
	{
		target = game.edicts + targets[i];

		// Missile detection code
		if( target->r.svflags & SVF_PROJECTILE && target->s.type != ET_PLASMA ) // (plasmas come in bunchs so are too complex for the bot to dodge)
		{
			if( target->r.owner && target->r.owner != self )
			{
				vec3_t end;
				trace_t trace;

				VectorMA( target->s.origin, 2, target->velocity, end );
				G_Trace( &trace, target->s.origin, target->r.mins, target->r.maxs, end, target, MASK_SOLID );
				if( trace.fraction < min_roxx_time )
				{
					vec_t l;

					any_rocket = true;
					min_roxx_time = trace.fraction;
					VectorSubtract( trace.endpos, self->s.origin, end );
					// ok... end is where the impact will be.
					// trace.fraction is the time.

					if( ( l = VectorLengthFast( end ) ) < AI_ROCKET_DANGER_RADIUS )
					{
						RotatePointAroundVector( away_from_rocket, &axis_identity[AXIS_UP], end, -self->s.angles[YAW] );
						VectorNormalize( away_from_rocket );

						if( fabs( away_from_rocket[0] ) < 0.3 ) away_from_rocket[0] = 0;
						if( fabs( away_from_rocket[1] ) < 0.3 ) away_from_rocket[1] = 0;
						away_from_rocket[2] = 0;
						away_from_rocket[0] *= -1.0f;
						away_from_rocket[1] *= -1.0f;

						if( nav.debugMode && bot_showcombat->integer > 2 )
							G_PrintChasersf( self, "%s: ^1projectile dodge: ^2%f, %f d=%f^7\n", self->ai->pers.netname, away_from_rocket[0], away_from_rocket[1], l );
					}
				}
			}
		}
	}

	return any_rocket;

#undef AI_ROCKET_DETECT_RADIUS
#undef AI_ROCKET_DANGER_RADIUS
}
Beispiel #3
0
/*
* G_ClientAddDamageIndicatorImpact
*/
void G_ClientAddDamageIndicatorImpact( gclient_t *client, int damage, const vec3_t basedir )
{
	edict_t *ent;
	vec3_t dir;
	float frac;

	if( damage < 1 )
		return;

	if( !client || client - game.clients < 0 || client - game.clients >= gs.maxclients )
		return;

	ent = &game.edicts[ ( client - game.clients ) + 1 ];

	if( !basedir )
	{
		VectorCopy( vec3_origin, dir );
	}
	else
	{
		VectorNormalize2( basedir, dir );

		//#define ACCENT_SCALE 2.0f
#ifdef ACCENT_SCALE
		// accent the vertical or horizontal aspect of the direction
		if( VectorLengthFast( tv( dir[0], dir[1], 0 ) ) > dir[2] )
		{
			dir[0] *= ACCENT_SCALE;
			dir[1] *= ACCENT_SCALE;
		}
		else
			dir[2] *= ACCENT_SCALE;

		VectorNormalizeFast( dir );
#endif
#undef ACCENT_SCALE
	}

	frac = damage / ( damage + client->resp.snap.damageTaken );
	VectorLerp( client->resp.snap.damageTakenDir, frac, dir, client->resp.snap.damageTakenDir );
	client->resp.snap.damageTaken += damage;
}
Beispiel #4
0
static void UpdatePoint( edict_t *who )
{
	vec3_t angles, forward, diff;
	trace_t trace;
	edict_t *ent, *ent_best = NULL;
	int i, j;
	float value, value_best = 0.35f; // if nothing better is found, print nothing
	gclient_t *client = who->r.client;
	vec3_t boxpoints[8], viewpoint;

	AngleVectors( client->ps.viewangles, forward, NULL, NULL );
	VectorCopy( who->s.origin, viewpoint );
	viewpoint[2] += who->viewheight;

	for( i = 0; i < game.numentities; i++ )
	{
		ent = game.edicts + i;

		if( !ent->r.inuse || !ent->s.modelindex || ent == who )
			continue;
		if( G_ISGHOSTING( ent ) )
			continue;
		if( ent->s.type != ET_PLAYER && ent->s.type != ET_ITEM )
			continue;

		VectorSubtract( ent->s.origin, viewpoint, angles );
		VectorNormalize( angles );
		VectorSubtract( forward, angles, diff );
		for( j = 0; j < 3; j++ ) if( diff[j] < 0 ) diff[j] = -diff[j];
		value = VectorLengthFast( diff );

		if( value < value_best )
		{
			BuildBoxPoints( boxpoints, ent->s.origin, ent->r.mins, ent->r.maxs );
			for( j = 0; j < 8; j++ )
			{
				G_Trace( &trace, viewpoint, vec3_origin, vec3_origin, boxpoints[j], who, MASK_OPAQUE );
				if( trace.fraction == 1 )
				{
					value_best = value;
					ent_best = ent;
					break;
				}
			}
		}
	}

	if( ent_best != NULL )
	{
		point = ent_best;
		VectorCopy( ent_best->s.origin, point_location );
	}
	else
	{
		vec3_t dest;

		VectorMA( viewpoint, 8192, forward, dest );
		G_Trace( &trace, viewpoint, vec3_origin, vec3_origin, dest, who, MASK_OPAQUE );

		point = NULL;
		VectorCopy( trace.endpos, point_location );
	}
}
Beispiel #5
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 );
	}
}
void BOT_DMclass_MoveWander( edict_t *self, usercmd_t *ucmd )
{
	vec3_t temp;

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

	// Special check for elevators, stand still until the ride comes to a complete stop.
	if( self->groundentity && self->groundentity->use == Use_Plat )
	{
		if( self->groundentity->moveinfo.state != STATE_UP &&
			self->groundentity->moveinfo.state != STATE_DOWN )
		{
			self->velocity[0] = 0;
			self->velocity[1] = 0;
			self->velocity[2] = 0;
			return;
		}
	}

	// Move To Goal (Short Range Goal, not following paths)
	if( !AI_MoveToShortRangeGoalEntity( self, ucmd ) )
	{
		// Swimming?
		VectorCopy( self->s.origin, temp );
		temp[2] += 24;

		if( G_PointContents( temp ) & MASK_WATER )
		{
			// If drowning and no node, move up
			if( self->r.client && self->r.client->resp.next_drown_time > 0 )
			{
				ucmd->upmove = 1;
				self->s.angles[PITCH] = -45;
			}
			else
				ucmd->upmove = 1;

			ucmd->forwardmove = 1;
		}
		// else self->r.client->next_drown_time = 0; // probably shound not be messing with this, but


		// Lava?
		temp[2] -= 48;
		if( G_PointContents( temp ) & ( CONTENTS_LAVA|CONTENTS_SLIME ) )
		{
			self->s.angles[YAW] += random() * 360 - 180;
			ucmd->forwardmove = 1;
			if( self->groundentity )
				ucmd->upmove = 1;
			else
				ucmd->upmove = 0;
			return;
		}


		// Check for special movement
		if( VectorLengthFast( self->velocity ) < 37 )
		{
			if( random() > 0.1 && AI_SpecialMove( self, ucmd ) )  //jumps, crouches, turns...
				return;

			self->s.angles[YAW] += random() * 180 - 90;

			if( !self->is_step )  // if there is ground continue otherwise wait for next move
				ucmd->forwardmove = 0; //0
			else if( AI_CanMove( self, BOT_MOVE_FORWARD ) )
			{
				ucmd->forwardmove = 1;
				ucmd->buttons |= BUTTON_WALK;
			}

			return;
		}

		// Otherwise move slowly, walking wondering what's going on
		ucmd->buttons |= BUTTON_WALK;
	}

	if( AI_CanMove( self, BOT_MOVE_FORWARD ) )
		ucmd->forwardmove = 1;
	else
		ucmd->forwardmove = -1;
}
void BOT_DMclass_Move( edict_t *self, usercmd_t *ucmd )
{
#define BOT_FORWARD_EPSILON 0.5f
	int i;
	unsigned int linkType;
	bool printLink = false;
	bool nodeReached = false;
	bool specialMovement = false;
	vec3_t v1, v2;
	vec3_t lookdir, pathdir;
	float lookDot;

	if( self->ai->next_node == NODE_INVALID || self->ai->goal_node == NODE_INVALID )
	{
		BOT_DMclass_MoveWander( self, ucmd );
		return;
	}

	linkType = AI_CurrentLinkType( self );

	specialMovement = ( self->ai->path.numNodes >= MIN_BUNNY_NODES ) ? true : false;

	if( AI_GetNodeFlags( self->ai->next_node ) & (NODEFLAGS_REACHATTOUCH|NODEFLAGS_ENTITYREACH) )
		specialMovement = false;

	if( linkType & (LINK_JUMP|LINK_JUMPPAD|LINK_CROUCH|LINK_FALL|LINK_WATER|LINK_LADDER|LINK_ROCKETJUMP) )
		specialMovement = false;

	if( self->ai->pers.skillLevel < 0.33f )
		specialMovement = false;

	if( specialMovement == false || self->groundentity )
		self->ai->is_bunnyhop = false;

	VectorSubtract( nodes[self->ai->next_node].origin, self->s.origin, self->ai->move_vector );

	// 2D, normalized versions of look and path directions
	pathdir[0] = self->ai->move_vector[0];
	pathdir[1] = self->ai->move_vector[1];
	pathdir[2] = 0.0f;
	VectorNormalize( pathdir );

	AngleVectors( self->s.angles, lookdir, NULL, NULL );
	lookdir[2] = 0.0f;
	VectorNormalize( lookdir );

	lookDot = DotProduct( lookdir, pathdir );

	// Ladder movement
	if( self->is_ladder )
	{
		ucmd->forwardmove = 0;
		ucmd->upmove = 1;
		ucmd->sidemove = 0;

		if( nav.debugMode && printLink )
			G_PrintChasersf( self, "LINK_LADDER\n" );

		nodeReached = AI_NodeReached_Generic( self );
	}
	else if( linkType & LINK_JUMPPAD )
	{
		VectorCopy( self->s.origin, v1 );
		VectorCopy( nodes[self->ai->next_node].origin, v2 );
		v1[2] = v2[2] = 0;
		if( DistanceFast( v1, v2 ) > 32 && lookDot > BOT_FORWARD_EPSILON ) {
			ucmd->forwardmove = 1; // push towards destination
			ucmd->buttons |= BUTTON_WALK;
		}
		nodeReached = self->groundentity != NULL && AI_NodeReached_Generic( self );
	}
	// Platform riding - No move, riding elevator
	else if( linkType & LINK_PLATFORM )
	{
		VectorCopy( self->s.origin, v1 );
		VectorCopy( nodes[self->ai->next_node].origin, v2 );
		v1[2] = v2[2] = 0;
		if( DistanceFast( v1, v2 ) > 32 && lookDot > BOT_FORWARD_EPSILON )
			ucmd->forwardmove = 1; // walk to center

		ucmd->buttons |= BUTTON_WALK;
		ucmd->upmove = 0;
		ucmd->sidemove = 0;

		if( nav.debugMode && printLink )
			G_PrintChasersf( self, "LINK_PLATFORM (riding)\n" );

		self->ai->move_vector[2] = 0; // put view horizontal

		nodeReached = AI_NodeReached_PlatformEnd( self );
	}
	// entering platform
	else if( AI_GetNodeFlags( self->ai->next_node ) & NODEFLAGS_PLATFORM )
	{
		ucmd->forwardmove = 1;
		ucmd->upmove = 0;
		ucmd->sidemove = 0;

		if( lookDot <= BOT_FORWARD_EPSILON )
			ucmd->buttons |= BUTTON_WALK;

		if( nav.debugMode && printLink )
			G_PrintChasersf( self, "NODEFLAGS_PLATFORM (moving to plat)\n" );

		// is lift down?
		for( i = 0; i < nav.num_navigableEnts; i++ )
		{
			if( nav.navigableEnts[i].node == self->ai->next_node )
			{
				//testing line
				//vec3_t	tPoint;
				//int		j;
				//for(j=0; j<3; j++)//center of the ent
				//	tPoint[j] = nav.ents[i].ent->s.origin[j] + 0.5*(nav.ents[i].ent->r.mins[j] + nav.ents[i].ent->r.maxs[j]);
				//tPoint[2] = nav.ents[i].ent->s.origin[2] + nav.ents[i].ent->r.maxs[2];
				//tPoint[2] += 8;
				//AITools_DrawLine( self->s.origin, tPoint );

				//if not reachable, wait for it (only height matters)
				if( ( nav.navigableEnts[i].ent->s.origin[2] + nav.navigableEnts[i].ent->r.maxs[2] ) > ( self->s.origin[2] + self->r.mins[2] + AI_JUMPABLE_HEIGHT ) &&
					nav.navigableEnts[i].ent->moveinfo.state != STATE_BOTTOM )
				{
					self->ai->blocked_timeout = level.time + 10000;
					ucmd->forwardmove = 0;
				}
			}
		}

		nodeReached = AI_NodeReached_PlatformStart( self );
	}
	// Falling off ledge or jumping
	else if( !self->groundentity && !self->is_step && !self->is_swim && !self->ai->is_bunnyhop )
	{
		ucmd->upmove = 0;
		ucmd->sidemove = 0;
		ucmd->forwardmove = 0;

		if( lookDot > BOT_FORWARD_EPSILON )
		{
			ucmd->forwardmove = 1;

			// add fake strafe accel
			if( !(linkType & LINK_FALL) || linkType & (LINK_JUMP|LINK_ROCKETJUMP) )
			{
				if( linkType & LINK_JUMP )
				{
					if( AI_AttemptWalljump( self ) ) {
						ucmd->buttons |= BUTTON_SPECIAL;
					}
					if( VectorLengthFast( tv( self->velocity[0], self->velocity[1], 0 ) ) < 600 )
						VectorMA( self->velocity, 6.0f, lookdir, self->velocity );
				}
				else
				{
					if( VectorLengthFast( tv( self->velocity[0], self->velocity[1], 0 ) ) < 450 )
						VectorMA( self->velocity, 1.0f, lookdir, self->velocity );
				}
			}
		}
		else if( lookDot < -BOT_FORWARD_EPSILON )
			ucmd->forwardmove = -1;

		if( nav.debugMode && printLink )
			G_PrintChasersf( self, "FLY MOVE\n" );

		nodeReached = AI_NodeReached_Generic( self );
	}
	else // standard movement
	{
		ucmd->forwardmove = 1;
		ucmd->upmove = 0;
		ucmd->sidemove = 0;

		// starting a jump
		if( ( linkType & LINK_JUMP ) )
		{
			if( self->groundentity )
			{
				trace_t trace;
				vec3_t v1, v2;

				if( nav.debugMode && printLink )
					G_PrintChasersf( self, "LINK_JUMP\n" );

				//check floor in front, if there's none... Jump!
				VectorCopy( self->s.origin, v1 );
				VectorNormalize2( self->ai->move_vector, v2 );
				VectorMA( v1, 18, v2, v1 );
				v1[2] += self->r.mins[2];
				VectorCopy( v1, v2 );
				v2[2] -= AI_JUMPABLE_HEIGHT;
				G_Trace( &trace, v1, vec3_origin, vec3_origin, v2, self, MASK_AISOLID );
				if( !trace.startsolid && trace.fraction == 1.0 )
				{
					//jump!

					// prevent double jumping on crates
					VectorCopy( self->s.origin, v1 );
					v1[2] += self->r.mins[2];
					G_Trace( &trace, v1, tv( -12, -12, -8 ), tv( 12, 12, 0 ), v1, self, MASK_AISOLID );
					if( trace.startsolid )
						ucmd->upmove = 1;
				}
			}

			nodeReached = AI_NodeReached_Generic( self );
		}
		// starting a rocket jump
		else if( ( linkType & LINK_ROCKETJUMP ) )
		{
			if( nav.debugMode && printLink )
				G_PrintChasersf( self, "LINK_ROCKETJUMP\n" );

			if( !self->ai->rj_triggered && self->groundentity && ( self->s.weapon == WEAP_ROCKETLAUNCHER ) )
			{
				self->s.angles[PITCH] = 170;
				ucmd->upmove = 1;
				ucmd->buttons |= BUTTON_ATTACK;
				self->ai->rj_triggered = true;
			}

			nodeReached = AI_NodeReached_Generic( self );
		}
		else
		{
			// Move To Short Range goal (not following paths)
			// plats, grapple, etc have higher priority than SR Goals, cause the bot will
			// drop from them and have to repeat the process from the beginning
			if( AI_MoveToShortRangeGoalEntity( self, ucmd ) )
			{
				nodeReached = AI_NodeReached_Generic( self );
			}
			else if( specialMovement && !self->is_swim ) // bunny-hopping movement here
			{
				BOT_DMclass_SpecialMove( self, lookdir, pathdir, ucmd );
				nodeReached = AI_NodeReached_Special( self );
			}
			else
			{
				nodeReached = AI_NodeReached_Generic( self );
			}
		}

		// if static assume blocked and try to get free
		if( VectorLengthFast( self->velocity ) < 37 && ( ucmd->forwardmove || ucmd->sidemove || ucmd->upmove ) )
		{
			if( random() > 0.1 && AI_SpecialMove( self, ucmd ) )  // jumps, crouches, turns...
				return;

			self->s.angles[YAW] += brandom( -90, 90 );
		}
	}

	// swimming
	if( self->is_swim )
	{
		if( !( G_PointContents( nodes[self->ai->next_node].origin ) & MASK_WATER ) )  // Exit water
			ucmd->upmove = 1;
	}

	AI_ChangeAngle( self );

	if( nodeReached )
		AI_NodeReached( self );

#undef BOT_FORWARD_EPSILON
}
void BOT_DMclass_SpecialMove( edict_t *self, vec3_t lookdir, vec3_t pathdir, usercmd_t *ucmd )
{
	bool wallJump = false;
	bool dash = true;
	bool bunnyhop = true;
	trace_t trace;
	vec3_t end;
	int n1, n2, nextMoveType;

	self->ai->is_bunnyhop = false;

	if( self->ai->path.numNodes < MIN_BUNNY_NODES )
		return;

	// verify that the 2nd node is in front of us for dashing
	n1 = self->ai->path.nodes[self->ai->path.numNodes];
	n2 = self->ai->path.nodes[self->ai->path.numNodes-1];

	if( !AI_infront2D( lookdir, self->s.origin, nodes[n2].origin, 0.5 ) )
		bunnyhop = false;

	// do not dash if the next link will be a fall, jump or 
	// any other kind of special link
	nextMoveType = AI_PlinkMoveType( n1, n2 );
	if( nextMoveType & (LINK_LADDER|LINK_PLATFORM|LINK_ROCKETJUMP|LINK_FALL|LINK_JUMP|LINK_CROUCH) )
		dash = false;

	if( nextMoveType &(LINK_LADDER|LINK_PLATFORM|LINK_FALL|LINK_CROUCH) )
		bunnyhop = false;
#if 0
	if( VectorLengthFast( self->velocity ) < AI_JUMP_SPEED )
	{
		if( dash && self->groundentity ) // attempt dash
		{
			if( DotProduct( lookdir, pathdir ) > 0.9 )
			{
				// do not dash unless both next nodes are visible
				if( AI_ReachabilityVisible( self, nodes[n1].origin ) &&
					AI_ReachabilityVisible( self, nodes[n2].origin ) )
				{
					ucmd->buttons |= BUTTON_SPECIAL;
					ucmd->sidemove = 0;
					ucmd->forwardmove = 1;
					self->ai->is_bunnyhop = true;
				}
			}
		}
	}
	else 
#endif
	if( bunnyhop && ( (nextMoveType &LINK_JUMP) || level.gametype.spawnableItemsMask == 0 ) )
	{
		if( self->groundentity )
			ucmd->upmove = 1;

#if 0
		// fake strafe-jumping acceleration
		if( VectorLengthFast( self->velocity ) < 700 && DotProduct( lookdir, pathdir ) > 0.6 )
			VectorMA( self->velocity, 0.1f, lookdir, self->velocity );
#endif
		self->ai->is_bunnyhop = true;
	}

	if( wallJump )
	{
		if( self->ai->move_vector[2] > 25 && DotProduct( self->velocity, pathdir ) < -0.2 )
		{
			VectorMA( self->s.origin, 0.02, self->velocity, end );
			G_Trace( &trace, self->s.origin, self->r.mins, self->r.maxs, end, self, MASK_AISOLID );

			if( trace.fraction != 1.0f )
				ucmd->buttons |= BUTTON_SPECIAL;
		}
	}

	// if pushing in the opposite direction of the path, reduce the push
	if( DotProduct( lookdir, pathdir ) < -0.33f )
		ucmd->forwardmove = 0;
}
Beispiel #9
0
static void old_teleporter_touch( edict_t *self, edict_t *other, cplane_t *plane, int surfFlags )
{
	edict_t	*dest;
	int i;
	vec3_t velocity, angles;
	mat3_t axis;
	float speed;
	vec3_t org;

	if( !other->r.client )
		return;
	if( self->s.team && self->s.team != other->s.team )
		return;
	if( other->r.client->ps.pmove.pm_type > PM_SPECTATOR )
		return;
	if( self->spawnflags & 1 && other->r.client->ps.pmove.pm_type != PM_SPECTATOR )
		return;

	// match countdown
	if( GS_MatchState() == MATCH_STATE_COUNTDOWN )
		return;

	// wait delay
	if( self->timeStamp > level.time )
		return;

	self->timeStamp = level.time + ( self->wait * 1000 );

	dest = G_Find( NULL, FOFS( targetname ), self->target );
	if( !dest )
	{
		if( developer->integer )
			G_Printf( "Couldn't find destination.\n" );
		return;
	}

	if( self->s.modelindex )
	{
		org[0] = self->s.origin[0] + 0.5 * ( self->r.mins[0] + self->r.maxs[0] );
		org[1] = self->s.origin[1] + 0.5 * ( self->r.mins[1] + self->r.maxs[1] );
		org[2] = self->s.origin[2] + 0.5 * ( self->r.mins[2] + self->r.maxs[2] );
	}
	else
		VectorCopy( self->s.origin, org );

	// play custom sound if any (played from the teleporter entrance)
	if( self->noise_index )
		G_PositionedSound( org, CHAN_AUTO, self->noise_index, ATTN_NORM );

	// draw the teleport entering effect
	G_TeleportEffect( other, false );

	//
	// teleport the player
	//

	VectorCopy( other->r.client->ps.pmove.velocity, velocity );

	velocity[2] = 0; // ignore vertical velocity
	speed = VectorLengthFast( velocity );

	// if someone enters a portal backwards, inverse the destination YAW angle
#if 0
	VectorCopy( other->s.angles, angles );
	angles[PITCH] = 0;
	AngleVectors( angles, axis[0], NULL, NULL );
	VectorSubtract( org, other->s.origin, org );

	VectorCopy( dest->s.angles, angles );
	if( DotProduct( org, axis[0] ) < 0 )
		angles[YAW] = anglemod( angles[YAW] - 180 );
#else
	VectorCopy( dest->s.angles, angles );
#endif

	AnglesToAxis( dest->s.angles, axis );
	VectorScale( &axis[AXIS_FORWARD], speed, other->r.client->ps.pmove.velocity );

	VectorCopy( angles, other->r.client->ps.viewangles );
	VectorCopy( dest->s.origin, other->r.client->ps.pmove.origin );

	// set the delta angle
	for( i = 0; i < 3; i++ )
		other->r.client->ps.pmove.delta_angles[i] = ANGLE2SHORT( other->r.client->ps.viewangles[i] ) - other->r.client->ucmd.angles[i];

	other->r.client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
	other->s.teleported = qtrue;
	other->r.client->ps.pmove.pm_time = 1; // force the minimum no control delay

	// update the entity from the pmove
	VectorCopy( other->r.client->ps.viewangles, other->s.angles );
	VectorCopy( other->r.client->ps.pmove.origin, other->s.origin );
	VectorCopy( other->r.client->ps.pmove.origin, other->s.old_origin );
	VectorCopy( other->r.client->ps.pmove.origin, other->olds.origin );
	VectorCopy( other->r.client->ps.pmove.velocity, other->velocity );

	// unlink to make sure it can't possibly interfere with KillBox
	GClip_UnlinkEntity( other );

	// kill anything at the destination
	if( !KillBox( other ) )
	{
	}

	GClip_LinkEntity( other );

	// add the teleport effect at the destination
	G_TeleportEffect( other, true );
}