Example #1
0
void CASW_Prediction::CheckMarineError( int nSlot, int commands_acknowledged )
{
	C_ASW_Player	*player;
	Vector		origin;
	Vector		delta;
	float		len;
	static int	pos = 0;

	// Not in the game yet
	if ( !engine->IsInGame() )
		return;

	// Not running prediction
	if ( !cl_predict->GetInt() )
		return;

	player = C_ASW_Player::GetLocalASWPlayer( nSlot );
	if ( !player )
		return;

	C_ASW_Marine* pMarine = player->GetMarine();
	if (!pMarine)
		return;

	// Not predictable yet (flush entity packet?)
	if ( !pMarine->IsIntermediateDataAllocated() )
		return;

	origin = pMarine->GetNetworkOrigin();

	const void *slot = pMarine->GetPredictedFrame( commands_acknowledged - 1 );
	if ( !slot )
		return;

	if ( !m_bMarineOriginTypedescriptionSearched )
	{
		m_bMarineOriginTypedescriptionSearched = true;
		const typedescription_t *td = CPredictionCopy::FindFlatFieldByName( "m_vecNetworkOrigin", pMarine->GetPredDescMap() );
		if ( td ) 
		{
			m_MarineOriginTypeDescription.AddToTail( td );
		}
	}

	if ( !m_MarineOriginTypeDescription.Count() )
		return;

	Vector predicted_origin;

	memcpy( (Vector *)&predicted_origin, (Vector *)( (byte *)slot + m_MarineOriginTypeDescription[ 0 ]->flatOffset[ TD_OFFSET_PACKED ] ), sizeof( Vector ) );

	// Compare what the server returned with what we had predicted it to be
	VectorSubtract ( predicted_origin, origin, delta );

	len = VectorLength( delta );
	if (len > MAX_PREDICTION_ERROR )
	{	
		// A teleport or something, clear out error
		len = 0;
	}
	else
	{
		if ( len > MIN_PREDICTION_EPSILON )
		{
			pMarine->NotePredictionError( delta );

			if ( cl_showerror.GetInt() >= 1 )
			{
				con_nprint_t np;
				np.fixed_width_font = true;
				np.color[0] = 1.0f;
				np.color[1] = 0.95f;
				np.color[2] = 0.7f;
				np.index = 20 + ( ++pos % 20 );
				np.time_to_live = 2.0f;

				engine->Con_NXPrintf( &np, "marine pred error %6.3f units (%6.3f %6.3f %6.3f)", len, delta.x, delta.y, delta.z );
			}
		}
	}
}
Example #2
0
/*
========================
func_explosive_objective
========================
*/
void func_explosive_objective_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	vec3_t	origin;
	vec3_t	chunkorigin;
	vec3_t	size;
	int		count;
	int		mass;
	int		enemy;
	int		otherteam;

	//gi.dprintf(DEVELOPER_MSG_GAME, "self: %s\ninflictor: %s\n attacker: %s\n",
	//	self->classname, inflictor->classname, attacker->classname);

	if (!attacker->client ||
		!attacker->client->resp.mos)
		return;

	// bmodel origins are (0 0 0), we need to adjust that here
	VectorScale (self->size, 0.5, size);
	VectorAdd (self->absmin, size, origin);
	VectorCopy (origin, self->s.origin);

	self->takedamage = DAMAGE_NO;

	if (self->dmg)
		T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);

	VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity);
	VectorNormalize (self->velocity);
	VectorScale (self->velocity, 150, self->velocity);

	// start chunks towards the center
	VectorScale (size, 0.5, size);

	mass = self->mass;
	if (!mass)
		mass = 75;

	// big chunks
	if (mass >= 100)
	{
		count = mass / 100;
		if (count > 8)
			count = 8;
		while(count--)
		{
			chunkorigin[0] = origin[0] + crandom() * size[0];
			chunkorigin[1] = origin[1] + crandom() * size[1];
			chunkorigin[2] = origin[2] + crandom() * size[2];
			ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin);
		}
	}

	// small chunks
	count = mass / 25;
	if (count > 16)
		count = 16;
	while(count--)
	{
		chunkorigin[0] = origin[0] + crandom() * size[0];
		chunkorigin[1] = origin[1] + crandom() * size[1];
		chunkorigin[2] = origin[2] + crandom() * size[2];
		ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin);
	}

	G_UseTargets (self, attacker);

	// hack for 2 team games

	if (self->obj_owner != 99) {
		team_list[self->obj_owner]->score -= self->obj_loss;
		enemy = (self->obj_owner) ? 0 : 1;
	} else
		enemy = 99;

	if (self->obj_owner != attacker->client->resp.team_on->index)
		team_list[attacker->client->resp.team_on->index]->score += self->obj_gain;
	else if (self->obj_owner == attacker->client->resp.team_on->index && enemy != 99)
		team_list[enemy]->score += self->obj_gain;

	if (dedicated->value)
		safe_cprintf(NULL, PRINT_HIGH, "%s destroyed by %s [%s]\n", 
			self->obj_name, 
			attacker->client->pers.netname,
			team_list[attacker->client->resp.team_on->index]->teamname);

	centerprintall("%s destroyed by:\n\n%s\n%s",
		self->obj_name, 
		attacker->client->pers.netname,
		team_list[attacker->client->resp.team_on->index]->teamname);

	otherteam = (self->obj_owner+1)%2;
	if ((!team_list[otherteam]->kills_and_points && team_list[otherteam]->score < team_list[otherteam]->need_points) ||
	    (team_list[otherteam]->kills_and_points && team_list[otherteam]->kills < team_list[otherteam]->need_kills))
	  gi.sound(self, CHAN_NO_PHS_ADD, gi.soundindex(va("%s/objectives/touch_cap.wav", team_list[otherteam]->teamid)), 1, 0, 0);

