Beispiel #1
0
/*
-------------------------
NPC_BSRancor_Default
-------------------------
*/
void NPC_BSRancor_Default( void )
{
	AddSightEvent( NPC, NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, 50 );

	Rancor_Crush();

	NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
	if ( NPC->count )
	{//holding someone
		NPC->client->ps.eFlags2 |= EF2_USE_ALT_ANIM;
		if ( NPC->count == 2 )
		{//in my mouth
			NPC->client->ps.eFlags2 |= EF2_GENERIC_NPC_FLAG;
		}
	}
	else
	{
		NPC->client->ps.eFlags2 &= ~(EF2_USE_ALT_ANIM|EF2_GENERIC_NPC_FLAG);
	}

	if ( TIMER_Done2( NPC, "clearGrabbed", qtrue ) )
	{
		Rancor_DropVictim( NPC );
	}
	else if ( NPC->client->ps.legsAnim == BOTH_PAIN2 
		&& NPC->count == 1 
		&& NPC->activator )
	{
		if ( !Q_irand( 0, 3 ) )
		{
			Rancor_CheckDropVictim();
		}
	}
	if ( !TIMER_Done( NPC, "rageTime" ) )
	{//do nothing but roar first time we see an enemy
		AddSoundEvent( NPC, NPC->r.currentOrigin, 1024, AEL_DANGER_GREAT, qfalse );//, qfalse );
		NPC_FaceEnemy( qtrue );
		return;
	}
	if ( NPC->enemy )
	{
		/*
		if ( NPC->enemy->client //enemy is a client
			&& (NPC->enemy->client->NPC_class == CLASS_UGNAUGHT || NPC->enemy->client->NPC_class == CLASS_JAWA )//enemy is a lowly jawa or ugnaught
			&& NPC->enemy->enemy != NPC//enemy's enemy is not me
			&& (!NPC->enemy->enemy || !NPC->enemy->enemy->client || NPC->enemy->enemy->client->NPC_class!=CLASS_RANCOR) )//enemy's enemy is not a client or is not a rancor (which is as scary as me anyway)
		{//they should be scared of ME and no-one else
			G_SetEnemy( NPC->enemy, NPC );
		}
		*/
		if ( TIMER_Done(NPC,"angrynoise") )
		{
			G_Sound( NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/misc/anger%d.wav", Q_irand(1, 3))) );

			TIMER_Set( NPC, "angrynoise", Q_irand( 5000, 10000 ) );
		}
		else
		{
			AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER_GREAT, qfalse );//, qfalse );
		}
		if ( NPC->count == 2 && NPC->client->ps.legsAnim == BOTH_ATTACK3 )
		{//we're still chewing our enemy up
			NPC_UpdateAngles( qtrue, qtrue );
			return;
		}
		//else, if he's in our hand, we eat, else if he's on the ground, we keep attacking his dead body for a while
		if( NPC->enemy->client && NPC->enemy->client->NPC_class == CLASS_RANCOR )
		{//got mad at another Rancor, look for a valid enemy
			if ( TIMER_Done( NPC, "rancorInfight" ) )
			{
				NPC_CheckEnemyExt( qtrue );
			}
		}
		else if ( !NPC->count )
		{
			if ( ValidEnemy( NPC->enemy ) == qfalse )
			{
				TIMER_Remove( NPC, "lookForNewEnemy" );//make them look again right now
				if ( !NPC->enemy->inuse || level.time - NPC->enemy->s.time > Q_irand( 10000, 15000 ) )
				{//it's been a while since the enemy died, or enemy is completely gone, get bored with him
					NPC->enemy = NULL;
					Rancor_Patrol();
					NPC_UpdateAngles( qtrue, qtrue );
					return;
				}
			}
			if ( TIMER_Done( NPC, "lookForNewEnemy" ) )
			{
				gentity_t *newEnemy, *sav_enemy = NPC->enemy;//FIXME: what about NPC->lastEnemy?
				NPC->enemy = NULL;
				newEnemy = NPC_CheckEnemy( NPCInfo->confusionTime < level.time, qfalse, qfalse );
				NPC->enemy = sav_enemy;
				if ( newEnemy && newEnemy != sav_enemy )
				{//picked up a new enemy!
					NPC->lastEnemy = NPC->enemy;
					G_SetEnemy( NPC, newEnemy );
					//hold this one for at least 5-15 seconds
					TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
				}
				else
				{//look again in 2-5 secs
					TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 2000, 5000 ) );
				}
			}
		}
		Rancor_Combat();
	}
	else 
	{
		if ( TIMER_Done(NPC,"idlenoise") )
		{
			G_Sound( NPC, CHAN_AUTO, G_SoundIndex( va("sound/chars/rancor/snort_%d.wav", Q_irand(1, 2))) );

			TIMER_Set( NPC, "idlenoise", Q_irand( 2000, 4000 ) );
			AddSoundEvent( NPC, NPC->r.currentOrigin, 384, AEL_DANGER, qfalse );//, qfalse );
		}
		if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
		{
			Rancor_Patrol();
		}
		else
		{
			Rancor_Idle();
		}
	}

	NPC_UpdateAngles( qtrue, qtrue );
}
Beispiel #2
0
void misc_model_breakable_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath,int dFlags,int hitLoc ) 
{
	int		numChunks;
	float	size = 0, scale;
	vec3_t	dir, up, dis;

	//NOTE: Stop any scripts that are currently running (FLUSH)... ?
	//Turn off animation
	self->s.frame = self->startFrame = self->endFrame = 0;
	self->svFlags &= ~SVF_ANIMATING;
			
	self->health = 0;

	//Throw some chunks
	AngleVectors( self->s.apos.trBase, dir, NULL, NULL );
	VectorNormalize( dir );

	numChunks = random() * 6 + 20;

	VectorSubtract( self->absmax, self->absmin, dis );

	// This formula really has no logical basis other than the fact that it seemed to be the closest to yielding the results that I wanted.
	// Volume is length * width * height...then break that volume down based on how many chunks we have
	scale = sqrt( sqrt( dis[0] * dis[1] * dis[2] )) * 1.75f;

	if ( scale > 48 )
	{
		size = 2;
	}
	else if ( scale > 24 )
	{
		size = 1;
	}

	scale = scale / numChunks;

	if ( self->radius > 0.0f )
	{
		// designer wants to scale number of chunks, helpful because the above scale code is far from perfect
		//	I do this after the scale calculation because it seems that the chunk size generally seems to be very close, it's just the number of chunks is a bit weak
		numChunks *= self->radius;
	}

	VectorAdd( self->absmax, self->absmin, dis );
	VectorScale( dis, 0.5f, dis );

	CG_Chunks( self->s.number, dis, dir, self->absmin, self->absmax, 300, numChunks, self->material, self->s.modelindex3, scale );

	self->e_PainFunc = painF_NULL;
	self->e_DieFunc  = dieF_NULL;
//	self->e_UseFunc  = useF_NULL;

	self->takedamage = qfalse;

	if ( !(self->spawnflags & 4) )
	{//We don't want to stay solid
		self->s.solid = 0;
		self->contents = 0;
		self->clipmask = 0;
		gi.linkentity(self);
	}

	VectorSet(up, 0, 0, 1);

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

	if(inflictor->client)
	{
		VectorSubtract( self->currentOrigin, inflictor->currentOrigin, dir );
		VectorNormalize( dir );
	}
	else
	{
		VectorCopy(up, dir);
	}

	if ( !(self->spawnflags & 2048) ) // NO_EXPLOSION
	{
		// Ok, we are allowed to explode, so do it now!
		if(self->splashDamage > 0 && self->splashRadius > 0)
		{//explode
			vec3_t org;
			AddSightEvent( attacker, self->currentOrigin, 256, AEL_DISCOVERED, 100 );
			AddSoundEvent( attacker, self->currentOrigin, 128, AEL_DISCOVERED );
			//FIXME: specify type of explosion?  (barrel, electrical, etc.)  Also, maybe just use the explosion effect below since it's
			//				a bit better?
			// up the origin a little for the damage check, because several models have their origin on the ground, so they don't alwasy do damage, not the optimal solution...
			VectorCopy( self->currentOrigin, org );
			if ( self->mins[2] > -4 )
			{//origin is going to be below it or very very low in the model
				//center the origin
				org[2] = self->currentOrigin[2] + self->mins[2] + (self->maxs[2] - self->mins[2])/2.0f;
			}
			G_RadiusDamage( org, self, self->splashDamage, self->splashRadius, self, MOD_UNKNOWN );

			if ( self->model && Q_stricmp( "models/map_objects/ships/tie_fighter.md3", self->model ) == 0 )
			{//TEMP HACK for Tie Fighters- they're HUGE
				G_PlayEffect( "fighter_explosion2", self->currentOrigin );
				G_Sound( self, G_SoundIndex( "sound/weapons/tie_fighter/TIEexplode.wav" ) );
			}
			else
			{
				CG_MiscModelExplosion( self->absmin, self->absmax, size, self->material );
				G_Sound( self, G_SoundIndex("sound/weapons/explosions/cargoexplode.wav") );
			}
		}
		else
		{//just break
			AddSightEvent( attacker, self->currentOrigin, 128, AEL_DISCOVERED );
			AddSoundEvent( attacker, self->currentOrigin, 64, AEL_SUSPICIOUS );
			// This is the default explosion
			CG_MiscModelExplosion( self->absmin, self->absmax, size, self->material );
			G_Sound(self, G_SoundIndex("sound/weapons/explosions/cargoexplode.wav"));
		}
	}

	self->e_ThinkFunc = thinkF_NULL;
	self->nextthink = -1;

	if(self->s.modelindex2 != -1 && !(self->spawnflags & 8))
	{//FIXME: modelindex doesn't get set to -1 if the damage model doesn't exist
		self->svFlags |= SVF_BROKEN;
		self->s.modelindex = self->s.modelindex2;
		G_ActivateBehavior( self, BSET_DEATH );
	}
	else
	{
		G_FreeEntity( self );
	}
}
Beispiel #3
0
//--------------------------------------
void funcBBrushDieGo (gentity_t *self)
{
	vec3_t		org, dir, up;
	gentity_t	*attacker = self->enemy;
	float		scale;
	int			numChunks, size = 0;
	material_t	chunkType = self->material;
	
	// if a missile is stuck to us, blow it up so we don't look dumb
	for ( int i = 0; i < MAX_GENTITIES; i++ )
	{
		if ( g_entities[i].s.groundEntityNum == self->s.number && ( g_entities[i].s.eFlags & EF_MISSILE_STICK ))
		{
			G_Damage( &g_entities[i], self, self, NULL, NULL, 99999, 0, MOD_CRUSH ); //?? MOD?
		}
	}

	//So chunks don't get stuck inside me
	self->s.solid = 0;
	self->contents = 0;
	self->clipmask = 0;
	gi.linkentity(self); 

	VectorSet(up, 0, 0, 1);

	if ( self->target && attacker != NULL )
	{
		G_UseTargets(self, attacker);
	}

	VectorSubtract( self->absmax, self->absmin, org );// size

	numChunks = random() * 6 + 18;

	// This formula really has no logical basis other than the fact that it seemed to be the closest to yielding the results that I wanted.
	// Volume is length * width * height...then break that volume down based on how many chunks we have
	scale = sqrt( sqrt( org[0] * org[1] * org[2] )) * 1.75f;

	if ( scale > 48 )
	{
		size = 2;
	}
	else if ( scale > 24 )
	{
		size = 1;
	}

	scale = scale / numChunks;

	if ( self->radius > 0.0f )
	{
		// designer wants to scale number of chunks, helpful because the above scale code is far from perfect
		//	I do this after the scale calculation because it seems that the chunk size generally seems to be very close, it's just the number of chunks is a bit weak
		numChunks *= self->radius;
	}

	VectorMA( self->absmin, 0.5, org, org );
	VectorAdd( self->absmin,self->absmax, org );
	VectorScale( org, 0.5f, org );

	if ( attacker != NULL && attacker->client )
	{
		VectorSubtract( org, attacker->currentOrigin, dir );
		VectorNormalize( dir );
	}
	else
	{
		VectorCopy(up, dir);
	} 

	if ( !(self->spawnflags & 2048) ) // NO_EXPLOSION
	{
		// we are allowed to explode
		CG_MiscModelExplosion( self->mins, self->maxs, size, chunkType );
	}

	if ( self->splashDamage > 0 && self->splashRadius > 0 )
	{
		//explode
		AddSightEvent( attacker, org, 256, AEL_DISCOVERED, 100 );
		AddSoundEvent( attacker, org, 128, AEL_DISCOVERED );
		G_RadiusDamage( org, self, self->splashDamage, self->splashRadius, self, MOD_UNKNOWN );

		gentity_t *te = G_TempEntity( org, EV_GENERAL_SOUND );
		te->s.eventParm = G_SoundIndex("sound/weapons/explosions/cargoexplode.wav");
	}
	else
	{//just break
		AddSightEvent( attacker, org, 128, AEL_DISCOVERED );
		AddSoundEvent( attacker, org, 64, AEL_SUSPICIOUS );
	}

	//FIXME: base numChunks off size?
	CG_Chunks( self->s.number, org, dir, self->mins, self->maxs, 300, numChunks, chunkType, 0, scale );

	gi.AdjustAreaPortalState( self, qtrue );
	self->e_ThinkFunc = thinkF_G_FreeEntity;
	self->nextthink = level.time + 50;
	//G_FreeEntity( self );
}
Beispiel #4
0
void Rancor_Smash( void )
{
	int			radiusEntNums[128];
	int			numEnts;
	const float	radius = 128;
	const float	halfRadSquared = ((radius/2)*(radius/2));
	const float	radiusSquared = (radius*radius);
	float		distSq;
	int			i;
	vec3_t		boltOrg;

	//[CoOp] SP Code
	//Added sight/sound event based on SP code.
	AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER, qfalse, qtrue );
	//AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER, qfalse );//, qtrue );
	//[/CoOp]

	numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.handLBolt, boltOrg );

	for ( i = 0; i < numEnts; i++ )
	{
		gentity_t *radiusEnt = &g_entities[radiusEntNums[i]];
		if ( !radiusEnt->inuse )
		{
			continue;
		}
		
		if ( radiusEnt == NPC )
		{//Skip the rancor ent
			continue;
		}
		
		if ( radiusEnt->client == NULL )
		{//must be a client
			continue;
		}

		if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) )
		{//can't be one being held
			continue;
		}
		
		distSq = DistanceSquared( radiusEnt->r.currentOrigin, boltOrg );
		if ( distSq <= radiusSquared )
		{
			G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) );
			if ( distSq < halfRadSquared )
			{//close enough to do damage, too
				G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 10, 25 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE );
			}
			if ( radiusEnt->health > 0 
				&& radiusEnt->client
				&& radiusEnt->client->NPC_class != CLASS_RANCOR
				&& radiusEnt->client->NPC_class != CLASS_ATST )
			{
				if ( distSq < halfRadSquared 
					|| radiusEnt->client->ps.groundEntityNum != ENTITYNUM_NONE )
				{//within range of my fist or withing ground-shaking range and not in the air
					//[KnockdownSys]
					//ported multi-direction knockdowns from SP.
					G_Knockdown( radiusEnt, NPC, vec3_origin, 100, qtrue );
					//G_Knockdown( radiusEnt );//, NPC, vec3_origin, 100, qtrue );
					//[/KnockdownSys]
				}
			}
		}
	}
}
Beispiel #5
0
//---------------------------------------------------------
void FireWeapon( gentity_t *ent, qboolean alt_fire ) 
//---------------------------------------------------------
{
	float alert = 256;
	Vehicle_t *pVeh = NULL;

	// track shots taken for accuracy tracking. 
	ent->client->ps.persistant[PERS_ACCURACY_SHOTS]++;

	// If this is a vehicle, fire it's weapon and we're done.
	if ( ent && ent->client && ent->client->NPC_class == CLASS_VEHICLE )
	{
		FireVehicleWeapon( ent, alt_fire );
		return;
	}

	// set aiming directions
	if ( ent->s.weapon == WP_DISRUPTOR && alt_fire )
	{
		if ( ent->NPC )
		{
			//snipers must use the angles they actually did their shot trace with
			AngleVectors( ent->lastAngles, forwardVec, vrightVec, up );
		}
	}
	else if ( ent->s.weapon == WP_ATST_SIDE || ent->s.weapon == WP_ATST_MAIN ) 
	{
		vec3_t	delta1, enemy_org1, muzzle1;
		vec3_t	angleToEnemy1;

		VectorCopy( ent->client->renderInfo.muzzlePoint, muzzle1 );

		if ( !ent->s.number )
		{//player driving an AT-ST
			//SIGH... because we can't anticipate alt-fire, must calc muzzle here and now
			mdxaBone_t		boltMatrix;
			int				bolt;

			if ( ent->client->ps.weapon == WP_ATST_MAIN )
			{//FIXME: alt_fire should fire both barrels, but slower?
				if ( ent->alt_fire )
				{
					bolt = ent->handRBolt;
				}
				else
				{
					bolt = ent->handLBolt;
				}
			}
			else
			{// ATST SIDE weapons
				if ( ent->alt_fire )
				{
					if ( gi.G2API_GetSurfaceRenderStatus( &ent->ghoul2[ent->playerModel], "head_light_blaster_cann" ) )
					{//don't have it!
						return;
					}
					bolt = ent->genericBolt2;
				}
				else
				{
					if ( gi.G2API_GetSurfaceRenderStatus( &ent->ghoul2[ent->playerModel], "head_concussion_charger" ) )
					{//don't have it!
						return;
					}
					bolt = ent->genericBolt1;
				}
			}

			vec3_t yawOnlyAngles = {0, ent->currentAngles[YAW], 0};
			if ( ent->currentAngles[YAW] != ent->client->ps.legsYaw )
			{
				yawOnlyAngles[YAW] = ent->client->ps.legsYaw;
			}
			gi.G2API_GetBoltMatrix( ent->ghoul2, ent->playerModel, bolt, &boltMatrix, yawOnlyAngles, ent->currentOrigin, (cg.time?cg.time:level.time), NULL, ent->s.modelScale );

			// work the matrix axis stuff into the original axis and origins used.
			gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->client->renderInfo.muzzlePoint );
			gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, ent->client->renderInfo.muzzleDir );
			ent->client->renderInfo.mPCalcTime = level.time;

			AngleVectors( ent->client->ps.viewangles, forwardVec, vrightVec, up );
			//CalcMuzzlePoint( ent, forwardVec, vrightVec, up, muzzle, 0 );
		}
		else if ( !ent->enemy )
		{//an NPC with no enemy to auto-aim at
			VectorCopy( ent->client->renderInfo.muzzleDir, forwardVec );
		}
		else
		{//NPC, auto-aim at enemy
			CalcEntitySpot( ent->enemy, SPOT_HEAD, enemy_org1 );
			
			VectorSubtract (enemy_org1, muzzle1, delta1);

			vectoangles ( delta1, angleToEnemy1 );
			AngleVectors (angleToEnemy1, forwardVec, vrightVec, up);
		}
	} 
	else if ( ent->s.weapon == WP_BOT_LASER && ent->enemy ) 
	{
		vec3_t	delta1, enemy_org1, muzzle1;
		vec3_t	angleToEnemy1;

		CalcEntitySpot( ent->enemy, SPOT_HEAD, enemy_org1 );
		CalcEntitySpot( ent, SPOT_WEAPON, muzzle1 );
		
		VectorSubtract (enemy_org1, muzzle1, delta1);

		vectoangles ( delta1, angleToEnemy1 );
		AngleVectors (angleToEnemy1, forwardVec, vrightVec, up);
	}
	else 
	{
  		if ( (pVeh = G_IsRidingVehicle( ent )) != NULL) //riding a vehicle
		{//use our muzzleDir, can't use viewangles or vehicle m_vOrientation because we may be animated to shoot left or right...
			if ((ent->s.eFlags&EF_NODRAW))//we're inside it
			{
				vec3_t	aimAngles;
				VectorCopy( ent->client->renderInfo.muzzleDir, forwardVec );
				vectoangles( forwardVec, aimAngles );
				//we're only keeping the yaw
				aimAngles[PITCH] = ent->client->ps.viewangles[PITCH];
				aimAngles[ROLL] = 0;
				AngleVectors( aimAngles, forwardVec, vrightVec, up );
			}
			else
			{
				vec3_t	actorRight;
				vec3_t	actorFwd;

				VectorCopy( ent->client->renderInfo.muzzlePoint, muzzle );
				AngleVectors(ent->currentAngles, actorFwd, actorRight, 0);
 
				// Aiming Left
				//-------------
				if (ent->client->ps.torsoAnim==BOTH_VT_ATL_G || ent->client->ps.torsoAnim==BOTH_VS_ATL_G)
				{
 					VectorScale(actorRight, -1.0f, forwardVec);
				}

				// Aiming Right
				//--------------
				else if (ent->client->ps.torsoAnim==BOTH_VT_ATR_G || ent->client->ps.torsoAnim==BOTH_VS_ATR_G)
				{
 					VectorCopy(actorRight, forwardVec);
				}

				// Aiming Forward
				//----------------
				else
				{
	 				VectorCopy(actorFwd, forwardVec);
				}

				// If We Have An Enemy, Fudge The Aim To Hit The Enemy
				if (ent->enemy)
				{
					vec3_t	toEnemy;
					VectorSubtract(ent->enemy->currentOrigin, ent->currentOrigin, toEnemy);
					VectorNormalize(toEnemy);
					if (DotProduct(toEnemy, forwardVec)>0.75f && 
						((ent->s.number==0 && !Q_irand(0,2)) ||		// the player has a 1 in 3 chance
						 (ent->s.number!=0 && !Q_irand(0,5))))		// other guys have a 1 in 6 chance
					{
						VectorCopy(toEnemy, forwardVec);
					}
					else
					{
						forwardVec[0] += Q_flrand(-0.1f, 0.1f);
						forwardVec[1] += Q_flrand(-0.1f, 0.1f);
						forwardVec[2] += Q_flrand(-0.1f, 0.1f);
					}
				}
			}
		}
		else
		{
			AngleVectors( ent->client->ps.viewangles, forwardVec, vrightVec, up );
		}
	}

	ent->alt_fire = alt_fire;
	if (!pVeh)
	{
		if (ent->NPC && (ent->NPC->scriptFlags&SCF_FIRE_WEAPON_NO_ANIM))
		{
		 	VectorCopy( ent->client->renderInfo.muzzlePoint, muzzle );
			VectorCopy( ent->client->renderInfo.muzzleDir, forwardVec );
			MakeNormalVectors(forwardVec, vrightVec, up);
		}
		else
		{
			CalcMuzzlePoint ( ent, forwardVec, vrightVec, up, muzzle , 0);
		}
	}

	// fire the specific weapon
	switch( ent->s.weapon ) 
	{
	// Player weapons
	//-----------------
	case WP_SABER:
		return;
		break;

	case WP_BRYAR_PISTOL:
	case WP_BLASTER_PISTOL:
		WP_FireBryarPistol( ent, alt_fire );
		break;

	case WP_BLASTER:
		WP_FireBlaster( ent, alt_fire );
		break;

	case WP_TUSKEN_RIFLE:
		if ( alt_fire )
		{
			WP_FireTuskenRifle( ent );
		}
		else
		{
			WP_Melee( ent );
		}
		break;

	case WP_DISRUPTOR:
		alert = 50; // if you want it to alert enemies, remove this
		WP_FireDisruptor( ent, alt_fire );
		break;

	case WP_BOWCASTER:
		WP_FireBowcaster( ent, alt_fire );
		break;

	case WP_REPEATER:
		WP_FireRepeater( ent, alt_fire );
		break;

	case WP_DEMP2:
		WP_FireDEMP2( ent, alt_fire );
		break;

	case WP_FLECHETTE:
		WP_FireFlechette( ent, alt_fire );
		break;

	case WP_ROCKET_LAUNCHER:
		WP_FireRocket( ent, alt_fire );
		break;

	case WP_CONCUSSION:
		WP_Concussion( ent, alt_fire );
		break;

	case WP_THERMAL:
		WP_FireThermalDetonator( ent, alt_fire );
		break;

	case WP_TRIP_MINE:
		alert = 0; // if you want it to alert enemies, remove this
		WP_PlaceLaserTrap( ent, alt_fire );
		break;

	case WP_DET_PACK:
		alert = 0; // if you want it to alert enemies, remove this
		WP_FireDetPack( ent, alt_fire );
		break;

	case WP_BOT_LASER:
		WP_BotLaser( ent );
		break;

	case WP_EMPLACED_GUN:
		// doesn't care about whether it's alt-fire or not.  We can do an alt-fire if needed
		WP_EmplacedFire( ent );
		break;

	case WP_MELEE:
		alert = 0; // if you want it to alert enemies, remove this
		if ( !alt_fire || !g_debugMelee->integer )
		{
			WP_Melee( ent );
		}
		break;

	case WP_ATST_MAIN:
		WP_ATSTMainFire( ent );
		break;

	case WP_ATST_SIDE:

		// TEMP
		if ( alt_fire )
		{
//			WP_FireRocket( ent, qfalse );
			WP_ATSTSideAltFire(ent);
		}
		else
		{
			// FIXME!
		/*	if ( ent->s.number == 0 
				&& ent->client->NPC_class == CLASS_VEHICLE
				&& vehicleData[((CVehicleNPC *)ent->NPC)->m_iVehicleTypeID].type == VH_FIGHTER )
			{
				WP_ATSTMainFire( ent );
			}
			else*/
			{
				WP_ATSTSideFire(ent);
			}
		}
		break;

	case WP_TIE_FIGHTER:
		// TEMP
		WP_EmplacedFire( ent );
		break;

	case WP_RAPID_FIRE_CONC:
		// TEMP
		if ( alt_fire )
		{
			WP_FireRepeater( ent, alt_fire );	
		}
		else
		{
			WP_EmplacedFire( ent );
		}
		break;

	case WP_STUN_BATON:
		WP_FireStunBaton( ent, alt_fire );
		break;

//	case WP_BLASTER_PISTOL:
	case WP_JAWA:
		WP_FireBryarPistol( ent, qfalse ); // never an alt-fire?
		break;

	case WP_SCEPTER:
		WP_FireScepter( ent, alt_fire );
		break;

	case WP_NOGHRI_STICK:
		if ( !alt_fire )
		{
			WP_FireNoghriStick( ent );
		}
		//else does melee attack/damage/func
		break;

	case WP_TUSKEN_STAFF:
	default:
		return;
		break;
	}

	if ( !ent->s.number )
	{
		if ( ent->s.weapon == WP_FLECHETTE || (ent->s.weapon == WP_BOWCASTER && !alt_fire) )
		{//these can fire multiple shots, count them individually within the firing functions
		}
		else if ( W_AccuracyLoggableWeapon( ent->s.weapon, alt_fire, MOD_UNKNOWN ) )
		{
			ent->client->sess.missionStats.shotsFired++;
		}
	}
	// We should probably just use this as a default behavior, in special cases, just set alert to false.
	if ( ent->s.number == 0 && alert > 0 )
	{
		if ( ent->client->ps.groundEntityNum == ENTITYNUM_WORLD//FIXME: check for sand contents type?
			&& ent->s.weapon != WP_STUN_BATON
			&& ent->s.weapon != WP_MELEE
			&& ent->s.weapon != WP_TUSKEN_STAFF
			&& ent->s.weapon != WP_THERMAL
			&& ent->s.weapon != WP_TRIP_MINE
			&& ent->s.weapon != WP_DET_PACK )
		{//the vibration of the shot carries through your feet into the ground
			AddSoundEvent( ent, muzzle, alert, AEL_DISCOVERED, qfalse, qtrue );
		}
		else
		{//an in-air alert
			AddSoundEvent( ent, muzzle, alert, AEL_DISCOVERED );
		}
		AddSightEvent( ent, muzzle, alert*2, AEL_DISCOVERED, 20 );
	}
}
Beispiel #6
0
//------------------------------------------------------
void G_MissileImpact( gentity_t *ent, trace_t *trace, int hitLoc=HL_NONE ) 
{
	gentity_t		*other;
	vec3_t			diff;

	other = &g_entities[trace->entityNum];
	if ( other == ent )
	{
		assert(0&&"missile hit itself!!!");
		return;
	}
	if ( trace->plane.normal[0] == 0.0f &&
		 trace->plane.normal[1] == 0.0f &&
		 trace->plane.normal[2] == 0.0f
		)
	{//model moved into missile in flight probably...
		trace->plane.normal[0] = -ent->s.pos.trDelta[0];
		trace->plane.normal[1] = -ent->s.pos.trDelta[1];
		trace->plane.normal[2] = -ent->s.pos.trDelta[2];
		VectorNormalize(trace->plane.normal);
	}

	if ( ent->owner && (other->takedamage||other->client) )
	{
		if ( !ent->lastEnemy || ent->lastEnemy == ent->owner )
		{//a missile that was not reflected or, if so, still is owned by original owner
			if( LogAccuracyHit( other, ent->owner ) ) 
			{
				ent->owner->client->ps.persistant[PERS_ACCURACY_HITS]++;
			}
			if ( ent->owner->client && !ent->owner->s.number )
			{
				if ( W_AccuracyLoggableWeapon( ent->s.weapon, qfalse, ent->methodOfDeath ) )
				{
					ent->owner->client->sess.missionStats.hits++;
				}
			}
		}
	}
	// check for bounce
	//OR: if the surfaceParm is has a reflect property (magnetic shielding) and the missile isn't an exploding missile
	qboolean bounce = !!( (!other->takedamage && (ent->s.eFlags&(EF_BOUNCE|EF_BOUNCE_HALF))) || (((trace->surfaceFlags&SURF_FORCEFIELD)||(other->flags&FL_SHIELDED))&&!ent->splashDamage&&!ent->splashRadius&&ent->s.weapon != WP_NOGHRI_STICK) );

	if ( ent->dflags & DAMAGE_HEAVY_WEAP_CLASS )
	{
		// heavy class missiles generally never bounce.
		bounce = qfalse;
	}

	if ( other->flags & (FL_DMG_BY_HEAVY_WEAP_ONLY | FL_SHIELDED ))
	{
		// Dumb assumption, but I guess we must be a shielded ion_cannon??  We should probably verify
		// if it's an ion_cannon that's Heavy Weapon only, we don't want to make it shielded do we...?
		if ( (!strcmp( "misc_ion_cannon", other->classname )) && (other->flags & FL_SHIELDED) )
		{
			// Anything will bounce off of us.
			bounce = qtrue;

			// Not exactly the debounce time, but rather the impact time for the shield effect...play effect for 1 second
			other->painDebounceTime = level.time + 1000;
		}
	}

	if ( ent->s.weapon == WP_DEMP2 )
	{
		// demp2 shots can never bounce
		bounce = qfalse;

		// in fact, alt-charge shots will not call the regular impact functions
		if ( ent->alt_fire )
		{
			// detonate at the trace end
			VectorCopy( trace->endpos, ent->currentOrigin );
			VectorCopy( trace->plane.normal, ent->pos1 );
			DEMP2_AltDetonate( ent );
			return;
		}
	}

	if ( bounce ) 
	{
		// Check to see if there is a bounce count
		if ( ent->bounceCount ) 
		{
			// decrement number of bounces and then see if it should be done bouncing
			if ( !(--ent->bounceCount) ) {
				// He (or she) will bounce no more (after this current bounce, that is).
				ent->s.eFlags &= ~( EF_BOUNCE | EF_BOUNCE_HALF );
			}
		}

		if ( other->NPC )
		{
			G_Damage( other, ent, ent->owner, ent->currentOrigin, ent->s.pos.trDelta, 0, DAMAGE_NO_DAMAGE, MOD_UNKNOWN );
		}

		G_BounceMissile( ent, trace );
		
		if ( ent->owner )//&& ent->owner->s.number == 0 ) 
		{
			G_MissileAddAlerts( ent );
		}
		G_MissileBounceEffect( ent, trace->endpos, trace->plane.normal, trace->entityNum==ENTITYNUM_WORLD );

		return;
	}
	
	// I would glom onto the EF_BOUNCE code section above, but don't feel like risking breaking something else
	if ( (!other->takedamage && ( ent->s.eFlags&(EF_BOUNCE_SHRAPNEL) ) ) 
		|| ((trace->surfaceFlags&SURF_FORCEFIELD)&&!ent->splashDamage&&!ent->splashRadius) ) 
	{
		if ( !(other->contents&CONTENTS_LIGHTSABER)
			|| g_spskill->integer <= 0//on easy, it reflects all shots
			|| (g_spskill->integer == 1 && ent->s.weapon != WP_FLECHETTE && ent->s.weapon != WP_DEMP2 )//on medium it won't reflect flechette or demp shots
			|| (g_spskill->integer >= 2 && ent->s.weapon != WP_FLECHETTE && ent->s.weapon != WP_DEMP2 && ent->s.weapon != WP_BOWCASTER && ent->s.weapon != WP_REPEATER )//on hard it won't reflect flechette, demp, repeater or bowcaster shots
			)
		{
			G_BounceMissile( ent, trace );

			if ( --ent->bounceCount < 0 )
			{
				ent->s.eFlags &= ~EF_BOUNCE_SHRAPNEL;
			}
			G_MissileBounceEffect( ent, trace->endpos, trace->plane.normal, trace->entityNum==ENTITYNUM_WORLD );
			return;
		}
	}

	if ( (!other->takedamage || (other->client && other->health <= 0))
		&& ent->s.weapon == WP_THERMAL 
		&& !ent->alt_fire )
	{//rolling thermal det - FIXME: make this an eFlag like bounce & stick!!!
		//G_BounceRollMissile( ent, trace );
		if ( ent->owner )//&& ent->owner->s.number == 0 ) 
		{
			G_MissileAddAlerts( ent );
		}
		//gi.linkentity( ent );
		return;
	}

	// check for sticking
	if ( ent->s.eFlags & EF_MISSILE_STICK ) 
	{
		if ( ent->owner )//&& ent->owner->s.number == 0 ) 
		{
			//Add the event
			if ( ent->s.weapon == WP_TRIP_MINE )
			{
				AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius/2, AEL_DISCOVERED/*AEL_DANGER*/, qfalse, qtrue );
				AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius*2, AEL_DISCOVERED/*AEL_DANGER*/, 60 );
				/*
				AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius*2, AEL_DANGER, qfalse, qtrue );
				AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius*2, AEL_DANGER, 60 );
				*/
			}
			else
			{
				AddSoundEvent( ent->owner, ent->currentOrigin, 128, AEL_DISCOVERED, qfalse, qtrue );
				AddSightEvent( ent->owner, ent->currentOrigin, 256, AEL_DISCOVERED, 10 );
			}
		}

		G_MissileStick( ent, other, trace );
		return;
	}

