Beispiel #1
0
/*
* CG_AddLocalEntities
*/
void CG_AddLocalEntities( void )
{
#define FADEINFRAMES 2
	int f;
	lentity_t *le, *next, *hnode;
	entity_t *ent;
	float scale, frac, fade, time, scaleIn, fadeIn;
	float backlerp;
	vec3_t angles;

	time = cg.frameTime;
	backlerp = 1.0f - cg.lerpfrac;

	hnode = &cg_localents_headnode;
	for( le = hnode->next; le != hnode; le = next )
	{
		next = le->next;

		frac = ( cg.time - le->start ) * 0.01f;
		f = ( int )floor( frac );
		clamp_low( f, 0 );

		// it's time to DIE
		if( f >= le->frames - 1 )
		{
			le->type = LE_FREE;
			CG_FreeLocalEntity( le );
			continue;
		}

		if( le->frames > 1 )
		{
			scale = 1.0f - frac / ( le->frames - 1 );
			scale = bound( 0.0f, scale, 1.0f );
			fade = scale * 255.0f;

			// quick fade in, if time enough
			if( le->frames > FADEINFRAMES * 2 )
			{
				scaleIn = frac / (float)FADEINFRAMES;
				clamp( scaleIn, 0.0f, 1.0f );
				fadeIn = scaleIn * 255.0f;
			}
			else
				fadeIn = 255.0f;
		}
		else
		{
			scale = 1.0f;
			fade = 255.0f;
			fadeIn = 255.0f;
		}

		ent = &le->ent;

		if( le->light && scale )
			CG_AddLightToScene( ent->origin, le->light * scale, le->lightcolor[0], le->lightcolor[1], le->lightcolor[2] );

		if( le->type == LE_LASER )
		{
			CG_QuickPolyBeam( ent->origin, ent->origin2, ent->radius, ent->customShader ); // wsw : jalfixme: missing the color (comes inside ent->skinnum)
			continue;
		}

		if( le->type == LE_DASH_SCALE )
		{
			if( f < 1 ) ent->scale = 0.15 * frac;
			else
			{
				VecToAngles( &ent->axis[AXIS_RIGHT], angles );
				ent->axis[1*3+1] += 0.005f *sin( DEG2RAD ( angles[YAW] ) ); //length
				ent->axis[1*3+0] += 0.005f *cos( DEG2RAD ( angles[YAW] ) ); //length
				ent->axis[0*3+1] += 0.008f *cos( DEG2RAD ( angles[YAW] ) ); //width
				ent->axis[0*3+0] -= 0.008f *sin( DEG2RAD ( angles[YAW] ) ); //width
				ent->axis[2*3+2] -= 0.052f;              //height

				if( ent->axis[AXIS_UP+2] <= 0 )
				{
					le->type = LE_FREE;
					CG_FreeLocalEntity( le );
				}
			}
		}
		if( le->type == LE_PUFF_SCALE )
		{
			if( le->frames - f < 4 )
				ent->scale = 1.0f - 1.0f * ( frac - abs( 4-le->frames ) )/4;
		}
		if( le->type == LE_PUFF_SHRINK )
		{
			if( frac < 3 )
				ent->scale = 1.0f - 0.2f * frac/4;
			else
			{
				ent->scale = 0.8 - 0.8*( frac-3 )/3;
				VectorScale( le->velocity, 0.85f, le->velocity );
			}
		}

		if( le->type == LE_EXPLOSION_TRACER )
		{
			if( cg.time - ent->rotation > 10.0f )
			{
				ent->rotation = cg.time;
				if( ent->radius - 16*frac > 4 )
					CG_Explosion_Puff( ent->origin, ent->radius-16*frac, le->frames - f );
			}
		}

		switch( le->type )
		{
		case LE_NO_FADE:
			break;
		case LE_RGB_FADE:
			fade = min( fade, fadeIn );
			ent->shaderRGBA[0] = ( uint8_t )( fade * le->color[0] );
			ent->shaderRGBA[1] = ( uint8_t )( fade * le->color[1] );
			ent->shaderRGBA[2] = ( uint8_t )( fade * le->color[2] );
			break;
		case LE_SCALE_ALPHA_FADE:
			fade = min( fade, fadeIn );
			ent->scale = 1.0f + 1.0f / scale;
			ent->scale = min( ent->scale, 5.0f );
			ent->shaderRGBA[3] = ( uint8_t )( fade * le->color[3] );
			break;
		case LE_INVERSESCALE_ALPHA_FADE:
			fade = min( fade, fadeIn );
			ent->scale = scale + 0.1f;
			clamp( ent->scale, 0.1f, 1.0f );
			ent->shaderRGBA[3] = ( uint8_t )( fade * le->color[3] );
			break;
		case LE_ALPHA_FADE:
			fade = min( fade, fadeIn );
			ent->shaderRGBA[3] = ( uint8_t )( fade * le->color[3] );
			break;
		default:
			break;
		}

		ent->backlerp = backlerp;

		if ( le->avelocity[0] || le->avelocity[1] || le->avelocity[2] ) {
			VectorMA( le->angles, time, le->avelocity, le->angles );
			AnglesToAxis( le->angles, le->ent.axis );
		}

		// apply rotational friction
		if( le->bounce ) { // FIXME?
			int i;
			const float adj = 100 * 6 * time; // magic constants here

			for( i = 0; i < 3; i++ ) {
				if( le->avelocity[i] > 0.0f ) {
					le->avelocity[i] -= adj;
					if( le->avelocity[i] < 0.0f ) {
						le->avelocity[i] = 0.0f;
					}
				}
				else if ( le->avelocity[i] < 0.0f ) {
					le->avelocity[i] += adj;
					if ( le->avelocity[i] > 0.0f ) {
						le->avelocity[i] = 0.0f;
					}
				}
			}
		}

		if( le->bounce )
		{
			trace_t	trace;
			vec3_t next_origin;

			VectorMA( ent->origin, time, le->velocity, next_origin );

			CG_Trace( &trace, ent->origin, debris_mins, debris_maxs, next_origin, 0, MASK_SOLID );

			// remove the particle when going out of the map
			if( ( trace.contents & CONTENTS_NODROP ) || ( trace.surfFlags & SURF_SKY ) )
			{
				le->frames = 0;
			}
			else if( trace.fraction != 1.0 ) // found solid
			{
				float dot;
				float xyzspeed, orig_xyzspeed;
				float bounce;
				
				orig_xyzspeed = VectorLength( le->velocity );

				// Reflect velocity
				dot = DotProduct( le->velocity, trace.plane.normal );
				VectorMA( le->velocity, -2.0f * dot, trace.plane.normal, le->velocity );
				//put new origin in the impact point, but move it out a bit along the normal
				VectorMA( trace.endpos, 1, trace.plane.normal, ent->origin );

				// make sure we don't gain speed from bouncing off
				bounce = 2.0f * le->bounce * 0.01f;
				if( bounce < 1.5f )
					bounce = 1.5f;
				xyzspeed = orig_xyzspeed / bounce;

				VectorNormalize( le->velocity );
				VectorScale( le->velocity, xyzspeed, le->velocity );
	
				//the entity has not speed enough. Stop checks
				if( xyzspeed * time < 1.0f )
				{
					trace_t traceground;
					vec3_t ground_origin;
					//see if we have ground
					VectorCopy( ent->origin, ground_origin );
					ground_origin[2] += ( debris_mins[2] - 4 );
					CG_Trace( &traceground, ent->origin, debris_mins, debris_maxs, ground_origin, 0, MASK_SOLID );
					if( traceground.fraction != 1.0 )
					{
						le->bounce = 0;
						VectorClear( le->velocity );
						VectorClear( le->accel );
						VectorClear( le->avelocity );
						if( le->type == LE_EXPLOSION_TRACER )
						{
							// blx
							le->type = LE_FREE;
							CG_FreeLocalEntity( le );
						}
					}
				}

			}
			else
			{
				VectorCopy( ent->origin, ent->origin2 );
				VectorCopy( next_origin, ent->origin );
			}
		}
		else
		{
			VectorCopy( ent->origin, ent->origin2 );
			VectorMA( ent->origin, time, le->velocity, ent->origin );
		}

		VectorCopy( ent->origin, ent->lightingOrigin );
		VectorMA( le->velocity, time, le->accel, le->velocity );

		CG_AddEntityToScene( ent );
	}
}
Beispiel #2
0
// RAFAEL
void Trap_Think (edict_t *ent)
{
	edict_t	*target = NULL;
	edict_t	*best = NULL;
	vec3_t	vec;
	int		len, i;
	int		oldlen = 8000;
	vec3_t	forward, right, up;

	if (!ent)
	{
		return;
	}

	if (ent->timestamp < level.time)
	{
		BecomeExplosion1(ent);
		return;
	}

	ent->nextthink = level.time + 0.1;

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

	/* ok lets do the blood effect */
	if (ent->s.frame > 4)
	{
		if (ent->s.frame == 5)
		{
			if (ent->wait == 64)
			{
				gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/trapdown.wav"),
					   	1, ATTN_IDLE, 0);
			}

			ent->wait -= 2;
			ent->delay += level.time;

			for (i = 0; i < 3; i++)
			{
				best = G_Spawn();

				if (strcmp(ent->enemy->classname, "monster_gekk") == 0)
				{
					best->s.modelindex = gi.modelindex("models/objects/gekkgib/torso/tris.md2");
					best->s.effects |= TE_GREENBLOOD;
				}
				else if (ent->mass > 200)
				{
					best->s.modelindex = gi.modelindex("models/objects/gibs/chest/tris.md2");
					best->s.effects |= TE_BLOOD;
				}
				else
				{
					best->s.modelindex = gi.modelindex("models/objects/gibs/sm_meat/tris.md2");
					best->s.effects |= TE_BLOOD;
				}

				AngleVectors(ent->s.angles, forward, right, up);

				RotatePointAroundVector(vec, up, right, ((360.0 / 3) * i) + ent->delay);
				VectorMA(vec, ent->wait / 2, vec, vec);
				VectorAdd(vec, ent->s.origin, vec);
				VectorAdd(vec, forward, best->s.origin);

				best->s.origin[2] = ent->s.origin[2] + ent->wait;

				VectorCopy(ent->s.angles, best->s.angles);

				best->solid = SOLID_NOT;
				best->s.effects |= EF_GIB;
				best->takedamage = DAMAGE_YES;

				best->movetype = MOVETYPE_TOSS;
				best->svflags |= SVF_MONSTER;
				best->deadflag = DEAD_DEAD;

				VectorClear(best->mins);
				VectorClear(best->maxs);

				best->watertype = gi.pointcontents(best->s.origin);

				if (best->watertype & MASK_WATER)
				{
					best->waterlevel = 1;
				}

				best->nextthink = level.time + 0.1;
				best->think = G_FreeEdict;
				gi.linkentity(best);
			}

			if (ent->wait < 19)
			{
				ent->s.frame++;
			}

			return;
		}

		ent->s.frame++;

		if (ent->s.frame == 8)
		{
			ent->nextthink = level.time + 1.0;
			ent->think = G_FreeEdict;

			best = G_Spawn();
			SP_item_foodcube(best);
			VectorCopy(ent->s.origin, best->s.origin);
			best->s.origin[2] += 16;
			best->velocity[2] = 400;
			best->count = ent->mass;
			gi.linkentity(best);
			return;
		}

		return;
	}

	ent->s.effects &= ~EF_TRAP;

	if (ent->s.frame >= 4)
	{
		ent->s.effects |= EF_TRAP;
		VectorClear(ent->mins);
		VectorClear(ent->maxs);
	}

	if (ent->s.frame < 4)
	{
		ent->s.frame++;
	}

	while ((target = findradius(target, ent->s.origin, 256)) != NULL)
	{
		if (target == ent)
		{
			continue;
		}

		if (!(target->svflags & SVF_MONSTER) && !target->client)
		{
			continue;
		}

		if (target->health <= 0)
		{
			continue;
		}

		if (!visible(ent, target))
		{
			continue;
		}

		if (!best)
		{
			best = target;
			continue;
		}

		VectorSubtract(ent->s.origin, target->s.origin, vec);
		len = VectorLength(vec);

		if (len < oldlen)
		{
			oldlen = len;
			best = target;
		}
	}

	/* pull the enemy in */
	if (best)
	{
		vec3_t forward;

		if (best->groundentity)
		{
			best->s.origin[2] += 1;
			best->groundentity = NULL;
		}

		VectorSubtract(ent->s.origin, best->s.origin, vec);
		len = VectorLength(vec);

		if (best->client)
		{
			VectorNormalize(vec);
			VectorMA(best->velocity, 250, vec, best->velocity);
		}
		else
		{
			best->ideal_yaw = vectoyaw(vec);
			M_ChangeYaw(best);
			AngleVectors(best->s.angles, forward, NULL, NULL);
			VectorScale(forward, 256, best->velocity);
		}

		gi.sound(ent, CHAN_VOICE, gi.soundindex(
						"weapons/trapsuck.wav"), 1, ATTN_IDLE, 0);

		if (len < 32)
		{
			if (best->mass < 400)
			{
				T_Damage(best, ent, ent->owner, vec3_origin, best->s.origin,
						vec3_origin, 100000, 1, 0, MOD_TRAP);
				ent->enemy = best;
				ent->wait = 64;
				VectorCopy(ent->s.origin, ent->s.old_origin);
				ent->timestamp = level.time + 30;

				if (deathmatch->value)
				{
					ent->mass = best->mass / 4;
				}
				else
				{
					ent->mass = best->mass / 10;
				}

				/* ok spawn the food cube */
				ent->s.frame = 5;
			}
			else
			{
				BecomeExplosion1(ent);
				return;
			}
		}
	}
}
int Pickup_Powerup( gentity_t *ent, gentity_t *other ) {
	int			quantity;
	int			i;
	gclient_t	*client;

	if ( !other->client->ps.powerups[ent->item->giTag] ) {
		// round timing to seconds to make multiple powerup timers
		// count in sync
		other->client->ps.powerups[ent->item->giTag] = 
			level.time - ( level.time % 1000 );
	}

	if ( ent->count ) {
		quantity = ent->count;
	} else {
		quantity = ent->item->quantity;
	}

	other->client->ps.powerups[ent->item->giTag] += quantity * 1000;

	// give any nearby players a "denied" anti-reward
	for ( i = 0 ; i < level.maxclients ; i++ ) {
		vec3_t		delta;
		float		len;
		vec3_t		forward;
		trace_t		tr;

		client = &level.clients[i];
		if ( client == other->client ) {
			continue;
		}
		if ( client->pers.connected == CON_DISCONNECTED ) {
			continue;
		}
		if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
			continue;
		}

    // if same team in team game, no sound
    // cannot use OnSameTeam as it expects to g_entities, not clients
  	if ( g_gametype.integer >= GT_TEAM && other->client->sess.sessionTeam == client->sess.sessionTeam  ) {
      continue;
    }

		// if too far away, no sound
		VectorSubtract( ent->s.pos.trBase, client->ps.origin, delta );
		len = VectorNormalize( delta );
		if ( len > 192 ) {
			continue;
		}

		// if not facing, no sound
		AngleVectors( client->ps.viewangles, forward, NULL, NULL );
		if ( DotProduct( delta, forward ) < 0.4 ) {
			continue;
		}

		// if not line of sight, no sound
		trap_Trace( &tr, client->ps.origin, NULL, NULL, ent->s.pos.trBase, ENTITYNUM_NONE, CONTENTS_SOLID );
		if ( tr.fraction != 1.0 ) {
			continue;
		}

		// anti-reward
		client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_DENIEDREWARD;
	}
	return RESPAWN_POWERUP;
}
//-----------------------------------------------------------------------------
// Purpose: This takes the current place the NPC's trying to get to, figures out
//			what keys to press to get the vehicle to go there, and then sends
//			them to the vehicle.
//-----------------------------------------------------------------------------
void CNPC_CraneDriver::DriveVehicle( void )
{
	// No targets?
	if ( !GetEnemy() && m_vecDesiredPosition == vec3_origin )
		return;

	Vector vecTarget = m_vecDesiredPosition;
	// Track our targets
	if ( m_hPickupTarget )
	{
		vecTarget = m_hPickupTarget->GetAbsOrigin();
	}
	else if ( !m_bForcedPickup && !m_bForcedDropoff && GetEnemy() )
	{
		vecTarget = GetEnemy()->GetAbsOrigin();
	}

	// Move the crane over the target
	// Use the crane type as a targeting point
	Vector vecCraneTip = m_hCrane->GetCraneTipPosition();
	Vector2D vecCraneTip2D( vecCraneTip.x, vecCraneTip.y );
	Vector2D vecTarget2D( vecTarget.x, vecTarget.y );
	Vector2D vecOrigin2D( m_hCrane->GetAbsOrigin().x, m_hCrane->GetAbsOrigin().y );

	if ( g_debug_vehicledriver.GetInt() )
	{
		NDebugOverlay::Box( vecTarget, -Vector(50,50,50), Vector(50,50,50), 0,255,0, true, 0.1 );
		NDebugOverlay::Box( vecCraneTip, -Vector(2,2,5000), Vector(2,2,5), 0,255,0, true, 0.1 );
		NDebugOverlay::Box( vecTarget, -Vector(2,2,5), Vector(2,2,5000), 0,255,0, true, 0.1 );
	}
	// Store off the distance to our target
	m_flDistanceToTarget = (vecTarget2D - vecCraneTip2D).Length();

	// First determine whether we need to extend / retract the arm
	float flDistToTarget = (vecOrigin2D - vecTarget2D).LengthSqr();
	float flDistToCurrent = (vecOrigin2D - vecCraneTip2D).LengthSqr();
	float flDelta = fabs(flDistToTarget - flDistToCurrent);
	// Slow down as we get closer, but do it based upon our current extension rate
	float flMinDelta = 50 + (50 * fabs(m_hCrane->GetExtensionRate() / CRANE_EXTENSION_RATE_MAX));
	flMinDelta *= flMinDelta;
	if ( flDelta > flMinDelta )
	{
		if ( flDistToCurrent > flDistToTarget )
		{
			// Retract
			m_pVehicleInterface->NPC_ThrottleReverse();
		}
		else if ( flDistToCurrent < flDistToTarget )
		{
			// Extend
			m_pVehicleInterface->NPC_ThrottleForward();
		}
	}
	else
	{
		m_pVehicleInterface->NPC_ThrottleCenter();
	}

	// Then figure out if we need to rotate. Do it all in 2D space.
	Vector vecRight, vecForward;
	m_hCrane->GetVectors( &vecForward, &vecRight, NULL );
	vecRight.z = 0;
	vecForward.z = 0;
	VectorNormalize( vecRight );
	VectorNormalize( vecForward );
	Vector vecToTarget = ( vecTarget - m_hCrane->GetAbsOrigin() );
	vecToTarget.z = 0;
	VectorNormalize( vecToTarget );
	float flDotRight = DotProduct( vecRight, vecToTarget );
	float flDotForward = DotProduct( vecForward, vecToTarget );

	// Start slowing if we're going to hit the point soon
	float flTurnInDeg = RAD2DEG( acos(flDotForward) );
	float flSpeed = m_hCrane->GetMaxTurnRate() * (flTurnInDeg / 15.0);
	flSpeed = min( m_hCrane->GetMaxTurnRate(), flSpeed );
	if ( fabs(flSpeed) < 0.05 )
	{
		// We're approaching the target, so stop turning
		m_pVehicleInterface->NPC_TurnCenter();
	}
	else
	{
		if ( flDotRight < 0 )
		{
			// Turn right
			m_pVehicleInterface->NPC_TurnRight( flSpeed );
		}
		else if ( flDotRight > 0 )
		{
			// Turn left
			m_pVehicleInterface->NPC_TurnLeft( flSpeed );
		}
	}
}
Beispiel #5
0
void bfg_think (edict_t *self)
{
	edict_t *ent;
	edict_t *ignore;
	vec3_t point;
	vec3_t dir;
	vec3_t start;
	vec3_t end;
	int dmg;
	trace_t tr;

	if (!self)
	{
		return;
	}

	if (deathmatch->value)
	{
		dmg = 5;
	}
	else
	{
		dmg = 10;
	}

	ent = NULL;

	while ((ent = findradius(ent, self->s.origin, 256)) != NULL)
	{
		if (ent == self)
		{
			continue;
		}

		if (ent == self->owner)
		{
			continue;
		}

		if (!ent->takedamage)
		{
			continue;
		}

		if (!(ent->svflags & SVF_MONSTER) && (!ent->client) &&
			(strcmp(ent->classname, "misc_explobox") != 0))
		{
			continue;
		}

		VectorMA(ent->absmin, 0.5, ent->size, point);

		VectorSubtract(point, self->s.origin, dir);
		VectorNormalize(dir);

		ignore = self;
		VectorCopy(self->s.origin, start);
		VectorMA(start, 2048, dir, end);

		while (1)
		{
			tr = gi.trace(start, NULL, NULL, end, ignore,
					CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_DEADMONSTER);

			if (!tr.ent)
			{
				break;
			}

			/* hurt it if we can */
			if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER) &&
				(tr.ent != self->owner))
			{
				T_Damage(tr.ent, self, self->owner, dir, tr.endpos,
						vec3_origin, dmg, 1, DAMAGE_ENERGY, MOD_BFG_LASER);
			}

			/* if we hit something that's not a monster or player we're done */
			if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
			{
				gi.WriteByte(svc_temp_entity);
				gi.WriteByte(TE_LASER_SPARKS);
				gi.WriteByte(4);
				gi.WritePosition(tr.endpos);
				gi.WriteDir(tr.plane.normal);
				gi.WriteByte(self->s.skinnum);
				gi.multicast(tr.endpos, MULTICAST_PVS);
				break;
			}

			ignore = tr.ent;
			VectorCopy(tr.endpos, start);
		}

		gi.WriteByte(svc_temp_entity);
		gi.WriteByte(TE_BFG_LASER);
		gi.WritePosition(self->s.origin);
		gi.WritePosition(tr.endpos);
		gi.multicast(self->s.origin, MULTICAST_PHS);
	}

	self->nextthink = level.time + FRAMETIME;
}
Beispiel #6
0
// Setup a CCoreDispInfo given a mapdispinfo_t.
// If pFace is non-NULL, then lightmap texture coordinates will be generated.
void DispMapToCoreDispInfo( mapdispinfo_t *pMapDisp, CCoreDispInfo *pCoreDispInfo, dface_t *pFace )
{
	winding_t *pWinding = pMapDisp->face.originalface->winding;

	Assert( pWinding->numpoints == 4 );

	//
	// set initial surface data
	//
	CCoreDispSurface *pSurf = pCoreDispInfo->GetSurface();

	texinfo_t *pTexInfo = &texinfo[ pMapDisp->face.texinfo ];

	// init material contents
	pMapDisp->contents = pMapDisp->face.contents;
	if (!(pMapDisp->contents & (ALL_VISIBLE_CONTENTS | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) )
	{
		pMapDisp->contents |= CONTENTS_SOLID;
	}

	pSurf->SetContents( pMapDisp->contents );

	// Calculate the lightmap coordinates.
	Vector2D lmCoords[4] = {Vector2D(0,0),Vector2D(0,1),Vector2D(1,0),Vector2D(1,1)};
	Vector2D tCoords[4] = {Vector2D(0,0),Vector2D(0,1),Vector2D(1,0),Vector2D(1,1)};
	if( pFace )
	{
		Assert( pFace->numedges == 4 );

		Vector pt[4];
		for( int i=0; i < 4; i++ )
			pt[i] = pWinding->p[i];

		CalcTextureCoordsAtPoints( 
			pTexInfo->lightmapVecsLuxelsPerWorldUnits,
			pFace->m_LightmapTextureMinsInLuxels,
			pt,
			4,
			lmCoords );

		int zeroOffset[2] = {0,0};
		CalcTextureCoordsAtPoints( 
			pTexInfo->textureVecsTexelsPerWorldUnits,
			zeroOffset,
			pt,
			4,
			tCoords );
	}
	
	//
	// set face point data ...
	//
	pSurf->SetPointCount( 4 );
	for( int i = 0; i < 4; i++ )
	{
		// position
		pSurf->SetPoint( i, pWinding->p[i] );
		for( int j = 0; j < ( NUM_BUMP_VECTS + 1 ); ++j )
		{
			pSurf->SetLuxelCoord( j, i, lmCoords[i] );
		}
		pSurf->SetTexCoord( i, tCoords[i] );
	}
	
	//
	// reset surface given start info
	//
	pSurf->SetPointStart( pMapDisp->startPosition );
	pSurf->FindSurfPointStartIndex();
	pSurf->AdjustSurfPointData();

	//
	// adjust face lightmap data - this will be done a bit more accurately
	// when the common code get written, for now it works!!! (GDC, E3)
	//
	Vector points[4];
	for( int ndxPt = 0; ndxPt < 4; ndxPt++ )
	{
		points[ndxPt] = pSurf->GetPoint( ndxPt );
	}
	Vector edgeU = points[3] - points[0];
	Vector edgeV = points[1] - points[0];
	bool bUMajor = ( edgeU.Length() > edgeV.Length() );

	if( pFace )
	{
		int lightmapWidth = pFace->m_LightmapTextureSizeInLuxels[0];
		int lightmapHeight = pFace->m_LightmapTextureSizeInLuxels[1];
		if ( ( bUMajor && ( lightmapHeight > lightmapWidth ) ) || 
			 ( !bUMajor && ( lightmapWidth > lightmapHeight ) ) )
		{
			pFace->m_LightmapTextureSizeInLuxels[0] = lightmapHeight;
			pFace->m_LightmapTextureSizeInLuxels[1] = lightmapWidth;

			lightmapWidth = lightmapHeight;
			lightmapHeight = pFace->m_LightmapTextureSizeInLuxels[1];
		}

		for ( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS + 1 ); ndxBump++ )
		{
			pSurf->SetLuxelCoord( ndxBump, 0, Vector2D( 0.0f, 0.0f ) );
			pSurf->SetLuxelCoord( ndxBump, 1, Vector2D( 0.0f, ( float )lightmapHeight ) );
			pSurf->SetLuxelCoord( ndxBump, 2, Vector2D( ( float )lightmapWidth, ( float )lightmapHeight ) );
			pSurf->SetLuxelCoord( ndxBump, 3, Vector2D( ( float )lightmapWidth, 0.0f ) );
		}
	}

	// Setup the displacement vectors and offsets.
	int size = ( ( ( 1 << pMapDisp->power ) + 1 ) * ( ( 1 << pMapDisp->power ) + 1 ) );

	Vector vectorDisps[2048];
	float dispDists[2048];
	Assert( size < sizeof(vectorDisps)/sizeof(vectorDisps[0]) );

	for( int j = 0; j < size; j++ )
	{
		Vector v;
		float dist;

		VectorScale( pMapDisp->vectorDisps[j], pMapDisp->dispDists[j], v );
		VectorAdd( v, pMapDisp->vectorOffsets[j], v );
		
		dist = VectorLength( v );
		VectorNormalize( v );
		
		vectorDisps[j] = v;
		dispDists[j] = dist;
	}


	// Use CCoreDispInfo to setup the actual vertex positions.
	pCoreDispInfo->InitDispInfo( pMapDisp->power, pMapDisp->minTess, pMapDisp->smoothingAngle,
						 pMapDisp->alphaValues, vectorDisps, dispDists );
	pCoreDispInfo->Create();
}
Beispiel #7
0
void UI_DoSFXSaber( vector3 *blade_muz, vector3 *blade_tip, vector3 *trail_tip, vector3 *trail_muz, float lengthMax, float radius, saber_colors_t color, int rfx, qboolean doLight, qboolean doTrail, int cnum, int bnum ) {
	vector3	mid, blade_dir, end_dir, trail_dir, base_dir;
	float	radiusmult, effectradius, coreradius, effectalpha = 1.0f, AngleScale = 1.0f;
	float	blade_len, trail_len, base_len;
	vector3 rgb = { 1, 1, 1 };
	int i;

	qhandle_t	glow = 0;
	refEntity_t saber, sbak;

	VectorSubtract( blade_tip, blade_muz, &blade_dir );
	VectorSubtract( trail_tip, trail_muz, &trail_dir );
	blade_len = lengthMax;//VectorLength(blade_dir);
	trail_len = VectorLength( &trail_dir );
	VectorNormalize( &blade_dir );
	VectorNormalize( &trail_dir );

	if ( lengthMax < 1.0f ) {
		return;
	}

	VectorSubtract( trail_tip, blade_tip, &end_dir );
	VectorSubtract( trail_muz, blade_muz, &base_dir );
	base_len = VectorLength( &base_dir );
	VectorNormalize( &end_dir );
	VectorNormalize( &base_dir );

	switch ( color ) {
	case SABER_RED:
		glow = redSaberGlowShader;
		break;
	case SABER_ORANGE:
		glow = orangeSaberGlowShader;
		break;
	case SABER_YELLOW:
		glow = yellowSaberGlowShader;
		break;
	case SABER_GREEN:
		glow = greenSaberGlowShader;
		break;
	case SABER_PURPLE:
		glow = purpleSaberGlowShader;
		break;
		//	case SABER_WHITE:
	case SABER_RGB:
	case SABER_FLAME1:
	case SABER_ELEC1:
	case SABER_FLAME2:
	case SABER_ELEC2:
		glow = rgbSaberGlowShader;
		break;
	case SABER_BLACK:
		glow = blackSaberGlowShader;
		break;
	default:
		glow = blueSaberGlowShader;
		break;
	}

	VectorMA( blade_muz, blade_len * 0.5f, &blade_dir, &mid );

	memset( &saber, 0, sizeof(refEntity_t) );

	if ( blade_len < lengthMax ) {
		radiusmult = 0.5f + ((blade_len / lengthMax) / 2);
	}
	else {
		radiusmult = 1.0f;
	}

	effectradius = ((radius * 1.6f * 1.0f) + crandom() * 0.1f)*radiusmult;
	coreradius = ((radius * 0.4f * 1.0f) + crandom() * 0.1f)*radiusmult;

	UI_RGBForSaberColor( color, &rgb, bnum );
	for ( i = 0; i<3; i++ )
		rgb.data[i] *= 255;
	{
		saber.renderfx = rfx;
		if ( blade_len - ((effectradius*1.0f) / 2) > 0 ) {
			saber.radius = effectradius*AngleScale;
			saber.saberLength = (blade_len - (saber.radius / 2));
			VectorCopy( blade_muz, &saber.origin );
			VectorCopy( &blade_dir, &saber.axis[0] );
			saber.reType = RT_SABER_GLOW;
			saber.customShader = glow;
			if ( color < SABER_RGB /*&& color != SABER_WHITE*/ )
				saber.shaderRGBA[0] = saber.shaderRGBA[1] = saber.shaderRGBA[2] = saber.shaderRGBA[3] = 0xff * 1.0f;
			else {
				for ( i = 0; i < 3; i++ )
					saber.shaderRGBA[i] = rgb.data[i] * effectalpha;
				saber.shaderRGBA[3] = 255 * effectalpha;
			}

			SE_R_AddRefEntityToScene( &saber, cnum );
		}

		// Do the hot core
		VectorMA( blade_muz, blade_len, &blade_dir, &saber.origin );
		VectorMA( blade_muz, -1, &blade_dir, &saber.oldorigin );

		saber.customShader = sfxSaberBladeShader;
		saber.reType = RT_LINE;

		saber.radius = coreradius;

		saber.shaderTexCoord.x = saber.shaderTexCoord.y = 1.0f;
		if ( color < SABER_RGB /*&& color != SABER_WHITE*/ )
			saber.shaderRGBA[0] = saber.shaderRGBA[1] = saber.shaderRGBA[2] = saber.shaderRGBA[3] = 0xff;
		else {
			for ( i = 0; i < 3; i++ )
				saber.shaderRGBA[i] = rgb.data[i];
		}
		sbak = saber;
		SE_R_AddRefEntityToScene( &saber, cnum );

		if ( color >= SABER_RGB /*|| color == SABER_WHITE*/ ) {// Add the saber surface that provides color.

			sbak.customShader = sfxSaberBlade2Shader;
			sbak.reType = RT_LINE;
			sbak.shaderTexCoord.x = sbak.shaderTexCoord.y = 1.0f;
			sbak.shaderRGBA[0] = sbak.shaderRGBA[1] = sbak.shaderRGBA[2] = sbak.shaderRGBA[3] = 0xff;
			sbak.radius = coreradius;
			SE_R_AddRefEntityToScene( &sbak, cnum );
		}
	}

	{
		saber.renderfx = rfx;
		if ( trail_len - ((effectradius*AngleScale) / 2) > 0 ) {
			saber.radius = effectradius*AngleScale;
			saber.saberLength = (trail_len - (saber.radius / 2));
			VectorCopy( trail_muz, &saber.origin );
			VectorCopy( &trail_dir, &saber.axis[0] );
			saber.reType = RT_SABER_GLOW;
			saber.customShader = glow;
			if ( color < SABER_RGB /*&& color != SABER_WHITE*/ )
				saber.shaderRGBA[0] = saber.shaderRGBA[1] = saber.shaderRGBA[2] = saber.shaderRGBA[3] = 0xff * effectalpha;
			else {
				for ( i = 0; i < 3; i++ )
					saber.shaderRGBA[i] = rgb.data[i] * effectalpha;
				saber.shaderRGBA[3] = 255 * effectalpha;
			}

			SE_R_AddRefEntityToScene( &saber, cnum );
		}

		// Do the hot core
		VectorMA( trail_muz, trail_len, &trail_dir, &saber.origin );
		VectorMA( trail_muz, -1, &trail_dir, &saber.oldorigin );

		saber.customShader = sfxSaberBladeShader;
		saber.reType = RT_LINE;

		saber.radius = coreradius;

		saber.shaderTexCoord.x = saber.shaderTexCoord.y = 1.0f;
		if ( color < SABER_RGB /*&& color != SABER_WHITE*/ )
			saber.shaderRGBA[0] = saber.shaderRGBA[1] = saber.shaderRGBA[2] = saber.shaderRGBA[3] = 0xff;
		else {
			for ( i = 0; i < 3; i++ )
				saber.shaderRGBA[i] = rgb.data[i];
			saber.shaderRGBA[3] = 255;
		}
		sbak = saber;
		SE_R_AddRefEntityToScene( &saber, cnum );

		if ( color >= SABER_RGB /*|| color == SABER_WHITE*/ ) {// Add the saber surface that provides color.

			sbak.customShader = sfxSaberBlade2Shader;
			sbak.reType = RT_LINE;
			sbak.shaderTexCoord.x = sbak.shaderTexCoord.y = 1.0f;
			sbak.shaderRGBA[0] = sbak.shaderRGBA[1] = sbak.shaderRGBA[2] = sbak.shaderRGBA[3] = 0xff;
			sbak.radius = coreradius;
			SE_R_AddRefEntityToScene( &sbak, cnum );
		}
	}

	VectorMA( blade_muz, blade_len - 0.5f, &blade_dir, blade_tip );
	VectorMA( trail_muz, trail_len - 0.5f, &trail_dir, trail_tip );

	if ( base_len > 2 ) {
		saber.renderfx = rfx;
		if ( base_len - (effectradius*AngleScale) > 0 ) {
			saber.radius = effectradius*AngleScale;
			saber.saberLength = (base_len - (effectradius*AngleScale));
			VectorMA( blade_muz, ((effectradius*AngleScale) / 2), &base_dir, &saber.origin );
			VectorCopy( &base_dir, &saber.axis[0] );
			saber.reType = RT_SABER_GLOW;
			saber.customShader = glow;
			if ( color < SABER_RGB /*&& color != SABER_WHITE*/ )
				saber.shaderRGBA[0] = saber.shaderRGBA[1] = saber.shaderRGBA[2] = saber.shaderRGBA[3] = 0xff * effectalpha;
			else {
				for ( i = 0; i < 3; i++ )
					saber.shaderRGBA[i] = rgb.data[i] * effectalpha;
				saber.shaderRGBA[3] = 255 * effectalpha;
			}
			SE_R_AddRefEntityToScene( &saber, cnum );
		}

		// Do the hot core
		VectorMA( blade_muz, base_len, &base_dir, &saber.origin );
		VectorMA( blade_muz, -0.1f, &base_dir, &saber.oldorigin );

		saber.customShader = sfxSaberBladeShader;
		saber.reType = RT_LINE;

		saber.radius = coreradius;
		saber.saberLength = base_len;

		saber.shaderTexCoord.x = saber.shaderTexCoord.y = 1.0f;
		if ( color < SABER_RGB /*&& color != SABER_WHITE*/ )
			saber.shaderRGBA[0] = saber.shaderRGBA[1] = saber.shaderRGBA[2] = saber.shaderRGBA[3] = 0xff;
		else {
			for ( i = 0; i < 3; i++ )
				saber.shaderRGBA[i] = rgb.data[i];
			saber.shaderRGBA[3] = 255;
		}
		sbak = saber;
		SE_R_AddRefEntityToScene( &saber, cnum );

		if ( color >= SABER_RGB /*|| color == SABER_WHITE*/ ) {// Add the saber surface that provides color.

			sbak.customShader = sfxSaberBlade2Shader;
			saber.reType = RT_LINE;
			saber.shaderTexCoord.x = saber.shaderTexCoord.y = 1.0f;
			saber.shaderRGBA[0] = saber.shaderRGBA[1] = saber.shaderRGBA[2] = saber.shaderRGBA[3] = 0xff;
			saber.radius = coreradius;
			saber.saberLength = base_len;
			SE_R_AddRefEntityToScene( &sbak, cnum );
		}
	}
}
Beispiel #8
0
/*
=================
R_TraceLine
=================
*/
msurface_t *R_TransformedTraceLine( trace_t *tr, const vec3_t start, const vec3_t end, ref_entity_t *test, int umask )
{
	ref_model_t	*model;

	r_fragmentframecount++;	// for multi-check avoidance

	// fill in a default trace
	Mem_Set( tr, 0, sizeof( trace_t ));

	trace_surface = NULL;
	trace_umask = umask;
	trace_fraction = 1;
	VectorCopy( end, trace_impact );
	Mem_Set( &trace_plane, 0, sizeof( trace_plane ));

	ClearBounds( trace_absmins, trace_absmaxs );
	AddPointToBounds( start, trace_absmins, trace_absmaxs );
	AddPointToBounds( end, trace_absmins, trace_absmaxs );

	model = test->model;
	if( model )
	{
		if( model->type == mod_world || model->type == mod_brush )
		{
			mbrushmodel_t *bmodel = ( mbrushmodel_t * )model->extradata;
			vec3_t temp, start_l, end_l, axis[3];
			bool rotated = !Matrix3x3_Compare( test->axis, matrix3x3_identity );

			// transform
			VectorSubtract( start, test->origin, start_l );
			VectorSubtract( end, test->origin, end_l );
			if( rotated )
			{
				VectorCopy( start_l, temp );
				Matrix3x3_Transform( test->axis, temp, start_l );
				VectorCopy( end_l, temp );
				Matrix3x3_Transform( test->axis, temp, end_l );
			}

			VectorCopy( start_l, trace_start );
			VectorCopy( end_l, trace_end );

			// world uses a recursive approach using BSP tree, submodels
			// just walk the list of surfaces linearly
			if( test->model->type == mod_world )
				R_RecursiveHullCheck( bmodel->nodes, start_l, end_l );
			else if( BoundsIntersect( model->mins, model->maxs, trace_absmins, trace_absmaxs ) )
				R_TraceAgainstBmodel( bmodel );

			// transform back
			if( rotated && trace_fraction != 1 )
			{
				Matrix3x3_Transpose( axis, test->axis );
				VectorCopy( tr->vecPlaneNormal, temp );
				Matrix3x3_Transform( axis, temp, trace_plane.normal );
			}
		}
	}

	// calculate the impact plane, if any
	if( trace_fraction < 1.0f )
	{
		VectorNormalize( trace_plane.normal );
		trace_plane.dist = DotProduct( trace_plane.normal, trace_impact );
		CategorizePlane( &trace_plane );

		tr->flPlaneDist = trace_plane.dist;
		VectorCopy( trace_plane.normal, tr->vecPlaneNormal );
		tr->iContents = trace_surface->contents;
		tr->pHit = (edict_t *)test;
	}
	
	tr->flFraction = trace_fraction;
	VectorCopy( trace_impact, tr->vecEndPos );

	return trace_surface;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_TEShatterSurface::PostDataUpdate( DataUpdateType_t updateType )
{
	RecordShatterSurface();

	CSmartPtr<CSimple3DEmitter> pGlassEmitter = CSimple3DEmitter::Create( "C_TEShatterSurface 1" );
	pGlassEmitter->SetSortOrigin( m_vecOrigin );

	Vector vecColor;
	engine->ComputeLighting( m_vecOrigin, NULL, true, vecColor );

	// HACK: Blend a little toward white to match the materials...
	VectorLerp( vecColor, Vector( 1, 1, 1 ), 0.3, vecColor );

	PMaterialHandle hMaterial1;
	PMaterialHandle hMaterial2;
	if (m_nSurfaceType == SHATTERSURFACE_GLASS)
	{
		hMaterial1 = pGlassEmitter->GetPMaterial( "effects/fleck_glass1" );
		hMaterial2 = pGlassEmitter->GetPMaterial( "effects/fleck_glass2" );
	}
	else
	{
		hMaterial1 = pGlassEmitter->GetPMaterial( "effects/fleck_tile1" );
		hMaterial2 = pGlassEmitter->GetPMaterial( "effects/fleck_tile2" );
	}

	// ---------------------------------------------------
	// Figure out number of particles required to fill space
	// ---------------------------------------------------
	int nNumWide = m_flWidth  / m_flShardSize;
	int nNumHigh = m_flHeight / m_flShardSize;

	Vector vWidthStep,vHeightStep;
	AngleVectors(m_vecAngles,NULL,&vWidthStep,&vHeightStep);
	vWidthStep	*= m_flShardSize;
	vHeightStep *= m_flShardSize;

	// ---------------------
	// Create glass shards
	// ----------------------
	Vector vCurPos = m_vecOrigin;
	vCurPos.x += 0.5*m_flShardSize;
	vCurPos.z += 0.5*m_flShardSize;

	float flMinSpeed = 9999999999;
	float flMaxSpeed = 0;

	Particle3D *pParticle = NULL;

	for (int width=0;width<nNumWide;width++)
	{
		for (int height=0;height<nNumHigh;height++)
		{			
			if (random->RandomInt(0,1))
			{
				pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), hMaterial1, vCurPos );
			}
			else
			{
				pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), hMaterial2, vCurPos );
			}

			Vector vForceVel = Vector(0,0,0);
			if (random->RandomInt(0, 3) != 0)
			{
				float flForceDistSqr = (vCurPos - m_vecForcePos).LengthSqr();
				vForceVel = m_vecForce;
				if (flForceDistSqr > 0 )
				{
					vForceVel *= ( 40.0f / flForceDistSqr );
				}
			}

			if (pParticle)
			{
				pParticle->m_flLifeRemaining	= random->RandomFloat(GLASS_SHARD_MIN_LIFE,GLASS_SHARD_MAX_LIFE);
				pParticle->m_vecVelocity		= vForceVel;
				pParticle->m_vecVelocity	   += RandomVector(-25,25);
				pParticle->m_uchSize			= m_flShardSize + random->RandomFloat(-0.5*m_flShardSize,0.5*m_flShardSize);
				pParticle->m_vAngles			= m_vecAngles;
				pParticle->m_flAngSpeed			= random->RandomFloat(-400,400);

				pParticle->m_uchFrontColor[0]	= (byte)(m_uchFrontColor[0] * vecColor.x );
				pParticle->m_uchFrontColor[1]	= (byte)(m_uchFrontColor[1] * vecColor.y );
				pParticle->m_uchFrontColor[2]	= (byte)(m_uchFrontColor[2] * vecColor.z );
				pParticle->m_uchBackColor[0]	= (byte)(m_uchBackColor[0] * vecColor.x );
				pParticle->m_uchBackColor[1]	= (byte)(m_uchBackColor[1] * vecColor.y );
				pParticle->m_uchBackColor[2]	= (byte)(m_uchBackColor[2] * vecColor.z );
			}

			// Keep track of min and max speed for collision detection
			float  flForceSpeed = vForceVel.Length();
			if (flForceSpeed > flMaxSpeed)
			{
				flMaxSpeed = flForceSpeed;
			}
			if (flForceSpeed < flMinSpeed)
			{
				flMinSpeed = flForceSpeed;
			}

			vCurPos += vHeightStep;
		}
		vCurPos	 -= nNumHigh*vHeightStep;
		vCurPos	 += vWidthStep;
	}

	// --------------------------------------------------
	// Set collision parameters
	// --------------------------------------------------
	Vector vMoveDir = m_vecForce;
	VectorNormalize(vMoveDir);

	pGlassEmitter->m_ParticleCollision.Setup( m_vecOrigin, &vMoveDir, GLASS_SHARD_NOISE, 
												flMinSpeed, flMaxSpeed, GLASS_SHARD_GRAVITY, GLASS_SHARD_DAMPING );
}
Beispiel #10
0
/*
================
CM_TraceThroughVerticalCylinder

get the first intersection of the ray with the cylinder
the cylinder extends halfheight above and below the origin
================
*/
void CM_TraceThroughVerticalCylinder( traceWork_t *tw, trace_t &trace, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end) {
	float length, scale, fraction, l1, l2;
	float /*a, */b, c, d, sqrtd;
	vec3_t v1, dir, start2d, end2d, org2d, intersection;

	// 2d coordinates
	VectorSet(start2d, start[0], start[1], 0);
	VectorSet(end2d, end[0], end[1], 0);
	VectorSet(org2d, origin[0], origin[1], 0);
	// if between lower and upper cylinder bounds
	if (start[2] <= origin[2] + halfheight &&
				start[2] >= origin[2] - halfheight) {
		// if inside the cylinder
		VectorSubtract(start2d, org2d, dir);
		l1 = VectorLengthSquared(dir);
		if (l1 < Square(radius)) {
			trace.fraction = 0;
			trace.startsolid = qtrue;
			VectorSubtract(end2d, org2d, dir);
			l1 = VectorLengthSquared(dir);
			if (l1 < Square(radius)) {
				trace.allsolid = qtrue;
			}
			return;
		}
	}
	//
	VectorSubtract(end2d, start2d, dir);
	length = VectorNormalize(dir);
	//
	l1 = CM_DistanceFromLineSquared(org2d, start2d, end2d, dir);
	VectorSubtract(end2d, org2d, v1);
	l2 = VectorLengthSquared(v1);
	// if no intersection with the cylinder and the end point is at least an epsilon away
	if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
		return;
	}
	//
	//
	// (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2
	// (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2;
	// v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 +
	//						v1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2
	// t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) +
	//						v1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0
	//
	VectorSubtract(start, origin, v1);
	// dir is normalized so we can use a = 1
	//a = 1.0f;// * (dir[0] * dir[0] + dir[1] * dir[1]);
	b = 2.0f * (v1[0] * dir[0] + v1[1] * dir[1]);
	c = v1[0] * v1[0] + v1[1] * v1[1] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);

	d = b * b - 4.0f * c;// * a;
	if (d > 0) {
		sqrtd = sqrtf(d);
		// = (- b + sqrtd) * 0.5f;// / (2.0f * a);
		fraction = (- b - sqrtd) * 0.5f;// / (2.0f * a);
		//
		if (fraction < 0) {
			fraction = 0;
		}
		else {
			fraction /= length;
		}
		if ( fraction < trace.fraction ) {
			VectorSubtract(end, start, dir);
			VectorMA(start, fraction, dir, intersection);
			// if the intersection is between the cylinder lower and upper bound
			if (intersection[2] <= origin[2] + halfheight &&
						intersection[2] >= origin[2] - halfheight) {
				//
				trace.fraction = fraction;
				VectorSubtract(intersection, origin, dir);
				dir[2] = 0;
				#ifdef CAPSULE_DEBUG
					l2 = VectorLength(dir);
					if (l2 <= radius) {
						int bah = 1;
					}
				#endif
				scale = 1 / (radius+RADIUS_EPSILON);
				VectorScale(dir, scale, dir);
				VectorCopy(dir, trace.plane.normal);
				VectorAdd( tw->modelOrigin, intersection, intersection);
				trace.plane.dist = DotProduct(trace.plane.normal, intersection);
				trace.contents = CONTENTS_BODY;
			}
		}
	}
	else if (d == 0) {
		//t[0] = (- b ) / 2 * a;
		// slide along the cylinder
	}
	// no intersection at all
}
Beispiel #11
0
/*
================
CM_TraceThroughLeaf
================
*/
void CM_TraceThroughLeaf( traceWork_t *tw, trace_t &trace, clipMap_t *local, cLeaf_t *leaf ) {
	int			k;
	int			brushnum;
	cbrush_t	*b;
	cPatch_t	*patch;

	// trace line against all brushes in the leaf
	for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
		brushnum = local->leafbrushes[leaf->firstLeafBrush+k];

		b = &local->brushes[brushnum];
		if ( b->checkcount == local->checkcount ) {
			continue;	// already checked this brush in another leaf
		}
		b->checkcount = local->checkcount;

		if ( !(b->contents & tw->contents) ) {
			continue;
		}

#ifndef BSPC
		if (com_terrainPhysics->integer && cmg.landScape && (b->contents & CONTENTS_TERRAIN) )
		{
			// Invalidate the checkcount for terrain as the terrain brush has to be processed
			// many times.
			b->checkcount--;

			CM_TraceThroughTerrain( tw, trace, b );
		}
		else
#endif
		{
			CM_TraceThroughBrush( tw, trace, b, false );
		}

		if ( !trace.fraction ) {
			return;
		}
	}

	// trace line against all patches in the leaf