//		gi.dprintf(DEVELOPER_MSG_GAME, "pts:%i  ndpts:%i  kills:%i  ndkills:%i\n",team_list[(self->obj_owner+1)%2]->score,team_list[(self->obj_owner+1)%2]->need_points,
//team_list[(self->obj_owner+1)%2]->kills,team_list[(self->obj_owner+1)%2]->need_kills);

	if (self->deathtarget)
	{	
		self->target = self->deathtarget;
		if (self->target)
			G_UseTargets (self, attacker);
	}

	if (self->dmg)
		BecomeExplosion1 (self);
	else
		G_FreeEdict (self);
}
Example #3
0
static void OldBuildST( triangle_t *ptri, int numtri ){
	int i, j;
	int width, height, iwidth, iheight, swidth;
	float basex, basey;
	float s_scale, t_scale;
	float scale;
	vec3_t mins, maxs;
	float       *pbasevert;
	vec3_t vtemp1, vtemp2, normal;

	//
	// find bounds of all the verts on the base frame
	//
	ClearBounds( mins, maxs );

	for ( i = 0 ; i < numtri ; i++ )
		for ( j = 0 ; j < 3 ; j++ )
			AddPointToBounds( ptri[i].verts[j], mins, maxs );

	for ( i = 0 ; i < 3 ; i++ )
	{
		mins[i] = floor( mins[i] );
		maxs[i] = ceil( maxs[i] );
	}

	width = maxs[0] - mins[0];
	height = maxs[2] - mins[2];

	if ( !g_fixedwidth ) { // old style
		scale = 8;
		if ( width * scale >= 150 ) {
			scale = 150.0 / width;
		}
		if ( height * scale >= 190 ) {
			scale = 190.0 / height;
		}

		s_scale = t_scale = scale;

		iwidth = ceil( width * s_scale );
		iheight = ceil( height * t_scale );

		iwidth += 4;
		iheight += 4;
	}
	else
	{   // new style
		iwidth = g_fixedwidth / 2;
		iheight = g_fixedheight;

		s_scale = (float)( iwidth - 4 ) / width;
		t_scale = (float)( iheight - 4 ) / height;
	}

//
// determine which side of each triangle to map the texture to
//
	for ( i = 0 ; i < numtri ; i++ )
	{
		VectorSubtract( ptri[i].verts[0], ptri[i].verts[1], vtemp1 );
		VectorSubtract( ptri[i].verts[2], ptri[i].verts[1], vtemp2 );
		CrossProduct( vtemp1, vtemp2, normal );

		if ( normal[1] > 0 ) {
			basex = iwidth + 2;
		}
		else
		{
			basex = 2;
		}
		basey = 2;

		for ( j = 0 ; j < 3 ; j++ )
		{
			pbasevert = ptri[i].verts[j];

			triangle_st[i][j][0] = Q_rint( ( pbasevert[0] - mins[0] ) * s_scale + basex );
			triangle_st[i][j][1] = Q_rint( ( maxs[2] - pbasevert[2] ) * t_scale + basey );
		}
	}

// make the width a multiple of 4; some hardware requires this, and it ensures
// dword alignment for each scan
	swidth = iwidth * 2;
	model.skinwidth = ( swidth + 3 ) & ~3;
	model.skinheight = iheight;
}
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;
}
Example #5
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;

	//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;
}
Example #6
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;
}
Example #7
0
/*
=================
fire_grenade
=================
*/
void Grenade_Explode (edict_t *ent)
{
	vec3_t origin;
	int mod;

	if (!ent)
	{
		return;
	}

	if (ent->owner->client)
	{
		PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
	}

	if (ent->enemy)
	{
		float points;
		vec3_t v;
		vec3_t dir;

		VectorAdd(ent->enemy->mins, ent->enemy->maxs, v);
		VectorMA(ent->enemy->s.origin, 0.5, v, v);
		VectorSubtract(ent->s.origin, v, v);
		points = ent->dmg - 0.5 * VectorLength(v);
		VectorSubtract(ent->enemy->s.origin, ent->s.origin, dir);

		if (ent->spawnflags & 1)
		{
			mod = MOD_HANDGRENADE;
		}
		else
		{
			mod = MOD_GRENADE;
		}

		T_Damage(ent->enemy, ent, ent->owner, dir, ent->s.origin, vec3_origin,
				(int)points, (int)points, DAMAGE_RADIUS, mod);
	}

	if (ent->spawnflags & 2)
	{
		mod = MOD_HELD_GRENADE;
	}
	else if (ent->spawnflags & 1)
	{
		mod = MOD_HG_SPLASH;
	}
	else
	{
		mod = MOD_G_SPLASH;
	}

	T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, mod);

	VectorMA(ent->s.origin, -0.02, ent->velocity, origin);
	gi.WriteByte(svc_temp_entity);

	if (ent->waterlevel)
	{
		if (ent->groundentity)
		{
			gi.WriteByte(TE_GRENADE_EXPLOSION_WATER);
		}
		else
		{
			gi.WriteByte(TE_ROCKET_EXPLOSION_WATER);
		}
	}
	else
	{
		if (ent->groundentity)
		{
			gi.WriteByte(TE_GRENADE_EXPLOSION);
		}
		else
		{
			gi.WriteByte(TE_ROCKET_EXPLOSION);
		}
	}

	gi.WritePosition(origin);
	gi.multicast(ent->s.origin, MULTICAST_PHS);

	G_FreeEdict(ent);
}
Example #8
0
static qboolean
InitFlyby (player_state_t * self, player_state_t * player, int checkvis)
{
	float       f, max;
	vec3_t      vec, vec2;
	vec3_t      forward, right, up;

	VectorCopy (player->viewangles, vec);
	vec[0] = 0;
	AngleVectors (vec, forward, right, up);
//  for (i = 0; i < 3; i++)
//      forward[i] *= 3;

	max = 1000;
	VectorAdd (forward, up, vec2);
	VectorAdd (vec2, right, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	VectorAdd (forward, up, vec2);
	VectorSubtract (vec2, right, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	VectorAdd (forward, right, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	VectorSubtract (forward, right, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	VectorAdd (forward, up, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	VectorSubtract (forward, up, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	VectorAdd (up, right, vec2);
	VectorSubtract (vec2, forward, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	VectorSubtract (up, right, vec2);
	VectorSubtract (vec2, forward, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	// invert
	VectorSubtract (vec3_origin, forward, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	VectorCopy (forward, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	// invert
	VectorSubtract (vec3_origin, right, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	VectorCopy (right, vec2);
	if ((f = Cam_TryFlyby (self, player, vec2, checkvis)) < max) {
		max = f;
		VectorCopy (vec2, vec);
	}
	// ack, can't find him
	if (max >= 1000) {
//      Cam_Unlock();
		return false;
	}
	locked = true;
	VectorCopy (vec, desired_position);
	return true;
}
Example #9
0
// ZOID
//
// Take over the user controls and track a player.
// We find a nice position to watch the player and move there
void
Cam_Track (usercmd_t *cmd)
{
	player_state_t *player, *self;
	frame_t    *frame;
	vec3_t      vec;
	float       len;

	if (!cl.spectator)
		return;

	if (cl_hightrack->int_val && !locked)
		Cam_CheckHighTarget ();

	if (!autocam || cls.state != ca_active)
		return;

	if (locked
		&& (!cl.players[spec_track].name[0]
			|| cl.players[spec_track].spectator)) {
		locked = false;
		if (cl_hightrack->int_val)
			Cam_CheckHighTarget ();
		else
			Cam_Unlock ();
		return;
	}

	frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
	player = frame->playerstate + spec_track;
	self = frame->playerstate + cl.playernum;

	if (!locked || !Cam_IsVisible (player, desired_position)) {
		if (!locked || realtime - cam_lastviewtime > 0.1) {
			if (!InitFlyby (self, player, true))
				InitFlyby (self, player, false);
			cam_lastviewtime = realtime;
		}
	} else
		cam_lastviewtime = realtime;

	// couldn't track for some reason
	if (!locked || !autocam)
		return;

	if (cl_chasecam->int_val) {
		cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;

		VectorCopy (player->viewangles, cl.viewangles);
		VectorCopy (player->origin, desired_position);
		if (memcmp (&desired_position, &self->origin, sizeof (desired_position))
			!= 0) {
			MSG_WriteByte (&cls.netchan.message, clc_tmove);
			MSG_WriteCoord (&cls.netchan.message, desired_position[0]);
			MSG_WriteCoord (&cls.netchan.message, desired_position[1]);
			MSG_WriteCoord (&cls.netchan.message, desired_position[2]);
			// move there locally immediately
			VectorCopy (desired_position, self->origin);
		}
		self->weaponframe = player->weaponframe;

	} else {
		// Ok, move to our desired position and set our angles to view
		// the player
		VectorSubtract (desired_position, self->origin, vec);
		len = vlen (vec);
		cmd->forwardmove = cmd->sidemove = cmd->upmove = 0;
		if (len > 16) {					// close enough?
			MSG_WriteByte (&cls.netchan.message, clc_tmove);
			MSG_WriteCoord (&cls.netchan.message, desired_position[0]);
			MSG_WriteCoord (&cls.netchan.message, desired_position[1]);
			MSG_WriteCoord (&cls.netchan.message, desired_position[2]);
		}
		// move there locally immediately
		VectorCopy (desired_position, self->origin);

		VectorSubtract (player->origin, desired_position, vec);
		vectoangles (vec, cl.viewangles);
		cl.viewangles[0] = -cl.viewangles[0];
	}
}
/*
=================
BaseWindingForPlane
=================
*/
winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
{
	int		i, x;
	vec_t	max, v;
	vec3_t	org, vright, vup;
	winding_t	*w;
	
// find the major axis

	max = -MAX_MAP_BOUNDS;
	x = -1;
	for (i=0 ; i<3; i++)
	{
		v = fabs(normal[i]);
		if (v > max)
		{
			x = i;
			max = v;
		}
	}
	if (x==-1)
		Com_Error (ERR_DROP, "BaseWindingForPlane: no axis found");
		
	VectorCopy (vec3_origin, vup);	
	switch (x)
	{
	case 0:
	case 1:
		vup[2] = 1;
		break;		
	case 2:
		vup[0] = 1;
		break;		
	}

	v = DotProduct (vup, normal);
	VectorMA (vup, -v, normal, vup);
	VectorNormalize2(vup, vup);
		
	VectorScale (normal, dist, org);
	
	CrossProduct (vup, normal, vright);
	
	VectorScale (vup, MAX_MAP_BOUNDS, vup);
	VectorScale (vright, MAX_MAP_BOUNDS, vright);

// project a really big	axis aligned box onto the plane
	w = AllocWinding (4);
	
	VectorSubtract (org, vright, w->p[0]);
	VectorAdd (w->p[0], vup, w->p[0]);
	
	VectorAdd (org, vright, w->p[1]);
	VectorAdd (w->p[1], vup, w->p[1]);
	
	VectorAdd (org, vright, w->p[2]);
	VectorSubtract (w->p[2], vup, w->p[2]);
	
	VectorSubtract (org, vright, w->p[3]);
	VectorSubtract (w->p[3], vup, w->p[3]);
	
	w->numpoints = 4;
	
	return w;	
}
void	AddWindingToConvexHull( winding_t *w, winding_t **hull, vec3_t normal ) {
	int			i, j, k;
	float		*p, *copy;
	vec3_t		dir;
	float		d;
	int			numHullPoints, numNew;
	vec3_t		hullPoints[MAX_HULL_POINTS];
	vec3_t		newHullPoints[MAX_HULL_POINTS];
	vec3_t		hullDirs[MAX_HULL_POINTS];
	qboolean	hullSide[MAX_HULL_POINTS];
	qboolean	outside;

	if ( !*hull ) {
		*hull = CopyWinding( w );
		return;
	}

	numHullPoints = (*hull)->numpoints;
	Com_Memcpy( hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t) );

	for ( i = 0 ; i < w->numpoints ; i++ ) {
		p = w->p[i];

		// calculate hull side vectors
		for ( j = 0 ; j < numHullPoints ; j++ ) {
			k = ( j + 1 ) % numHullPoints;

			VectorSubtract( hullPoints[k], hullPoints[j], dir );
			VectorNormalize2( dir, dir );
			CrossProduct( normal, dir, hullDirs[j] );
		}

		outside = qfalse;
		for ( j = 0 ; j < numHullPoints ; j++ ) {
			VectorSubtract( p, hullPoints[j], dir );
			d = DotProduct( dir, hullDirs[j] );
			if ( d >= ON_EPSILON ) {
				outside = qtrue;
			}
			if ( d >= -ON_EPSILON ) {
				hullSide[j] = qtrue;
			} else {
				hullSide[j] = qfalse;
			}
		}

		// if the point is effectively inside, do nothing
		if ( !outside ) {
			continue;
		}

		// find the back side to front side transition
		for ( j = 0 ; j < numHullPoints ; j++ ) {
			if ( !hullSide[ j % numHullPoints ] && hullSide[ (j + 1) % numHullPoints ] ) {
				break;
			}
		}
		if ( j == numHullPoints ) {
			continue;
		}

		// insert the point here
		VectorCopy( p, newHullPoints[0] );
		numNew = 1;

		// copy over all points that aren't double fronts
		j = (j+1)%numHullPoints;
		for ( k = 0 ; k < numHullPoints ; k++ ) {
			if ( hullSide[ (j+k) % numHullPoints ] && hullSide[ (j+k+1) % numHullPoints ] ) {
				continue;
			}
			copy = hullPoints[ (j+k+1) % numHullPoints ];
			VectorCopy( copy, newHullPoints[numNew] );
			numNew++;
		}

		numHullPoints = numNew;
		Com_Memcpy( hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t) );
	}

	FreeWinding( *hull );
	w = AllocWinding( numHullPoints );
	w->numpoints = numHullPoints;
	*hull = w;
	Com_Memcpy( w->p, hullPoints, numHullPoints * sizeof(vec3_t) );
}
Example #12
0
/*
** RB_DrawSun
*/
void RB_DrawSun( void ) {
	float		size;
	float		dist;
	vec3_t		origin, vec1, vec2;
	vec3_t		temp;

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

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

	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 );

	// FIXME: use quad stamp
	RB_BeginSurface( tr.sunShader, tess.fogNum );
		VectorCopy( origin, temp );
		VectorSubtract( temp, vec1, temp );
		VectorSubtract( temp, vec2, temp );
		VectorCopy( temp, tess.xyz[tess.numVertexes] );
		tess.texCoords[tess.numVertexes][0][0] = 0;
		tess.texCoords[tess.numVertexes][0][1] = 0;
		tess.vertexColors[tess.numVertexes][0] = 255;
		tess.vertexColors[tess.numVertexes][1] = 255;
		tess.vertexColors[tess.numVertexes][2] = 255;
		tess.numVertexes++;

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

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

		VectorCopy( origin, temp );
		VectorSubtract( temp, vec1, temp );
		VectorAdd( temp, vec2, temp );
		VectorCopy( temp, tess.xyz[tess.numVertexes] );
		tess.texCoords[tess.numVertexes][0][0] = 1;
		tess.texCoords[tess.numVertexes][0][1] = 0;
		tess.vertexColors[tess.numVertexes][0] = 255;
		tess.vertexColors[tess.numVertexes][1] = 255;
		tess.vertexColors[tess.numVertexes][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();

	// back to normal depth range
	qglDepthRange( 0.0, 1.0 );
}
Example #13
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);
        }
    }
}
Example #14
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
        }
    }
}
Example #15
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 );
		}
	}
}
Example #16
0
void
Cam_FinishMove (usercmd_t *cmd)
{
	int         i;
	player_info_t *s;
	int         end;

	if (cls.state != ca_active)
		return;

	if (!cl.spectator)					// only in spectator mode
		return;

#if 0
	if (autocam && locked) {
		frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
		player = frame->playerstate + spec_track;
		self = frame->playerstate + cl.playernum;

		VectorSubtract (player->origin, self->origin, vec);
		if (cam_forceview) {
			cam_forceview = false;
			vectoangles (vec, cam_viewangles);
			cam_viewangles[0] = -cam_viewangles[0];
		} else {
			vectoangles (vec, vec2);
			vec2[PITCH] = -vec2[PITCH];

			cam_viewangles[PITCH] =
				adjustang (cam_viewangles[PITCH], vec2[PITCH],
						   cl_camera_maxpitch->value);
			cam_viewangles[YAW] =
				adjustang (cam_viewangles[YAW], vec2[YAW],
						   cl_camera_maxyaw->value);
		}
		VectorCopy (cam_viewangles, cl.viewangles);
	}
#endif

	if (cmd->buttons & BUTTON_ATTACK) {
		if (!(oldbuttons & BUTTON_ATTACK)) {

			oldbuttons |= BUTTON_ATTACK;
			autocam++;

			if (autocam > CAM_TRACK) {
				Cam_Unlock ();
				VectorCopy (cl.viewangles, cmd->angles);
				return;
			}
		} else
			return;
	} else {
		oldbuttons &= ~BUTTON_ATTACK;
		if (!autocam)
			return;
	}

	if (autocam && cl_hightrack->int_val) {
		Cam_CheckHighTarget ();
		return;
	}

	if (locked) {
		if ((cmd->buttons & BUTTON_JUMP) && (oldbuttons & BUTTON_JUMP))
			return;						// don't pogo stick

		if (!(cmd->buttons & BUTTON_JUMP)) {
			oldbuttons &= ~BUTTON_JUMP;
			return;
		}
		oldbuttons |= BUTTON_JUMP;		// don't jump again until released
	}
//  Con_Printf("Selecting track target...\n");

	if (locked && autocam)
		end = (spec_track + 1) % MAX_CLIENTS;
	else
		end = spec_track;
	i = end;
	do {
		s = &cl.players[i];
		if (s->name[0] && !s->spectator) {
			Cam_Lock (i);
			return;
		}
		i = (i + 1) % MAX_CLIENTS;
	} while (i != end);
	// stay on same guy?
	i = spec_track;
	s = &cl.players[i];
	if (s->name[0] && !s->spectator) {
		Cam_Lock (i);
		return;
	}
	Con_Printf ("No target found ...\n");
	autocam = locked = false;
}
Example #17
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;
			*/
	}
}
Example #18
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;
}
Example #19
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;
			}
		}
	}
}
Example #20
0
/*
   ============
   LoadPortals
   ============
 */
