示例#1
0
/*
* AI_FlagsForNode
* check the world and set up node flags
*/
int AI_FlagsForNode( vec3_t origin, edict_t *passent )
{
	trace_t	trace;
	int flagsmask = 0;
	int contents;

	contents = G_PointContents( origin );
	//water
	if( contents & MASK_WATER )
		flagsmask |= NODEFLAGS_WATER;

	if( contents & CONTENTS_DONOTENTER )
		flagsmask |= NODEFLAGS_DONOTENTER;

	//floor
	G_Trace( &trace, origin, tv( -15, -15, 0 ), tv( 15, 15, 0 ), tv( origin[0], origin[1], origin[2] - AI_JUMPABLE_HEIGHT ), passent, MASK_NODESOLID );
	if( trace.fraction < 1.0 )
		flagsmask &= ~NODEFLAGS_FLOAT; //ok, it wasn't set, I know...
	else
		flagsmask |= NODEFLAGS_FLOAT;

	//ladder
	//	G_Trace( &trace, origin, tv(-18, -18, -16), tv(18, 18, 16), origin, passent, MASK_ALL );
	//	if( trace.startsolid && trace.contents & CONTENTS_LADDER )
	//		flagsmask |= NODEFLAGS_LADDER;

	return flagsmask;
}
示例#2
0
//==========================================
// BOT_DMclass_PredictProjectileShot
// predict target movement
//==========================================
static void BOT_DMclass_PredictProjectileShot( edict_t *self, vec3_t fire_origin, float projectile_speed, vec3_t target, vec3_t target_velocity )
{
	vec3_t predictedTarget;
	vec3_t targetMovedir;
	float targetSpeed;
	float predictionTime;
	float distance;
	trace_t	trace;
	int contents;

	if( projectile_speed <= 0.0f )
		return;

	targetSpeed = VectorNormalize2( target_velocity, targetMovedir );

	// ok, this is not going to be 100% precise, since we will find the
	// time our projectile will take to travel to enemy's CURRENT position,
	// and them find enemy's position given his CURRENT velocity and his CURRENT dir
	// after prediction time. The result will be much better if the player
	// is moving to the sides (relative to us) than in depth (relative to us).
	// And, of course, when the player moves in a curve upwards it will totally miss (ie, jumping).

	// but in general it does a great job, much better than any human player :)

	distance = DistanceFast( fire_origin, target );
	predictionTime = distance/projectile_speed;
	VectorMA( target, predictionTime*targetSpeed, targetMovedir, predictedTarget );

	// if this position is inside solid, try finding a position at half of the prediction time
	contents = G_PointContents( predictedTarget );
	if( contents & CONTENTS_SOLID && !( contents & CONTENTS_PLAYERCLIP ) )
	{
		VectorMA( target, ( predictionTime * 0.5f )*targetSpeed, targetMovedir, predictedTarget );
		contents = G_PointContents( predictedTarget );
		if( contents & CONTENTS_SOLID && !( contents & CONTENTS_PLAYERCLIP ) )
			return; // INVALID
	}

	// if we can see this point, we use it, otherwise we keep the current position
	G_Trace( &trace, fire_origin, vec3_origin, vec3_origin, predictedTarget, self, MASK_SHOT );
	if( trace.fraction == 1.0f || ( trace.ent && game.edicts[trace.ent].takedamage ) )
		VectorCopy( predictedTarget, target );
}
示例#3
0
void ThrowSmallPileOfGibs( edict_t *self, int damage )
{
	vec3_t origin;
	edict_t	*event;
	int contents;
	int i;

	contents = G_PointContents( self->s.origin );
	if( contents & CONTENTS_NODROP )
		return;

	for( i = 0; i < 3; i++ )
		origin[i] = self->s.origin[i] + ( 0.5f * ( self->r.maxs[i] + self->r.mins[i] ) ) + 24;

	event = G_SpawnEvent( EV_SPOG, damage, origin );
	event->r.svflags |= SVF_TRANSMITORIGIN2;
	VectorCopy( self->velocity, event->s.origin2 );
}
示例#4
0
void G_Gametype_GENERIC_PlayerKilled( edict_t *targ, edict_t *attacker, edict_t *inflictor )
{
	if( !attacker || GS_MatchState() != MATCH_STATE_PLAYTIME || ( targ->r.svflags & SVF_CORPSE ) )
		return;

	if( !attacker->r.client || attacker == targ || attacker == world )
		teamlist[targ->s.team].stats.score--;
	else
	{
		if( GS_InvidualGameType() )
			teamlist[attacker->s.team].stats.score = attacker->r.client->level.stats.score;
		if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
			teamlist[attacker->s.team].stats.score--;
		else
			teamlist[attacker->s.team].stats.score++;
	}

	// drop items
	if( targ->r.client && !( G_PointContents( targ->s.origin ) & CONTENTS_NODROP ) )
	{
		// drop the weapon
		if ( targ->r.client->ps.stats[STAT_WEAPON] > WEAP_GUNBLADE )
		{
			gsitem_t *weaponItem = GS_FindItemByTag( targ->r.client->ps.stats[STAT_WEAPON] );
			if( weaponItem )
			{
				edict_t *drop = Drop_Item( targ, weaponItem );
				if( drop )
				{
					drop->count = targ->r.client->ps.inventory[ weaponItem->weakammo_tag ];
					targ->r.client->ps.inventory[ weaponItem->weakammo_tag ] = 0;
				}
			}
		}

		// drop ammo pack (won't drop anything if player doesn't have any strong ammo)
		Drop_Item( targ, GS_FindItemByTag( AMMO_PACK ) );
	}
}
示例#5
0
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;
}
示例#6
0
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
}
示例#7
0
文件: g_phys.cpp 项目: Picmip/qfusion
/*
* SV_Physics_Toss
*
* Toss, bounce, and fly movement.  When onground, do nothing.
*
* FIXME: This function needs a serious rewrite
*/
static void SV_Physics_Toss( edict_t *ent ) {
	trace_t trace;
	vec3_t move;
	float backoff;
	edict_t *slave;
	bool wasinwater;
	bool isinwater;
	vec3_t old_origin;
	float oldSpeed;

	// if not a team captain, so movement will be handled elsewhere
	if( ent->flags & FL_TEAMSLAVE ) {
		return;
	}

	// refresh the ground entity
	if( ent->movetype == MOVETYPE_BOUNCE || ent->movetype == MOVETYPE_BOUNCEGRENADE ) {
		if( ent->velocity[2] > 0.1f ) {
			ent->groundentity = NULL;
		}
	}

	if( ent->groundentity && ent->groundentity != world && !ent->groundentity->r.inuse ) {
		ent->groundentity = NULL;
	}

	oldSpeed = VectorLength( ent->velocity );

	if( ent->groundentity ) {
		if( !oldSpeed ) {
			return;
		}

		if( ent->movetype == MOVETYPE_TOSS ) {
			if( ent->velocity[2] >= 8 ) {
				ent->groundentity = NULL;
			} else {
				VectorClear( ent->velocity );
				VectorClear( ent->avelocity );
				G_CallStop( ent );
				return;
			}
		}
	}

	VectorCopy( ent->s.origin, old_origin );

	if( ent->accel != 0 ) {
		if( ent->accel < 0 && VectorLength( ent->velocity ) < 50 ) {
			VectorClear( ent->velocity );
		} else {
			vec3_t acceldir;
			VectorNormalize2( ent->velocity, acceldir );
			VectorScale( acceldir, ent->accel * FRAMETIME, acceldir );
			VectorAdd( ent->velocity, acceldir, ent->velocity );
		}
	}

	SV_CheckVelocity( ent );

	// add gravity
	if( ent->movetype != MOVETYPE_FLY && !ent->groundentity ) {
		SV_AddGravity( ent );
	}

	// move angles
	VectorMA( ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles );

	// move origin
	VectorScale( ent->velocity, FRAMETIME, move );

	trace = SV_PushEntity( ent, move );
	if( !ent->r.inuse ) {
		return;
	}

	if( trace.fraction < 1.0f ) {
		if( ent->movetype == MOVETYPE_BOUNCE ) {
			backoff = 1.5;
		} else if( ent->movetype == MOVETYPE_BOUNCEGRENADE ) {
			backoff = 1.5;
		} else {
			backoff = 1;
		}

		GS_ClipVelocity( ent->velocity, trace.plane.normal, ent->velocity, backoff );

		// stop if on ground

		if( ent->movetype == MOVETYPE_BOUNCE || ent->movetype == MOVETYPE_BOUNCEGRENADE ) {
			// stop dead on allsolid

			// LA: hopefully will fix grenades bouncing down slopes
			// method taken from Darkplaces sourcecode
			if( trace.allsolid ||
				( ISWALKABLEPLANE( &trace.plane ) &&
				  fabs( DotProduct( trace.plane.normal, ent->velocity ) ) < 40
				)
				) {
				ent->groundentity = &game.edicts[trace.ent];
				ent->groundentity_linkcount = ent->groundentity->linkcount;
				VectorClear( ent->velocity );
				VectorClear( ent->avelocity );
				G_CallStop( ent );
			}
		} else {
			// in movetype_toss things stop dead when touching ground
#if 0
			G_CheckGround( ent );

			if( ent->groundentity ) {
#else

			// walkable or trapped inside solid brush
			if( trace.allsolid || ISWALKABLEPLANE( &trace.plane ) ) {
				ent->groundentity = trace.ent < 0 ? world : &game.edicts[trace.ent];
				ent->groundentity_linkcount = ent->groundentity->linkcount;
#endif
				VectorClear( ent->velocity );
				VectorClear( ent->avelocity );
				G_CallStop( ent );
			}
		}
	}

	// check for water transition
	wasinwater = ( ent->watertype & MASK_WATER ) ? true : false;
	ent->watertype = G_PointContents( ent->s.origin );
	isinwater = ent->watertype & MASK_WATER ? true : false;

	// never allow items in CONTENTS_NODROP
	if( ent->item && ( ent->watertype & CONTENTS_NODROP ) ) {
		G_FreeEdict( ent );
		return;
	}

	if( isinwater ) {
		ent->waterlevel = 1;
	} else {
		ent->waterlevel = 0;
	}

	if( !wasinwater && isinwater ) {
		G_PositionedSound( old_origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE );
	} else if( wasinwater && !isinwater ) {
		G_PositionedSound( ent->s.origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE );
	}

	// move teamslaves
	for( slave = ent->teamchain; slave; slave = slave->teamchain ) {
		VectorCopy( ent->s.origin, slave->s.origin );
		GClip_LinkEntity( slave );
	}
}

//============================================================================

void SV_Physics_LinearProjectile( edict_t *ent ) {
	vec3_t start, end;
	int mask;
	float startFlyTime, endFlyTime;
	trace_t trace;
	int old_waterLevel;

	// if not a team captain movement will be handled elsewhere
	if( ent->flags & FL_TEAMSLAVE ) {
		return;
	}

	old_waterLevel = ent->waterlevel;

	mask = ( ent->r.clipmask ) ? ent->r.clipmask : MASK_SOLID;

	// find it's current position given the starting timeStamp
	startFlyTime = (float)( max( game.prevServerTime - ent->s.linearMovementTimeStamp, 0 ) ) * 0.001f;
	endFlyTime = (float)( game.serverTime - ent->s.linearMovementTimeStamp ) * 0.001f;

	VectorMA( ent->s.linearMovementBegin, startFlyTime, ent->s.linearMovementVelocity, start );
	VectorMA( ent->s.linearMovementBegin, endFlyTime, ent->s.linearMovementVelocity, end );

	G_Trace4D( &trace, start, ent->r.mins, ent->r.maxs, end, ent, mask, ent->timeDelta );
	VectorCopy( trace.endpos, ent->s.origin );
	GClip_LinkEntity( ent );
	SV_Impact( ent, &trace );

	if( !ent->r.inuse ) { // the projectile may be freed if touched something
		return;
	}

	// update some data required for the transmission
	//VectorCopy( ent->velocity, ent->s.linearMovementVelocity );

	GClip_TouchTriggers( ent );
	ent->groundentity = NULL; // projectiles never have ground entity
	ent->waterlevel = ( G_PointContents4D( ent->s.origin, ent->timeDelta ) & MASK_WATER ) ? true : false;

	if( !old_waterLevel && ent->waterlevel ) {
		G_PositionedSound( start, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE );
	} else if( old_waterLevel && !ent->waterlevel ) {
		G_PositionedSound( ent->s.origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE );
	}
}
示例#8
0
/*
* CopyToBodyQue
*/
static edict_t *CopyToBodyQue( edict_t *ent, edict_t *attacker, int damage )
{
	edict_t	*body;
	int contents;

	if( GS_RaceGametype() )
		return NULL;

	contents = G_PointContents( ent->s.origin );
	if( contents & CONTENTS_NODROP )
		return NULL;

	G_Client_UnlinkBodies( ent );

	// grab a body que and cycle to the next one
	body = &game.edicts[gs.maxclients + level.body_que + 1];
	level.body_que = ( level.body_que + 1 ) % BODY_QUEUE_SIZE;

	// send an effect on the removed body
	if( body->s.modelindex && body->s.type == ET_CORPSE )
		ThrowSmallPileOfGibs( body, 10 );

	GClip_UnlinkEntity( body );

	memset( body, 0, sizeof( edict_t ) ); //clean up garbage

	//init body edict
	G_InitEdict( body );
	body->classname = "body";
	body->health = ent->health;
	body->mass = ent->mass;
	body->r.owner = ent->r.owner;
	body->s.type = ent->s.type;
	body->s.team = ent->s.team;
	body->s.effects = 0;
	body->r.svflags = SVF_CORPSE;
	body->r.svflags &= ~SVF_NOCLIENT;
	body->activator = ent;
	if( g_deadbody_followkiller->integer )
		body->enemy = attacker;

	//use flat yaw
	body->s.angles[PITCH] = 0;
	body->s.angles[ROLL] = 0;
	body->s.angles[YAW] = ent->s.angles[YAW];
	body->s.modelindex2 = 0; // <-  is bodyOwner when in ET_CORPSE, but not in ET_GENERIC or ET_PLAYER
	body->s.weapon = 0;

	//copy player position and box size
	VectorCopy( ent->s.old_origin, body->s.old_origin );
	VectorCopy( ent->s.origin, body->s.origin );
	VectorCopy( ent->s.origin, body->olds.origin );
	VectorCopy( ent->r.mins, body->r.mins );
	VectorCopy( ent->r.maxs, body->r.maxs );
	VectorCopy( ent->r.absmin, body->r.absmin );
	VectorCopy( ent->r.absmax, body->r.absmax );
	VectorCopy( ent->r.size, body->r.size );
	VectorCopy( ent->velocity, body->velocity );
	body->r.maxs[2] = body->r.mins[2] + 8;

	body->r.solid = SOLID_YES;
	body->takedamage = DAMAGE_YES;
	body->r.clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
	body->movetype = MOVETYPE_TOSS;
	body->die = body_die;
	body->think = body_think; // body self destruction countdown

	if( ent->health < GIB_HEALTH
		|| meansOfDeath == MOD_ELECTROBOLT_S /* electrobolt always gibs */ )
	{
		ThrowSmallPileOfGibs( body, damage );

		// reset gib impulse
		VectorClear( body->velocity );
		ThrowClientHead( body, damage ); // sets ET_GIB

		body->s.frame = 0;
		body->nextThink = level.time + 3000 + random() * 3000;
		body->deadflag = DEAD_DEAD;
	}
	else if( ent->s.type == ET_PLAYER )
	{
		// copy the model
		body->s.type = ET_CORPSE;
		body->s.modelindex = ent->s.modelindex;
		body->s.bodyOwner = ent->s.number; // bodyOwner is the same as modelindex2
		body->s.skinnum = ent->s.skinnum;
		body->s.teleported = true;

		// launch the death animation on the body
		{
			static int i;
			i = ( i+1 )%3;
			G_AddEvent( body, EV_DIE, i, true );
			switch( i )
			{
			default:
			case 0:
				body->s.frame = ( ( BOTH_DEAD1&0x3F )|( BOTH_DEAD1&0x3F )<<6|( 0 &0xF )<<12 );
				break;
			case 1:
				body->s.frame = ( ( BOTH_DEAD2&0x3F )|( BOTH_DEAD2&0x3F )<<6|( 0 &0xF )<<12 );
				break;
			case 2:
				body->s.frame = ( ( BOTH_DEAD3&0x3F )|( BOTH_DEAD3&0x3F )<<6|( 0 &0xF )<<12 );
				break;
			}
		}

		body->think = body_ready;
		body->takedamage = DAMAGE_NO;
		body->r.solid = SOLID_NOT;
		body->nextThink = level.time + 500; // make damageable in 0.5 seconds
	}
	else // wasn't a player, just copy it's model
	{
		VectorClear( body->velocity );
		body->s.modelindex = ent->s.modelindex;
		body->s.frame = ent->s.frame;
		body->nextThink = level.time + 5000 + random()*10000;
	}

	GClip_LinkEntity( body );
	return body;
}