#ifdef BSPC
	if (1) {
#else
	if ( !cm_noCurves->integer ) {
#endif
		for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
			patch = local->surfaces[ local->leafsurfaces[ leaf->firstLeafSurface + k ] ];
			if ( !patch ) {
				continue;
			}
			if ( patch->checkcount == local->checkcount ) {
				continue;	// already checked this patch in another leaf
			}
			patch->checkcount = local->checkcount;

			if ( !(patch->contents & tw->contents) ) {
				continue;
			}

			CM_TraceThroughPatch( tw, trace, patch );
			if ( !trace.fraction ) {
				return;
			}
		}
	}
}

#define RADIUS_EPSILON		1.0f

/*
================
CM_TraceThroughSphere

get the first intersection of the ray with the sphere
================
*/
void CM_TraceThroughSphere( traceWork_t *tw, trace_t &trace, vec3_t origin, float radius, vec3_t start, vec3_t end ) {
	float l1, l2, length, scale, fraction;
	float /*a, */b, c, d, sqrtd;
	vec3_t v1, dir, intersection;

	// if inside the sphere
	VectorSubtract(start, origin, dir);
	l1 = VectorLengthSquared(dir);
	if (l1 < Square(radius)) {
		trace.fraction = 0;
		trace.startsolid = qtrue;
		// test for allsolid
		VectorSubtract(end, origin, dir);
		l1 = VectorLengthSquared(dir);
		if (l1 < Square(radius)) {
			trace.allsolid = qtrue;
		}
		return;
	}
	//
	VectorSubtract(end, start, dir);
	length = VectorNormalize(dir);
	//
	l1 = CM_DistanceFromLineSquared(origin, start, end, dir);
	VectorSubtract(end, origin, v1);
	l2 = VectorLengthSquared(v1);
	// if no intersection with the sphere and the end point is at least an epsilon away
	if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
		return;
	}
	//
	//	| origin - (start + t * dir) | = radius
	//	a = dir[0]^2 + dir[1]^2 + dir[2]^2;
	//	b = 2 * (dir[0] * (start[0] - origin[0]) + dir[1] * (start[1] - origin[1]) + dir[2] * (start[2] - origin[2]));
	//	c = (start[0] - origin[0])^2 + (start[1] - origin[1])^2 + (start[2] - origin[2])^2 - radius^2;
	//
	VectorSubtract(start, origin, v1);
	// dir is normalized so a = 1
	//a = 1.0f;//dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
	b = 2.0f * (dir[0] * v1[0] + dir[1] * v1[1] + dir[2] * v1[2]);
	c = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);

	d = b * b - 4.0f * c;// * a;
	if (d > 0) {
		sqrtd = sqrtf(d);
		// = (- b + sqrtd) * 0.5f; // / (2.0f * a);
		fraction = (- b - sqrtd) * 0.5f; // / (2.0f * a);
		//
		if (fraction < 0) {
			fraction = 0;
		}
		else {
			fraction /= length;
		}
		if ( fraction < trace.fraction ) {
			trace.fraction = fraction;
			VectorSubtract(end, start, dir);
			VectorMA(start, fraction, dir, intersection);
			VectorSubtract(intersection, origin, dir);
			#ifdef CAPSULE_DEBUG
				l2 = VectorLength(dir);
				if (l2 < radius) {
					int bah = 1;
				}
			#endif
			scale = 1 / (radius+RADIUS_EPSILON);
			VectorScale(dir, scale, dir);
			VectorCopy(dir, trace.plane.normal);
			VectorAdd( tw->modelOrigin, intersection, intersection);
			trace.plane.dist = DotProduct(trace.plane.normal, intersection);
			trace.contents = CONTENTS_BODY;
		}
	}
	else if (d == 0) {
		//t1 = (- b ) / 2;
		// slide along the sphere
	}
	// no intersection at all
}
Beispiel #12
0
//NOTE NOTE NOTE NOTE NOTE NOTE
//I want to keep this function BG too, because it's fairly generic already, and it
//would be nice to have proper prediction of animations. -rww
// This function makes sure that the rider's in this vehicle are properly animated.
void AnimateRiders( Vehicle_t *pVeh )
{
	animNumber_t Anim = BOTH_VS_IDLE;
	float fSpeedPercToMax;
	int iFlags = SETANIM_FLAG_NORMAL, iBlend = 300;
	playerState_t *pilotPS;
	playerState_t *parentPS;
	int curTime;


	// Boarding animation.
	if ( pVeh->m_iBoarding != 0 )
	{
		// We've just started moarding, set the amount of time it will take to finish moarding.
		if ( pVeh->m_iBoarding < 0 )
		{
			int iAnimLen;

			// Boarding from left...
			if ( pVeh->m_iBoarding == -1 )
			{
				Anim = BOTH_VS_MOUNT_L;
			}
			else if ( pVeh->m_iBoarding == -2 )
			{
				Anim = BOTH_VS_MOUNT_R;
			}
			else if ( pVeh->m_iBoarding == -3 )
			{
				Anim = BOTH_VS_MOUNTJUMP_L;
			}
			else if ( pVeh->m_iBoarding == VEH_MOUNT_THROW_LEFT)
			{
				iBlend = 0;
				Anim = BOTH_VS_MOUNTTHROW_R;
			}
			else if ( pVeh->m_iBoarding == VEH_MOUNT_THROW_RIGHT)
			{
				iBlend = 0;
				Anim = BOTH_VS_MOUNTTHROW_L;
			}

			// Set the delay time (which happens to be the time it takes for the animation to complete).
			// NOTE: Here I made it so the delay is actually 40% (0.4f) of the animation time.
#ifdef _JK2MP
			iAnimLen = BG_AnimLength( pVeh->m_pPilot->localAnimIndex, Anim ) * 0.4f;
			pVeh->m_iBoarding = BG_GetTime() + iAnimLen;
#else
 			iAnimLen = PM_AnimLength( pVeh->m_pPilot->client->clientInfo.animFileIndex, Anim );// * 0.4f;
			if (pVeh->m_iBoarding!=VEH_MOUNT_THROW_LEFT && pVeh->m_iBoarding!=VEH_MOUNT_THROW_RIGHT)
			{
				pVeh->m_iBoarding = level.time + (iAnimLen*0.4f);
			}
			else
			{
				pVeh->m_iBoarding = level.time + iAnimLen;
			}
#endif
			// Set the animation, which won't be interrupted until it's completed.
			// TODO: But what if he's killed? Should the animation remain persistant???
			iFlags = SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
			
#ifdef _JK2MP
			BG_SetAnim(pVeh->m_pPilot->playerState, bgAllAnims[pVeh->m_pPilot->localAnimIndex].anims,
				SETANIM_BOTH, Anim, iFlags, iBlend);
#else
			NPC_SetAnim( pVeh->m_pPilot, SETANIM_BOTH, Anim, iFlags, iBlend );
			if (pVeh->m_pOldPilot)
			{
				iAnimLen = PM_AnimLength( pVeh->m_pPilot->client->clientInfo.animFileIndex, BOTH_VS_MOUNTTHROWEE);
				NPC_SetAnim( pVeh->m_pOldPilot, SETANIM_BOTH, BOTH_VS_MOUNTTHROWEE, iFlags, iBlend );
			}
#endif
		}

#ifndef _JK2MP
		if (pVeh->m_pOldPilot && pVeh->m_pOldPilot->client->ps.torsoAnimTimer<=0)
		{
			if (Q_irand(0, player->count)==0)
			{
				player->count++;
 				player->lastEnemy = pVeh->m_pOldPilot;
				G_StartMatrixEffect(player, MEF_LOOK_AT_ENEMY|MEF_NO_RANGEVAR|MEF_NO_VERTBOB|MEF_NO_SPIN, 1000);
			}

 			gentity_t*	oldPilot = pVeh->m_pOldPilot;
			pVeh->m_pVehicleInfo->Eject(pVeh, pVeh->m_pOldPilot, qtrue);		// will set pointer to zero

			// Kill Him
			//----------
			oldPilot->client->noRagTime = -1;	// no ragdoll for you
			G_Damage(oldPilot, pVeh->m_pPilot, pVeh->m_pPilot, pVeh->m_pPilot->currentAngles, pVeh->m_pPilot->currentOrigin, 1000, 0, MOD_CRUSH);

			// Compute THe Throw Direction As Backwards From The Vehicle's Velocity
			//----------------------------------------------------------------------
			vec3_t		throwDir;
			VectorScale(pVeh->m_pParentEntity->client->ps.velocity, -1.0f, throwDir);
			VectorNormalize(throwDir);
			throwDir[2] += 0.3f;	// up a little

			// Now Throw Him Out
			//-------------------
			G_Throw(oldPilot, throwDir, VectorLength(pVeh->m_pParentEntity->client->ps.velocity)/10.0f);
			NPC_SetAnim(oldPilot, SETANIM_BOTH, BOTH_DEATHBACKWARD1, SETANIM_FLAG_OVERRIDE, iBlend );
		}
#endif

		return;
	}

#ifdef _JK2MP //fixme
	if (1) return;
#endif

#ifdef _JK2MP
	pilotPS = pVeh->m_pPilot->playerState;
	parentPS = pVeh->m_pPilot->playerState;
#else
	pilotPS = &pVeh->m_pPilot->client->ps;
	parentPS = &pVeh->m_pParentEntity->client->ps;
#endif

#ifndef _JK2MP//SP
	curTime = level.time;
#elif QAGAME//MP GAME
	curTime = level.time;
#elif CGAME//MP CGAME
	//FIXME: pass in ucmd?  Not sure if this is reliable...
	curTime = pm->cmd.serverTime;
#endif

	// Percentage of maximum speed relative to current speed.
	fSpeedPercToMax = parentPS->speed / pVeh->m_pVehicleInfo->speedMax;

	// Going in reverse...
#ifdef _JK2MP
	if ( pVeh->m_ucmd.forwardmove < 0 && !(pVeh->m_ulFlags & VEH_SLIDEBREAKING))
#else
	if ( fSpeedPercToMax < -0.018f && !(pVeh->m_ulFlags & VEH_SLIDEBREAKING))
#endif
	{
		Anim = BOTH_VS_REV;
		iBlend = 500;
	}
	else 
	{
		bool		HasWeapon	= ((pilotPS->weapon != WP_NONE) && (pilotPS->weapon != WP_MELEE));
		bool		Attacking	= (HasWeapon && !!(pVeh->m_ucmd.buttons&BUTTON_ATTACK));
#ifdef _JK2MP //fixme: flying tends to spaz out a lot
		bool		Flying		= false;
		bool		Crashing	= false;
#else
		bool		Flying		= !!(pVeh->m_ulFlags & VEH_FLYING);
		bool		Crashing	= !!(pVeh->m_ulFlags & VEH_CRASHING);
#endif
		bool		Right		= (pVeh->m_ucmd.rightmove>0);
		bool		Left		= (pVeh->m_ucmd.rightmove<0);
		bool		Turbo		= (curTime<pVeh->m_iTurboTime);
		EWeaponPose	WeaponPose	= WPOSE_NONE;


		// Remove Crashing Flag
		//----------------------
		pVeh->m_ulFlags &= ~VEH_CRASHING;


		// Put Away Saber When It Is Not Active
		//--------------------------------------
#ifndef _JK2MP
		if (HasWeapon && (Turbo || (pilotPS->weapon==WP_SABER && !pilotPS->SaberActive())))
		{
			if (pVeh->m_pPilot->s.number<MAX_CLIENTS)
			{
				CG_ChangeWeapon(WP_NONE);
			}

			pVeh->m_pPilot->client->ps.weapon = WP_NONE;
			G_RemoveWeaponModels(pVeh->m_pPilot);
		}
#endif

		// Don't Interrupt Attack Anims
		//------------------------------
#ifdef _JK2MP
		if (pilotPS->weaponTime>0)
		{
			return;
		}
#else		
		if (pilotPS->torsoAnim>=BOTH_VS_ATL_S && pilotPS->torsoAnim<=BOTH_VS_ATF_G)
		{
			float		bodyCurrent	  = 0.0f;
			int			bodyEnd		  = 0;
			if (!!gi.G2API_GetBoneAnimIndex(&pVeh->m_pPilot->ghoul2[pVeh->m_pPilot->playerModel], pVeh->m_pPilot->rootBone, level.time, &bodyCurrent, NULL, &bodyEnd, NULL, NULL, NULL))
			{
				if (bodyCurrent<=((float)(bodyEnd)-1.5f))
				{
					return;
				}
			}
		}
#endif

		// Compute The Weapon Pose
		//--------------------------
		if (pilotPS->weapon==WP_BLASTER)
		{
			WeaponPose = WPOSE_BLASTER;
		}
		else if (pilotPS->weapon==WP_SABER)
		{
			if ( (pVeh->m_ulFlags&VEH_SABERINLEFTHAND) && pilotPS->torsoAnim==BOTH_VS_ATL_TO_R_S)
			{
				pVeh->m_ulFlags	&= ~VEH_SABERINLEFTHAND;
			}
			if (!(pVeh->m_ulFlags&VEH_SABERINLEFTHAND) && pilotPS->torsoAnim==BOTH_VS_ATR_TO_L_S)
			{
				pVeh->m_ulFlags	|=  VEH_SABERINLEFTHAND;
			}
			WeaponPose = (pVeh->m_ulFlags&VEH_SABERINLEFTHAND)?(WPOSE_SABERLEFT):(WPOSE_SABERRIGHT);
		}
		

 		if (Attacking && WeaponPose)
		{// Attack!
			iBlend	= 100;
 			iFlags	= SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART;
	
			// Auto Aiming
			//===============================================
			if (!Left && !Right)		// Allow player strafe keys to override
			{
#ifndef _JK2MP
				if (pVeh->m_pPilot->enemy)
				{
					vec3_t	toEnemy;
					float	toEnemyDistance;
					vec3_t	actorRight;
					float	actorRightDot;

					VectorSubtract(pVeh->m_pPilot->currentOrigin, pVeh->m_pPilot->enemy->currentOrigin, toEnemy);
					toEnemyDistance = VectorNormalize(toEnemy);

					AngleVectors(pVeh->m_pParentEntity->currentAngles, 0, actorRight, 0);
					actorRightDot = DotProduct(toEnemy, actorRight);

	 				if (fabsf(actorRightDot)>0.5f || pilotPS->weapon==WP_SABER)
					{
						Left	= (actorRightDot>0.0f);
						Right	= !Left;
					}
					else
					{
						Right = Left = false;
					}
				}
				else 
#endif
				if (pilotPS->weapon==WP_SABER && !Left && !Right)
				{
					Left = (WeaponPose==WPOSE_SABERLEFT);
					Right	= !Left;
				}
			}


			if (Left)
			{// Attack Left
				switch(WeaponPose)
				{
				case WPOSE_BLASTER:		Anim = BOTH_VS_ATL_G;		break;
				case WPOSE_SABERLEFT:	Anim = BOTH_VS_ATL_S;		break;
				case WPOSE_SABERRIGHT:	Anim = BOTH_VS_ATR_TO_L_S;	break;
				default:				assert(0);
				}
			}
			else if (Right)
			{// Attack Right
				switch(WeaponPose)
				{
				case WPOSE_BLASTER:		Anim = BOTH_VS_ATR_G;		break;
				case WPOSE_SABERLEFT:	Anim = BOTH_VS_ATL_TO_R_S;	break;
				case WPOSE_SABERRIGHT:	Anim = BOTH_VS_ATR_S;		break;
				default:				assert(0);
				}
			}
			else
			{// Attack Ahead
				switch(WeaponPose)
				{
				case WPOSE_BLASTER:		Anim = BOTH_VS_ATF_G;		break;
				default:				assert(0);
				}
			}

		}
		else if (Left && pVeh->m_ucmd.buttons&BUTTON_USE)
		{// Look To The Left Behind
			iBlend	= 400;
			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
			switch(WeaponPose)
			{
			case WPOSE_SABERLEFT:	Anim = BOTH_VS_IDLE_SL;		break;
			case WPOSE_SABERRIGHT:	Anim = BOTH_VS_IDLE_SR;		break;
			default:				Anim = BOTH_VS_LOOKLEFT;
			}
		}
		else if (Right && pVeh->m_ucmd.buttons&BUTTON_USE)
		{// Look To The Right Behind
			iBlend	= 400;
			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;
			switch(WeaponPose)
			{
			case WPOSE_SABERLEFT:	Anim = BOTH_VS_IDLE_SL;		break;
			case WPOSE_SABERRIGHT:	Anim = BOTH_VS_IDLE_SR;		break;
			default:				Anim = BOTH_VS_LOOKRIGHT;
			}
		}
		else if (Turbo)
		{// Kicked In Turbo
			iBlend	= 50;
			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;
			Anim	= BOTH_VS_TURBO;
		}
		else if (Flying)
		{// Off the ground in a jump
			iBlend	= 800;
			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD;

			switch(WeaponPose)
			{
			case WPOSE_NONE:		Anim = BOTH_VS_AIR;			break;
			case WPOSE_BLASTER:		Anim = BOTH_VS_AIR_G;		break;
			case WPOSE_SABERLEFT:	Anim = BOTH_VS_AIR_SL;		break;
			case WPOSE_SABERRIGHT:	Anim = BOTH_VS_AIR_SR;		break;
			default:				assert(0);
			}
		}
		else if (Crashing)
		{// Hit the ground!
			iBlend	= 100;
			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;

			switch(WeaponPose)
			{
			case WPOSE_NONE:		Anim = BOTH_VS_LAND;		break;
			case WPOSE_BLASTER:		Anim = BOTH_VS_LAND_G;		break;
			case WPOSE_SABERLEFT:	Anim = BOTH_VS_LAND_SL;		break;
			case WPOSE_SABERRIGHT:	Anim = BOTH_VS_LAND_SR;		break;
			default:				assert(0);
			}
		}
		else
		{// No Special Moves
			iBlend	= 300;
 			iFlags	= SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLDLESS;

			if (pVeh->m_vOrientation[ROLL] <= -20)
			{// Lean Left
				switch(WeaponPose)
				{
				case WPOSE_NONE:		Anim = BOTH_VS_LEANL;			break;
				case WPOSE_BLASTER:		Anim = BOTH_VS_LEANL_G;			break;
				case WPOSE_SABERLEFT:	Anim = BOTH_VS_LEANL_SL;		break;
				case WPOSE_SABERRIGHT:	Anim = BOTH_VS_LEANL_SR;		break;
				default:				assert(0);
				}
			}
			else if (pVeh->m_vOrientation[ROLL] >= 20)
			{// Lean Right
				switch(WeaponPose)
				{
				case WPOSE_NONE:		Anim = BOTH_VS_LEANR;			break;
				case WPOSE_BLASTER:		Anim = BOTH_VS_LEANR_G;			break;
				case WPOSE_SABERLEFT:	Anim = BOTH_VS_LEANR_SL;		break;
				case WPOSE_SABERRIGHT:	Anim = BOTH_VS_LEANR_SR;		break;
				default:				assert(0);
				}
			}
			else
			{// No Lean
				switch(WeaponPose)
				{
				case WPOSE_NONE:		Anim = BOTH_VS_IDLE;			break;
				case WPOSE_BLASTER:		Anim = BOTH_VS_IDLE_G;			break;
				case WPOSE_SABERLEFT:	Anim = BOTH_VS_IDLE_SL;			break;
				case WPOSE_SABERRIGHT:	Anim = BOTH_VS_IDLE_SR;			break;
				default:				assert(0);
				}
			}
		}// No Special Moves
	}// Going backwards?

#ifdef _JK2MP
	iFlags &= ~SETANIM_FLAG_OVERRIDE;
	if (pVeh->m_pPilot->playerState->torsoAnim == Anim)
	{
		pVeh->m_pPilot->playerState->torsoTimer = BG_AnimLength(pVeh->m_pPilot->localAnimIndex, Anim);
	}
	if (pVeh->m_pPilot->playerState->legsAnim == Anim)
	{
		pVeh->m_pPilot->playerState->legsTimer = BG_AnimLength(pVeh->m_pPilot->localAnimIndex, Anim);
	}
	BG_SetAnim(pVeh->m_pPilot->playerState, bgAllAnims[pVeh->m_pPilot->localAnimIndex].anims,
		SETANIM_BOTH, Anim, iFlags|SETANIM_FLAG_HOLD, iBlend);
#else
	NPC_SetAnim( pVeh->m_pPilot, SETANIM_BOTH, Anim, iFlags, iBlend );
#endif
}
/*
===============
G_UpdateZaps
===============
*/
void G_UpdateZaps( int msec )
{
  int   i, j;
  zap_t *zap;
  int   damage;

  for( i = 0; i < MAX_ZAPS; i++ )
  {
    zap = &zaps[ i ];

    if( zap->used )
    {
      //check each target is valid
      for( j = 0; j < zap->numTargets; j++ )
      {
        gentity_t *source;
        gentity_t *target = zap->targets[ j ];

        if( j == 0 )
          source = zap->creator;
        else
          source = zap->targets[ j - 1 ];

        if( target->health <= 0 || !target->inuse || //early out
            Distance( source->s.origin, target->s.origin ) > LEVEL2_AREAZAP_RANGE )
        {
          target = zap->targets[ j ] = G_FindNewZapTarget( source );

          //couldn't find a target, so forget about the rest of the chain
          if( !target )
            zap->numTargets = j;
        }
      }

      if( zap->numTargets )
      {
        for( j = 0; j < zap->numTargets; j++ )
        {
          gentity_t *source;
          gentity_t *target = zap->targets[ j ];
          float     r = 1.0f / zap->numTargets;
          float     damageFraction = 2 * r - 2 * j * r * r - r * r;
          vec3_t    forward;

          if( j == 0 )
            source = zap->creator;
          else
            source = zap->targets[ j - 1 ];

          damage = ceil( ( (float)msec / LEVEL2_AREAZAP_TIME ) *
              LEVEL2_AREAZAP_DMG * damageFraction );

          // don't let a high msec value inflate the total damage
          if( damage + zap->damageUsed > LEVEL2_AREAZAP_DMG )
            damage = LEVEL2_AREAZAP_DMG - zap->damageUsed;

          VectorSubtract( target->s.origin, source->s.origin, forward );
          VectorNormalize( forward );

          //do the damage
          if( damage )
          {
            G_Damage( target, source, zap->creator, forward, target->s.origin,
                    damage, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP );
            if( g_modAlienRate.integer > 0 )
              damage = damage * 100 / g_modAlienRate.integer;
            zap->damageUsed += damage;
          }
        }
      }

      G_UpdateZapEffect( zap );

      zap->timeToLive -= msec;

      if( zap->timeToLive <= 0 || zap->numTargets == 0 || zap->creator->health <= 0 )
      {
        zap->used = qfalse;
        G_FreeEntity( zap->effectChannel );
      }
    }
  }
}
Beispiel #14
0
//------------------------------------------------------------------------------
// Purpose : Update the direction and position of my spotlight
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CPointSpotlight::SpotlightUpdate(void)
{
	// ---------------------------------------------------
	//  If I don't have a spotlight attempt to create one
	// ---------------------------------------------------
	if ( !m_hSpotlight )
	{
		if ( m_bSpotlightOn )
		{
			// Make the spotlight
			SpotlightCreate();
		}
		else
		{
			return;
		}
	}
	else if ( !m_bSpotlightOn )
	{
		SpotlightDestroy();
		return;
	}
	
	if ( !m_hSpotlightTarget )
	{
		DevWarning( "**Attempting to update point_spotlight but target ent is NULL\n" );
		SpotlightDestroy();
		SpotlightCreate();
		if ( !m_hSpotlightTarget )
			return;
	}

	m_vSpotlightCurrentPos = SpotlightCurrentPos();

	//  Update spotlight target velocity
	Vector vTargetDir;
	VectorSubtract( m_vSpotlightCurrentPos, m_hSpotlightTarget->GetAbsOrigin(), vTargetDir );
	float vTargetDist = vTargetDir.Length();

	// If we haven't moved at all, don't recompute
	if ( vTargetDist < 1 )
	{
		m_hSpotlightTarget->SetAbsVelocity( vec3_origin );
		return;
	}

	Vector vecNewVelocity = vTargetDir;
	VectorNormalize(vecNewVelocity);
	vecNewVelocity *= (10 * vTargetDist);

	// If a large move is requested, just jump to final spot as we probably hit a discontinuity
	if (vecNewVelocity.Length() > 200)
	{
		VectorNormalize(vecNewVelocity);
		vecNewVelocity *= 200;
		VectorNormalize(vTargetDir);
		m_hSpotlightTarget->SetAbsOrigin( m_vSpotlightCurrentPos );
	}
	m_hSpotlightTarget->SetAbsVelocity( vecNewVelocity );
	m_hSpotlightTarget->m_vSpotlightOrg = GetAbsOrigin();

	// Avoid sudden change in where beam fades out when cross disconinuities
	VectorSubtract( m_hSpotlightTarget->GetAbsOrigin(), m_hSpotlightTarget->m_vSpotlightOrg, m_hSpotlightTarget->m_vSpotlightDir );
	float flBeamLength	= VectorNormalize( m_hSpotlightTarget->m_vSpotlightDir );
	m_flSpotlightCurLength = (0.60*m_flSpotlightCurLength) + (0.4*flBeamLength);

	ComputeRenderInfo();

	//NDebugOverlay::Cross3D(GetAbsOrigin(),Vector(-5,-5,-5),Vector(5,5,5),0,255,0,true,0.1);
	//NDebugOverlay::Cross3D(m_vSpotlightCurrentPos,Vector(-5,-5,-5),Vector(5,5,5),0,255,0,true,0.1);
	//NDebugOverlay::Cross3D(m_vSpotlightTargetPos,Vector(-5,-5,-5),Vector(5,5,5),255,0,0,true,0.1);
}
Beispiel #15
0
void CG_MiscModelExplosion( vec3_t mins, vec3_t maxs, int size, material_t chunkType )
{
	int		ct = 13;
	float	r;
	vec3_t	org, mid, dir;
	char	*effect = NULL, *effect2 = NULL;

	VectorAdd( mins, maxs, mid );
	VectorScale( mid, 0.5f, mid );

	switch( chunkType )
	{
	case MAT_GLASS:
		effect = "chunks/glassbreak";
		ct = 5;
		break;
	case MAT_GLASS_METAL:
		effect = "chunks/glassbreak";
		effect2 = "chunks/metalexplode";
		ct = 5;
		break;
	case MAT_ELECTRICAL:
	case MAT_ELEC_METAL:
		effect = "chunks/sparkexplode";
		ct = 5;
		break;
	case MAT_METAL:
	case MAT_METAL2:
	case MAT_METAL3:
	case MAT_CRATE1:
	case MAT_CRATE2:
		effect = "chunks/metalexplode";
		ct = 2;
		break;
	case MAT_GRATE1:
		effect = "chunks/grateexplode";
		ct = 8;
		break;
	case MAT_ROPE:
		ct = 20;
		effect = "chunks/ropebreak";
		break;
	case MAT_WHITE_METAL: //not sure what this crap is really supposed to be..
	case MAT_DRK_STONE:
	case MAT_LT_STONE:
	case MAT_GREY_STONE:
		switch( size )
		{
		case 2:
			effect = "chunks/rockbreaklg";
			break;
		case 1:
		default:
			effect = "chunks/rockbreakmed";
			break;
		}
	}

	if ( !effect )
	{
		return;
	}

	ct += 7 * size;

	// FIXME: real precache .. VERify that these need to be here...don't think they would because the effects should be registered in g_breakable
	theFxScheduler.RegisterEffect( effect );

	if ( effect2 )
	{
		// FIXME: real precache
		theFxScheduler.RegisterEffect( effect2 );
	}

	// spawn chunk roughly in the bbox of the thing..
	for ( int i = 0; i < ct; i++ )
	{
		for( int j = 0; j < 3; j++ )
		{
			r = random() * 0.8f + 0.1f;
			org[j] = ( r * mins[j] + ( 1 - r ) * maxs[j] );
		}

		// shoot effect away from center
		VectorSubtract( org, mid, dir );
		VectorNormalize( dir );

		if ( effect2 && ( rand() & 1 ))
		{
			theFxScheduler.PlayEffect( effect2, org, dir );
		}
		else
		{
			theFxScheduler.PlayEffect( effect, org, dir );
		}
	}
}
void FX_8472Teleport( vec3_t org, int parm )
{
	int		i, t;
	vec3_t	dir = {0,0,1}, start, end, vel, color;

	if ( parm )
	{
		// Beaming out
		for ( i = 0; i < 32; i++ )
		{
			// Pick a random direction..
			VectorSet( dir, crandom(), crandom(), crandom() );
			VectorNormalize( dir );
			
			start[0] = org[0] + dir[0] * 26;
			start[1] = org[1] + dir[1] * 26;
			start[2] = org[2] + fabs(dir[2] * 10) - 18;

			// Now build the velocity vector
			vel[0] = dir[0] * 8;
			vel[1] = dir[1] * 8;
			vel[2] = dir[2] * 6;

			FX_AddSprite( start, vel, NULL, 
						24 + random() * 8, -18, 
						1.0, 0.0, 
						crandom()*180,0, 
						1000, cgs.media.portalFlareShader, FXF_NON_LINEAR_FADE );
		}

		cgi_S_StartSound( org, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.speciesBeamoutSound );
	}
	else
	{
		// Beaming in
		VectorMA( org, 65, dir, start );
		VectorMA( org, -40, dir, end );

		FX_AddLine( start, end, 1.0f, 0.5f, 48.0f, 0.4f, 0.1f, 1500, cgs.media.speciesPortalShader, FXF_NON_LINEAR_FADE );

		for ( i = -1; i <= 1; i++ )
		{ 
			VectorCopy( org, start );
			start[2] += 10.0f + i * 16.0f;

			for ( t = -1; t <= 1; t++ ) 
			{
				// create a 3 x 3 grid of starting points for the effect
				VectorClear( vel );
				VectorMA( vel, t * 16, cg.refdef.viewaxis[1], vel );
				
				FX_AddSprite( start, vel, NULL, 56.0f, -10.0f, 0.3f, 0.0f, -90.0f, 0, 1800, cgs.media.portalFlareShader, FXF_NON_LINEAR_FADE );
			}
		}

		cgi_S_StartSound( org, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.speciesBeaminSound );
	}

	VectorSet( color, 1.0f, 1.0f, 0.7f );
	CG_AddTempLight( org, 200, color, 1000 );
}
Beispiel #17
0
void CG_Chunks( int owner, vec3_t origin, const vec3_t normal, const vec3_t mins, const vec3_t maxs, 
						float speed, int numChunks, material_t chunkType, int customChunk, float baseScale, int customSound = 0 )
{
	localEntity_t	*le;
	refEntity_t		*re;
	vec3_t			dir;
	int				i, j, k;
	int				chunkModel = 0;
	leBounceSound_t	bounce = LEBS_NONE;
	float			r, speedMod = 1.0f;
	qboolean		chunk = qfalse;

	if ( chunkType == MAT_NONE )
	{
		// Well, we should do nothing
		return;
	}

	if ( customSound )
	{
		if ( cgs.sound_precache[customSound] ) 
		{
			cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.sound_precache[customSound] );
		}
	}
	// Set up our chunk sound info...breaking sounds are done here so they are done once on breaking..some return instantly because the chunks are done with effects instead of models
	switch( chunkType )
	{
	case MAT_GLASS:
		if ( !customSound )
		{
			cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.glassChunkSound );
		}
		return;
		break;
	case MAT_GRATE1:
		if ( !customSound )
		{
			cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.grateSound );
		}
		return;
		break;
	case MAT_ELECTRICAL:// (sparks)
		if ( !customSound )
		{
			cgi_S_StartSound( NULL, owner, CHAN_BODY, cgi_S_RegisterSound (va("sound/ambience/spark%d.wav", Q_irand(1, 6))) );
		}
		return;
		break;
	case MAT_DRK_STONE:
	case MAT_LT_STONE:
	case MAT_GREY_STONE:
	case MAT_WHITE_METAL:  // not quite sure what this stuff is supposed to be...it's for Stu
		if ( !customSound )
		{
			cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.rockBreakSound );
			bounce = LEBS_ROCK;
		}
		speedMod = 0.5f; // rock blows up less
		break;
	case MAT_GLASS_METAL:
		if ( !customSound )
		{
			cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.glassChunkSound ); // FIXME: should probably have a custom sound
			bounce = LEBS_METAL;
		}
		break;
	case MAT_CRATE1:
	case MAT_CRATE2:
		if ( !customSound )
		{
			cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.crateBreakSound[Q_irand(0,1)] );
		}
		break;
	case MAT_METAL:
	case MAT_METAL2:
	case MAT_METAL3:
	case MAT_ELEC_METAL:// FIXME: maybe have its own sound?
		if ( !customSound )
		{
			cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.chunkSound );
			bounce = LEBS_METAL;
		}
		speedMod = 0.8f; // metal blows up a bit more
		break;
	case MAT_ROPE:
		/*
		if ( !customSound )
		{
			cgi_S_StartSound( NULL, owner, CHAN_BODY, cgi_S_RegisterSound( "" ));  FIXME:  needs a sound
		}
		*/
		return;
		break;
	}

	if ( baseScale <= 0.0f )
	{
		baseScale = 1.0f;
	}

	// Chunks
	for( i = 0; i < numChunks; i++ )
	{
		if ( customChunk > 0 )
		{
			// Try to use a custom chunk.
			if ( cgs.model_draw[customChunk] )
			{
				chunk = qtrue;
				chunkModel = cgs.model_draw[customChunk];
			}
		}

		if ( !chunk )
		{
			// No custom chunk.  Pick a random chunk type at run-time so we don't get the same chunks
			switch( chunkType )
			{
			case MAT_METAL2: //bluegrey
				chunkModel = cgs.media.chunkModels[CHUNK_METAL2][Q_irand(0, 3)];
				break;
			case MAT_GREY_STONE://gray
				chunkModel = cgs.media.chunkModels[CHUNK_ROCK1][Q_irand(0, 3)];
				break;
			case MAT_LT_STONE: //tan
				chunkModel = cgs.media.chunkModels[CHUNK_ROCK2][Q_irand(0, 3)];
				break;
			case MAT_DRK_STONE://brown
				chunkModel = cgs.media.chunkModels[CHUNK_ROCK3][Q_irand(0, 3)];
				break;
			case MAT_WHITE_METAL:
				chunkModel = cgs.media.chunkModels[CHUNK_WHITE_METAL][Q_irand(0, 3)];
				break;
			case MAT_CRATE1://yellow multi-colored crate chunks
				chunkModel = cgs.media.chunkModels[CHUNK_CRATE1][Q_irand(0, 3)];
				break;
			case MAT_CRATE2://red multi-colored crate chunks
				chunkModel = cgs.media.chunkModels[CHUNK_CRATE2][Q_irand(0, 3)];
				break;
			case MAT_ELEC_METAL:
			case MAT_GLASS_METAL:
			case MAT_METAL://grey
				chunkModel = cgs.media.chunkModels[CHUNK_METAL1][Q_irand(0, 3)];
				break;
			case MAT_METAL3:
				if ( rand() & 1 )
				{
					chunkModel = cgs.media.chunkModels[CHUNK_METAL1][Q_irand(0, 3)];
				}
				else
				{
					chunkModel = cgs.media.chunkModels[CHUNK_METAL2][Q_irand(0, 3)];
				}
				break;
			}
		}

		// It wouldn't look good to throw a bunch of RGB axis models...so make sure we have something to work with.
		if ( chunkModel )
		{
			le = CG_AllocLocalEntity();
			re = &le->refEntity;

			re->hModel = chunkModel;
			le->leType = LE_FRAGMENT;
			le->endTime = cg.time + 1300 + random() * 900;

			// spawn chunk roughly in the bbox of the thing...bias towards center in case thing blowing up doesn't complete fill its bbox.
			for( j = 0; j < 3; j++ )
			{
				r = random() * 0.8f + 0.1f;
				re->origin[j] = ( r * mins[j] + ( 1 - r ) * maxs[j] );
			}
			VectorCopy( re->origin, le->pos.trBase );

			// Move out from center of thing, otherwise you can end up things moving across the brush in an undesirable direction.  Visually looks wrong
			VectorSubtract( re->origin, origin, dir );
			VectorNormalize( dir );
			VectorScale( dir, Q_flrand( speed * 0.5f, speed * 1.25f ) * speedMod, le->pos.trDelta );

			// Angular Velocity
			VectorSet( le->angles.trBase, random() * 360, random() * 360, random() * 360 );

			le->angles.trDelta[0] = crandom();
			le->angles.trDelta[1] = crandom();
			le->angles.trDelta[2] = 0; // don't do roll

			VectorScale( le->angles.trDelta, random() * 600.0f + 200.0f, le->angles.trDelta );

			le->pos.trType = TR_GRAVITY;
			le->angles.trType = TR_LINEAR;
			le->pos.trTime = le->angles.trTime = cg.time;
			le->bounceFactor = 0.2f + random() * 0.2f;
			le->leFlags |= LEF_TUMBLE;
			le->ownerGentNum = owner;
			le->leBounceSoundType = bounce; 

			// Make sure that we have the desired start size set
			le->radius = Q_flrand( baseScale * 0.75f, baseScale * 1.25f );
			re->nonNormalizedAxes = qtrue;
			AxisCopy( axisDefault, re->axis ); // could do an angles to axis, but this is cheaper and works ok
			for( k = 0; k < 3; k++ )
			{
				VectorScale( re->axis[k], le->radius, re->axis[k] );
			}
		}
	}
}
Beispiel #18
0
//------------------
void Cmd_Fx( gentity_t *ent )
{
	vec3_t		dir;
	gentity_t	*fx_ent = NULL;

	if ( Q_stricmp( gi.argv(1), "play" ) == 0 )
	{
		if ( gi.argc() == 3 )
		{
			// I guess, only allow one active at a time
			while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL ) 
			{
				G_FreeEntity( fx_ent );
			}

			fx_ent = G_Spawn();

			fx_ent->fxFile = gi.argv( 2 );

			// Move out in front of the person spawning the effect
			AngleVectors( ent->currentAngles, dir, NULL, NULL );
			VectorMA( ent->currentOrigin, 32, dir, fx_ent->s.origin );

extern void SP_fx_runner( gentity_t *ent );

			SP_fx_runner( fx_ent );
			fx_ent->delay = 2000;			// adjusting delay
			fx_ent->classname = "cmd_fx";	//	and classname

			return;
		}
	}
	else if ( Q_stricmp( gi.argv(1), "stop" ) == 0 )
	{
		while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL ) 
		{
			G_FreeEntity( fx_ent );
		}

		return;
	}
	else if ( Q_stricmp( gi.argv(1), "delay" ) == 0 )
	{
		while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL ) 
		{
			if ( gi.argc() == 3 )
			{
				fx_ent->delay = atoi( gi.argv( 2 ));
			}
			else
			{
				gi.Printf( S_COLOR_GREEN"FX: current delay is: %i\n", fx_ent->delay );
			}

			return;
		}
	}
	else if ( Q_stricmp( gi.argv(1), "random" ) == 0 )
	{
		while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL ) 
		{
			if ( gi.argc() == 3 )
			{
				fx_ent->random = atoi( gi.argv( 2 ));
			}
			else
			{
				gi.Printf( S_COLOR_GREEN"FX: current random is: %6.2f\n", fx_ent->random );
			}

			return;
		}
	}
	else if ( Q_stricmp( gi.argv(1), "origin" ) == 0 )
	{
		while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL ) 
		{
			if ( gi.argc() == 5 )
			{
				fx_ent->s.origin[0] = atof( gi.argv( 2 ));
				fx_ent->s.origin[1] = atof( gi.argv( 3 ));
				fx_ent->s.origin[2] = atof( gi.argv( 4 ));

				G_SetOrigin( fx_ent, fx_ent->s.origin );
			}
			else
			{
				gi.Printf( S_COLOR_GREEN"FX: current origin is: <%6.2f %6.2f %6.2f>\n", 
									fx_ent->currentOrigin[0], fx_ent->currentOrigin[1], fx_ent->currentOrigin[2] );
			}

			return;
		}
	}
	else if ( Q_stricmp( gi.argv(1), "dir" ) == 0 )
	{
		while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL ) 
		{
			if ( gi.argc() == 5 )
			{
				fx_ent->s.angles[0] = atof( gi.argv( 2 ));
				fx_ent->s.angles[1] = atof( gi.argv( 3 ));
				fx_ent->s.angles[2] = atof( gi.argv( 4 ));

				if ( !VectorNormalize( fx_ent->s.angles ))
				{
					// must have been zero length
					fx_ent->s.angles[2] = 1;
				}
			}
			else
			{
				gi.Printf( S_COLOR_GREEN"FX: current dir is: <%6.2f %6.2f %6.2f>\n", 
									fx_ent->s.angles[0], fx_ent->s.angles[1], fx_ent->s.angles[2] );
			}

			return;
		}
	}

	gi.Printf( S_COLOR_CYAN"Fx--------------------------------------------------------\n" );
	gi.Printf( S_COLOR_CYAN"commands:              sample usage:\n" );
	gi.Printf( S_COLOR_CYAN"----------------------------------------------------------\n" );
	gi.Printf( S_COLOR_CYAN"fx play <filename>     fx play sparks, fx play env/fire\n" );
	gi.Printf( S_COLOR_CYAN"fx stop                fx stop\n" );		
	gi.Printf( S_COLOR_CYAN"fx delay <#>           fx delay 1000\n" );
	gi.Printf( S_COLOR_CYAN"fx random <#>          fx random 200\n" );
	gi.Printf( S_COLOR_CYAN"fx origin <#><#><#>    fx origin 10 20 30\n" );
	gi.Printf( S_COLOR_CYAN"fx dir <#><#><#>       fx dir 0 0 -1\n\n" );
}
Beispiel #19
0
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void EmitInitialDispInfos( void )
{
	int					i;
	mapdispinfo_t		*pMapDisp;
	ddispinfo_t			*pDisp;
	Vector				v;
	
	// Calculate the total number of verts.
	int nTotalVerts = 0;
	int nTotalTris = 0;
	for ( i=0; i < nummapdispinfo; i++ )
	{
		nTotalVerts += NUM_DISP_POWER_VERTS( mapdispinfo[i].power );
		nTotalTris += NUM_DISP_POWER_TRIS( mapdispinfo[i].power );
	}

	// Clear the output arrays..
	g_dispinfo.Purge();
	g_dispinfo.SetSize( nummapdispinfo );
	g_DispVerts.SetSize( nTotalVerts );
	g_DispTris.SetSize( nTotalTris );

	int iCurVert = 0;
	int iCurTri = 0;
	for( i = 0; i < nummapdispinfo; i++ )
	{
		pDisp = &g_dispinfo[i];
		pMapDisp = &mapdispinfo[i];
		
		CDispVert *pOutVerts = &g_DispVerts[iCurVert];
		CDispTri *pOutTris = &g_DispTris[iCurTri];

		// Setup the vert pointers.
		pDisp->m_iDispVertStart = iCurVert;
		pDisp->m_iDispTriStart = iCurTri;
		iCurVert += NUM_DISP_POWER_VERTS( pMapDisp->power );
		iCurTri += NUM_DISP_POWER_TRIS( pMapDisp->power );

		//
		// save power, minimum tesselation, and smoothing angle
		//
		pDisp->power = pMapDisp->power;
		
		// If the high bit is set - this is FLAGS!
		pDisp->minTess = pMapDisp->flags;
		pDisp->minTess |= 0x80000000;
//		pDisp->minTess = pMapDisp->minTess;
		pDisp->smoothingAngle = pMapDisp->smoothingAngle;
		pDisp->m_iMapFace = -2;

		// get surface contents
		pDisp->contents = pMapDisp->face.contents;
		
		pDisp->startPosition = pMapDisp->startPosition;
		//
		// add up the vectorOffsets and displacements, save alphas (per vertex)
		//
		int size = ( ( ( 1 << pDisp->power ) + 1 ) * ( ( 1 << pDisp->power ) + 1 ) );
		for( int j = 0; j < size; j++ )
		{
			VectorScale( pMapDisp->vectorDisps[j], pMapDisp->dispDists[j], v );
			VectorAdd( v, pMapDisp->vectorOffsets[j], v );
			
			float dist = VectorLength( v );
			VectorNormalize( v );
			
			VectorCopy( v, pOutVerts[j].m_vVector );
			pOutVerts[j].m_flDist = dist;

			pOutVerts[j].m_flAlpha = pMapDisp->alphaValues[j];
		}

		int nTriCount = ( (1 << (pDisp->power)) * (1 << (pDisp->power)) * 2 );
		for ( int iTri = 0; iTri< nTriCount; ++iTri )
		{
			pOutTris[iTri].m_uiTags = pMapDisp->triTags[iTri];
		}
		//===================================================================
		//===================================================================

		// save the index for face data reference
		pMapDisp->face.dispinfo = i;
	}
}
Beispiel #20
0
void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace)
{
    // See if the vehicle has crashed into the ground.
    Vehicle_t *pSelfVeh = pEnt->m_pVehicle;
    float magnitude = VectorLength( pm->ps->velocity ) * pSelfVeh->m_pVehicleInfo->mass / 50.0f;
    qboolean forceSurfDestruction = qfalse;
#ifdef QAGAME
    gentity_t *hitEnt = trace!=NULL?&g_entities[trace->entityNum]:NULL;

    if (!hitEnt || //nothing to hit
            (pSelfVeh && pSelfVeh->m_pPilot &&//I'm a piloted vehicle
             hitEnt && hitEnt->s.eType == ET_MISSILE && hitEnt->inuse &&//that hit a missile
             hitEnt->r.ownerNum == pSelfVeh->m_pPilot->s.number)//and the missile is owned by my pilot
       )
    {   //don't hit it
        return;
    }

    if ( pSelfVeh//I have a vehicle struct
            && pSelfVeh->m_iRemovedSurfaces )//vehicle has bits removed
    {   //spiralling to our deaths, explode on any solid impact
        if ( hitEnt->s.NPC_class == CLASS_VEHICLE )
        {   //hit another vehicle, explode!
            //Give credit to whoever got me into this death spiral state
            //[Asteroids]
            G_DamageFromKiller( (gentity_t *)pEnt, (gentity_t *)pSelfVeh->m_pParentEntity, (gentity_t *)hitEnt, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_COLLISION );
            /*
            gentity_t *parent = (gentity_t *)pSelfVeh->m_pParentEntity;
            gentity_t *killer = NULL;
            if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
            	parent->client->ps.otherKillerTime > level.time)
            {
            	gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];

            	if (potentialKiller->inuse && potentialKiller->client)
            	{ //he's valid I guess
            		killer = potentialKiller;
            	}
            }
            //FIXME: damage hitEnt, some, too?  Our explosion should hurt them some, but...
            G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT
            */
            //[/Asteroids]
            return;
        }
        else if ( !VectorCompare( trace->plane.normal, vec3_origin )
                  && (trace->entityNum == ENTITYNUM_WORLD || hitEnt->r.bmodel ) )
        {   //have a valid hit plane and we hit a solid brush
            vec3_t	moveDir;
            float	impactDot;
            VectorCopy( pm->ps->velocity, moveDir );
            VectorNormalize( moveDir );
            impactDot = DotProduct( moveDir, trace->plane.normal );
            if ( impactDot <= -0.7f )//hit rather head-on and hard
            {   // Just DIE now
                //Give credit to whoever got me into this death spiral state
                //[Asteroids]
                G_DamageFromKiller( (gentity_t *)pEnt, (gentity_t *)pSelfVeh->m_pParentEntity, (gentity_t *)hitEnt, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );
                /*
                gentity_t *killer = NULL;
                if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
                	parent->client->ps.otherKillerTime > level.time)
                {
                	gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];

                	if (potentialKiller->inuse && potentialKiller->client)
                	{ //he's valid I guess
                		killer = potentialKiller;
                	}
                }
                G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT
                */
                //[/Asteroids]
                return;
            }
        }
    }

    if ( trace->entityNum < ENTITYNUM_WORLD
            && hitEnt->s.eType == ET_MOVER
            && hitEnt->s.apos.trType != TR_STATIONARY//rotating
            && (hitEnt->spawnflags&16) //IMPACT
            && Q_stricmp( "func_rotating", hitEnt->classname ) == 0 )
    {   //hit a func_rotating that is supposed to destroy anything it touches!
        //guarantee the hit will happen, thereby taking off a piece of the ship
        forceSurfDestruction = qtrue;
    }
    else if ( (fabs(pm->ps->velocity[0])+fabs(pm->ps->velocity[1])) < 100.0f
              && pm->ps->velocity[2] > -100.0f )
#else
    if ( (fabs(pm->ps->velocity[0])+fabs(pm->ps->velocity[1])) < 100.0f
            && pm->ps->velocity[2] > -100.0f )
#endif
        /*
        if ( (pSelfVeh->m_ulFlags&VEH_GEARSOPEN)
        && trace->plane.normal[2] > 0.7f
        && fabs(pSelfVeh->m_vOrientation[PITCH]) < 0.2f
        && fabs(pSelfVeh->m_vOrientation[ROLL]) < 0.2f )*/
    {   //we're landing, we're cool
        //FIXME: some sort of landing "thump", not the impactFX
        /*
        if ( pSelfVeh->m_pVehicleInfo->iImpactFX )
        {
        	vec3_t up = {0,0,1};
        #ifdef QAGAME
        	G_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, up );
        #else
        	trap_FX_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, up, -1, -1 );
        #endif
        }
        */
        //this was annoying me -rww
        //FIXME: this shouldn't even be getting called when the vehicle is at rest!
#ifdef QAGAME
        if (hitEnt && (hitEnt->s.eType == ET_PLAYER || hitEnt->s.eType == ET_NPC) && pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
        {   //always smack players
        }
        else
#endif
        {
            return;
        }
    }
    if ( pSelfVeh &&
            (pSelfVeh->m_pVehicleInfo->type == VH_SPEEDER || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER) && //this is kind of weird on tauntauns and atst's..
            (magnitude >= 100||forceSurfDestruction) )
    {
        if ( pEnt->m_pVehicle->m_iHitDebounce < pm->cmd.serverTime
                || forceSurfDestruction )
        {   //a bit of a hack, may conflict with getting shot, but...
            //FIXME: impact sound and effect should be gotten from g_vehicleInfo...?
            //FIXME: should pass in trace.endpos and trace.plane.normal
            vec3_t	vehUp;
//[Asteroids]
#ifdef QAGAME
            qboolean noDamage = qfalse;
#else
//#ifndef QAGAME
//[/Asteroids]
            bgEntity_t *hitEnt;
#endif

            if ( trace && !pSelfVeh->m_iRemovedSurfaces && !forceSurfDestruction )
            {
                qboolean turnFromImpact = qfalse, turnHitEnt = qfalse;
                float l = pm->ps->speed*0.5f;
                vec3_t	bounceDir;
#ifndef QAGAME
                bgEntity_t *hitEnt = PM_BGEntForNum(trace->entityNum);
#endif
                if ( (trace->entityNum == ENTITYNUM_WORLD || hitEnt->s.solid == SOLID_BMODEL)//bounce off any brush
                        && !VectorCompare(trace->plane.normal, vec3_origin) )//have a valid plane to bounce off of
                {   //bounce off in the opposite direction of the impact
                    if (pSelfVeh->m_pVehicleInfo->type == VH_SPEEDER)
                    {
                        pm->ps->speed *= pml.frametime;
                        VectorCopy(trace->plane.normal, bounceDir);
                    }
                    else if ( trace->plane.normal[2] >= MIN_LANDING_SLOPE//flat enough to land on
                              && pSelfVeh->m_LandTrace.fraction < 1.0f //ground present
                              && pm->ps->speed <= MIN_LANDING_SPEED )
                    {   //could land here, don't bounce off, in fact, return altogether!
                        return;
                    }
                    else
                    {
                        if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
                        {
                            turnFromImpact = qtrue;
                        }
                        VectorCopy(trace->plane.normal, bounceDir);
                    }
                }
                else if ( pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER )
                {   //check for impact with another fighter
#ifndef QAGAME
                    bgEntity_t *hitEnt = PM_BGEntForNum(trace->entityNum);
#endif
                    if ( hitEnt->s.NPC_class == CLASS_VEHICLE
                            && hitEnt->m_pVehicle
                            && hitEnt->m_pVehicle->m_pVehicleInfo
                            && hitEnt->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
                    {   //two vehicles hit each other, turn away from the impact
                        turnFromImpact = qtrue;
                        turnHitEnt = qtrue;
#ifndef QAGAME
                        VectorSubtract( pm->ps->origin, hitEnt->s.origin, bounceDir );
#else
                        VectorSubtract( pm->ps->origin, hitEnt->r.currentOrigin, bounceDir );
#endif
                        VectorNormalize( bounceDir );
                    }
                }
                if ( turnFromImpact )
                {   //bounce off impact surf and turn away
                    vec3_t	pushDir= {0}, turnAwayAngles, turnDelta;
                    float	turnStrength, pitchTurnStrength, yawTurnStrength;
                    vec3_t	moveDir;
                    float bounceDot, turnDivider;
                    //bounce
                    if ( !turnHitEnt )
                    {   //hit wall
                        VectorScale(bounceDir, (pm->ps->speed*0.25f/pSelfVeh->m_pVehicleInfo->mass), pushDir);
                    }
                    else
                    {   //hit another fighter
#ifndef QAGAME
                        VectorScale( bounceDir, (pm->ps->speed+hitEnt->s.speed)*0.5f, bounceDir );
#else
                        if ( hitEnt->client )
                        {
                            VectorScale( bounceDir, (pm->ps->speed+hitEnt->client->ps.speed)*0.5f, pushDir );
                        }
                        else
                        {
                            VectorScale( bounceDir, (pm->ps->speed+hitEnt->s.speed)*0.5f, pushDir );
                        }
#endif
                        VectorScale(pushDir, (l/pSelfVeh->m_pVehicleInfo->mass), pushDir);
                        VectorScale(pushDir, 0.1f, pushDir);
                    }
                    VectorNormalize2( pm->ps->velocity, moveDir );
                    bounceDot = DotProduct( moveDir, bounceDir )*-1;
                    if ( bounceDot < 0.1f )
                    {
                        bounceDot = 0.1f;
                    }
                    VectorScale( pushDir, bounceDot, pushDir );
                    VectorAdd(pm->ps->velocity, pushDir, pm->ps->velocity);
                    //turn
                    turnDivider = (pSelfVeh->m_pVehicleInfo->mass/400.0f);
                    if ( turnHitEnt )
                    {   //don't turn as much when hit another ship
                        turnDivider *= 4.0f;
                    }
                    if ( turnDivider < 0.5f )
                    {
                        turnDivider = 0.5f;
                    }
                    turnStrength = (magnitude/2000.0f);
                    if ( turnStrength < 0.1f )
                    {
                        turnStrength = 0.1f;
                    }
                    else if ( turnStrength > 2.0f )
                    {
                        turnStrength = 2.0f;
                    }
                    //get the angles we are going to turn towards
                    vectoangles( bounceDir, turnAwayAngles );
                    //get the delta from our current angles to those new angles
                    AnglesSubtract( turnAwayAngles, pSelfVeh->m_vOrientation, turnDelta );
                    //now do pitch
                    if ( !bounceDir[2] )
                    {   //shouldn't be any pitch
                    }
                    else
                    {
                        pitchTurnStrength = turnStrength*turnDelta[PITCH];
                        if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
                        {
                            pitchTurnStrength = MAX_IMPACT_TURN_ANGLE;
                        }
                        else if ( pitchTurnStrength < -MAX_IMPACT_TURN_ANGLE )
                        {
                            pitchTurnStrength = -MAX_IMPACT_TURN_ANGLE;
                        }
                        //pSelfVeh->m_vOrientation[PITCH] = AngleNormalize180(pSelfVeh->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
                        pSelfVeh->m_vFullAngleVelocity[PITCH] = AngleNormalize180(pSelfVeh->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
                    }
                    //now do yaw
                    if ( !bounceDir[0]
                            && !bounceDir[1] )
                    {   //shouldn't be any yaw
                    }
                    else
                    {
                        yawTurnStrength = turnStrength*turnDelta[YAW];
                        if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
                        {
                            yawTurnStrength = MAX_IMPACT_TURN_ANGLE;
                        }
                        else if ( yawTurnStrength < -MAX_IMPACT_TURN_ANGLE )
                        {
                            yawTurnStrength = -MAX_IMPACT_TURN_ANGLE;
                        }
                        //pSelfVeh->m_vOrientation[ROLL] = AngleNormalize180(pSelfVeh->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
                        pSelfVeh->m_vFullAngleVelocity[ROLL] = AngleNormalize180(pSelfVeh->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
                    }
                    /*
                    PM_SetPMViewAngle(pm->ps, pSelfVeh->m_vOrientation, &pSelfVeh->m_ucmd);
                    if ( pm_entVeh )
                    {//I'm a vehicle, so pm_entVeh is actually my pilot
                    	bgEntity_t *pilot = pm_entVeh;
                    	if ( !BG_UnrestrainedPitchRoll( pilot->playerState, pSelfVeh ) )
                    	{
                    		//set the rider's viewangles to the vehicle's viewangles
                    		PM_SetPMViewAngle(pilot->playerState, pSelfVeh->m_vOrientation, &pSelfVeh->m_ucmd);
                    	}
                    }
                    */
#ifdef QAGAME//server-side, turn the guy we hit away from us, too
                    if ( turnHitEnt//make the other guy turn and get pushed
                            && hitEnt->client //must be a valid client
                            && !FighterIsLanded( hitEnt->m_pVehicle, &hitEnt->client->ps )//but not if landed
                            && !(hitEnt->spawnflags&2) )//and not if suspended
                    {
                        l = hitEnt->client->ps.speed;
                        //now bounce *them* away and turn them
                        //flip the bounceDir
                        VectorScale( bounceDir, -1, bounceDir );
                        //do bounce
                        VectorScale( bounceDir, (pm->ps->speed+l)*0.5f, pushDir );
                        VectorScale(pushDir, (l*0.5f/hitEnt->m_pVehicle->m_pVehicleInfo->mass), pushDir);
                        VectorNormalize2( hitEnt->client->ps.velocity, moveDir );
                        bounceDot = DotProduct( moveDir, bounceDir )*-1;
                        if ( bounceDot < 0.1f )
                        {
                            bounceDot = 0.1f;
                        }
                        VectorScale( pushDir, bounceDot, pushDir );
                        VectorAdd(hitEnt->client->ps.velocity, pushDir, hitEnt->client->ps.velocity);
                        //turn
                        turnDivider = (hitEnt->m_pVehicle->m_pVehicleInfo->mass/400.0f);
                        if ( turnHitEnt )
                        {   //don't turn as much when hit another ship
                            turnDivider *= 4.0f;
                        }
                        if ( turnDivider < 0.5f )
                        {
                            turnDivider = 0.5f;
                        }
                        //get the angles we are going to turn towards
                        vectoangles( bounceDir, turnAwayAngles );
                        //get the delta from our current angles to those new angles
                        AnglesSubtract( turnAwayAngles, hitEnt->m_pVehicle->m_vOrientation, turnDelta );
                        //now do pitch
                        if ( !bounceDir[2] )
                        {   //shouldn't be any pitch
                        }
                        else
                        {
                            pitchTurnStrength = turnStrength*turnDelta[PITCH];
                            if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
                            {
                                pitchTurnStrength = MAX_IMPACT_TURN_ANGLE;
                            }
                            else if ( pitchTurnStrength < -MAX_IMPACT_TURN_ANGLE )
                            {
                                pitchTurnStrength = -MAX_IMPACT_TURN_ANGLE;
                            }
                            //hitEnt->m_pVehicle->m_vOrientation[PITCH] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
                            hitEnt->m_pVehicle->m_vFullAngleVelocity[PITCH] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
                        }
                        //now do yaw
                        if ( !bounceDir[0]
                                && !bounceDir[1] )
                        {   //shouldn't be any yaw
                        }
                        else
                        {
                            yawTurnStrength = turnStrength*turnDelta[YAW];
                            if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
                            {
                                yawTurnStrength = MAX_IMPACT_TURN_ANGLE;
                            }
                            else if ( yawTurnStrength < -MAX_IMPACT_TURN_ANGLE )
                            {
                                yawTurnStrength = -MAX_IMPACT_TURN_ANGLE;
                            }

                            hitEnt->m_pVehicle->m_vFullAngleVelocity[ROLL] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
                        }
                    }
#endif
                }
            }

#ifdef QAGAME
            if (!hitEnt)
            {
                return;
            }

            AngleVectors( pSelfVeh->m_vOrientation, NULL, NULL, vehUp );
            if ( pSelfVeh->m_pVehicleInfo->iImpactFX )
            {
                //G_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, vehUp );
                //tempent use bad!
                G_AddEvent((gentity_t *)pEnt, EV_PLAY_EFFECT_ID, pSelfVeh->m_pVehicleInfo->iImpactFX);
            }
            pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200;
            magnitude /= pSelfVeh->m_pVehicleInfo->toughness * 50.0f;

            if (hitEnt
                    && (hitEnt->s.eType != ET_TERRAIN || !(hitEnt->spawnflags & 1) || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER))
            {   //don't damage the vehicle from terrain that doesn't want to damage vehicles
                //[Asteroids]
                gentity_t *killer = NULL;
                //[/Asteroids]
                if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
                {   //increase the damage...
                    float mult = (pSelfVeh->m_vOrientation[PITCH]*0.1f);
                    if (mult < 1.0f)
                    {
                        mult = 1.0f;
                    }
                    if (hitEnt->inuse && hitEnt->takedamage)
                    {   //if the other guy takes damage, don't hurt us a lot for ramming him
                        //unless it's a vehicle, then we get 1.5 times damage
                        if (hitEnt->s.eType == ET_NPC &&
                                hitEnt->s.NPC_class == CLASS_VEHICLE &&
                                hitEnt->m_pVehicle)
                        {
                            mult = 1.5f;
                        }
                        else
                        {
                            mult = 0.5f;
                        }
                    }

                    magnitude *= mult;
                }
                pSelfVeh->m_iLastImpactDmg = magnitude;
                //FIXME: what about proper death credit to the guy who shot you down?
                //FIXME: actually damage part of the ship that impacted?
                if ( hitEnt->s.eType == ET_MISSILE )//missile
                {
                    //FIX: NEVER do or take impact damage from a missile...
                    noDamage = qtrue;
                    if ( (hitEnt->s.eFlags&EF_JETPACK_ACTIVE)//vehicle missile
                            && ((gentity_t *)hitEnt)->r.ownerNum < MAX_CLIENTS )//valid client owner
                    {   //I ran into a missile and died because of the impact, give credit to the missile's owner (PROBLEM: might this ever accidently give improper credit to client 0?)
                        /*
                        if ( ((gentity_t *)hitEnt)->r.ownerNum == pEnt->s.number )
                        {//hit our own missile?  Don't damage ourselves or it... (so we don't kill ourselves!) if it hits *us*, then fine, but not here
                        	noDamage = qtrue;
                        }
                        */
                        killer = &g_entities[((gentity_t *)hitEnt)->r.ownerNum];
                    }
                }
                if ( !noDamage )
                {
                    G_Damage( (gentity_t *)pEnt, ((gentity_t*)hitEnt), killer!=NULL?killer:((gentity_t *)hitEnt), NULL, pm->ps->origin, magnitude*5, DAMAGE_NO_ARMOR, (hitEnt->s.NPC_class==CLASS_VEHICLE?MOD_COLLISION:MOD_FALLING) );//FIXME: MOD_IMPACT
                }
                //G_Damage( (gentity_t *)pEnt, NULL, NULL, NULL, pm->ps->origin, magnitude*5, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT
                //[/Asteroids]

                if (pSelfVeh->m_pVehicleInfo->surfDestruction)
                {
                    G_FlyVehicleSurfaceDestruction((gentity_t *)pEnt, trace, magnitude, forceSurfDestruction );
                }

                pSelfVeh->m_ulFlags |= VEH_CRASHING;
            }

            if (hitEnt &&
                    hitEnt->inuse &&
                    hitEnt->takedamage)
            {   //damage this guy because we hit him
                float pmult = 1.0f;
                int finalD;
                gentity_t *attackEnt;

                if ( (hitEnt->s.eType == ET_PLAYER && hitEnt->s.number < MAX_CLIENTS) ||
                        (hitEnt->s.eType == ET_NPC && hitEnt->s.NPC_class != CLASS_VEHICLE) )
                {   //probably a humanoid, or something
                    if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
                    {   //player die good.. if me fighter
                        pmult = 2000.0f;
                    }
                    else
                    {
                        pmult = 40.0f;
                    }

                    if (hitEnt->client &&
                            BG_IsKnockDownable(&hitEnt->client->ps) &&
                            G_CanBeEnemy((gentity_t *)pEnt, hitEnt))
                    {   //smash!
                        if (hitEnt->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
                        {
                            hitEnt->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
                            hitEnt->client->ps.forceHandExtendTime = pm->cmd.serverTime + 1100;
                            hitEnt->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
                        }

                        hitEnt->client->ps.otherKiller = pEnt->s.number;
                        hitEnt->client->ps.otherKillerTime = pm->cmd.serverTime + 5000;
                        hitEnt->client->ps.otherKillerDebounceTime = pm->cmd.serverTime + 100;
                        //[Asteroids]
                        hitEnt->client->otherKillerMOD = MOD_COLLISION;
                        hitEnt->client->otherKillerVehWeapon = 0;
                        hitEnt->client->otherKillerWeaponType = WP_NONE;
                        //[/Asteroids]

                        //add my velocity into his to force him along in the correct direction from impact
                        VectorAdd(hitEnt->client->ps.velocity, pm->ps->velocity, hitEnt->client->ps.velocity);
                        //upward thrust
                        hitEnt->client->ps.velocity[2] += 200.0f;
                    }
                }

                if (pSelfVeh->m_pPilot)
                {
                    attackEnt = (gentity_t *)pSelfVeh->m_pPilot;
                }
                else
                {
                    attackEnt = (gentity_t *)pEnt;
                }

                finalD = magnitude*pmult;
                if (finalD < 1)
                {
                    finalD = 1;
                }
                //[/Asteroids]
                if ( !noDamage )
                {
                    G_Damage( hitEnt, attackEnt, attackEnt, NULL, pm->ps->origin, finalD, 0, (hitEnt->s.NPC_class==CLASS_VEHICLE?MOD_COLLISION:MOD_FALLING/*MOD_MELEE*/) );//FIXME: MOD_IMPACT
                }
                //[Asteroids]
            }
#else	//this is gonna result in "double effects" for the client doing the prediction.
            //it doesn't look bad though. could just use predicted events, but I'm too lazy.
            hitEnt = PM_BGEntForNum(trace->entityNum);

            if (!hitEnt || hitEnt->s.owner != pEnt->s.number)
            {   //don't hit your own missiles!
                AngleVectors( pSelfVeh->m_vOrientation, NULL, NULL, vehUp );
                pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200;
                trap_FX_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, vehUp, -1, -1 );

                pSelfVeh->m_ulFlags |= VEH_CRASHING;
            }
#endif
        }
    }
}
Beispiel #21
0
void UI_SaberDrawBlade( itemDef_t *item, char *saberName, int saberModel, saberType_t saberType, vector3 *origin, vector3 *angles, int bladeNum ) {
	vector3	org_, end,
		axis_[3] = { { 0.0f } };	// shut the compiler up
	mdxaBone_t	boltMatrix;
	effectTrailArgStruct_t fx;
	saber_colors_t bladeColor;
	float bladeLength, bladeRadius;
	char bladeColorString[MAX_QPATH];
	int snum;
	const char *tagName;
	int bolt;
	qboolean tagHack = qfalse;
	int styleToUse = atoi( UI_Cvar_VariableString( "cg_saberBladeStyle" ) );


	if ( (item->flags&ITF_ISSABER) && saberModel < 2 ) {
		snum = 0;
		trap->Cvar_VariableStringBuffer( "ui_saber_color", bladeColorString, sizeof(bladeColorString) );
	}
	else//if ( item->flags&ITF_ISSABER2 ) - presumed
	{
		snum = 1;
		trap->Cvar_VariableStringBuffer( "ui_saber2_color", bladeColorString, sizeof(bladeColorString) );
	}

	if ( !trap->G2API_HasGhoul2ModelOnIndex( &(item->ghoul2), saberModel ) ) {//invalid index!
		return;
	}

	bladeColor = TranslateSaberColor( bladeColorString );

	bladeLength = UI_SaberBladeLengthForSaber( saberName, bladeNum );
	bladeRadius = UI_SaberBladeRadiusForSaber( saberName, bladeNum );

	tagName = va( "*blade%d", bladeNum + 1 );
	bolt = trap->G2API_AddBolt( item->ghoul2, saberModel, tagName );

	if ( bolt == -1 ) {
		tagHack = qtrue;
		//hmm, just fall back to the most basic tag (this will also make it work with pre-JKA saber models
		bolt = trap->G2API_AddBolt( item->ghoul2, saberModel, "*flash" );
		if ( bolt == -1 ) {//no tag_flash either?!!
			bolt = 0;
		}
	}

	//	angles.pitch = curYaw;
	//	angles.roll = 0;

	trap->G2API_GetBoltMatrix( item->ghoul2, saberModel, bolt, &boltMatrix, angles, origin, uiInfo.uiDC.realTime, NULL, &vec3_origin );//NULL was cgs.model_draw

	// work the matrix axis stuff into the original axis and origins used.
	BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, &org_ );
	BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, &axis_[0] );//front (was NEGATIVE_Y, but the md3->glm exporter screws up this tag somethin' awful)
	//		...changed this back to NEGATIVE_Y
	BG_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_X, &axis_[1] );//right ... and changed this to NEGATIVE_X
	BG_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_Z, &axis_[2] );//up

	VectorMA( &org_, bladeLength, &axis_[0], &end );

	VectorAdd( &end, &axis_[0], &end );

	if ( tagHack ) {
		switch ( saberType ) {
		default:
		case SABER_SINGLE:
			VectorMA( &org_, 1.0f, &axis_[0], &org_ );
			break;
		case SABER_DAGGER:
		case SABER_LANCE:
			break;
		case SABER_STAFF:
			if ( bladeNum == 0 )
				VectorMA( &org_, 12 * 1.0f, &axis_[0], &org_ );

			if ( bladeNum == 1 ) {
				VectorScale( &axis_[0], -1, &axis_[0] );
				VectorMA( &org_, 12 * 1.0f, &axis_[0], &org_ );
			}
			break;
		case SABER_BROAD:
			if ( bladeNum == 0 )
				VectorMA( &org_, -1 * 1.0f, &axis_[1], &org_ );
			else if ( bladeNum == 1 )
				VectorMA( &org_, 1 * 1.0f, &axis_[1], &org_ );
			break;
		case SABER_PRONG:
			if ( bladeNum == 0 )
				VectorMA( &org_, -3 * 1.0f, &axis_[1], &org_ );
			else if ( bladeNum == 1 )
				VectorMA( &org_, 3 * 1.0f, &axis_[1], &org_ );
			break;
		case SABER_ARC:
			VectorSubtract( &axis_[1], &axis_[2], &axis_[1] );
			VectorNormalize( &axis_[1] );
			switch ( bladeNum ) {
			case 0:
				VectorMA( &org_, 8 * 1.0f, &axis_[0], &org_ );
				VectorScale( &axis_[0], 0.75f, &axis_[0] );
				VectorScale( &axis_[1], 0.25f, &axis_[1] );
				VectorAdd( &axis_[0], &axis_[1], &axis_[0] );
				break;
			case 1:
				VectorScale( &axis_[0], 0.25f, &axis_[0] );
				VectorScale( &axis_[1], 0.75f, &axis_[1] );
				VectorAdd( &axis_[0], &axis_[1], &axis_[0] );
				break;
			case 2:
				VectorMA( &org_, -8 * 1.0f, &axis_[0], &org_ );
				VectorScale( &axis_[0], -0.25f, &axis_[0] );
				VectorScale( &axis_[1], 0.75f, &axis_[1] );
				VectorAdd( &axis_[0], &axis_[1], &axis_[0] );
				break;
			case 3:
				VectorMA( &org_, -16 * 1.0f, &axis_[0], &org_ );
				VectorScale( &axis_[0], -0.75f, &axis_[0] );
				VectorScale( &axis_[1], 0.25f, &axis_[1] );
				VectorAdd( &axis_[0], &axis_[1], &axis_[0] );
				break;
			default:
				break;
			}
			break;
		case SABER_SAI:
			if ( bladeNum == 1 )
				VectorMA( &org_, -3 * 1.0f, &axis_[1], &org_ );
			else if ( bladeNum == 2 )
				VectorMA( &org_, 3 * 1.0f, &axis_[1], &org_ );
			break;
		case SABER_CLAW:
			switch ( bladeNum ) {
			case 0:
				VectorMA( &org_, 2 * 1.0f, &axis_[0], &org_ );
				VectorMA( &org_, 2 * 1.0f, &axis_[2], &org_ );
				break;
			case 1:
				VectorMA( &org_, 2 * 1.0f, &axis_[0], &org_ );
				VectorMA( &org_, 2 * 1.0f, &axis_[2], &org_ );
				VectorMA( &org_, 2 * 1.0f, &axis_[1], &org_ );
				break;
			case 2:
				VectorMA( &org_, 2 * 1.0f, &axis_[0], &org_ );
				VectorMA( &org_, 2 * 1.0f, &axis_[2], &org_ );
				VectorMA( &org_, -2 * 1.0f, &axis_[1], &org_ );
				break;
			default:
				break;
			}
			break;
		case SABER_STAR:
			switch ( bladeNum ) {
			case 0:
				VectorMA( &org_, 8 * 1.0f, &axis_[0], &org_ );
				break;
			case 1:
				VectorScale( &axis_[0], 0.33f, &axis_[0] );
				VectorScale( &axis_[2], 0.67f, &axis_[2] );
				VectorAdd( &axis_[0], &axis_[2], &axis_[0] );
				VectorMA( &org_, 8 * 1.0f, &axis_[0], &org_ );
				break;
			case 2:
				VectorScale( &axis_[0], -0.33f, &axis_[0] );
				VectorScale( &axis_[2], 0.67f, &axis_[2] );
				VectorAdd( &axis_[0], &axis_[2], &axis_[0] );
				VectorMA( &org_, 8 * 1.0f, &axis_[0], &org_ );
				break;
			case 3:
				VectorScale( &axis_[0], -1, &axis_[0] );
				VectorMA( &org_, 8 * 1.0f, &axis_[0], &org_ );
				break;
			case 4:
				VectorScale( &axis_[0], -0.33f, &axis_[0] );
				VectorScale( &axis_[2], -0.67f, &axis_[2] );
				VectorAdd( &axis_[0], &axis_[2], &axis_[0] );
				VectorMA( &org_, 8 * 1.0f, &axis_[0], &org_ );
				break;
			case 5:
				VectorScale( &axis_[0], 0.33f, &axis_[0] );
				VectorScale( &axis_[2], -0.67f, &axis_[2] );
				VectorAdd( &axis_[0], &axis_[2], &axis_[0] );
				VectorMA( &org_, 8 * 1.0f, &axis_[0], &org_ );
				break;
			default:
				break;
			}
			break;
		case SABER_TRIDENT:
			switch ( bladeNum ) {
			case 0:
				VectorMA( &org_, 24 * 1.0f, &axis_[0], &org_ );
				break;
			case 1:
				VectorMA( &org_, -6 * 1.0f, &axis_[1], &org_ );
				VectorMA( &org_, 24 * 1.0f, &axis_[0], &org_ );
				break;
			case 2:
				VectorMA( &org_, 6 * 1.0f, &axis_[1], &org_ );
				VectorMA( &org_, 24 * 1.0f, &axis_[0], &org_ );
				break;
			case 3:
				VectorMA( &org_, -32 * 1.0f, &axis_[0], &org_ );
				VectorScale( &axis_[0], -1, &axis_[0] );
				break;
			default:
				break;
			}
			break;
		case SABER_SITH_SWORD:
			//no blade
			break;
		}
	}

	VectorCopy( &org_, &fx.mVerts[0].origin );
	VectorMA( &end, 3.0f, &axis_[0], &fx.mVerts[1].origin );
	VectorCopy( &end, &fx.mVerts[2].origin );
	VectorMA( &org_, 3.0f, &axis_[0], &fx.mVerts[3].origin );


	//Raz: Temporarily switch to basejka sabers for flame and electric users
	if ( bladeColor == SABER_FLAME1 || bladeColor == SABER_ELEC1 ||
		bladeColor == SABER_FLAME2 || bladeColor == SABER_ELEC2 ||
		bladeColor == SABER_BLACK )
		styleToUse = 0;

	// Pass in the renderfx flags attached to the saber weapon model...this is done so that saber glows
	//	will get rendered properly in a mirror...not sure if this is necessary??
	//CG_DoSaber( org_, axis_[0], saberLen, client->saber[saberNum].blade[bladeNum].lengthMax, client->saber[saberNum].blade[bladeNum].radius,
	//	scolor, renderfx, (qboolean)(saberNum==0&&bladeNum==0) );
	switch ( styleToUse ) {
	case 0:
		UI_DoSaber( &org_, &axis_[0], bladeLength, bladeLength, bladeRadius, bladeColor, 0, qfalse, 0, snum );
		break;
		/*
			case 1:
			UI_DoEp1Saber( fx.mVerts[0].origin, fx.mVerts[1].origin, fx.mVerts[2].origin, fx.mVerts[3].origin, bladeLength, bladeRadius, bladeColor, 0, false, false, 0, snum );
			break;
			case 2:
			UI_DoEp2Saber( fx.mVerts[0].origin, fx.mVerts[1].origin, fx.mVerts[2].origin, fx.mVerts[3].origin, bladeLength, bladeRadius, bladeColor, 0, false, false, 0, snum );
			break;
			case 3:
			UI_DoEp3Saber( fx.mVerts[0].origin, fx.mVerts[1].origin, fx.mVerts[2].origin, fx.mVerts[3].origin, bladeLength, bladeRadius, bladeColor, 0, false, false, 0, snum );
			break;
			*/
	default:
	case 1:
		UI_DoSFXSaber( &fx.mVerts[0].origin, &fx.mVerts[1].origin, &fx.mVerts[2].origin, &fx.mVerts[3].origin, bladeLength, bladeRadius, bladeColor, 0, qfalse, qfalse, 0, snum );
		break;
		/*
			case 5:
			UI_DoOTSaber( fx.mVerts[0].origin, fx.mVerts[1].origin, fx.mVerts[2].origin, fx.mVerts[3].origin, bladeLength, bladeRadius, bladeColor, 0, false, false, 0, snum );
			break;
			*/
	}
}
Beispiel #22
0
qboolean	PM_SlideMove( qboolean gravity ) {
    int			bumpcount, numbumps;
    vec3_t		dir;
    float		d;
    int			numplanes;
    vec3_t		normal, planes[MAX_CLIP_PLANES];
    vec3_t		primal_velocity;
    vec3_t		clipVelocity;
    int			i, j, k;
    trace_t	trace;
    vec3_t		end;
    float		time_left;
    float		into;
    vec3_t		endVelocity;
    vec3_t		endClipVelocity;
    //qboolean	damageSelf = qtrue;

    numbumps = 4;

    VectorCopy (pm->ps->velocity, primal_velocity);

    if ( gravity ) {
        VectorCopy( pm->ps->velocity, endVelocity );
        endVelocity[2] -= pm->ps->gravity * pml.frametime+3;
        //[JetpackChange1.3]
        if(pm->ps->pm_type == PM_JETPACK && pm->cmd.upmove <= 0 && !(pm->ps->pm_flags & PMF_DUCKED))
            endVelocity[2] -= endVelocity[2]/100*20;
        //[/JetpackChange1.3]
        pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
        primal_velocity[2] = endVelocity[2];
        if ( pml.groundPlane ) {
            if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) )
            {   // slide along the ground plane
                PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
                                 pm->ps->velocity, OVERCLIP );
            }
        }
    }

    time_left = pml.frametime;

    // never turn against the ground plane
    if ( pml.groundPlane ) {
        numplanes = 1;
        VectorCopy( pml.groundTrace.plane.normal, planes[0] );
        if ( !PM_GroundSlideOkay( planes[0][2] ) )
        {
            planes[0][2] = 0;
            VectorNormalize( planes[0] );
        }
    } else {
        numplanes = 0;
    }

    // never turn against original velocity
    VectorNormalize2( pm->ps->velocity, planes[numplanes] );
    numplanes++;

    for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {

        // calculate position we are trying to move to
        VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );

        // see if we can make it there
        pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);

        if (trace.allsolid) {
            // entity is completely trapped in another solid
            pm->ps->velocity[2] = 0;	// don't build up falling damage, but allow sideways acceleration
            return qtrue;
        }

        if (trace.fraction > 0) {
            // actually covered some distance
            VectorCopy (trace.endpos, pm->ps->origin);
        }

        if (trace.fraction == 1) {
            break;		// moved the entire distance
        }

        // save entity for contact
        PM_AddTouchEnt( trace.entityNum );

        if (pm->ps->clientNum >= MAX_CLIENTS)
        {
            bgEntity_t *pEnt = pm_entSelf;

            if (pEnt && pEnt->s.eType == ET_NPC && pEnt->s.NPC_class == CLASS_VEHICLE &&
                    pEnt->m_pVehicle)
            {   //do vehicle impact stuff then
                PM_VehicleImpact(pEnt, &trace);
            }
        }