void LoadPortals( char *name ){
	int i, j, hint;
	vportal_t   *p;
	leaf_t      *l;
	char magic[80];
	FILE        *f;
	int numpoints;
	fixedWinding_t  *w;
	int leafnums[2];
	visPlane_t plane;

	if ( !strcmp( name,"-" ) ) {
		f = stdin;
	}
	else
	{
		f = fopen( name, "r" );
		if ( !f ) {
			Error( "LoadPortals: couldn't read %s\n",name );
		}
	}

	if ( fscanf( f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces ) != 4 ) {
		Error( "LoadPortals: failed to read header" );
	}
	if ( strcmp( magic,PORTALFILE ) ) {
		Error( "LoadPortals: not a portal file" );
	}

	Sys_Printf( "%6i portalclusters\n", portalclusters );
	Sys_Printf( "%6i numportals\n", numportals );
	Sys_Printf( "%6i numfaces\n", numfaces );

	// these counts should take advantage of 64 bit systems automatically
	leafbytes = ( ( portalclusters + 63 ) & ~63 ) >> 3;
	leaflongs = leafbytes / sizeof( long );

	portalbytes = ( ( numportals * 2 + 63 ) & ~63 ) >> 3;
	portallongs = portalbytes / sizeof( long );

	// each file portal is split into two memory portals
	portals = safe_malloc( 2 * numportals * sizeof( vportal_t ) );
	memset( portals, 0, 2 * numportals * sizeof( vportal_t ) );

	leafs = safe_malloc( portalclusters * sizeof( leaf_t ) );
	memset( leafs, 0, portalclusters * sizeof( leaf_t ) );

	for ( i = 0; i < portalclusters; i++ )
		leafs[i].merged = -1;

	numBSPVisBytes = VIS_HEADER_SIZE + portalclusters * leafbytes;

	if ( numBSPVisBytes > MAX_MAP_VISIBILITY ) {
		Error( "MAX_MAP_VISIBILITY exceeded" );
	}

	( (int *)bspVisBytes )[0] = portalclusters;
	( (int *)bspVisBytes )[1] = leafbytes;

	for ( i = 0, p = portals ; i < numportals ; i++ )
	{
		if ( fscanf( f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1] ) != 3 ) {
			Error( "LoadPortals: reading portal %i", i );
		}
		if ( numpoints > MAX_POINTS_ON_WINDING ) {
			Error( "LoadPortals: portal %i has too many points", i );
		}
		if ( (unsigned)leafnums[0] > portalclusters
			 || (unsigned)leafnums[1] > portalclusters ) {
			Error( "LoadPortals: reading portal %i", i );
		}
		if ( fscanf( f, "%i ", &hint ) != 1 ) {
			Error( "LoadPortals: reading hint state" );
		}

		w = p->winding = NewFixedWinding( numpoints );
		w->numpoints = numpoints;

		for ( j = 0 ; j < numpoints ; j++ )
		{
			double v[3];
			int k;

			// scanf into double, then assign to vec_t
			// so we don't care what size vec_t is
			if ( fscanf( f, "(%lf %lf %lf ) "
						 , &v[0], &v[1], &v[2] ) != 3 ) {
				Error( "LoadPortals: reading portal %i", i );
			}
			for ( k = 0 ; k < 3 ; k++ )
				w->points[j][k] = v[k];
		}
		fscanf( f, "\n" );

		// calc plane
		PlaneFromWinding( w, &plane );

		// create forward portal
		l = &leafs[leafnums[0]];
		if ( l->numportals == MAX_PORTALS_ON_LEAF ) {
			Error( "Leaf with too many portals" );
		}
		l->portals[l->numportals] = p;
		l->numportals++;

		p->num = i + 1;
		p->hint = hint;
		p->winding = w;
		VectorSubtract( vec3_origin, plane.normal, p->plane.normal );
		p->plane.dist = -plane.dist;
		p->leaf = leafnums[1];
		SetPortalSphere( p );
		p++;

		// create backwards portal
		l = &leafs[leafnums[1]];
		if ( l->numportals == MAX_PORTALS_ON_LEAF ) {
			Error( "Leaf with too many portals" );
		}
		l->portals[l->numportals] = p;
		l->numportals++;

		p->num = i + 1;
		p->hint = hint;
		p->winding = NewFixedWinding( w->numpoints );
		p->winding->numpoints = w->numpoints;
		for ( j = 0 ; j < w->numpoints ; j++ )
		{
			VectorCopy( w->points[w->numpoints - 1 - j], p->winding->points[j] );
		}

		p->plane = plane;
		p->leaf = leafnums[0];
		SetPortalSphere( p );
		p++;

	}

	faces = safe_malloc( 2 * numfaces * sizeof( vportal_t ) );
	memset( faces, 0, 2 * numfaces * sizeof( vportal_t ) );

	faceleafs = safe_malloc( portalclusters * sizeof( leaf_t ) );
	memset( faceleafs, 0, portalclusters * sizeof( leaf_t ) );

	for ( i = 0, p = faces; i < numfaces; i++ )
	{
		if ( fscanf( f, "%i %i ", &numpoints, &leafnums[0] ) != 2 ) {
			Error( "LoadPortals: reading portal %i", i );
		}

		w = p->winding = NewFixedWinding( numpoints );
		w->numpoints = numpoints;

		for ( j = 0 ; j < numpoints ; j++ )
		{
			double v[3];
			int k;

			// scanf into double, then assign to vec_t
			// so we don't care what size vec_t is
			if ( fscanf( f, "(%lf %lf %lf ) "
						 , &v[0], &v[1], &v[2] ) != 3 ) {
				Error( "LoadPortals: reading portal %i", i );
			}
			for ( k = 0 ; k < 3 ; k++ )
				w->points[j][k] = v[k];
		}
		fscanf( f, "\n" );

		// calc plane
		PlaneFromWinding( w, &plane );

		l = &faceleafs[leafnums[0]];
		l->merged = -1;
		if ( l->numportals == MAX_PORTALS_ON_LEAF ) {
			Error( "Leaf with too many faces" );
		}
		l->portals[l->numportals] = p;
		l->numportals++;

		p->num = i + 1;
		p->winding = w;
		// normal pointing out of the leaf
		VectorSubtract( vec3_origin, plane.normal, p->plane.normal );
		p->plane.dist = -plane.dist;
		p->leaf = -1;
		SetPortalSphere( p );
		p++;
	}

	fclose( f );
}
Example #21
0
/*
=================
fire_bfg
=================
*/
void bfg_explode (edict_t *self)
{
	edict_t *ent;
	float points;
	vec3_t v;
	float dist;

	if (!self)
	{
		return;
	}

	if (self->s.frame == 0)
	{
		/* the BFG effect */
		ent = NULL;

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

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

			if (!CanDamage(ent, self))
			{
				continue;
			}

			if (!CanDamage(ent, self->owner))
			{
				continue;
			}

			VectorAdd(ent->mins, ent->maxs, v);
			VectorMA(ent->s.origin, 0.5, v, v);
			VectorSubtract(self->s.origin, v, v);
			dist = VectorLength(v);
			points = self->radius_dmg * (1.0 - sqrt(dist / self->dmg_radius));

			if (ent == self->owner)
			{
				points = points * 0.5;
			}

			gi.WriteByte(svc_temp_entity);
			gi.WriteByte(TE_BFG_EXPLOSION);
			gi.WritePosition(ent->s.origin);
			gi.multicast(ent->s.origin, MULTICAST_PHS);
			T_Damage(ent, self, self->owner, self->velocity, ent->s.origin,
					vec3_origin, (int)points, 0, DAMAGE_ENERGY, MOD_BFG_EFFECT);
		}
	}

	self->nextthink = level.time + FRAMETIME;
	self->s.frame++;

	if (self->s.frame == 5)
	{
		self->think = G_FreeEdict;
	}
}
Example #22
0
/*
================
R_EmitEdge
================
*/
void R_EmitEdge(mvertex_t *pv0, mvertex_t *pv1){
	edge_t	*edge, *pcheck;
	int	u_check;
	float	u, u_step;
	vec3_t	local, transformed;
	float	*world;
	int	v, v2, ceilv0;
	float	scale, lzi0, u0, v0;
	int	side;
	
	if(r_lastvertvalid){
		u0 = r_u1;
		v0 = r_v1;
		lzi0 = r_lzi1;
		ceilv0 = r_ceilv1;
	} else {
		world = &pv0->position[0];
		
		// transform and project
		VectorSubtract(world, modelorg, local);
		TransformVector(local, transformed);
		
		if(transformed[2] < NEAR_CLIP)
			transformed[2] = NEAR_CLIP;
			
		lzi0 = 1.0 / transformed[2];
		
		// FIXME: build x/yscale into transform?
		scale = xscale * lzi0;
		u0 =(xcenter + scale * transformed[0]);
		if(u0 < r_refdef.fvrectx_adj)
			u0 = r_refdef.fvrectx_adj;
		if(u0 > r_refdef.fvrectright_adj)
			u0 = r_refdef.fvrectright_adj;
			
		scale = yscale * lzi0;
		v0 =(ycenter - scale * transformed[1]);
		if(v0 < r_refdef.fvrecty_adj)
			v0 = r_refdef.fvrecty_adj;
		if(v0 > r_refdef.fvrectbottom_adj)
			v0 = r_refdef.fvrectbottom_adj;
			
		ceilv0 =(int) ceil(v0);
	}
	
	world = &pv1->position[0];
	
	// transform and project
	VectorSubtract(world, modelorg, local);
	TransformVector(local, transformed);
	
	if(transformed[2] < NEAR_CLIP)
		transformed[2] = NEAR_CLIP;
		
	r_lzi1 = 1.0 / transformed[2];
	
	scale = xscale * r_lzi1;
	r_u1 =(xcenter + scale * transformed[0]);
	if(r_u1 < r_refdef.fvrectx_adj)
		r_u1 = r_refdef.fvrectx_adj;
	if(r_u1 > r_refdef.fvrectright_adj)
		r_u1 = r_refdef.fvrectright_adj;
		
	scale = yscale * r_lzi1;
	r_v1 =(ycenter - scale * transformed[1]);
	if(r_v1 < r_refdef.fvrecty_adj)
		r_v1 = r_refdef.fvrecty_adj;
	if(r_v1 > r_refdef.fvrectbottom_adj)
		r_v1 = r_refdef.fvrectbottom_adj;
		
	if(r_lzi1 > lzi0)
		lzi0 = r_lzi1;
		
	if(lzi0 > r_nearzi)	// for mipmap finding
		r_nearzi = lzi0;
		
	// for right edges, all we want is the effect on 1/z
	if(r_nearzionly)
		return;
		
	r_emitted = 1;
	
	r_ceilv1 =(int) ceil(r_v1);
	
	
	// create the edge
	if(ceilv0 == r_ceilv1){
		// we cache unclipped horizontal edges as fully clipped
		if(cacheoffset != 0x7FFFFFFF){
			cacheoffset = FULLY_CLIPPED_CACHED |
						 (r_framecount & FRAMECOUNT_MASK);
		}
		
		return;		// horizontal edge
	}
	
	side = ceilv0 > r_ceilv1;
	
	edge = edge_p++;
	
	edge->owner = r_pedge;
	
	edge->nearzi = lzi0;
	
	if(side == 0){
		// trailing edge(go from p1 to p2)
		v = ceilv0;
		v2 = r_ceilv1 - 1;
		
		edge->surfs[0] = surface_p - surfaces;
		edge->surfs[1] = 0;
		
		u_step =((r_u1 - u0) /(r_v1 - v0));
		u = u0 +((float)v - v0) * u_step;
	} else {
		// leading edge(go from p2 to p1)
		v2 = ceilv0 - 1;
		v = r_ceilv1;
		
		edge->surfs[0] = 0;
		edge->surfs[1] = surface_p - surfaces;
		
		u_step =((u0 - r_u1) /(v0 - r_v1));
		u = r_u1 +((float)v - r_v1) * u_step;
	}
	
	edge->u_step = u_step * 0x100000;
	edge->u = u * 0x100000 + 0xFFFFF;
	
	// we need to do this to avoid stepping off the edges if a very nearly
	// horizontal edge is less than epsilon above a scan, and numeric error causes
	// it to incorrectly extend to the scan, and the extension of the line goes off
	// the edge of the screen
	// FIXME: is this actually needed?
	if(edge->u < r_refdef.vrect_x_adj_shift20)
		edge->u = r_refdef.vrect_x_adj_shift20;
	if(edge->u > r_refdef.vrectright_adj_shift20)
		edge->u = r_refdef.vrectright_adj_shift20;
		
	//
	// sort the edge in normally
	//
	u_check = edge->u;
	if(edge->surfs[0])
		u_check++;	// sort trailers after leaders
		
	if(!newedges[v] || newedges[v]->u >= u_check){
		edge->next = newedges[v];
		newedges[v] = edge;
	} else {
		pcheck = newedges[v];
		while(pcheck->next && pcheck->next->u < u_check)
			pcheck = pcheck->next;
		edge->next = pcheck->next;
		pcheck->next = edge;
	}
	
	edge->nextremove = removeedges[v2];
	removeedges[v2] = edge;
}
Example #23
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);
	}
}
Example #24
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 );
}
Example #25
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 (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                          v this is an immune to laser flag
			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;
}
Example #26
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 );
		}
	}
}
Example #27
0
/*
   ===============
   GrabFrame
   ===============
 */