extern bool WP_DoingMoronicForcedAnimationForForcePowers(gentity_t *ent);
	// check for hitting a lightsaber
	if ( other->contents & CONTENTS_LIGHTSABER )
	{
		if ( other->owner && !other->owner->s.number && other->owner->client )
		{
			other->owner->client->sess.missionStats.saberBlocksCnt++;
		}
		if ( ( g_spskill->integer <= 0//on easy, it reflects all shots
				|| (g_spskill->integer == 1 && ent->s.weapon != WP_FLECHETTE && ent->s.weapon != WP_DEMP2 )//on medium it won't reflect flechette or demp shots
				|| (g_spskill->integer >= 2 && ent->s.weapon != WP_FLECHETTE && ent->s.weapon != WP_DEMP2 && ent->s.weapon != WP_BOWCASTER && ent->s.weapon != WP_REPEATER )//on hard it won't reflect flechette, demp, repeater or bowcaster shots
			 )
			&& (!ent->splashDamage || !ent->splashRadius) //this would be cool, though, to "bat" the thermal det away...
			&& ent->s.weapon != WP_NOGHRI_STICK )//gas bomb, don't reflect
		{	
			//FIXME: take other's owner's FP_SABER_DEFENSE into account here somehow?
			if (  !other->owner || !other->owner->client || other->owner->client->ps.saberInFlight 
				|| (InFront( ent->currentOrigin, other->owner->currentOrigin, other->owner->client->ps.viewangles, SABER_REFLECT_MISSILE_CONE ) &&
				!WP_DoingMoronicForcedAnimationForForcePowers(other)) )//other->owner->s.number != 0 || 
			{//Jedi cannot block shots from behind!
				int blockChance = 0;
				switch ( other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] )
				{//level 1 reflects 50% of the time, level 2 reflects 75% of the time
				case FORCE_LEVEL_3:
					blockChance = 10;
					break;
				case FORCE_LEVEL_2:
					blockChance = 3;
					break;
				case FORCE_LEVEL_1:
					blockChance = 1;
					break;
				}
				if ( blockChance && (other->owner->client->ps.forcePowersActive&(1<<FP_SPEED)) )
				{//in in force speed, better chance of deflecting the shot
					blockChance += other->owner->client->ps.forcePowerLevel[FP_SPEED]*2;
				}
				if ( Q_irand( 0, blockChance ) )
				{
					VectorSubtract(ent->currentOrigin, other->currentOrigin, diff);
					VectorNormalize(diff);
					G_ReflectMissile( other, ent, diff);
					if ( other->owner && other->owner->client )
					{
						other->owner->client->ps.saberEventFlags |= SEF_DEFLECTED;
					}
					//do the effect
					VectorCopy( ent->s.pos.trDelta, diff );
					VectorNormalize( diff );
					G_MissileReflectEffect( ent, trace->endpos, trace->plane.normal );
					return;
				}
			}
		}
		else
		{//still do the bounce effect
			G_MissileReflectEffect( ent, trace->endpos, trace->plane.normal );
		}
	}

	G_MissileImpacted( ent, other, trace->endpos, trace->plane.normal, hitLoc );
}
Beispiel #7
0
static void Howler_Howl( void )
{
	gentity_t	*radiusEnts[ 128 ];
	int			numEnts;
	const float	radius = (NPC->spawnflags&1)?256:128;
	const float	halfRadSquared = ((radius/2)*(radius/2));
	const float	radiusSquared = (radius*radius);
	float		distSq;
	int			i;
	vec3_t		boltOrg;

	AddSoundEvent( NPC, NPC->currentOrigin, 512, AEL_DANGER, qfalse, qtrue );

	numEnts = NPC_GetEntsNearBolt( radiusEnts, radius, NPC->handLBolt, boltOrg );

	for ( i = 0; i < numEnts; i++ )
	{
		if ( !radiusEnts[i]->inuse )
		{
			continue;
		}
		
		if ( radiusEnts[i] == NPC )
		{//Skip the rancor ent
			continue;
		}
		
		if ( radiusEnts[i]->client == NULL )
		{//must be a client
			continue;
		}

		if ( radiusEnts[i]->client->NPC_class == CLASS_HOWLER )
		{//other howlers immune
			continue;
		}

		distSq = DistanceSquared( radiusEnts[i]->currentOrigin, boltOrg );
		if ( distSq <= radiusSquared )
		{
			if ( distSq < halfRadSquared )
			{//close enough to do damage, too
				if ( Q_irand( 0, g_spskill->integer ) )
				{//does no damage on easy, does 1 point every other frame on medium, more often on hard
					G_Damage( radiusEnts[i], NPC, NPC, vec3_origin, NPC->currentOrigin, 1, DAMAGE_NO_KNOCKBACK, MOD_IMPACT );
				}
			}
			if ( radiusEnts[i]->health > 0 
				&& radiusEnts[i]->client
				&& radiusEnts[i]->client->NPC_class != CLASS_RANCOR
				&& radiusEnts[i]->client->NPC_class != CLASS_ATST 
				&& !PM_InKnockDown( &radiusEnts[i]->client->ps ) )
			{
				if ( PM_HasAnimation( radiusEnts[i], BOTH_SONICPAIN_START ) )
				{
					if ( radiusEnts[i]->client->ps.torsoAnim != BOTH_SONICPAIN_START 
						&& radiusEnts[i]->client->ps.torsoAnim != BOTH_SONICPAIN_HOLD )
					{
						NPC_SetAnim( radiusEnts[i], SETANIM_LEGS, BOTH_SONICPAIN_START, SETANIM_FLAG_NORMAL );
						NPC_SetAnim( radiusEnts[i], SETANIM_TORSO, BOTH_SONICPAIN_START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
						radiusEnts[i]->client->ps.torsoAnimTimer += 100;
						radiusEnts[i]->client->ps.weaponTime = radiusEnts[i]->client->ps.torsoAnimTimer;
					}
					else if ( radiusEnts[i]->client->ps.torsoAnimTimer <= 100 )
					{//at the end of the sonic pain start or hold anim
						NPC_SetAnim( radiusEnts[i], SETANIM_LEGS, BOTH_SONICPAIN_HOLD, SETANIM_FLAG_NORMAL );
						NPC_SetAnim( radiusEnts[i], SETANIM_TORSO, BOTH_SONICPAIN_HOLD, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
						radiusEnts[i]->client->ps.torsoAnimTimer += 100; 
						radiusEnts[i]->client->ps.weaponTime = radiusEnts[i]->client->ps.torsoAnimTimer;
					}
				}
				/*
				else if ( distSq < halfRadSquared 
					&& radiusEnts[i]->client->ps.groundEntityNum != ENTITYNUM_NONE 
					&& !Q_irand( 0, 10 ) )//FIXME: base on skill
				{//within range
					G_Knockdown( radiusEnts[i], NPC, vec3_origin, 500, qfalse );
				}
				*/
			}
		}
	}

	float playerDist = NPC_EntRangeFromBolt( player, NPC->genericBolt1 );
	if ( playerDist < 256.0f )
	{
		CGCam_Shake( 1.0f*playerDist/128.0f, 200 );
	}
}
Beispiel #8
0
void G_MissileImpacted( gentity_t *ent, gentity_t *other, vec3_t impactPos, vec3_t normal, int hitLoc=HL_NONE )
{
	// impact damage
	if ( other->takedamage ) 
	{
		// FIXME: wrong damage direction?
		if ( ent->damage ) 
		{
			vec3_t	velocity;

			EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
			if ( VectorLength( velocity ) == 0 ) 
			{
				velocity[2] = 1;	// stepped on a grenade
			}

			int damage = ent->damage;

			if( other->client )
			{
				class_t	npc_class = other->client->NPC_class;

				// If we are a robot and we aren't currently doing the full body electricity...
				if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE ||
					   npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 || npc_class == CLASS_REMOTE ||
					   npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || //npc_class == CLASS_PROTOCOL ||//no protocol, looks odd
					   npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY )
				{
					// special droid only behaviors
					if ( other->client->ps.powerups[PW_SHOCKED] < level.time + 100 )
					{
						// ... do the effect for a split second for some more feedback
						other->s.powerups |= ( 1 << PW_SHOCKED );
						other->client->ps.powerups[PW_SHOCKED] = level.time + 450;
					}
					//FIXME: throw some sparks off droids,too
				}
			}

			G_Damage( other, ent, ent->owner, velocity,
					impactPos, damage, 
					ent->dflags, ent->methodOfDeath, hitLoc);

			if ( ent->s.weapon == WP_DEMP2 )
			{//a hit with demp2 decloaks saboteurs
				if ( other && other->client && other->client->NPC_class == CLASS_SABOTEUR )
				{//FIXME: make this disabled cloak hold for some amount of time?
					Saboteur_Decloak( other, Q_irand( 3000, 10000 ) );
					if ( ent->methodOfDeath == MOD_DEMP2_ALT )
					{//direct hit with alt disabled cloak forever
						if ( other->NPC )
						{//permanently disable the saboteur's cloak
							other->NPC->aiFlags &= ~NPCAI_SHIELDS;
						}
					}
				}
			}
		}
	}

	// is it cheaper in bandwidth to just remove this ent and create a new
	// one, rather than changing the missile into the explosion?
	//G_FreeEntity(ent);
	
	if ( (other->takedamage && other->client ) || (ent->s.weapon == WP_FLECHETTE && other->contents&CONTENTS_LIGHTSABER) ) 
	{
		G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( normal ) );
		ent->s.otherEntityNum = other->s.number;
	} 
	else 
	{
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( normal ) );
		ent->s.otherEntityNum = other->s.number;
	}

	VectorCopy( normal, ent->pos1 );

	if ( ent->owner )//&& ent->owner->s.number == 0 )
	{
		//Add the event
		AddSoundEvent( ent->owner, ent->currentOrigin, 256, AEL_SUSPICIOUS, qfalse, qtrue );
		AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED, 75 );
	}

	ent->freeAfterEvent = qtrue;

	// change over to a normal entity right at the point of impact
	ent->s.eType = ET_GENERAL;

	//SnapVectorTowards( trace->endpos, ent->s.pos.trBase );	// save net bandwidth
	VectorCopy( impactPos, ent->s.pos.trBase );

	G_SetOrigin( ent, impactPos );

	// splash damage (doesn't apply to person directly hit)
	if ( ent->splashDamage ) 
	{
		G_RadiusDamage( impactPos, ent->owner, ent->splashDamage, ent->splashRadius, 
			other, ent->splashMethodOfDeath );
	}

	if ( ent->s.weapon == WP_NOGHRI_STICK )
	{
		G_SpawnNoghriGasCloud( ent );
	}

	gi.linkentity( ent );
}
Beispiel #9
0
void G_RunMissile( gentity_t *ent ) 
{
	vec3_t		oldOrg;
	trace_t		tr;
	int			trHitLoc=HL_NONE;

	if ( (ent->s.eFlags&EF_HELD_BY_SAND_CREATURE) )
	{//in a sand creature's mouth
		if ( ent->activator )
		{
			mdxaBone_t	boltMatrix;
			// Getting the bolt here
			//in hand
			vec3_t scAngles = {0};
			scAngles[YAW] = ent->activator->currentAngles[YAW];
			gi.G2API_GetBoltMatrix( ent->activator->ghoul2, ent->activator->playerModel, ent->activator->gutBolt, 
					&boltMatrix, scAngles, ent->activator->currentOrigin, (cg.time?cg.time:level.time),
					NULL, ent->activator->s.modelScale );
			// Storing ent position, bolt position, and bolt axis
			gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->currentOrigin );
			G_SetOrigin( ent, ent->currentOrigin );
		}
		// check think function
		G_RunThink( ent );
		return;
	}

	VectorCopy( ent->currentOrigin, oldOrg );

	// get current position
	if ( ent->s.pos.trType == TR_INTERPOLATE )
	{//rolling missile?
		//FIXME: WTF?!!  Sticks to stick missiles?
		//FIXME: they stick inside the player
		G_RollMissile( ent );
		if ( ent->s.eType != ET_GENERAL )
		{//didn't explode
			VectorCopy( ent->currentOrigin, ent->s.pos.trBase );
			gi.trace( &tr, oldOrg, ent->mins, ent->maxs, ent->currentOrigin, ent->s.number, ent->clipmask, G2_RETURNONHIT, 10 );
			if ( VectorCompare( ent->s.pos.trDelta, vec3_origin ) )
			{
				//VectorCopy( ent->currentAngles, ent->s.apos.trBase );
				VectorClear( ent->s.apos.trDelta );
			}
			else
			{
				vec3_t	ang, fwdDir, rtDir;
				float	speed;
				
				ent->s.apos.trType = TR_INTERPOLATE;
				VectorSet( ang, 0, ent->s.apos.trBase[1], 0 );
				AngleVectors( ang, fwdDir, rtDir, NULL );
				speed = VectorLength( ent->s.pos.trDelta )*4;

				//HMM, this works along an axis-aligned dir, but not along diagonals
				//This is because when roll gets to 90, pitch becomes yaw, and vice-versa
				//Maybe need to just set the angles directly?
				ent->s.apos.trDelta[0] = DotProduct( fwdDir, ent->s.pos.trDelta );
				ent->s.apos.trDelta[1] = 0;//never spin!
				ent->s.apos.trDelta[2] = DotProduct( rtDir, ent->s.pos.trDelta );

				VectorNormalize( ent->s.apos.trDelta );
				VectorScale( ent->s.apos.trDelta, speed, ent->s.apos.trDelta );

				ent->s.apos.trTime = level.previousTime;
			}
		}
	}
	else
	{
		vec3_t		origin; 
		EvaluateTrajectory( &ent->s.pos, level.time, origin );
		// trace a line from the previous position to the current position,
		// ignoring interactions with the missile owner
		gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
			ent->owner ? ent->owner->s.number : ent->s.number, ent->clipmask, G2_COLLIDE, 10 );
		
		if ( tr.entityNum != ENTITYNUM_NONE )
		{
			gentity_t *other = &g_entities[tr.entityNum];
			// check for hitting a lightsaber
			if ( other->contents & CONTENTS_LIGHTSABER )
			{//hit a lightsaber bbox
				if ( other->owner 
					&& other->owner->client 
					&& !other->owner->client->ps.saberInFlight 
					&& ( Q_irand( 0, (other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]*other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]) ) == 0 
						|| !InFront( ent->currentOrigin, other->owner->currentOrigin, other->owner->client->ps.viewangles, SABER_REFLECT_MISSILE_CONE ) ) )//other->owner->s.number == 0 &&
				{//Jedi cannot block shots from behind!
					//re-trace from here, ignoring the lightsaber
					gi.trace( &tr, tr.endpos, ent->mins, ent->maxs, origin, tr.entityNum, ent->clipmask, G2_RETURNONHIT, 10 );
				}
			}
		}

		VectorCopy( tr.endpos, ent->currentOrigin );
	}

	// get current angles
	VectorMA( ent->s.apos.trBase, (level.time - ent->s.apos.trTime) * 0.001, ent->s.apos.trDelta, ent->s.apos.trBase );

	//FIXME: Rolling things hitting G2 polys is weird
	///////////////////////////////////////////////////////