#ifdef QAGAME
        else
        {
            if ( PM_ClientImpact( &trace ) )
            {
                continue;
            }
        }
#endif

        time_left -= time_left * trace.fraction;

        if (numplanes >= MAX_CLIP_PLANES) {
            // this shouldn't really happen
            VectorClear( pm->ps->velocity );
            return qtrue;
        }

        VectorCopy( trace.plane.normal, normal );

        if ( !PM_GroundSlideOkay( normal[2] ) )
        {   //wall-running
            //never push up off a sloped wall
            normal[2] = 0;
            VectorNormalize( normal );
        }
        //
        // if this is the same plane we hit before, nudge velocity
        // out along it, which fixes some epsilon issues with
        // non-axial planes
        //
        if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) )
        {   //no sliding if stuck to wall!
            for ( i = 0 ; i < numplanes ; i++ ) {
                if ( VectorCompare( normal, planes[i] ) ) {//DotProduct( normal, planes[i] ) > 0.99 ) {
                    VectorAdd( normal, pm->ps->velocity, pm->ps->velocity );
                    break;
                }
            }
            if ( i < numplanes ) {
                continue;
            }
        }
        VectorCopy (normal, planes[numplanes]);
        numplanes++;

        //
        // modify velocity so it parallels all of the clip planes
        //

        // find a plane that it enters
        for ( i = 0 ; i < numplanes ; i++ ) {
            into = DotProduct( pm->ps->velocity, planes[i] );
            if ( into >= 0.1 ) {
                continue;		// move doesn't interact with the plane
            }

            // see how hard we are hitting things
            if ( -into > pml.impactSpeed ) {
                pml.impactSpeed = -into;
            }

            // slide along the plane
            PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );

            // slide along the plane
            PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );

            // see if there is a second plane that the new move enters
            for ( j = 0 ; j < numplanes ; j++ ) {
                if ( j == i ) {
                    continue;
                }
                if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
                    continue;		// move doesn't interact with the plane
                }

                // try clipping the move to the plane
                PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
                PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );

                // see if it goes back into the first clip plane
                if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
                    continue;
                }

                // slide the original velocity along the crease
                CrossProduct (planes[i], planes[j], dir);
                VectorNormalize( dir );
                d = DotProduct( dir, pm->ps->velocity );
                VectorScale( dir, d, clipVelocity );

                CrossProduct (planes[i], planes[j], dir);
                VectorNormalize( dir );
                d = DotProduct( dir, endVelocity );
                VectorScale( dir, d, endClipVelocity );

                // see if there is a third plane the the new move enters
                for ( k = 0 ; k < numplanes ; k++ ) {
                    if ( k == i || k == j ) {
                        continue;
                    }
                    if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
                        continue;		// move doesn't interact with the plane
                    }

                    // stop dead at a triple plane interaction
                    VectorClear( pm->ps->velocity );
                    return qtrue;
                }
            }

            // if we have fixed all interactions, try another move
            VectorCopy( clipVelocity, pm->ps->velocity );
            VectorCopy( endClipVelocity, endVelocity );
            break;
        }
    }

    if ( gravity ) {
        VectorCopy( endVelocity, pm->ps->velocity );
    }

    // don't change velocity if in a timer (FIXME: is this correct?)
    if ( pm->ps->pm_time ) {
        VectorCopy( primal_velocity, pm->ps->velocity );
    }

    return (qboolean)( bumpcount != 0 );
}
Beispiel #23
0
/*
==============
RB_DrawSun
	(SA) FIXME: sun should render behind clouds, so passing dark areas cover it up
==============
*/
void RB_DrawSun( void ) {
	float size;
	float dist;
	vec3_t origin, vec1, vec2;
	vec3_t temp;
	byte color[4];

	if ( !tr.sunShader ) {
		return;
	}

	if ( !backEnd.skyRenderedThisView ) {
		return;
	}
	if ( !r_drawSun->integer ) {
		return;
	}
	qglPushMatrix();
	qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
	qglTranslatef( backEnd.viewParms.orientation.origin[0], backEnd.viewParms.orientation.origin[1], backEnd.viewParms.orientation.origin[2] );

	dist =  backEnd.viewParms.zFar / 1.75;      // div sqrt(3)

	// (SA) shrunk the size of the sun
	size = dist * 0.2;

	VectorScale( tr.sunDirection, dist, origin );
	PerpendicularVector( vec1, tr.sunDirection );
	CrossProduct( tr.sunDirection, vec1, vec2 );

	VectorScale( vec1, size, vec1 );
	VectorScale( vec2, size, vec2 );

	// farthest depth range
	qglDepthRange( 1.0, 1.0 );

	color[0] = color[1] = color[2] = color[3] = 255;

	// (SA) simpler sun drawing
	RB_BeginSurface( tr.sunShader, tess.fogNum );

	RB_AddQuadStamp( origin, vec1, vec2, color );
/*
		VectorCopy( origin, temp );
		VectorSubtract( temp, vec1, temp );
		VectorSubtract( temp, vec2, temp );
		VectorCopy( temp, tess.xyz[tess.numVertexes].v );
		tess.texCoords0[tess.numVertexes].v[0] = 0;
		tess.texCoords0[tess.numVertexes].v[1] = 0;
		tess.vertexColors[tess.numVertexes].v[0] = 255;
		tess.vertexColors[tess.numVertexes].v[1] = 255;
		tess.vertexColors[tess.numVertexes].v[2] = 255;
		tess.numVertexes++;

		VectorCopy( origin, temp );
		VectorAdd( temp, vec1, temp );
		VectorSubtract( temp, vec2, temp );
		VectorCopy( temp, tess.xyz[tess.numVertexes].v );
		tess.texCoords0[tess.numVertexes].v[0] = 0;
		tess.texCoords0[tess.numVertexes].v[1] = 1;
		tess.vertexColors[tess.numVertexes].v[0] = 255;
		tess.vertexColors[tess.numVertexes].v[1] = 255;
		tess.vertexColors[tess.numVertexes].v[2] = 255;
		tess.numVertexes++;

		VectorCopy( origin, temp );
		VectorAdd( temp, vec1, temp );
		VectorAdd( temp, vec2, temp );
		VectorCopy( temp, tess.xyz[tess.numVertexes].v );
		tess.texCoords0[tess.numVertexes].v[0] = 1;
		tess.texCoords0[tess.numVertexes].v[1] = 1;
		tess.vertexColors[tess.numVertexes].v[0] = 255;
		tess.vertexColors[tess.numVertexes].v[1] = 255;
		tess.vertexColors[tess.numVertexes].v[2] = 255;
		tess.numVertexes++;

		VectorCopy( origin, temp );
		VectorSubtract( temp, vec1, temp );
		VectorAdd( temp, vec2, temp );
		VectorCopy( temp, tess.xyz[tess.numVertexes].v );
		tess.texCoords0[tess.numVertexes].v[0] = 1;
		tess.texCoords0[tess.numVertexes].v[1] = 0;
		tess.vertexColors[tess.numVertexes].v[0] = 255;
		tess.vertexColors[tess.numVertexes].v[1] = 255;
		tess.vertexColors[tess.numVertexes].v[2] = 255;
		tess.numVertexes++;

		tess.indexes[tess.numIndexes++] = 0;
		tess.indexes[tess.numIndexes++] = 1;
		tess.indexes[tess.numIndexes++] = 2;
		tess.indexes[tess.numIndexes++] = 0;
		tess.indexes[tess.numIndexes++] = 2;
		tess.indexes[tess.numIndexes++] = 3;
*/
	RB_EndSurface();


	if ( r_drawSun->integer > 1 ) { // draw flare effect
		// (SA) FYI:	This is cheezy and was only a test so far.
		//				If we decide to use the flare business I will /definatly/ improve all this

		// get a point a little closer
		dist = dist * 0.7;
		VectorScale( tr.sunDirection, dist, origin );

		// and make the flare a little smaller
		VectorScale( vec1, 0.5f, vec1 );
		VectorScale( vec2, 0.5f, vec2 );

		// add the vectors to give an 'off angle' result
		VectorAdd( tr.sunDirection, backEnd.viewParms.orientation.axis[0], temp );
		VectorNormalize( temp );

		// amplify the result
		origin[0] += temp[0] * 500.0;
		origin[1] += temp[1] * 500.0;
		origin[2] += temp[2] * 500.0;

		// (SA) FIXME: todo: flare effect should render last (on top of everything else) and only when sun is in view (sun moving out of camera past degree n should start to cause flare dimming until view angle to sun is off by angle n + x.

		// draw the flare
		RB_BeginSurface( tr.sunflareShader[0], tess.fogNum );
		RB_AddQuadStamp( origin, vec1, vec2, color );
		RB_EndSurface();
	}

	// back to normal depth range
	qglDepthRange( 0.0, 1.0 );
	qglPopMatrix();
}
Beispiel #24
0
/*
==================
PM_StepSlideMove

==================
*/
void PM_StepSlideMove( qboolean gravity ) {
    vec3_t		start_o, start_v;
    vec3_t		down_o, down_v;
    trace_t		trace;
//	float		down_dist, up_dist;
//	vec3_t		delta, delta2;
    vec3_t		up, down;
    float		stepSize;
    qboolean	isGiant = qfalse;
    bgEntity_t	*pEnt;
    qboolean skipStep = qfalse;

    VectorCopy (pm->ps->origin, start_o);
    VectorCopy (pm->ps->velocity, start_v);

    if ( BG_InReboundHold( pm->ps->legsAnim ) )
    {
        gravity = qfalse;
    }

    if ( PM_SlideMove( gravity ) == 0 ) {
        return;		// we got exactly where we wanted to go first try
    }

    pEnt = pm_entSelf;

    if (pm->ps->clientNum >= MAX_CLIENTS)
    {
        if (pEnt && pEnt->s.NPC_class == CLASS_VEHICLE &&
                pEnt->m_pVehicle && pEnt->m_pVehicle->m_pVehicleInfo->hoverHeight > 0)
        {
            return;
        }
    }

    VectorCopy(start_o, down);
    down[2] -= STEPSIZE;
    pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
    VectorSet(up, 0, 0, 1);
    // never step up when you still have up velocity
    if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
                                     DotProduct(trace.plane.normal, up) < 0.7))
    {
        return;
    }

    VectorCopy (pm->ps->origin, down_o);
    VectorCopy (pm->ps->velocity, down_v);

    VectorCopy (start_o, up);

    if (pm->ps->clientNum >= MAX_CLIENTS)
    {
        // apply ground friction, even if on ladder
        if (pEnt &&
                pEnt->s.NPC_class == CLASS_ATST ||
                (pEnt->s.NPC_class == CLASS_VEHICLE &&
                 pEnt->m_pVehicle &&
                 pEnt->m_pVehicle->m_pVehicleInfo->type == VH_WALKER)
           )
        {   //AT-STs can step high
            up[2] += 66.0f;
            isGiant = qtrue;
        }
        else if ( pEnt && pEnt->s.NPC_class == CLASS_RANCOR )
        {   //also can step up high
            up[2] += 64.0f;
            isGiant = qtrue;
        }
        else
        {
            up[2] += STEPSIZE;
        }
    }
    else
    {
        up[2] += STEPSIZE;
    }

    // test the player position if they were a stepheight higher
    pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
    if ( trace.allsolid ) {
        if ( pm->debugLevel ) {
            Com_Printf("%i:bend can't step\n", c_pmove);
        }
        return;		// can't step up
    }

    stepSize = trace.endpos[2] - start_o[2];
    // try slidemove from this position
    VectorCopy (trace.endpos, pm->ps->origin);
    VectorCopy (start_v, pm->ps->velocity);

    PM_SlideMove( gravity );

    // push down the final amount
    VectorCopy (pm->ps->origin, down);
    down[2] -= stepSize;
    pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);

    if ( pm->stepSlideFix )
    {
        if ( pm->ps->clientNum < MAX_CLIENTS
                && trace.plane.normal[2] < MIN_WALK_NORMAL )
        {   //normal players cannot step up slopes that are too steep to walk on!
            vec3_t stepVec;
            //okay, the step up ends on a slope that it too steep to step up onto,
            //BUT:
            //If the step looks like this:
            //  (B)\__
            //        \_____(A)
            //Then it might still be okay, so we figure out the slope of the entire move
            //from (A) to (B) and if that slope is walk-upabble, then it's okay
            VectorSubtract( trace.endpos, down_o, stepVec );
            VectorNormalize( stepVec );
            if ( stepVec[2] > (1.0f-MIN_WALK_NORMAL) )
            {
                skipStep = qtrue;
            }
        }
    }

    if ( !trace.allsolid
            && !skipStep ) //normal players cannot step up slopes that are too steep to walk on!
    {
        if ( pm->ps->clientNum >= MAX_CLIENTS//NPC
                && isGiant
                && trace.entityNum < MAX_CLIENTS
                && pEnt
                && pEnt->s.NPC_class == CLASS_RANCOR )
        {   //Rancor don't step on clients
            if ( pm->stepSlideFix )
            {
                VectorCopy (down_o, pm->ps->origin);
                VectorCopy (down_v, pm->ps->velocity);
            }
            else
            {
                VectorCopy (start_o, pm->ps->origin);
                VectorCopy (start_v, pm->ps->velocity);
            }
        }
        /*
        else if ( pm->ps->clientNum >= MAX_CLIENTS//NPC
        	&& isGiant
        	&& trace.entityNum < MAX_CLIENTS
        	&& pEnt
        	&& pEnt->s.NPC_class == CLASS_ATST
        	&& OnSameTeam( pEnt, traceEnt) )
        {//NPC AT-ST's don't step up on allies
        	VectorCopy (start_o, pm->ps->origin);
        	VectorCopy (start_v, pm->ps->velocity);
        }
        */
        else
        {
            VectorCopy (trace.endpos, pm->ps->origin);
            if ( pm->stepSlideFix )
            {
                if ( trace.fraction < 1.0 ) {
                    PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
                }
            }
        }
    }
    else
    {
        if ( pm->stepSlideFix )
        {
            VectorCopy (down_o, pm->ps->origin);
            VectorCopy (down_v, pm->ps->velocity);
        }
    }
    if ( !pm->stepSlideFix )
    {
        if ( trace.fraction < 1.0 ) {
            PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
        }
    }
    {
        // use the step move
        float	delta;

        delta = pm->ps->origin[2] - start_o[2];
        if ( delta > 2 ) {
            if ( delta < 7 ) {
                PM_AddEvent( EV_STEP_4 );
            } else if ( delta < 11 ) {
                PM_AddEvent( EV_STEP_8 );
            } else if ( delta < 15 ) {
                PM_AddEvent( EV_STEP_12 );
            } else {
                PM_AddEvent( EV_STEP_16 );
            }
        }
        if ( pm->debugLevel ) {
            Com_Printf("%i:stepped\n", c_pmove);
        }
    }
}
Beispiel #25
0
void heat_think (edict_t *self)
{
	edict_t *target = NULL;
	edict_t *aquire = NULL;
	vec3_t vec;
	int len;
	int oldlen = 0;

	if (!self)
	{
		return;
	}

	VectorClear(vec);

	/* aquire new target */
	while ((target = findradius(target, self->s.origin, 1024)) != NULL)
	{
		if (self->owner == target)
		{
			continue;
		}

		if (!(target->svflags & SVF_MONSTER))
		{
			continue;
		}

		if (!target->client)
		{
			continue;
		}

		if (target->health <= 0)
		{
			continue;
		}

		if (!visible(self, target))
		{
			continue;
		}

		if (!infront(self, target))
		{
			continue;
		}

		VectorSubtract(self->s.origin, target->s.origin, vec);
		len = VectorLength(vec);

		if ((aquire == NULL) || (len < oldlen))
		{
			aquire = target;
			self->target_ent = aquire;
			oldlen = len;
		}
	}

	if (aquire != NULL)
	{
		VectorSubtract(aquire->s.origin, self->s.origin, vec);
		vectoangles(vec, self->s.angles);
		VectorNormalize(vec);
		VectorCopy(vec, self->movedir);
		VectorScale(vec, 500, self->velocity);
	}

	self->nextthink = level.time + 0.1;
}
Beispiel #26
0
fixedWinding_t *TryMergeWinding( fixedWinding_t *f1, fixedWinding_t *f2, vec3_t planenormal ){
	vec_t       *p1, *p2, *p3, *p4, *back;
	fixedWinding_t  *newf;
	int i, j, k, l;
	vec3_t normal, delta;
	vec_t dot;
	qboolean keep1, keep2;


	//
	// find a common edge
	//
	p1 = p2 = NULL; // stop compiler warning
	j = 0;          //

	for ( i = 0; i < f1->numpoints; i++ )
	{
		p1 = f1->points[i];
		p2 = f1->points[( i + 1 ) % f1->numpoints];
		for ( j = 0; j < f2->numpoints; j++ )
		{
			p3 = f2->points[j];
			p4 = f2->points[( j + 1 ) % f2->numpoints];
			for ( k = 0; k < 3; k++ )
			{
				if ( fabs( p1[k] - p4[k] ) > 0.1 ) { //EQUAL_EPSILON) //ME
					break;
				}
				if ( fabs( p2[k] - p3[k] ) > 0.1 ) { //EQUAL_EPSILON) //ME
					break;
				}
			} //end for
			if ( k == 3 ) {
				break;
			}
		} //end for
		if ( j < f2->numpoints ) {
			break;
		}
	} //end for

	if ( i == f1->numpoints ) {
		return NULL;            // no matching edges

	}
	//
	// check slope of connected lines
	// if the slopes are colinear, the point can be removed
	//
	back = f1->points[( i + f1->numpoints - 1 ) % f1->numpoints];
	VectorSubtract( p1, back, delta );
	CrossProduct( planenormal, delta, normal );
	VectorNormalize( normal, normal );

	back = f2->points[( j + 2 ) % f2->numpoints];
	VectorSubtract( back, p1, delta );
	dot = DotProduct( delta, normal );
	if ( dot > CONTINUOUS_EPSILON ) {
		return NULL;            // not a convex polygon
	}
	keep1 = (qboolean)( dot < -CONTINUOUS_EPSILON );

	back = f1->points[( i + 2 ) % f1->numpoints];
	VectorSubtract( back, p2, delta );
	CrossProduct( planenormal, delta, normal );
	VectorNormalize( normal, normal );

	back = f2->points[( j + f2->numpoints - 1 ) % f2->numpoints];
	VectorSubtract( back, p2, delta );
	dot = DotProduct( delta, normal );
	if ( dot > CONTINUOUS_EPSILON ) {
		return NULL;            // not a convex polygon
	}
	keep2 = (qboolean)( dot < -CONTINUOUS_EPSILON );

	//
	// build the new polygon
	//
	newf = NewFixedWinding( f1->numpoints + f2->numpoints );

	// copy first polygon
	for ( k = ( i + 1 ) % f1->numpoints ; k != i ; k = ( k + 1 ) % f1->numpoints )
	{
		if ( k == ( i + 1 ) % f1->numpoints && !keep2 ) {
			continue;
		}

		VectorCopy( f1->points[k], newf->points[newf->numpoints] );
		newf->numpoints++;
	}

	// copy second polygon
	for ( l = ( j + 1 ) % f2->numpoints ; l != j ; l = ( l + 1 ) % f2->numpoints )
	{
		if ( l == ( j + 1 ) % f2->numpoints && !keep1 ) {
			continue;
		}
		VectorCopy( f2->points[l], newf->points[newf->numpoints] );
		newf->numpoints++;
	}

	return newf;
}
Beispiel #27
0
/*
=================
fire_hit

Used for all impact (hit/punch/slash) attacks
=================
*/
qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick)
{
	trace_t tr;
	vec3_t forward, right, up;
	vec3_t v;
	vec3_t point;
	float range;
	vec3_t dir;

	if (!self)
	{
		return false;
	}

	/* see if enemy is in range */
	VectorSubtract(self->enemy->s.origin, self->s.origin, dir);
	range = VectorLength(dir);

	if (range > aim[0])
	{
		return false;
	}

	if ((aim[1] > self->mins[0]) && (aim[1] < self->maxs[0]))
	{
		/* the hit is straight on so back the range up to the edge of their bbox */
		range -= self->enemy->maxs[0];
	}
	else
	{
		/* this is a side hit so adjust the "right" value out to the edge of their bbox */
		if (aim[1] < 0)
		{
			aim[1] = self->enemy->mins[0];
		}
		else
		{
			aim[1] = self->enemy->maxs[0];
		}
	}

	VectorMA(self->s.origin, range, dir, point);

	tr = gi.trace(self->s.origin, NULL, NULL, point, self, MASK_SHOT);

	if (tr.fraction < 1)
	{
		if (!tr.ent->takedamage)
		{
			return false;
		}

		/* if it will hit any client/monster then hit the one we wanted to hit */
		if ((tr.ent->svflags & SVF_MONSTER) || (tr.ent->client))
		{
			tr.ent = self->enemy;
		}
	}

	AngleVectors(self->s.angles, forward, right, up);
	VectorMA(self->s.origin, range, forward, point);
	VectorMA(point, aim[1], right, point);
	VectorMA(point, aim[2], up, point);
	VectorSubtract(point, self->enemy->s.origin, dir);

	/* do the damage */
	T_Damage(tr.ent, self, self, dir, point, vec3_origin,
			damage, kick / 2, DAMAGE_NO_KNOCKBACK, MOD_HIT);

	if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client))
	{
		return false;
	}

	/* do our special form of knockback here */
	VectorMA(self->enemy->absmin, 0.5, self->enemy->size, v);
	VectorSubtract(v, point, v);
	VectorNormalize(v);
	VectorMA(self->enemy->velocity, kick, v, self->enemy->velocity);

	if (self->enemy->velocity[2] > 0)
	{
		self->enemy->groundentity = NULL;
	}

	return true;
}
Beispiel #28
0
//---------------------------------------------------------
void WP_DisruptorAltFire( gentity_t *ent )
//---------------------------------------------------------
{
	int			damage = weaponData[WP_DISRUPTOR].altDamage, skip, traces = DISRUPTOR_ALT_TRACES;
	qboolean	render_impact = qtrue;
	vec3_t		start, end;
	vec3_t		muzzle2, spot, dir;
	trace_t		tr;
	gentity_t	*traceEnt, *tent;
	float		dist, shotDist, shotRange = 8192;
	qboolean	hitDodged = qfalse, fullCharge = qfalse;

	VectorCopy( muzzle, muzzle2 ); // making a backup copy

	// The trace start will originate at the eye so we can ensure that it hits the crosshair.
	if ( ent->NPC )
	{
		switch ( g_spskill->integer )
		{
		case 0:
			damage = DISRUPTOR_NPC_ALT_DAMAGE_EASY;
			break;
		case 1:
			damage = DISRUPTOR_NPC_ALT_DAMAGE_MEDIUM;
			break;
		case 2:
		default:
			damage = DISRUPTOR_NPC_ALT_DAMAGE_HARD;
			break;
		}
		VectorCopy( muzzle, start );

		fullCharge = qtrue;
	}
	else
	{
		VectorCopy( ent->client->renderInfo.eyePoint, start );
		AngleVectors( ent->client->renderInfo.eyeAngles, forwardVec, NULL, NULL );

		// don't let NPC's do charging
		int count = ( level.time - ent->client->ps.weaponChargeTime - 50 ) / DISRUPTOR_CHARGE_UNIT;

		if ( count < 1 )
		{
			count = 1;
		}
		else if ( count >= 10 )
		{
			count = 10;
			fullCharge = qtrue;
		}

		// more powerful charges go through more things
		if ( count < 3 )
		{
			traces = 1;
		}
		else if ( count < 6 )
		{
			traces = 2;
		}
		//else do full traces

		damage = damage * count + weaponData[WP_DISRUPTOR].damage * 0.5f; // give a boost to low charge shots
	}

	skip = ent->s.number;

//	if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time )
//	{
//		// in overcharge mode, so doing double damage
//		damage *= 2;
//	}

	for ( int i = 0; i < traces; i++ )
	{
		VectorMA( start, shotRange, forwardVec, end );

		//NOTE: if you want to be able to hit guys in emplaced guns, use "G2_COLLIDE, 10" instead of "G2_RETURNONHIT, 0"
		//alternately, if you end up hitting an emplaced_gun that has a sitter, just redo this one trace with the "G2_COLLIDE, 10" to see if we it the sitter
		gi.trace( &tr, start, NULL, NULL, end, skip, MASK_SHOT, G2_COLLIDE, 10 );//G2_RETURNONHIT, 0 );

		if ( tr.surfaceFlags & SURF_NOIMPACT )
		{
			render_impact = qfalse;
		}

		if ( tr.entityNum == ent->s.number )
		{
			// should never happen, but basically we don't want to consider a hit to ourselves?
			// Get ready for an attempt to trace through another person
			VectorCopy( tr.endpos, muzzle2 );
			VectorCopy( tr.endpos, start );
			skip = tr.entityNum;
#ifdef _DEBUG
			gi.Printf( "BAD! Disruptor gun shot somehow traced back and hit the owner!\n" );
#endif
			continue;
		}

		// always render a shot beam, doing this the old way because I don't much feel like overriding the effect.
		//NOTE: let's just draw one beam, at the end
		//tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_SNIPER_SHOT );
		//tent->svFlags |= SVF_BROADCAST;
		//tent->alt_fire = fullCharge; // mark us so we can alter the effect

		//VectorCopy( muzzle2, tent->s.origin2 );

		if ( tr.fraction >= 1.0f )
		{
			// draw the beam but don't do anything else
			break;
		}

		traceEnt = &g_entities[tr.entityNum];

		if ( traceEnt //&& traceEnt->NPC
			&& ( traceEnt->s.weapon == WP_SABER || (traceEnt->client && (traceEnt->client->NPC_class == CLASS_BOBAFETT||traceEnt->client->NPC_class == CLASS_REBORN) ) ) )
		{//FIXME: need a more reliable way to know we hit a jedi?
			hitDodged = Jedi_DodgeEvasion( traceEnt, ent, &tr, HL_NONE );
			//acts like we didn't even hit him
		}
		if ( !hitDodged )
		{
			if ( render_impact )
			{
				if (( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage )
					|| !Q_stricmp( traceEnt->classname, "misc_model_breakable" )
					|| traceEnt->s.eType == ET_MOVER )
				{
					// Create a simple impact type mark that doesn't last long in the world
					G_PlayEffect( G_EffectIndex( "disruptor/alt_hit" ), tr.endpos, tr.plane.normal );

					if ( traceEnt->client && LogAccuracyHit( traceEnt, ent ))
					{//NOTE: hitting multiple ents can still get you over 100% accuracy
						ent->client->ps.persistant[PERS_ACCURACY_HITS]++;
					}

					int hitLoc = G_GetHitLocFromTrace( &tr, MOD_DISRUPTOR );
					if ( traceEnt && traceEnt->client && traceEnt->client->NPC_class == CLASS_GALAKMECH )
					{//hehe
						G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, 10, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, fullCharge ? MOD_SNIPER : MOD_DISRUPTOR, hitLoc );
						break;
					}
					G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, damage, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, fullCharge ? MOD_SNIPER : MOD_DISRUPTOR, hitLoc );
					if ( traceEnt->s.eType == ET_MOVER )
					{//stop the traces on any mover
						break;
					}
				}
				else
				{
					 // we only make this mark on things that can't break or move
					tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_SNIPER_MISS );
					tent->svFlags |= SVF_BROADCAST;
					VectorCopy( tr.plane.normal, tent->pos1 );
					break; // hit solid, but doesn't take damage, so stop the shot...we _could_ allow it to shoot through walls, might be cool?
				}
			}
			else // not rendering impact, must be a skybox or other similar thing?
			{
				break; // don't try anymore traces
			}
		}
		// Get ready for an attempt to trace through another person
		VectorCopy( tr.endpos, muzzle2 );
		VectorCopy( tr.endpos, start );
		skip = tr.entityNum;
		hitDodged = qfalse;
	}
	//just draw one solid beam all the way to the end...
	tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_SNIPER_SHOT );
	tent->svFlags |= SVF_BROADCAST;
	tent->alt_fire = fullCharge; // mark us so we can alter the effect
	VectorCopy( muzzle, tent->s.origin2 );

	// now go along the trail and make sight events
	VectorSubtract( tr.endpos, muzzle, dir );

	shotDist = VectorNormalize( dir );

	//FIXME: if shoot *really* close to someone, the alert could be way out of their FOV
	for ( dist = 0; dist < shotDist; dist += 64 )
	{
		//FIXME: on a really long shot, this could make a LOT of alerts in one frame...
		VectorMA( muzzle, dist, dir, spot );
		AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 );
	}
	//FIXME: spawn a temp ent that continuously spawns sight alerts here?  And 1 sound alert to draw their attention?
	VectorMA( start, shotDist-4, forwardVec, spot );
	AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 );
}
Beispiel #29
0
/*
=================
fire_lead

This is an internal support routine used for bullet/pellet based weapons.
=================
*/
static void fire_lead (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int te_impact, int hspread, int vspread, int mod)
{
	trace_t		tr;
	vec3_t		dir;
	vec3_t		forward, right, up;
	vec3_t		end;
	float		r;
	float		u;
	vec3_t		water_start;
	qboolean	water = false;
	int			content_mask = MASK_SHOT | MASK_WATER;

	tr = gi.trace (self->s.origin, NULL, NULL, start, self, MASK_SHOT);
	if (!(tr.fraction < 1.0))
	{
		vectoangles (aimdir, dir);
		AngleVectors (dir, forward, right, up);

		r = crandom()*hspread;
		u = crandom()*vspread;
		VectorMA (start, 8192, forward, end);
		VectorMA (end, r, right, end);
		VectorMA (end, u, up, end);

		if (gi.pointcontents (start) & MASK_WATER)
		{
			water = true;
			VectorCopy (start, water_start);
			content_mask &= ~MASK_WATER;
		}

		tr = gi.trace (start, NULL, NULL, end, self, content_mask);

		// see if we hit water
		if (tr.contents & MASK_WATER)
		{
			int		color;

			water = true;
			VectorCopy (tr.endpos, water_start);

			if (!VectorCompare (start, tr.endpos))
			{
				if (tr.contents & CONTENTS_WATER)
				{
					if (strcmp(tr.surface->name, "*brwater") == 0)
						color = SPLASH_BROWN_WATER;
					else
						color = SPLASH_BLUE_WATER;
				}
				else if (tr.contents & CONTENTS_SLIME)
					color = SPLASH_SLIME;
				else if (tr.contents & CONTENTS_LAVA)
					color = SPLASH_LAVA;
				else
					color = SPLASH_UNKNOWN;

				if (color != SPLASH_UNKNOWN)
				{
					gi.WriteByte (svc_temp_entity);
					gi.WriteByte (TE_SPLASH);
					gi.WriteByte (8);
					gi.WritePosition (tr.endpos);
					gi.WriteDir (tr.plane.normal);
					gi.WriteByte (color);
					gi.multicast (tr.endpos, MULTICAST_PVS);
				}

				// change bullet's course when it enters water
				VectorSubtract (end, start, dir);
				vectoangles (dir, dir);
				AngleVectors (dir, forward, right, up);
				r = crandom()*hspread*2;
				u = crandom()*vspread*2;
				VectorMA (water_start, 8192, forward, end);
				VectorMA (end, r, right, end);
				VectorMA (end, u, up, end);
			}

			// re-trace ignoring water this time
			tr = gi.trace (water_start, NULL, NULL, end, self, MASK_SHOT);
		}
	}

	// send gun puff / flash
	if (!((tr.surface) && (tr.surface->flags & SURF_SKY)))
	{
		if (tr.fraction < 1.0)
		{
			if (tr.ent->takedamage)
			{
				T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, DAMAGE_BULLET, mod);
			}
			else
			{
				if (strncmp (tr.surface->name, "sky", 3) != 0)
				{
					gi.WriteByte (svc_temp_entity);
					gi.WriteByte (te_impact);
					gi.WritePosition (tr.endpos);
					gi.WriteDir (tr.plane.normal);
					gi.multicast (tr.endpos, MULTICAST_PVS);

					if (self->client)
						PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
				}
			}
		}
	}

	// if went through water, determine where the end and make a bubble trail
	if (water)
	{
		vec3_t	pos;

		VectorSubtract (tr.endpos, water_start, dir);
		VectorNormalize (dir);
		VectorMA (tr.endpos, -2, dir, pos);
		if (gi.pointcontents (pos) & MASK_WATER)
			VectorCopy (pos, tr.endpos);
		else
			tr = gi.trace (pos, NULL, NULL, water_start, tr.ent, MASK_WATER);

		VectorAdd (water_start, tr.endpos, pos);
		VectorScale (pos, 0.5, pos);

		gi.WriteByte (svc_temp_entity);
		gi.WriteByte (TE_BUBBLETRAIL);
		gi.WritePosition (water_start);
		gi.WritePosition (tr.endpos);
		gi.multicast (pos, MULTICAST_PVS);
	}
}
Beispiel #30
0
void CG_SmallPileOfGibs( const vec3_t origin, int damage, const vec3_t initialVelocity, int team )
{
	lentity_t *le;
	int i, j, count;
	vec3_t angles, velocity;
	int time;

	if( !cg_gibs->integer )
		return;

	time = 50;
	count = 14 + cg_gibs->integer; // 15 models minimum
	clamp( count, 15, 128 );

	for( i = 0; i < count; i++ )
	{
		vec4_t color;

		// coloring
		switch ( rand( ) % 3 ) {
		case 0:
			// orange
			Vector4Set( color, 1, 0.5, 0, 1 );
			break;
		case 1:
			// purple
			Vector4Set( color, 1, 0, 1, 1 );
			break;
		case 2:
		default:
			if( ( team == TEAM_ALPHA ) || ( team == TEAM_BETA ) ) {
				// team
				CG_TeamColor( team, color );
				for( j = 0; j < 3; j++ ) {
					color[j] = bound( 60.0f / 255.0f, color[j], 1.0f );
				}
			} else {
				// grey
				Vector4Set( color, 60.0f / 255.0f, 60.0f / 255.0f, 60.0f / 255.0f, 1.0f );
			}
			break;
		}

		le = CG_AllocModel( LE_ALPHA_FADE, origin, vec3_origin, time + time * random( ),
			color[0], color[1], color[2], color[3],
			0, 0, 0, 0,
			CG_MediaModel( cgs.media.modIlluminatiGibs ),
			NULL );

		// random rotation and scale variations
		VectorSet( angles, crandom() * 360, crandom() * 360, crandom() * 360 );
		AnglesToAxis( angles, le->ent.axis );
		le->ent.scale = 0.8f - ( random() * 0.25 );
		le->ent.renderfx = RF_FULLBRIGHT|RF_NOSHADOW;

		velocity[0] = crandom() * 0.5;
		velocity[1] = crandom() * 0.5;
		velocity[2] = 0.5 + random() * 0.5; // always have upwards
		VectorNormalize( velocity );
		VectorScale( velocity, min( damage * 10, 300 ), velocity );

		velocity[0] += crandom() * bound( 0, damage, 150 );
		velocity[1] += crandom() * bound( 0, damage, 150 );
		velocity[2] += random() * bound( 0, damage, 250 );

		VectorAdd( initialVelocity, velocity, le->velocity );

		le->avelocity[0] = random() * 1200;
		le->avelocity[1] = random() * 1200;
		le->avelocity[2] = random() * 1200;

		//friction and gravity
		VectorSet( le->accel, -0.2f, -0.2f, -900 );

		le->bounce = 75;
	}
}