static void GrabFrame( char *frame ){
	triangle_t      *ptri;
	int i, j;
	trivert_t       *ptrivert;
	int num_tris;
	char file1[1024];
	frame_t         *fr;
	vertexnormals_t vnorms[MAX_VERTS];
	int index_xyz;
	char            *framefile;

	// the frame 'run1' will be looked for as either
	// run.1 or run1.tri, so the new alias sequence save
	// feature an be used
	framefile = FindFrameFile( frame );

	sprintf( file1, "%s/%s", cdarchive, framefile );
	ExpandPathAndArchive( file1 );

	sprintf( file1, "%s/%s",cddir, framefile );

	printf( "grabbing %s  ", file1 );

	if ( model.num_frames >= MAX_FRAMES ) {
		Error( "model.num_frames >= MAX_FRAMES" );
	}
	fr = &g_frames[model.num_frames];
	model.num_frames++;

	strcpy( fr->name, frame );

//
// load the frame
//
	if ( do3ds ) {
		Load3DSTriangleList( file1, &ptri, &num_tris, NULL, NULL );
	}
	else{
		LoadTriangleList( file1, &ptri, &num_tris, NULL, NULL );
	}

	if ( num_tris != model.num_tris ) {
		Error( "%s: number of triangles doesn't match base frame\n", file1 );
	}

//
// allocate storage for the frame's vertices
//
	ptrivert = fr->v;

	for ( i = 0 ; i < model.num_xyz ; i++ )
	{
		vnorms[i].numnormals = 0;
		VectorClear( vnorms[i].normalsum );
	}
	ClearBounds( fr->mins, fr->maxs );

//
// store the frame's vertices in the same order as the base. This assumes the
// triangles and vertices in this frame are in exactly the same order as in the
// base
//
	for ( i = 0 ; i < num_tris ; i++ )
	{
		vec3_t vtemp1, vtemp2, normal;
		float ftemp;

		VectorSubtract( ptri[i].verts[0], ptri[i].verts[1], vtemp1 );
		VectorSubtract( ptri[i].verts[2], ptri[i].verts[1], vtemp2 );
		CrossProduct( vtemp1, vtemp2, normal );

		VectorNormalize( normal, normal );

		// rotate the normal so the model faces down the positive x axis
		ftemp = normal[0];
		normal[0] = -normal[1];
		normal[1] = ftemp;

		for ( j = 0 ; j < 3 ; j++ )
		{
			index_xyz = triangles[i].index_xyz[j];

			// rotate the vertices so the model faces down the positive x axis
			// also adjust the vertices to the desired origin
			ptrivert[index_xyz].v[0] = ( ( -ptri[i].verts[j][1] ) * scale_up ) +
									   adjust[0];
			ptrivert[index_xyz].v[1] = ( ptri[i].verts[j][0] * scale_up ) +
									   adjust[1];
			ptrivert[index_xyz].v[2] = ( ptri[i].verts[j][2] * scale_up ) +
									   adjust[2];

			AddPointToBounds( ptrivert[index_xyz].v, fr->mins, fr->maxs );

			VectorAdd( vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum );
			vnorms[index_xyz].numnormals++;
		}
	}

//
// calculate the vertex normals, match them to the template list, and store the
// index of the best match
//
	for ( i = 0 ; i < model.num_xyz ; i++ )
	{
		int j;
		vec3_t v;
		float maxdot;
		int maxdotindex;
		int c;

		c = vnorms[i].numnormals;
		if ( !c ) {
			Error( "Vertex with no triangles attached" );
		}

		VectorScale( vnorms[i].normalsum, 1.0 / c, v );
		VectorNormalize( v, v );

		maxdot = -999999.0;
		maxdotindex = -1;

		for ( j = 0 ; j < NUMVERTEXNORMALS ; j++ )
		{
			float dot;

			dot = DotProduct( v, avertexnormals[j] );
			if ( dot > maxdot ) {
				maxdot = dot;
				maxdotindex = j;
			}
		}

		ptrivert[i].lightnormalindex = maxdotindex;
	}

	free( ptri );
}
Example #28
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] );
			}
		}
	}
}
Example #29
0
/*
===========
SelectRandomFurthestSpawnPoint

Chooses a player start, deathmatch start, etc
============
*/
gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles, qboolean isbot ) {
	gentity_t	*spot;
	vec3_t		delta;
	float		dist;
	float		list_dist[MAX_SPAWN_POINTS];
	gentity_t	*list_spot[MAX_SPAWN_POINTS];
	int			numSpots, rnd, i, j;

	numSpots = 0;
	spot = NULL;

	while((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
	{
		if(SpotWouldTelefrag(spot))
			continue;

		if(((spot->flags & FL_NO_BOTS) && isbot) ||
		   ((spot->flags & FL_NO_HUMANS) && !isbot))
		{
			// spot is not for this human/bot player
			continue;
		}

		VectorSubtract( spot->s.origin, avoidPoint, delta );
		dist = VectorLength( delta );

		for (i = 0; i < numSpots; i++)
		{
			if(dist > list_dist[i])
			{
				if (numSpots >= MAX_SPAWN_POINTS)
					numSpots = MAX_SPAWN_POINTS - 1;
					
				for(j = numSpots; j > i; j--)
				{
					list_dist[j] = list_dist[j-1];
					list_spot[j] = list_spot[j-1];
				}
				
				list_dist[i] = dist;
				list_spot[i] = spot;
				
				numSpots++;
				break;
			}
		}
		
		if(i >= numSpots && numSpots < MAX_SPAWN_POINTS)
		{
			list_dist[numSpots] = dist;
			list_spot[numSpots] = spot;
			numSpots++;
		}
	}
	
	if(!numSpots)
	{
		spot = G_Find(NULL, FOFS(classname), "info_player_deathmatch");

		if (!spot)
			G_Error( "Couldn't find a spawn point" );

		VectorCopy (spot->s.origin, origin);
		origin[2] += 9;
		VectorCopy (spot->s.angles, angles);
		return spot;
	}

	// select a random spot from the spawn points furthest away
	rnd = random() * (numSpots / 2);

	VectorCopy (list_spot[rnd]->s.origin, origin);
	origin[2] += 9;
	VectorCopy (list_spot[rnd]->s.angles, angles);

	return list_spot[rnd];
}
Example #30
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;
}