//?	if ( tr.fraction != 1 ) 
	{
	// did we hit or go near a Ghoul2 model?
//		qboolean hitModel = qfalse;
		for (int i=0; i < MAX_G2_COLLISIONS; i++)
		{
			if (tr.G2CollisionMap[i].mEntityNum == -1)
			{
				break;
			}

			CCollisionRecord &coll = tr.G2CollisionMap[i];
			gentity_t	*hitEnt = &g_entities[coll.mEntityNum];

			// process collision records here...
			// make sure we only do this once, not for all the entrance wounds we might generate
			if ((coll.mFlags & G2_FRONTFACE)/* && !(hitModel)*/ && hitEnt->health)
			{
				if (trHitLoc==HL_NONE)
				{
					G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, NULL, NULL, ent->methodOfDeath );
				}

				break; // NOTE: the way this whole section was working, it would only get inside of this IF once anyway, might as well break out now
			}
		}
	}
/////////////////////////////////////////////////////////

	if ( tr.startsolid ) 
	{
		tr.fraction = 0;
	}

	gi.linkentity( ent );

	if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
	{//stuck missiles should check some special stuff
		G_RunStuckMissile( ent );
		return;
	}

	// check think function
	G_RunThink( ent );

	if ( ent->s.eType != ET_MISSILE ) 
	{
		return;		// exploded
	}

	if ( ent->mass )
	{
		G_MoverTouchPushTriggers( ent, oldOrg );
	}
	/*
	if ( !(ent->s.eFlags & EF_TELEPORT_BIT) )
	{
		G_MoverTouchTeleportTriggers( ent, oldOrg );
		if ( ent->s.eFlags & EF_TELEPORT_BIT )
		{//was teleported
			return;
		}
	}
	else
	{
		ent->s.eFlags &= ~EF_TELEPORT_BIT;
	}
	*/

	AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED, 75 );//wakes them up when see a shot passes in front of them
	if ( !Q_irand( 0, 10 ) )
	{//not so often...
		if ( ent->splashDamage && ent->splashRadius )
		{//I'm an exploder, let people around me know danger is coming
			if ( ent->s.weapon == WP_TRIP_MINE )
			{//???
			}
			else 
			{
				if ( ent->s.weapon == WP_ROCKET_LAUNCHER && ent->e_ThinkFunc == thinkF_rocketThink )
				{//homing rocket- run like hell!
					AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER_GREAT, 50 );
				}
				else
				{
					AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER, 50 );
				}
				AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER );
			}
		}
		else
		{//makes them run from near misses
			AddSightEvent( ent->owner, ent->currentOrigin, 48, AEL_DANGER, 50 );
		}
	}

	if ( tr.fraction == 1 ) 
	{
		if ( ent->s.weapon == WP_THERMAL && ent->s.pos.trType == TR_INTERPOLATE )
		{//a rolling thermal that didn't hit anything
			G_MissileAddAlerts( ent );
		}
		return;
	}

	// never explode or bounce on sky
	if ( tr.surfaceFlags & SURF_NOIMPACT ) 
	{
		G_FreeEntity( ent );
		return;
	}

	G_MissileImpact( ent, &tr, trHitLoc );
}
Beispiel #10
0
void G_RunMissile( gentity_t *ent ) 
{
	vec3_t		origin, oldOrg;
	trace_t		tr;
	int			trHitLoc=HL_NONE;

	VectorCopy( ent->currentOrigin, oldOrg );

	// get current position
	if ( ent->s.pos.trType == TR_INTERPOLATE )
	{//rolling missile?
		//FIXME: WTF?!!  Sticks to stick missiles?
		//FIXME: they stick inside the player
		G_RollMissile( ent );
		if ( ent->s.eType != ET_GENERAL )
		{//didn't explode
			VectorCopy( ent->currentOrigin, ent->s.pos.trBase );
			gi.trace( &tr, oldOrg, ent->mins, ent->maxs, ent->currentOrigin, ent->s.number, ent->clipmask, G2_RETURNONHIT, 10 );
			if ( VectorCompare( ent->s.pos.trDelta, vec3_origin ) )
			{
				//VectorCopy( ent->currentAngles, ent->s.apos.trBase );
				VectorClear( ent->s.apos.trDelta );
			}
			else
			{
				vec3_t	ang, fwdDir, rtDir;
				float	speed;
				
				ent->s.apos.trType = TR_INTERPOLATE;
				VectorSet( ang, 0, ent->s.apos.trBase[1], 0 );
				AngleVectors( ang, fwdDir, rtDir, NULL );
				speed = VectorLength( ent->s.pos.trDelta )*4;

				//HMM, this works along an axis-aligned dir, but not along diagonals
				//This is because when roll gets to 90, pitch becomes yaw, and vice-versa
				//Maybe need to just set the angles directly?
				ent->s.apos.trDelta[0] = DotProduct( fwdDir, ent->s.pos.trDelta );
				ent->s.apos.trDelta[1] = 0;//never spin!
				ent->s.apos.trDelta[2] = DotProduct( rtDir, ent->s.pos.trDelta );

				VectorNormalize( ent->s.apos.trDelta );
				VectorScale( ent->s.apos.trDelta, speed, ent->s.apos.trDelta );

				ent->s.apos.trTime = level.previousTime;
			}
		}
	}
	else
	{
		EvaluateTrajectory( &ent->s.pos, level.time, origin );
		// trace a line from the previous position to the current position,
		// ignoring interactions with the missile owner
		/*
		gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
			ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask, G2_RETURNONHIT, 10 );
		*/
		gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
			ent->owner ? ent->owner->s.number : ent->s.number, ent->clipmask, G2_COLLIDE, 10 );
		/*
		if ( !VectorCompare( ent->mins, vec3_origin ) || !VectorCompare( ent->maxs, vec3_origin ) )
		{//don't do ghoul trace if ent has size because g2 just ignores that anyway
			gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
				ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask, G2_NOCOLLIDE, 10 );
		}
		else
		//Now we always do ghoul trace, regardless of bbox size of missile, this is presuming that non-point ghoul traces will be possible...?
		{
			gi.trace( &tr, ent->currentOrigin, vec3_origin, vec3_origin, origin, 
				ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask, G2_RETURNONHIT, 10 );
		}
		*/
		/*
		if ( tr.fraction == 0.0f && tr.plane.normal[2] == 1.0f && origin[2] < ent->currentOrigin[2] )
		{
			if ( ent->s.pos.trType == TR_GRAVITY && !(ent->s.eFlags&EF_BOUNCE) && !(ent->s.eFlags&EF_BOUNCE_HALF) && ent->s.weapon == WP_THERMAL )//FIXME: EF_ROLLING
			{
				//FIXME: Needs to stop sometime!
				ent->s.pos.trType = TR_LINEAR;
				ent->s.pos.trDelta[2] = 0;
				EvaluateTrajectory( &ent->s.pos, level.time, origin );
				// trace a line from the previous position to the current position,
				// ignoring interactions with the missile owner
				gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
					ent->owner ? ent->owner->s.number : ENTITYNUM_NONE, ent->clipmask | CONTENTS_GHOUL2 );
				if ( tr.fraction == 1.0f )
				{
					VectorCopy( tr.endpos, ent->s.pos.trBase );
					VectorScale( ent->s.pos.trDelta, 0.975f, ent->s.pos.trDelta );
					ent->s.pos.trTime = level.time;
				}
				ent->s.pos.trType = TR_GRAVITY;
			}
		}
		*/

		if ( tr.entityNum != ENTITYNUM_NONE && &g_entities[tr.entityNum] != NULL )
		{
			gentity_t *other = &g_entities[tr.entityNum];
			// check for hitting a lightsaber
			if ( other->contents & CONTENTS_LIGHTSABER )
			{//hit a lightsaber bbox
				if ( other->owner && other->owner->client && !other->owner->client->ps.saberInFlight && !InFront( ent->currentOrigin, other->owner->currentOrigin, other->owner->client->ps.viewangles, SABER_REFLECT_MISSILE_CONE ) )//other->owner->s.number == 0 &&
				{//Jedi cannot block shots from behind!
					//re-trace from here, ignoring the lightsaber
					gi.trace( &tr, tr.endpos, ent->mins, ent->maxs, origin, tr.entityNum, ent->clipmask, G2_RETURNONHIT, 10 );
				}
			}
		}

		VectorCopy( tr.endpos, ent->currentOrigin );
	}

	// get current angles
	VectorMA( ent->s.apos.trBase, (level.time - ent->s.apos.trTime) * 0.001, ent->s.apos.trDelta, ent->s.apos.trBase );

	//FIXME: Rolling things hitting G2 polys is weird
	///////////////////////////////////////////////////////
//?	if ( tr.fraction != 1 ) 
	{
	// did we hit or go near a Ghoul2 model?
//		qboolean hitModel = qfalse;
		for (int i=0; i < MAX_G2_COLLISIONS; i++)
		{
			if (tr.G2CollisionMap[i].mEntityNum == -1)
			{
				break;
			}

			CCollisionRecord &coll = tr.G2CollisionMap[i];
			gentity_t	*hitEnt = &g_entities[coll.mEntityNum];

/*	Sorry...this was just getting in the way....
#if _DEBUG
			vec3_t delta;
			VectorSubtract(origin, coll.mCollisionPosition, delta);
			VectorNormalize(delta);
			VectorScale(delta, 30, delta);

			if (coll.mFlags & G2_BACKFACE)
			{
				VectorAdd(delta, coll.mCollisionPosition, delta);
				G_DebugLine(coll.mCollisionPosition, delta, 10000, 0x00ff0000, qtrue);
			}
			else
			{
				VectorSubtract(coll.mCollisionPosition, delta, delta);
				G_DebugLine(coll.mCollisionPosition, delta, 10000, 0x0000ff00, qtrue);
			}

//loadsavecrash
//			VectorCopy(hitEnt->mins, hitEnt->s.mins);
//			VectorCopy(hitEnt->maxs, hitEnt->s.maxs);
#endif
*/

			// process collision records here...
			// make sure we only do this once, not for all the entrance wounds we might generate
			if ((coll.mFlags & G2_FRONTFACE)/* && !(hitModel)*/ && hitEnt->health)
			{
				// create a new surface using the details of what poly/surface/model we hit
//				int newSurface = gi.G2API_AddSurface(&hitEnt->ghoul2[coll.mModelIndex], coll.mSurfaceIndex, coll.mPolyIndex, coll.mBarycentricI, coll.mBarycentricJ, 10);
//				surfaceInfo_t	*newSuf = &hitEnt->ghoul2[coll.mModelIndex].mSlist[newSurface];
				// attach a bolt to this surface
//				int newBolt = gi.G2API_AddBoltSurfNum(&hitEnt->ghoul2[coll.mModelIndex], newSurface);
				// now attach an effect to this new bolt

//	Bolting on this effect just looks dumb and adds lots of unnecessary effects to the scene
//				
//				G_PlayEffect( G_EffectIndex( "blaster/smoke_bolton") , coll.mModelIndex, newBolt, hitEnt->s.number);
//
//

//				G_SetBoltSurfaceRemoval(coll.mEntityNum, coll.mModelIndex, newBolt, newSurface, 10000);
//				hitModel = qtrue;

				if (trHitLoc==HL_NONE)
				{
					G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, NULL, NULL, ent->methodOfDeath );
				}

				break; // NOTE: the way this whole section was working, it would only get inside of this IF once anyway, might as well break out now
			}
		}
	}
/////////////////////////////////////////////////////////

	if ( tr.startsolid ) 
	{
		tr.fraction = 0;
	}

	gi.linkentity( ent );

	if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
	{//stuck missiles should check some special stuff
		G_RunStuckMissile( ent );
		return;
	}

	// check think function
	G_RunThink( ent );

	if ( ent->s.eType != ET_MISSILE ) 
	{
		return;		// exploded
	}

	if ( ent->mass )
	{
		G_MoverTouchPushTriggers( ent, oldOrg );
	}
	/*
	if ( !(ent->s.eFlags & EF_TELEPORT_BIT) )
	{
		G_MoverTouchTeleportTriggers( ent, oldOrg );
		if ( ent->s.eFlags & EF_TELEPORT_BIT )
		{//was teleported
			return;
		}
	}
	else
	{
		ent->s.eFlags &= ~EF_TELEPORT_BIT;
	}
	*/

	AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED, 75 );//wakes them up when see a shot passes in front of them
	if ( !Q_irand( 0, 10 ) )
	{//not so often...
		if ( ent->splashDamage && ent->splashRadius )
		{//I'm an exploder, let people around me know danger is coming
			if ( ent->s.weapon == WP_TRIP_MINE )
			{//???
			}
			else 
			{
				if ( ent->s.weapon == WP_ROCKET_LAUNCHER && ent->e_ThinkFunc == thinkF_rocketThink )
				{//homing rocket- run like hell!
					AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER_GREAT, 50 );
				}
				else
				{
					AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER, 50 );
				}
				AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER );
			}
		}
		else
		{//makes them run from near misses
			AddSightEvent( ent->owner, ent->currentOrigin, 48, AEL_DANGER, 50 );
		}
	}

	if ( tr.fraction == 1 ) 
	{
		return;
	}

	// never explode or bounce on sky
	if ( tr.surfaceFlags & SURF_NOIMPACT ) 
	{
		G_FreeEntity( ent );
		return;
	}

	G_MissileImpact( ent, &tr, trHitLoc );
}
Beispiel #11
0
//---------------------------------------------------------
void FireWeapon( gentity_t *ent, qboolean alt_fire )
//---------------------------------------------------------
{
	float alert = 256;

	// track shots taken for accuracy tracking.
	ent->client->ps.persistant[PERS_ACCURACY_SHOTS]++;

	// set aiming directions
	if ( ent->s.weapon == WP_DISRUPTOR && alt_fire )
	{
		if ( ent->NPC )
		{
			//snipers must use the angles they actually did their shot trace with
			AngleVectors( ent->lastAngles, wpFwd, wpVright, wpUp );
		}
	}
	else if ( ent->s.weapon == WP_ATST_SIDE || ent->s.weapon == WP_ATST_MAIN )
	{
		vec3_t	delta1, enemy_org1, muzzle1;
		vec3_t	angleToEnemy1;

		VectorCopy( ent->client->renderInfo.muzzlePoint, muzzle1 );

		if ( !ent->s.number )
		{//player driving an AT-ST
			//SIGH... because we can't anticipate alt-fire, must calc muzzle here and now
			mdxaBone_t		boltMatrix;
			int				bolt;

			if ( ent->client->ps.weapon == WP_ATST_MAIN )
			{//FIXME: alt_fire should fire both barrels, but slower?
				if ( ent->alt_fire )
				{
					bolt = ent->handRBolt;
				}
				else
				{
					bolt = ent->handLBolt;
				}
			}
			else
			{// ATST SIDE weapons
				if ( ent->alt_fire )
				{
					if ( gi.G2API_GetSurfaceRenderStatus( &ent->ghoul2[ent->playerModel], "head_light_blaster_cann" ) )
					{//don't have it!
						return;
					}
					bolt = ent->genericBolt2;
				}
				else
				{
					if ( gi.G2API_GetSurfaceRenderStatus( &ent->ghoul2[ent->playerModel], "head_concussion_charger" ) )
					{//don't have it!
						return;
					}
					bolt = ent->genericBolt1;
				}
			}

			vec3_t yawOnlyAngles = {0, ent->currentAngles[YAW], 0};
			if ( ent->currentAngles[YAW] != ent->client->ps.legsYaw )
			{
				yawOnlyAngles[YAW] = ent->client->ps.legsYaw;
			}
			gi.G2API_GetBoltMatrix( ent->ghoul2, ent->playerModel, bolt, &boltMatrix, yawOnlyAngles, ent->currentOrigin, (cg.time?cg.time:level.time), NULL, ent->s.modelScale );

			// work the matrix axis stuff into the original axis and origins used.
			gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->client->renderInfo.muzzlePoint );
			gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, ent->client->renderInfo.muzzleDir );
			ent->client->renderInfo.mPCalcTime = level.time;

			AngleVectors( ent->client->ps.viewangles, wpFwd, wpVright, wpUp );
			//CalcMuzzlePoint( ent, wpFwd, vright, wpUp, wpMuzzle, 0 );
		}
		else if ( !ent->enemy )
		{//an NPC with no enemy to auto-aim at
			VectorCopy( ent->client->renderInfo.muzzleDir, wpFwd );
		}
		else
		{//NPC, auto-aim at enemy
			CalcEntitySpot( ent->enemy, SPOT_HEAD, enemy_org1 );

			VectorSubtract (enemy_org1, muzzle1, delta1);

			vectoangles ( delta1, angleToEnemy1 );
			AngleVectors (angleToEnemy1, wpFwd, wpVright, wpUp);
		}
	}
	else if ( ent->s.weapon == WP_BOT_LASER && ent->enemy )
	{
		vec3_t	delta1, enemy_org1, muzzle1;
		vec3_t	angleToEnemy1;

		CalcEntitySpot( ent->enemy, SPOT_HEAD, enemy_org1 );
		CalcEntitySpot( ent, SPOT_WEAPON, muzzle1 );

		VectorSubtract (enemy_org1, muzzle1, delta1);

		vectoangles ( delta1, angleToEnemy1 );
		AngleVectors (angleToEnemy1, wpFwd, wpVright, wpUp);
	}
	else
	{
		AngleVectors( ent->client->ps.viewangles, wpFwd, wpVright, wpUp );
	}

	ent->alt_fire = alt_fire;
	CalcMuzzlePoint ( ent, wpFwd, wpVright, wpUp, wpMuzzle , 0);

	// fire the specific weapon
	switch( ent->s.weapon )
	{
	// Player weapons
	//-----------------
	case WP_SABER:
		return;
		break;

	case WP_BRYAR_PISTOL:
		WP_FireBryarPistol( ent, alt_fire );
		break;

	case WP_BLASTER:
		WP_FireBlaster( ent, alt_fire );
		break;

	case WP_DISRUPTOR:
		alert = 50; // if you want it to alert enemies, remove this
		WP_FireDisruptor( ent, alt_fire );
		break;

	case WP_BOWCASTER:
		WP_FireBowcaster( ent, alt_fire );
		break;

	case WP_REPEATER:
		WP_FireRepeater( ent, alt_fire );
		break;

	case WP_DEMP2:
		WP_FireDEMP2( ent, alt_fire );
		break;

	case WP_FLECHETTE:
		WP_FireFlechette( ent, alt_fire );
		break;

	case WP_ROCKET_LAUNCHER:
		WP_FireRocket( ent, alt_fire );
		break;

	case WP_THERMAL:
		WP_FireThermalDetonator( ent, alt_fire );
		break;

	case WP_TRIP_MINE:
		alert = 0; // if you want it to alert enemies, remove this
		WP_PlaceLaserTrap( ent, alt_fire );
		break;

	case WP_DET_PACK:
		alert = 0; // if you want it to alert enemies, remove this
		WP_FireDetPack( ent, alt_fire );
		break;

	case WP_BOT_LASER:
		WP_BotLaser( ent );
		break;

	case WP_EMPLACED_GUN:
		// doesn't care about whether it's alt-fire or not.  We can do an alt-fire if needed
		WP_EmplacedFire( ent );
		break;

	case WP_MELEE:
		alert = 0; // if you want it to alert enemies, remove this
		WP_Melee( ent );
		break;

	case WP_ATST_MAIN:
		WP_ATSTMainFire( ent );
		break;

	case WP_ATST_SIDE:

		// TEMP
		if ( alt_fire )
		{
//			WP_FireRocket( ent, qfalse );
			WP_ATSTSideAltFire(ent);
		}
		else
		{
			if ( ent->s.number == 0 && ent->client->ps.vehicleModel )
			{
				WP_ATSTMainFire( ent );
			}
			else
			{
				WP_ATSTSideFire(ent);
			}
		}
		break;

	case WP_TIE_FIGHTER:
		// TEMP
		WP_EmplacedFire( ent );
		break;

	case WP_RAPID_FIRE_CONC:
		// TEMP
		if ( alt_fire )
		{
			WP_FireRepeater( ent, alt_fire );
		}
		else
		{
			WP_EmplacedFire( ent );
		}
		break;

	case WP_STUN_BATON:
		WP_FireStunBaton( ent, alt_fire );
		break;

	case WP_BLASTER_PISTOL: // enemy version
		WP_FireBryarPistol( ent, qfalse ); // never an alt-fire?
		break;

//	case WP_TRICORDER:
//		WP_TricorderScan( ent, alt_fire );
//		break;

	default:
		return;
		break;
	}

	if ( !ent->s.number )
	{
		if ( ent->s.weapon == WP_FLECHETTE || (ent->s.weapon == WP_BOWCASTER && !alt_fire) )
		{//these can fire multiple shots, count them individually within the firing functions
		}
		else if ( W_AccuracyLoggableWeapon( ent->s.weapon, alt_fire, MOD_UNKNOWN ) )
		{
			ent->client->sess.missionStats.shotsFired++;
		}
	}
	// We should probably just use this as a default behavior, in special cases, just set alert to false.
	if ( ent->s.number == 0 && alert > 0 )
	{
		AddSoundEvent( ent, wpMuzzle, alert, AEL_DISCOVERED );
		AddSightEvent( ent, wpMuzzle, alert*2, AEL_DISCOVERED, 20 );
	}
}
Beispiel #12
0
void drop_charge (gentity_t *self, vec3_t start, vec3_t dir) 
{
	gentity_t	*bolt;

	VectorNormalize (dir);

	bolt = G_Spawn();
	bolt->classname = "detpack";
	bolt->nextthink = level.time + FRAMETIME;
	bolt->think = G_RunObject;
	bolt->s.eType = ET_GENERAL;
	bolt->s.g2radius = 100;
	bolt->s.modelGhoul2 = 1;
	bolt->s.modelindex = G_ModelIndex("models/weapons2/detpack/det_pack_proj.glm");

	bolt->parent = self;
	bolt->r.ownerNum = self->s.number;
	bolt->damage = Detpack_Damage;
	bolt->splashDamage = Detpack_Damage;
	bolt->splashRadius = 200;
	bolt->methodOfDeath = MOD_DET_PACK_SPLASH;
	bolt->splashMethodOfDeath = MOD_DET_PACK_SPLASH;
	bolt->clipmask = MASK_SHOT;
	bolt->s.solid = 2;
	bolt->r.contents = MASK_SHOT;
	bolt->touch = charge_stick;

	bolt->physicsObject = qtrue;

	bolt->s.genericenemyindex = self->s.number+MAX_GENTITIES;
	//rww - so client prediction knows we own this and won't hit it

	VectorSet( bolt->r.mins, -2, -2, -2 );
	VectorSet( bolt->r.maxs, 2, 2, 2 );

	bolt->health = 1;
	bolt->takedamage = qtrue;
	bolt->pain = DetPackPain;
	bolt->die = DetPackDie;

	bolt->s.weapon = WP_DET_PACK;

	bolt->setTime = level.time;

	G_SetOrigin(bolt, start);
	bolt->s.pos.trType = TR_GRAVITY;
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale(dir, 300, bolt->s.pos.trDelta );
	bolt->s.pos.trTime = level.time;

	bolt->s.apos.trType = TR_GRAVITY;
	bolt->s.apos.trTime = level.time;
	bolt->s.apos.trBase[YAW] = rand()%360;
	bolt->s.apos.trBase[PITCH] = rand()%360;
	bolt->s.apos.trBase[ROLL] = rand()%360;

	if (rand()%10 < 5)
	{
		bolt->s.apos.trBase[YAW] = -bolt->s.apos.trBase[YAW];
	}

	vectoangles(dir, bolt->s.angles);
	VectorCopy(bolt->s.angles, bolt->s.apos.trBase);
	VectorSet(bolt->s.apos.trDelta, 300, 0, 0 );
	bolt->s.apos.trTime = level.time;

	trap_LinkEntity(bolt);

	//[CoOp]
	//make some sight/sound events
	AddSoundEvent( NULL, bolt->r.currentOrigin, 128, AEL_MINOR, qtrue, qfalse );
	AddSightEvent( NULL, bolt->r.currentOrigin, 128, AEL_SUSPICIOUS, 10 );
	//[/CoOp]
}