Пример #1
0
//----------------------------------------------------------
void fx_explosion_trail_link( gentity_t *ent )
{
    vec3_t		dir;
    gentity_t	*target = NULL;

    // we ony activate when used
    ent->e_UseFunc = useF_fx_explosion_trail_use;

    if ( ent->target )
    {
        // try to use the target to override the orientation
        target = G_Find( target, FOFS(targetname), ent->target );

        if ( !target )
        {
            gi.Printf( S_COLOR_RED"ERROR: fx_explosion_trail %s could not find target %s\n", ent->targetname, ent->target );
            G_FreeEntity( ent );
            return;
        }

        // Our target is valid so lets use that
        VectorSubtract( target->s.origin, ent->s.origin, dir );
        VectorNormalize( dir );
    }
    else
    {
        // we are assuming that we have angles, but there are no checks to verify this
        AngleVectors( ent->s.angles, dir, NULL, NULL );
    }

    // NOTE: this really isn't an angle, but rather an orientation vector
    G_SetAngles( ent, dir );
}
Пример #2
0
//-----------------------------------------------------
void SP_misc_turret( gentity_t *base )
//-----------------------------------------------------
{
	base->s.modelindex2 = G_ModelIndex( "models/map_objects/hoth/turret_bottom.md3" );
	base->s.modelindex = G_ModelIndex( "models/map_objects/hoth/turret_base.md3" );
	//base->playerModel = gi.G2API_InitGhoul2Model( base->ghoul2, "models/map_objects/imp_mine/turret_canon.glm", base->s.modelindex );
	//base->s.radius = 80.0f;

	//gi.G2API_SetBoneAngles( &base->ghoul2[base->playerModel], "Bone_body", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL ); 
	//base->torsoBolt = gi.G2API_AddBolt( &base->ghoul2[base->playerModel], "*flash03" );

	G_SetAngles( base, base->s.angles );
	G_SetOrigin( base, base->s.origin );

	base->r.contents = CONTENTS_BODY;

	VectorSet( base->r.maxs, 32.0f, 32.0f, 128.0f );
	VectorSet( base->r.mins, -32.0f, -32.0f, 0.0f );

	base->use = turret_base_use;
	base->think = turret_base_think;
	// don't start working right away
	base->nextthink = level.time + FRAMETIME * 5;

	trap_LinkEntity( base );

	if ( !turret_base_spawn_top( base ) )
	{
		G_FreeEntity( base );
	}
}
Пример #3
0
//[/CoOp]
//-----------------------------------------------------
void SP_misc_turret( gentity_t *base )
//-----------------------------------------------------
{
	char* s;

	//[CoOp]
	//wahoo turret - actually a spawn flag of 5 spawns a huge space turbo turret
	//and others spawn the normal g2 turret so fixed this if statement.  In sp, spawnflags
	//are checked for the value of 5 to spawn the turbo turrets, but in mp it checks for
	//a spawn flag of 8 in sp_misc_turretg2, so setting to 8 before spawning.  No hoth style
	//turrets can be found in sp so far.
	if( g_gametype.integer == GT_SINGLE_PLAYER )
	{//SP uses this same map entity name for the ceiling turrets.  Override to use them
		//in CoOp.
		if( base->spawnflags & 5 )
			base->spawnflags |= 8;
		
		SP_misc_turretG2( base );
			return;
	}
	//[/CoOp]

	base->s.modelindex2 = G_ModelIndex( "models/map_objects/hoth/turret_bottom.md3" );
	base->s.modelindex = G_ModelIndex( "models/map_objects/hoth/turret_base.md3" );
	//base->playerModel = gi.G2API_InitGhoul2Model( base->ghoul2, "models/map_objects/imp_mine/turret_canon.glm", base->s.modelindex );
	//base->s.radius = 80.0f;

	//gi.G2API_SetBoneAngles( &base->ghoul2[base->playerModel], "Bone_body", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL ); 
	//base->torsoBolt = gi.G2API_AddBolt( &base->ghoul2[base->playerModel], "*flash03" );

	G_SpawnString( "icon", "", &s );
	if (s && s[0])
	{ 
		// We have an icon, so index it now.  We are reusing the genericenemyindex
		// variable rather than adding a new one to the entity state.
		base->s.genericenemyindex = G_IconIndex(s);
	}

	G_SetAngles( base, base->s.angles );
	G_SetOrigin( base, base->s.origin );

	base->r.contents = CONTENTS_BODY;

	VectorSet( base->r.maxs, 32.0f, 32.0f, 128.0f );
	VectorSet( base->r.mins, -32.0f, -32.0f, 0.0f );

	base->use = turret_base_use;
	base->think = turret_base_think;
	// don't start working right away
	base->nextthink = level.time + FRAMETIME * 5;

	trap_LinkEntity( base );

	if ( !turret_base_spawn_top( base ) )
	{
		G_FreeEntity( base );
	}
}
Пример #4
0
//----------------------------------------------------------
void fx_explosion_trail_use( gentity_t *self, gentity_t *other, gentity_t *activator )
{
	gentity_t *missile = G_Spawn();

	// We aren't a missile in the truest sense, rather we just move through the world and spawn effects
	if ( missile )
	{
		missile->classname = "fx_exp_trail";

		missile->nextthink = level.time + 50;
		missile->e_ThinkFunc = thinkF_fx_explosion_trail_think;

		missile->s.eType = ET_MOVER;

		missile->owner = self;

		missile->s.modelindex = self->s.modelindex2;

		missile->s.pos.trTime = level.time;
		G_SetOrigin( missile, self->currentOrigin );
		if ( self->spawnflags & 1 ) // gravity
		{
			missile->s.pos.trType = TR_GRAVITY;
		}
		else
		{
			missile->s.pos.trType = TR_LINEAR;
		}

		missile->spawnflags = self->spawnflags;

		G_SetAngles( missile, self->currentAngles );
		VectorScale( self->currentAngles, self->speed, missile->s.pos.trDelta );
		missile->s.pos.trTime = level.time;
		missile->radius = self->radius;
		missile->damage = self->damage;
		missile->splashDamage = self->splashDamage;
		missile->splashRadius = self->splashRadius;
		missile->fxID = self->fxID;
		missile->fullName = self->fullName;

		missile->clipmask = MASK_SHOT;

		gi.linkentity( missile );

		if ( VALIDSTRING( self->soundSet ) == true )
		{
			G_AddEvent( self, EV_BMODEL_SOUND, CAS_GetBModelSound( self->soundSet, BMS_START ));
			missile->s.loopSound = CAS_GetBModelSound( self->soundSet, BMS_MID );
			missile->soundSet = self->soundSet;

			if ( missile->s.loopSound < 0 )
			{
				missile->s.loopSound = 0;
			}
		}
	}
}
Пример #5
0
void Rancor_DropVictim( gentity_t *self )
{
	//FIXME: if Rancor dies, it should drop its victim.
	//FIXME: if Rancor is removed, it must remove its victim.
	if ( self->activator )
	{
		if ( self->activator->client )
		{
			self->activator->client->ps.eFlags2 &= ~EF2_HELD_BY_MONSTER;
			self->activator->client->ps.hasLookTarget = qfalse;
			self->activator->client->ps.lookTarget = ENTITYNUM_NONE;
			self->activator->client->ps.viewangles[ROLL] = 0;
			SetClientViewAngle( self->activator, self->activator->client->ps.viewangles );
			self->activator->r.currentAngles[PITCH] = self->activator->r.currentAngles[ROLL] = 0;
			G_SetAngles( self->activator, self->activator->r.currentAngles );
		}
		if ( self->activator->health <= 0 )
		{
			//if ( self->activator->s.number )
			{//never free player
				if ( self->count == 1 )
				{//in my hand, just drop them
					if ( self->activator->client )
					{
						self->activator->client->ps.legsTimer = self->activator->client->ps.torsoTimer = 0;
						//FIXME: ragdoll?
					}
				}
				else
				{
					if ( self->activator->client )
					{
						self->activator->client->ps.eFlags |= EF_NODRAW;//so his corpse doesn't drop out of me...
					}
					//G_FreeEntity( self->activator );
				}
			}
		}
		else
		{
			if ( self->activator->NPC )
			{//start thinking again
				self->activator->NPC->nextBStateThink = level.time;
			}
			//clear their anim and let them fall
			self->activator->client->ps.legsTimer = self->activator->client->ps.torsoTimer = 0;
		}
		if ( self->enemy == self->activator )
		{
			self->enemy = NULL;
		}
		self->activator = NULL;
	}
	self->count = 0;//drop him
}
Пример #6
0
//----------------------------------------------------------
void fx_runner_link( gentity_t *ent )
{
	vec3_t	dir;

	if ( ent->roffname && ent->roffname[0] )
	{
		// try to use the target to override the orientation
		gentity_t	*target = NULL;

		target = G_Find( target, FOFS(targetname), ent->roffname );

		if ( !target )
		{
			// Bah, no good, dump a warning, but continue on and use the UP vector
			Com_Printf( "fx_runner_link: target specified but not found: %s\n", ent->roffname );
			Com_Printf( "  -assuming UP orientation.\n" );
		}
		else
		{
			// Our target is valid so let's override the default UP vector
			VectorSubtract( target->s.origin, ent->s.origin, dir );
			VectorNormalize( dir );
			vectoangles( dir, ent->s.angles );
		}
	}

	// don't really do anything with this right now other than do a check to warn the designers if the target is bogus
	if ( ent->target )
	{
		gentity_t	*target = NULL;

		target = G_Find( target, FOFS(targetname), ent->target );

		if ( !target )
		{
			// Target is bogus, but we can still continue
			Com_Printf( "fx_runner_link: target was specified but is not valid: %s\n", ent->target );
		}
	}

	G_SetAngles( ent, ent->s.angles );

	if ( ent->spawnflags & 1 || ent->spawnflags & 2 ) // STARTOFF || ONESHOT
	{
		// We won't even consider thinking until we are used
		ent->nextthink = -1;
	}
	else
	{
		// Let's get to work right now!
		ent->think = fx_runner_think;
		ent->nextthink = level.time + 100; // wait a small bit, then start working
	}
}
Пример #7
0
//---------------------------------------------
void SP_misc_model_ammo_rack( gentity_t *ent )
{
// If BLASTER is checked...or nothing is checked then we'll do blasters
	if (( ent->spawnflags & RACK_BLASTER ) || !(ent->spawnflags & ( RACK_BLASTER | RACK_METAL_BOLTS | RACK_ROCKETS | RACK_PWR_CELL )))
	{
		if ( ent->spawnflags & RACK_WEAPONS )
		{
			RegisterItem( FindItemForWeapon( WP_BLASTER ));
		}
		RegisterItem( FindItemForAmmo( AMMO_BLASTER ));
	}

	if (( ent->spawnflags & RACK_METAL_BOLTS ))
	{
		if ( ent->spawnflags & RACK_WEAPONS )
		{
			RegisterItem( FindItemForWeapon( WP_REPEATER ));
		}
		RegisterItem( FindItemForAmmo( AMMO_METAL_BOLTS ));
	}

	if (( ent->spawnflags & RACK_ROCKETS ))
	{
		if ( ent->spawnflags & RACK_WEAPONS )
		{
			RegisterItem( FindItemForWeapon( WP_ROCKET_LAUNCHER ));
		}
		RegisterItem( FindItemForAmmo( AMMO_ROCKETS ));
	}

	if (( ent->spawnflags & RACK_PWR_CELL ))
	{
		RegisterItem( FindItemForAmmo( AMMO_POWERCELL ));
	}

	if (( ent->spawnflags & RACK_HEALTH ))
	{
		RegisterItem( FindItem( "item_medpak_instant" ));
	}

	ent->e_ThinkFunc = thinkF_spawn_rack_goods;
	ent->nextthink = level.time + 100;

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );

	ent->contents = CONTENTS_SHOTCLIP|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP;//CONTENTS_SOLID;//so use traces can go through them

	gi.linkentity( ent );
}
Пример #8
0
//===========================================================================
// Routine      : AOTCTC_Create_Holocron
// Description  : Put a single holocron on the map...
void AOTCTC_Create_Holocron( int type, vec3_t point )
{// Put a single holocron on the map...
	gentity_t *holocron = G_Spawn();
	vec3_t angles;

	VectorSet(angles, 0, 0, 0);
	G_SetOrigin( holocron, point );
	G_SetAngles( holocron, angles );
	holocron->count = type;
	holocron->classname = "misc_holocron";
	VectorCopy(point, holocron->s.pos.trBase);
	VectorCopy(point, holocron->s.origin);
	trap_LinkEntity(holocron);
	SP_misc_holocron( holocron );
}
Пример #9
0
//-----------------------------------------------------
void SP_misc_turret( gentity_t *base )
//-----------------------------------------------------
{
	char* s;

	base->s.modelindex2 = G_ModelIndex( "models/map_objects/hoth/turret_bottom.md3" );
	base->s.modelindex = G_ModelIndex( "models/map_objects/hoth/turret_base.md3" );
	//base->playerModel = trap->G2API_InitGhoul2Model( base->ghoul2, "models/map_objects/imp_mine/turret_canon.glm", base->s.modelindex );
	//base->s.radius = 80.0f;

	//trap->G2API_SetBoneAngles( &base->ghoul2[base->playerModel], "Bone_body", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL ); 
	//base->torsoBolt = trap->G2API_AddBolt( &base->ghoul2[base->playerModel], "*flash03" );

	G_SpawnString( "icon", "", &s );
	if (s && s[0])
	{ 
		// We have an icon, so index it now.  We are reusing the genericenemyindex
		// variable rather than adding a new one to the entity state.
		base->s.genericenemyindex = G_IconIndex(s);
	}

	G_SetAngles( base, base->s.angles );
	G_SetOrigin( base, base->s.origin );

	base->r.contents = CONTENTS_BODY;

	VectorSet( base->r.maxs, 32.0f, 32.0f, 128.0f );
	VectorSet( base->r.mins, -32.0f, -32.0f, 0.0f );

	base->use = turret_base_use;
	base->think = turret_base_think;
	// don't start working right away
	base->nextthink = level.time + FRAMETIME * 5;

	trap->LinkEntity( (sharedEntity_t *)base );

	if ( !turret_base_spawn_top( base ) )
	{
		G_FreeEntity( base );
	}
}
Пример #10
0
//-----------------------------------------------------------------------------
void WP_Stick( gentity_t *missile, trace_t *trace, float fudge_distance )
//-----------------------------------------------------------------------------
{
	vec3_t org, ang;

	// not moving or rotating
	missile->s.pos.trType = TR_STATIONARY;
	VectorClear( missile->s.pos.trDelta );
	VectorClear( missile->s.apos.trDelta );

	// so we don't stick into the wall
	VectorMA( trace->endpos, fudge_distance, trace->plane.normal, org );
	G_SetOrigin( missile, org );

	vectoangles( trace->plane.normal, ang );
	G_SetAngles( missile, ang );

	// I guess explode death wants me as the normal?
//	VectorCopy( trace->plane.normal, missile->pos1 );
	gi.linkentity( missile );
}
Пример #11
0
/*
================
Cmd_UseSeeker_f
================
*/
void Cmd_UseSeeker_f( gentity_t *ent )
{
	if ( ent->health < 1 || in_camera )
	{
		return;
	}

	// don't use them if we don't have any...also don't use them if one is already going
	if ( ent->client && ent->client->ps.inventory[INV_SEEKER] > 0 && level.time > ent->client->ps.powerups[PW_SEEKER] )
	{
		gentity_t	*tent = G_Spawn();
	
		if ( tent )
		{
			vec3_t	fwd, right, spot;

			AngleVectors( ent->client->ps.viewangles, fwd, right, NULL );

			VectorCopy( ent->currentOrigin, spot ); // does nothing really, just initialize the goods...

			if ( PickSeekerSpawnPoint( ent->currentOrigin, fwd, right, ent->s.number, spot ))
			{
				VectorCopy( spot, tent->s.origin );
				G_SetOrigin( tent, spot );
				G_SetAngles( tent, ent->currentAngles );

extern void SP_NPC_Droid_Seeker( gentity_t *ent );

				SP_NPC_Droid_Seeker( tent );
				G_Sound( tent, G_SoundIndex( "sound/chars/seeker/misc/hiss" ));

				// make sure that we even have some
				ent->client->ps.inventory[INV_SEEKER]--;
				ent->client->ps.powerups[PW_SEEKER] = level.time + 1000;// can only drop one every second..maybe this is annoying?

			}
		}
	}
}
Пример #12
0
gentity_t *G_DropSaberItem( const char *saberType, saber_colors_t saberColor, vec3_t saberPos, vec3_t saberVel, vec3_t saberAngles, gentity_t *copySaber )
{//turn it into a pick-uppable item!
	gentity_t *newItem = NULL;
	if ( saberType
		&& saberType[0] )
	{//have a valid string to use for saberType
		newItem = G_Spawn();
		if ( newItem )
		{
			newItem->classname = G_NewString( "weapon_saber" );
			VectorCopy( saberPos, newItem->s.origin );
			G_SetOrigin( newItem, newItem->s.origin );
			VectorCopy( saberAngles, newItem->s.angles );
			G_SetAngles( newItem, newItem->s.angles );
			newItem->spawnflags = 128;/*ITMSF_USEPICKUP*/
			newItem->spawnflags |= 64;/*ITMSF_NOGLOW*/
			newItem->NPC_type = G_NewString( saberType );//saberType
			//FIXME: transfer per-blade color somehow?
			newItem->NPC_targetname = (char *)saberColorStringForColor[saberColor];
			newItem->count = 1;
			newItem->flags = FL_DROPPED_ITEM;
			G_SpawnItem( newItem, FindItemForWeapon( WP_SABER ) );
			newItem->s.pos.trType = TR_GRAVITY;
			newItem->s.pos.trTime = level.time;
			VectorCopy( saberVel, newItem->s.pos.trDelta );
			//newItem->s.eFlags |= EF_BOUNCE_HALF;
			//copy some values from another saber, if provided:
			G_CopySaberItemValues( copySaber, newItem );
			//don't *think* about calling FinishSpawningItem, just do it!
			newItem->e_ThinkFunc = thinkF_NULL;
			newItem->nextthink = -1;
			FinishSpawningItem( newItem );
			newItem->delay = level.time + 500;//so you can't pick it back up right away
		}
	}
	return newItem;
}
Пример #13
0
//-----------------------------------------------------
void SP_misc_turret( gentity_t *base )
//-----------------------------------------------------
{
	char* s;

	base->s.modelindex2 = G_ModelIndex( "models/map_objects/hoth/turret_bottom.md3" );
	base->s.modelindex = G_ModelIndex( "models/map_objects/hoth/turret_base.md3" );

	G_SpawnString( "icon", "", &s );
	if (s && s[0])
	{ 
		// We have an icon, so index it now.  We are reusing the genericenemyindex
		// variable rather than adding a new one to the entity state.
		base->s.genericenemyindex = G_IconIndex(s);
	}

	G_SetAngles( base, base->s.angles );
	G_SetOrigin( base, base->s.origin );

	base->r.contents = CONTENTS_BODY;

	VectorSet( base->r.maxs, 32.0f, 32.0f, 128.0f );
	VectorSet( base->r.mins, -32.0f, -32.0f, 0.0f );

	base->use = turret_base_use;
	base->think = turret_base_think;
	// don't start working right away
	base->nextthink = level.time + FRAMETIME * 5;

	trap_LinkEntity( base );

	if ( !turret_base_spawn_top( base ) )
	{
		G_FreeEntity( base );
	}
}
Пример #14
0
//---------------------------------------------
void SP_misc_model_gun_rack( gentity_t *ent )
{
	gitem_t		*blaster = NULL, *repeater = NULL, *rocket = NULL;
	int			ct = 0;
	float		ofz[3];
	gitem_t		*itemList[3];

	// If BLASTER is checked...or nothing is checked then we'll do blasters
	if (( ent->spawnflags & RACK_BLASTER ) || !(ent->spawnflags & ( RACK_BLASTER | RACK_REPEATER | RACK_ROCKET )))
	{
		blaster	= FindItemForWeapon( WP_BLASTER );
	}

	if (( ent->spawnflags & RACK_REPEATER ))
	{
		repeater = FindItemForWeapon( WP_REPEATER );
	}

	if (( ent->spawnflags & RACK_ROCKET ))
	{
		rocket = FindItemForWeapon( WP_ROCKET_LAUNCHER );
	}

	//---------weapon types
	if ( blaster )
	{
		ofz[ct] = 23.0f;
		itemList[ct++] = blaster;
	}

	if ( repeater )
	{
		ofz[ct] = 24.5f;
		itemList[ct++] = repeater;
	}

	if ( rocket )
	{
		ofz[ct] = 25.5f;
		itemList[ct++] = rocket;
	}

	if ( ct ) //..should always have at least one item on their, but just being safe
	{
		for ( ; ct < 3 ; ct++ )
		{
			ofz[ct] = ofz[0];
			itemList[ct] = itemList[0]; // first weapon ALWAYS propagates to fill up the shelf
		}
	}

	// now actually add the items to the shelf...validate that we have a list to add
	if ( ct )
	{
		for ( int i = 0; i < ct; i++ )
		{
			GunRackAddItem( itemList[i], ent->s.origin, ent->s.angles, crandom() * 2, ( i - 1 ) * 9 + crandom() * 2, ofz[i] );
		}
	}

	ent->s.modelindex = G_ModelIndex( "models/map_objects/kejim/weaponsrack.md3" );

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );

	ent->contents = CONTENTS_SOLID;

	gi.linkentity( ent );
}
Пример #15
0
void GunRackAddItem( gitem_t *gun, vec3_t org, vec3_t angs, float ffwd, float fright, float fup )
{
	vec3_t		fwd, right;
	gentity_t	*it_ent = G_Spawn();
	qboolean	rotate = qtrue;

	AngleVectors( angs, fwd, right, NULL );

	if ( it_ent && gun )
	{
		// FIXME: scaling the ammo will probably need to be tweaked to a reasonable amount...adjust as needed
		// Set base ammo per type
		if ( gun->giType == IT_WEAPON )
		{
			it_ent->spawnflags |= 16;// VERTICAL

			switch( gun->giTag )
			{
			case WP_BLASTER:
				it_ent->count = 15;
				break;
			case WP_REPEATER:
				it_ent->count = 100;
				break;
			case WP_ROCKET_LAUNCHER:
				it_ent->count = 4;
				break;
			}
		}
		else
		{
			rotate = qfalse;

			// must deliberately make it small, or else the objects will spawn inside of each other.
			VectorSet( it_ent->maxs, 6.75f, 6.75f, 6.75f );
			VectorScale( it_ent->maxs, -1, it_ent->mins );
		}

		it_ent->spawnflags |= 1;// ITMSF_SUSPEND
		it_ent->classname = G_NewString(gun->classname);	//copy it so it can be freed safely
		G_SpawnItem( it_ent, gun );

		// FinishSpawningItem handles everything, so clear the thinkFunc that was set in G_SpawnItem
		FinishSpawningItem( it_ent );

		if ( gun->giType == IT_AMMO )
		{
			if ( gun->giTag == AMMO_BLASTER ) // I guess this just has to use different logic??
			{
				if ( g_spskill->integer >= 2 )
				{
					it_ent->count += 10; // give more on higher difficulty because there will be more/harder enemies?
				}
			}
			else
			{
				// scale ammo based on skill
				switch ( g_spskill->integer )
				{
				case 0: // do default
					break;
				case 1:
					it_ent->count *= 0.75f;
					break;
				case 2:
					it_ent->count *= 0.5f;
					break;
				}
			}
		}

		it_ent->nextthink = 0;

		VectorCopy( org, it_ent->s.origin );
		VectorMA( it_ent->s.origin, fright, right, it_ent->s.origin );
		VectorMA( it_ent->s.origin, ffwd, fwd, it_ent->s.origin );
		it_ent->s.origin[2] += fup;

		VectorCopy( angs, it_ent->s.angles );

		// by doing this, we can force the amount of ammo we desire onto the weapon for when it gets picked-up
		it_ent->flags |= ( FL_DROPPED_ITEM | FL_FORCE_PULLABLE_ONLY );
		it_ent->physicsBounce = 0.1f;

		for ( int t = 0; t < 3; t++ )
		{
			if ( rotate )
			{
				if ( t == YAW )
				{
					it_ent->s.angles[t] = AngleNormalize180( it_ent->s.angles[t] + 180 + crandom() * 14 );
				}
				else
				{
					it_ent->s.angles[t] = AngleNormalize180( it_ent->s.angles[t] + crandom() * 4 );
				}
			}
			else
			{
				if ( t == YAW )
				{
					it_ent->s.angles[t] = AngleNormalize180( it_ent->s.angles[t] + 90 + crandom() * 4 );
				}
			}
		}

		G_SetAngles( it_ent, it_ent->s.angles );
		G_SetOrigin( it_ent, it_ent->s.origin );
		gi.linkentity( it_ent );
	}
}
Пример #16
0
/*QUAKED misc_model_breakable (1 0 0) (-16 -16 -16) (16 16 16) SOLID AUTOANIMATE DEADSOLID NO_DMODEL NO_SMOKE USE_MODEL USE_NOT_BREAK PLAYER_USE NO_EXPLOSION START_OFF
SOLID - Movement is blocked by it, if not set, can still be broken by explosions and shots if it has health
AUTOANIMATE - Will cycle it's anim
DEADSOLID - Stay solid even when destroyed (in case damage model is rather large).
NO_DMODEL - Makes it NOT display a damage model when destroyed, even if one exists
USE_MODEL - When used, will toggle to it's usemodel (model + "_u1.md3")... this obviously does nothing if USE_NOT_BREAK is not checked
USE_NOT_BREAK - Using it, doesn't make it break, still can be destroyed by damage
PLAYER_USE - Player can use it with the use button
NO_EXPLOSION - By default, will explode when it dies...this is your override.
START_OFF - Will start off and will not appear until used.

"model"		arbitrary .md3 file to display
"modelscale"	"x" uniform scale
"modelscale_vec" "x y z" scale model in each axis - height, width and length - bbox will scale with it
"health"	how much health to have - default is zero (not breakable)  If you don't set the SOLID flag, but give it health, it can be shot but will not block NPCs or players from moving
"targetname" when used, dies and displays damagemodel (model + "_d1.md3"), if any (if not, removes itself)
"target" What to use when it dies
"target2" What to use when it's repaired
"target3" What to use when it's used while it's broken
"paintarget" target to fire when hit (but not destroyed)
"count"  the amount of armor/health/ammo given (default 50)
"radius"  Chunk code tries to pick a good volume of chunks, but you can alter this to scale the number of spawned chunks. (default 1)  (.5) is half as many chunks, (2) is twice as many chunks
"NPC_targetname" - Only the NPC with this name can damage this
"forcevisible" - When you turn on force sight (any level), you can see these draw through the entire level...
"redCrosshair" - crosshair turns red when you look at this

"gravity"	if set to 1, this will be affected by gravity
"throwtarget" if set (along with gravity), this thing, when used, will throw itself at the entity whose targetname matches this string
"mass"		if gravity is on, this determines how much damage this thing does when it hits someone.  Default is the size of the object from one corner to the other, that works very well.  Only override if this is an object whose mass should be very high or low for it's size (density)

Damage: default is none
"splashDamage" - damage to do (will make it explode on death)
"splashRadius" - radius for above damage

"team" - This cannot take damage from members of this team:
	"player"
	"neutral"
	"enemy"

"material" - default is "8 - MAT_NONE" - choose from this list:
0 = MAT_METAL		(grey metal)
1 = MAT_GLASS		
2 = MAT_ELECTRICAL	(sparks only)
3 = MAT_ELEC_METAL	(METAL chunks and sparks)
4 =	MAT_DRK_STONE	(brown stone chunks)
5 =	MAT_LT_STONE	(tan stone chunks)
6 =	MAT_GLASS_METAL (glass and METAL chunks)
7 = MAT_METAL2		(blue/grey metal)
8 = MAT_NONE		(no chunks-DEFAULT)
9 = MAT_GREY_STONE	(grey colored stone)
10 = MAT_METAL3		(METAL and METAL2 chunk combo)
11 = MAT_CRATE1		(yellow multi-colored crate chunks)
12 = MAT_GRATE1		(grate chunks--looks horrible right now)
13 = MAT_ROPE		(for yavin_trial, no chunks, just wispy bits )
14 = MAT_CRATE2		(red multi-colored crate chunks)
15 = MAT_WHITE_METAL (white angular chunks for Stu, NS_hideout )
*/
void SP_misc_model_breakable( gentity_t *ent ) 
{
	char	damageModel[MAX_QPATH];
	char	chunkModel[MAX_QPATH];
	char	useModel[MAX_QPATH];
	int		len;
	
	// Chris F. requested default for misc_model_breakable to be NONE...so don't arbitrarily change this.
	G_SpawnInt( "material", "8", (int*)&ent->material );
	G_SpawnFloat( "radius", "1", &ent->radius ); // used to scale chunk code if desired by a designer
	qboolean bHasScale = G_SpawnVector("modelscale_vec", "0 0 0", ent->s.modelScale);
	if (!bHasScale)
	{
		float temp;
		G_SpawnFloat( "modelscale", "0", &temp);
		if (temp != 0.0f)
		{
			ent->s.modelScale[ 0 ] = ent->s.modelScale[ 1 ] = ent->s.modelScale[ 2 ] = temp;
			bHasScale = qtrue;
		}
	}

	CacheChunkEffects( ent->material );
	misc_model_breakable_init( ent );

	len = strlen( ent->model ) - 4;
	assert(ent->model[len]=='.');//we're expecting ".md3"
	strncpy( damageModel, ent->model, sizeof(damageModel) );
	damageModel[len] = 0;	//chop extension
	strncpy( chunkModel, damageModel, sizeof(chunkModel));
	strncpy( useModel, damageModel, sizeof(useModel));
	
	if (ent->takedamage) {
		//Dead/damaged model
		if( !(ent->spawnflags & 8) ) {	//no dmodel
			strcat( damageModel, "_d1.md3" );
			ent->s.modelindex2 = G_ModelIndex( damageModel );
		}
		
		//Chunk model
		strcat( chunkModel, "_c1.md3" );
		ent->s.modelindex3 = G_ModelIndex( chunkModel );
	}

	//Use model
	if( ent->spawnflags & 32 ) {	//has umodel
		strcat( useModel, "_u1.md3" );
		ent->sound1to2 = G_ModelIndex( useModel );
	}
	if ( !ent->mins[0] && !ent->mins[1] && !ent->mins[2] )
	{
		VectorSet (ent->mins, -16, -16, -16);
	}
	if ( !ent->maxs[0] && !ent->maxs[1] && !ent->maxs[2] )
	{
		VectorSet (ent->maxs, 16, 16, 16);
	}

	// Scale up the tie-bomber bbox a little.
	if ( ent->model && Q_stricmp( "models/map_objects/ships/tie_bomber.md3", ent->model ) == 0 )
	{
		VectorSet (ent->mins, -80, -80, -80);
		VectorSet (ent->maxs, 80, 80, 80); 

		//ent->s.modelScale[ 0 ] = ent->s.modelScale[ 1 ] = ent->s.modelScale[ 2 ] *= 2.0f;
		//bHasScale = qtrue;
	}

	if (bHasScale)
	{
		//scale the x axis of the bbox up.
		ent->maxs[0] *= ent->s.modelScale[0];//*scaleFactor;
		ent->mins[0] *= ent->s.modelScale[0];//*scaleFactor;
		
		//scale the y axis of the bbox up.
		ent->maxs[1] *= ent->s.modelScale[1];//*scaleFactor;
		ent->mins[1] *= ent->s.modelScale[1];//*scaleFactor;
		
		//scale the z axis of the bbox up and adjust origin accordingly
		ent->maxs[2] *= ent->s.modelScale[2];
		float oldMins2 = ent->mins[2];
		ent->mins[2] *= ent->s.modelScale[2];
		ent->s.origin[2] += (oldMins2-ent->mins[2]);
	}

	if ( ent->spawnflags & 2 )
	{
		ent->s.eFlags |= EF_ANIM_ALLFAST;
	}

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );
	gi.linkentity (ent);

	if ( ent->spawnflags & 128 )
	{//Can be used by the player's BUTTON_USE
		ent->svFlags |= SVF_PLAYER_USABLE;
	}

	if ( ent->team && ent->team[0] )
	{
		ent->noDamageTeam = (team_t)GetIDForString( TeamTable, ent->team );
		if ( ent->noDamageTeam == TEAM_FREE )
		{
			G_Error("team name %s not recognized\n", ent->team);
		}
	}
	
	ent->team = NULL;

	//HACK
	if ( ent->model && Q_stricmp( "models/map_objects/ships/x_wing_nogear.md3", ent->model ) == 0 )
	{
		if( ent->splashDamage > 0 && ent->splashRadius > 0 )
		{
			ent->s.loopSound = G_SoundIndex( "sound/vehicles/x-wing/loop.wav" );
			ent->s.eFlags |= EF_LESS_ATTEN;
		}
	}
	else if ( ent->model && Q_stricmp( "models/map_objects/ships/tie_fighter.md3", ent->model ) == 0 )
	{//run a think
		G_EffectIndex( "explosions/fighter_explosion2" );
		G_SoundIndex( "sound/weapons/tie_fighter/tiepass1.wav" );
/*		G_SoundIndex( "sound/weapons/tie_fighter/tiepass2.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tiepass3.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tiepass4.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tiepass5.wav" );*/
		G_SoundIndex( "sound/weapons/tie_fighter/tie_fire.wav" );
/*		G_SoundIndex( "sound/weapons/tie_fighter/tie_fire2.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tie_fire3.wav" );*/
		G_SoundIndex( "sound/weapons/tie_fighter/TIEexplode.wav" );
		RegisterItem( FindItemForWeapon( WP_TIE_FIGHTER ));

		ent->s.eFlags |= EF_LESS_ATTEN;

		if( ent->splashDamage > 0 && ent->splashRadius > 0 )
		{
			ent->s.loopSound = G_SoundIndex( "sound/vehicles/tie-bomber/loop.wav" );
			//ent->e_ThinkFunc = thinkF_TieFighterThink;
			//ent->e_UseFunc = thinkF_TieFighterThink;
			//ent->nextthink = level.time + FRAMETIME;
			ent->e_UseFunc = useF_TieFighterUse;

			// Yeah, I could have just made this value changable from the editor, but I
			// need it immediately!
			float		light;
			vec3_t		color;
			qboolean	lightSet, colorSet;

			// if the "color" or "light" keys are set, setup constantLight
			lightSet = qtrue;//G_SpawnFloat( "light", "100", &light );
			light = 255;
			//colorSet = "1 1 1"//G_SpawnVector( "color", "1 1 1", color );
			colorSet = qtrue;
			color[0] = 1;	color[1] = 1;	color[2] = 1;
			if ( lightSet || colorSet ) 
			{
				int		r, g, b, i;

				r = color[0] * 255;
				if ( r > 255 ) {
					r = 255;
				}
				g = color[1] * 255;
				if ( g > 255 ) {
					g = 255;
				}
				b = color[2] * 255;
				if ( b > 255 ) {
					b = 255;
				}
				i = light / 4;
				if ( i > 255 ) {
					i = 255;
				}
				ent->s.constantLight = r | ( g << 8 ) | ( b << 16 ) | ( i << 24 );
			}
		}
	}
	else if ( ent->model && Q_stricmp( "models/map_objects/ships/tie_bomber.md3", ent->model ) == 0 )
	{
		G_EffectIndex( "ships/tiebomber_bomb_falling" );
		G_EffectIndex( "ships/tiebomber_explosion2" );
		G_EffectIndex( "explosions/fighter_explosion2" );
		G_SoundIndex( "sound/weapons/tie_fighter/TIEexplode.wav" );
		ent->e_ThinkFunc = thinkF_TieBomberThink;
		ent->nextthink = level.time + FRAMETIME;
		ent->attackDebounceTime = level.time + 1000;
		// We only take damage from a heavy weapon class missiles.
		ent->flags |= FL_DMG_BY_HEAVY_WEAP_ONLY;
		ent->s.loopSound = G_SoundIndex( "sound/vehicles/tie-bomber/loop.wav" );
		ent->s.eFlags |= EF_LESS_ATTEN;
	}

	float grav = 0;
	G_SpawnFloat( "gravity", "0", &grav );
	if ( grav )
	{//affected by gravity
		G_SetAngles( ent, ent->s.angles );
		G_SetOrigin( ent, ent->currentOrigin );
		G_SpawnString( "throwtarget", NULL, &ent->target4 ); // used to throw itself at something
		misc_model_breakable_gravity_init( ent, qtrue );
	}

	// Start off.
	if ( ent->spawnflags & 4096 )
	{
		ent->spawnContents = ent->contents;	// It Navs can temporarly turn it "on"
		ent->s.solid = 0;
		ent->contents = 0;
		ent->clipmask = 0;
		ent->svFlags |= SVF_NOCLIENT;
		ent->s.eFlags |= EF_NODRAW;
		ent->count = 0;
	}

	int forceVisible = 0;
	G_SpawnInt( "forcevisible", "0", &forceVisible );
	if ( forceVisible )
	{//can see these through walls with force sight, so must be broadcast
		//ent->svFlags |= SVF_BROADCAST;
		ent->s.eFlags |= EF_FORCE_VISIBLE;
	}

	int redCrosshair = 0;
	G_SpawnInt( "redCrosshair", "0", &redCrosshair );
	if ( redCrosshair )
	{//can see these through walls with force sight, so must be broadcast
		ent->flags |= FL_RED_CROSSHAIR;
	}
}
Пример #17
0
//-----------------------------------------------------
qboolean turret_base_spawn_top( gentity_t *base )
{
	vec3_t		org;
	int			t;

	gentity_t *top = G_Spawn();
	if ( !top )
	{
		return qfalse;
	}

	top->s.modelindex = G_ModelIndex( "models/map_objects/hoth/turret_top_new.md3" );
	top->s.modelindex2 = G_ModelIndex( "models/map_objects/hoth/turret_top.md3" );
	G_SetAngles( top, base->s.angles );
	VectorCopy( base->s.origin, org );
	org[2] += 128;
	G_SetOrigin( top, org );

	base->r.ownerNum = top->s.number;
	top->r.ownerNum = base->s.number;

	if ( base->team && base->team[0] && //g_gametype.integer == GT_SIEGE &&
		!base->teamnodmg)
	{
		base->teamnodmg = atoi(base->team);
	}
	base->team = NULL;
	top->teamnodmg = base->teamnodmg;
	top->alliedTeam = base->alliedTeam;

	base->s.eType = ET_GENERAL;

	// Set up our explosion effect for the ExplodeDeath code....
	G_EffectIndex( "turret/explode" );
	G_EffectIndex( "sparks/spark_exp_nosnd" );
	G_EffectIndex( "turret/hoth_muzzle_flash" );

	// this is really the pitch angle.....
	top->speed = 0;

	// this is a random time offset for the no-enemy-search-around-mode
	top->count = random() * 9000;

	if ( !base->health )
	{
		base->health = 3000;
	}
	top->health = base->health;

	G_SpawnInt( "showhealth", "0", &t );

	if (t)
	{ //a non-0 maxhealth value will mean we want to show the health on the hud
		top->maxHealth = base->health; //acts as "maxhealth"
		G_ScaleNetHealth(top);

		base->maxHealth = base->health;
		G_ScaleNetHealth(base);
	}

	base->takedamage = qtrue;
	base->pain = TurretBasePain;
	base->die = bottom_die;

	//design specified shot speed
	G_SpawnFloat( "shotspeed", "1100", &base->mass );
	top->mass = base->mass;

	//even if we don't want to show health, let's at least light the crosshair up properly over ourself
	if ( !top->s.teamowner )
	{
		top->s.teamowner = top->alliedTeam;
	}

	base->alliedTeam = top->alliedTeam;
	base->s.teamowner = top->s.teamowner;

	base->s.shouldtarget = qtrue;
	top->s.shouldtarget = qtrue;

	//link them to each other
	base->target_ent = top;
	top->target_ent = base;

	//top->s.owner = MAX_CLIENTS; //not owned by any client

	// search radius
	if ( !base->radius )
	{
		base->radius = 1024;
	}
	top->radius = base->radius;

	// How quickly to fire
	if ( !base->wait )
	{
		base->wait = 300 + random() * 55;
	}
	top->wait = base->wait;

	if ( !base->splashDamage )
	{
		base->splashDamage = 300;
	}
	top->splashDamage = base->splashDamage;

	if ( !base->splashRadius )
	{
		base->splashRadius = 128;
	}
	top->splashRadius = base->splashRadius;

	// how much damage each shot does
	if ( !base->damage )
	{
		base->damage = 100;
	}
	top->damage = base->damage;

	// how fast it turns
	if ( !base->speed )
	{
		base->speed = 20;
	}
	top->speed = base->speed;

	VectorSet( top->r.maxs, 48.0f, 48.0f, 16.0f );
	VectorSet( top->r.mins, -48.0f, -48.0f, 0.0f );
	// Precache moving sounds
	//G_SoundIndex( "sound/chars/turret/startup.wav" );
	//G_SoundIndex( "sound/chars/turret/shutdown.wav" );
	//G_SoundIndex( "sound/chars/turret/ping.wav" );
	G_SoundIndex( "sound/vehicles/weapons/hoth_turret/turn.wav" );
	top->genericValue13 = G_EffectIndex( "turret/hoth_muzzle_flash" );
	top->genericValue14 = G_EffectIndex( "turret/hoth_shot" );
	top->genericValue15 = G_EffectIndex( "turret/hoth_impact" );

	top->r.contents = CONTENTS_BODY;

	//base->max_health = base->health;
	top->takedamage = qtrue;
	top->pain = TurretPain;
	top->die  = auto_turret_die;

	top->material = MAT_METAL;
	//base->r.svFlags |= SVF_NO_TELEPORT|SVF_NONNPC_ENEMY|SVF_SELF_ANIMATING;

	// Register this so that we can use it for the missile effect
	RegisterItem( BG_FindItemForWeapon( WP_EMPLACED_GUN ));

	// But set us as a turret so that we can be identified as a turret
	top->s.weapon = WP_EMPLACED_GUN;

	trap_LinkEntity( top );
	return qtrue;
}
Пример #18
0
/*QUAKED misc_model_breakable (1 0 0) (-16 -16 -16) (16 16 16) SOLID AUTOANIMATE DEADSOLID NO_DMODEL NO_SMOKE USE_MODEL USE_NOT_BREAK PLAYER_USE NO_EXPLOSION
SOLID - Movement is blocked by it, if not set, can still be broken by explosions and shots if it has health
AUTOANIMATE - Will cycle it's anim
DEADSOLID - Stay solid even when destroyed (in case damage model is rather large).
NO_DMODEL - Makes it NOT display a damage model when destroyed, even if one exists
USE_MODEL - When used, will toggle to it's usemodel (model name + "_u1.md3")... this obviously does nothing if USE_NOT_BREAK is not checked
USE_NOT_BREAK - Using it, doesn't make it break, still can be destroyed by damage
PLAYER_USE - Player can use it with the use button
NO_EXPLOSION - By default, will explode when it dies...this is your override.

"model"		arbitrary .md3 file to display
"health"	how much health to have - default is zero (not breakable)  If you don't set the SOLID flag, but give it health, it can be shot but will not block NPCs or players from moving
"targetname" when used, dies and displays damagemodel, if any (if not, removes itself)
"target" What to use when it dies
"target2" What to use when it's repaired
"target3" What to use when it's used while it's broken
"paintarget" target to fire when hit (but not destroyed)
"count"  the amount of armor/health/ammo given (default 50)
"gravity"	if set to 1, this will be affected by gravity
"radius"  Chunk code tries to pick a good volume of chunks, but you can alter this to scale the number of spawned chunks. (default 1)  (.5) is half as many chunks, (2) is twice as many chunks

Damage: default is none
"splashDamage" - damage to do (will make it explode on death)
"splashRadius" - radius for above damage

"team" - This cannot take damage from members of this team:
	"player"
	"neutral"
	"enemy"

"material" - default is "8 - MAT_NONE" - choose from this list:
0 = MAT_METAL		(grey metal)
1 = MAT_GLASS		
2 = MAT_ELECTRICAL	(sparks only)
3 = MAT_ELEC_METAL	(METAL chunks and sparks)
4 =	MAT_DRK_STONE	(brown stone chunks)
5 =	MAT_LT_STONE	(tan stone chunks)
6 =	MAT_GLASS_METAL (glass and METAL chunks)
7 = MAT_METAL2		(blue/grey metal)
8 = MAT_NONE		(no chunks-DEFAULT)
9 = MAT_GREY_STONE	(grey colored stone)
10 = MAT_METAL3		(METAL and METAL2 chunk combo)
11 = MAT_CRATE1		(yellow multi-colored crate chunks)
12 = MAT_GRATE1		(grate chunks--looks horrible right now)
13 = MAT_ROPE		(for yavin_trial, no chunks, just wispy bits )
14 = MAT_CRATE2		(red multi-colored crate chunks)
15 = MAT_WHITE_METAL (white angular chunks for Stu, NS_hideout )
FIXME/TODO: 
set size better?
multiple damage models?
custom explosion effect/sound?
*/
void SP_misc_model_breakable( gentity_t *ent ) 
{
	char	damageModel[MAX_QPATH];
	char	chunkModel[MAX_QPATH];
	char	useModel[MAX_QPATH];
	int		len;
	
	// Chris F. requested default for misc_model_breakable to be NONE...so don't arbitrarily change this.
	G_SpawnInt( "material", "8", (int*)&ent->material );
	G_SpawnFloat( "radius", "1", &ent->radius ); // used to scale chunk code if desired by a designer
	CacheChunkEffects( ent->material );

	misc_model_breakable_init( ent );

	len = strlen( ent->model ) - 4;
	strncpy( damageModel, ent->model, len );
	damageModel[len] = 0;	//chop extension
	strncpy( chunkModel, damageModel, sizeof(chunkModel));
	strncpy( useModel, damageModel, sizeof(useModel));
	
	if (ent->takedamage) {
		//Dead/damaged model
		if( !(ent->spawnflags & 8) ) {	//no dmodel
			strcat( damageModel, "_d1.md3" );
			ent->s.modelindex2 = G_ModelIndex( damageModel );
		}
		
		//Chunk model
		strcat( chunkModel, "_c1.md3" );
		ent->s.modelindex3 = G_ModelIndex( chunkModel );
	}

	//Use model
	if( ent->spawnflags & 32 ) {	//has umodel
		strcat( useModel, "_u1.md3" );
		ent->sound1to2 = G_ModelIndex( useModel );
	}
	if ( !ent->mins[0] && !ent->mins[1] && !ent->mins[2] )
	{
		VectorSet (ent->mins, -16, -16, -16);
	}
	if ( !ent->maxs[0] && !ent->maxs[1] && !ent->maxs[2] )
	{
		VectorSet (ent->maxs, 16, 16, 16);
	}

	if ( ent->spawnflags & 2 )
	{
		ent->s.eFlags |= EF_ANIM_ALLFAST;
	}

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );
	gi.linkentity (ent);

	if ( ent->spawnflags & 128 )
	{//Can be used by the player's BUTTON_USE
		ent->svFlags |= SVF_PLAYER_USABLE;
	}

	if ( ent->team && ent->team[0] )
	{
		ent->noDamageTeam = TranslateTeamName( ent->team );
		if ( ent->noDamageTeam == TEAM_FREE )
		{
			G_Error("team name %s not recognized\n", ent->team);
		}
	}
	
	ent->team = NULL;

	//HACK
	if ( ent->model && Q_stricmp( "models/map_objects/ships/tie_fighter.md3", ent->model ) == 0 )
	{//run a think
		G_EffectIndex( "fighter_explosion2" );
		G_SoundIndex( "sound/weapons/tie_fighter/tiepass1.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tiepass2.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tiepass3.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tiepass4.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tiepass5.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tie_fire.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tie_fire2.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/tie_fire3.wav" );
		G_SoundIndex( "sound/weapons/tie_fighter/TIEexplode.wav" );
		ent->e_ThinkFunc = thinkF_TieFighterThink;
		ent->nextthink = level.time + FRAMETIME;
	}
	float grav = 0;
	G_SpawnFloat( "gravity", "0", &grav );
	if ( grav )
	{//affected by gravity
		G_SetAngles( ent, ent->s.angles );
		G_SetOrigin( ent, ent->currentOrigin );
		misc_model_breakable_gravity_init( ent, qtrue );
	}
}
Пример #19
0
//----------------------------------------------------------
void fx_runner_link( gentity_t *ent )
{
	vec3_t	dir;

	if ( ent->target )
	{
		// try to use the target to override the orientation
		gentity_t	*target = NULL;

		target = G_Find( target, FOFS(targetname), ent->target );

		if ( !target )
		{
			// Bah, no good, dump a warning, but continue on and use the UP vector
			Com_Printf( "fx_runner_link: target specified but not found: %s\n", ent->target );
			Com_Printf( "  -assuming UP orientation.\n" );
		}
		else
		{
			// Our target is valid so let's override the default UP vector
			VectorSubtract( target->s.origin, ent->s.origin, dir );
			VectorNormalize( dir );
			vectoangles( dir, ent->s.angles );
		}
	}

	// don't really do anything with this right now other than do a check to warn the designers if the target2 is bogus
	if ( ent->target2 )
	{
		gentity_t	*target = NULL;

		target = G_Find( target, FOFS(targetname), ent->target2 );

		if ( !target )
		{
			// Target2 is bogus, but we can still continue
			Com_Printf( "fx_runner_link: target2 was specified but is not valid: %s\n", ent->target2 );
		}
	}

	G_SetAngles( ent, ent->s.angles );

	if ( ent->spawnflags & 1 || ent->spawnflags & 2 ) // STARTOFF || ONESHOT
	{
		// We won't even consider thinking until we are used
		ent->nextthink = -1;
	}
	else
	{
		if ( VALIDSTRING( ent->soundSet ) == true )
		{
			ent->s.loopSound = CAS_GetBModelSound( ent->soundSet, BMS_MID );

			if ( ent->s.loopSound < 0 )
			{
				ent->s.loopSound = 0;
			}
		}

		// Let's get to work right now!
		ent->e_ThinkFunc = thinkF_fx_runner_think;
		ent->nextthink = level.time + 200; // wait a small bit, then start working
	}

	// make us useable if we can be targeted
	if ( ent->targetname )
	{
		ent->e_UseFunc = useF_fx_runner_use;
	}
}
Пример #20
0
//----------------------------------------------------------
void emplaced_gun_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc )
{
	vec3_t org;

	// turn off any firing animations it may have been doing
	self->s.frame = self->startFrame = self->endFrame = 0;
	self->svFlags &= ~SVF_ANIMATING;
			
	self->health = 0;
//	self->s.weapon = WP_EMPLACED_GUN; // we need to be able to switch back to the old weapon

	self->takedamage = qfalse;
	self->lastEnemy = attacker;

	// we defer explosion so the player has time to get out
	if ( self->e_DieFunc )
	{
		self->e_ThinkFunc = thinkF_emplaced_blow;
		self->nextthink = level.time + 3000; // don't blow for a couple of seconds
		return;
	}

	if ( self->activator && self->activator->client )
	{
		if ( self->activator->NPC )
		{
			vec3_t right;

			// radius damage seems to throw them, but add an extra bit to throw them away from the weapon
			AngleVectors( self->currentAngles, NULL, right, NULL );
			VectorMA( self->activator->client->ps.velocity, 140, right, self->activator->client->ps.velocity );
			self->activator->client->ps.velocity[2] = -100;

			// kill them
			self->activator->health = 0;
			self->activator->client->ps.stats[STAT_HEALTH] = 0;
		}

		// kill the players emplaced ammo, cheesy way to keep the gun from firing
		self->activator->client->ps.ammo[weaponData[WP_EMPLACED_GUN].ammoIndex] = 0;
	}

	self->e_PainFunc = painF_NULL;
	self->e_ThinkFunc = thinkF_NULL;

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

	G_RadiusDamage( self->currentOrigin, self, self->splashDamage, self->splashRadius, self, MOD_UNKNOWN );

	// when the gun is dead, add some ugliness to it.
	vec3_t ugly;

	ugly[YAW] = 4;
	ugly[PITCH] = self->lastAngles[PITCH] * 0.8f + crandom() * 6;
	ugly[ROLL] = crandom() * 7;
	gi.G2API_SetBoneAnglesIndex( &self->ghoul2[self->playerModel], self->lowerLumbarBone, ugly, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL, 0, 0 ); 

	VectorCopy( self->currentOrigin,  org );
	org[2] += 20;

	G_PlayEffect( "emplaced/explode", org );

	// create some persistent smoke by using a dynamically created fx runner
	gentity_t *ent = G_Spawn();

	if ( ent )
	{
		ent->delay = 200;
		ent->random = 100;

		ent->fxID = G_EffectIndex( "emplaced/dead_smoke" );

		ent->e_ThinkFunc = thinkF_fx_runner_think; 
		ent->nextthink = level.time + 50;

		// move up above the gun origin
		VectorCopy( self->currentOrigin, org );
		org[2] += 35;
		G_SetOrigin( ent, org );
		VectorCopy( org, ent->s.origin );

		VectorSet( ent->s.angles, -90, 0, 0 ); // up
		G_SetAngles( ent, ent->s.angles );

		gi.linkentity( ent );
	}

	G_ActivateBehavior( self, BSET_DEATH );
}
Пример #21
0
//----------------------------------------------------------
void SP_emplaced_eweb( gentity_t *ent )
{
	char name[] = "models/map_objects/hoth/eweb_model.glm";

	ent->svFlags |= SVF_PLAYER_USABLE;
	ent->contents = CONTENTS_BODY;

	if ( ent->spawnflags & EMPLACED_INACTIVE )
	{
		ent->svFlags |= SVF_INACTIVE;
	}

	VectorSet( ent->mins, -12, -12, -24 );
	VectorSet( ent->maxs, 12, 12, 24 );

	ent->takedamage = qtrue;

	if ( ( ent->spawnflags & EWEB_INVULNERABLE ))
	{
		ent->flags |= FL_GODMODE;
	}

	ent->s.radius = 80;
	ent->spawnflags |= 4; // deadsolid

	//ent->e_ThinkFunc = thinkF_NULL;
	ent->e_PainFunc = painF_eweb_pain;
	ent->e_DieFunc  = dieF_eweb_die;

	G_EffectIndex( "emplaced/explode" );
	G_EffectIndex( "emplaced/dead_smoke" );

	G_SoundIndex( "sound/weapons/eweb/eweb_aim.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_dismount.mp3" );
	//G_SoundIndex( "sound/weapons/eweb/eweb_empty.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_fire.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_hitplayer.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_hitsurface.wav" );
	//G_SoundIndex( "sound/weapons/eweb/eweb_load.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_mount.mp3" );

	// Set up our defaults and override with custom amounts as necessary
	G_SpawnInt( "count", "999", &ent->count );
	G_SpawnInt( "health", "250", &ent->health );
	G_SpawnInt( "splashDamage", "40", &ent->splashDamage );
	G_SpawnInt( "splashRadius", "100", &ent->splashRadius );
	G_SpawnFloat( "delay", "200", &ent->random ); // NOTE: spawning into a different field!!
	G_SpawnFloat( "wait", "800", &ent->wait );

	ent->max_health = ent->health;
	ent->dflags |= DAMAGE_CUSTOM_HUD; // dumb, but we draw a custom hud

	ent->s.modelindex = G_ModelIndex( name );
	ent->playerModel = gi.G2API_InitGhoul2Model( ent->ghoul2, name, ent->s.modelindex, NULL, NULL, 0, 0 );

	// Activate our tags and bones
	ent->handLBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*cannonflash" ); //muzzle bolt
	ent->headBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "cannon_Xrot" ); //for placing the owner relative to rotation
	ent->rootBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "model_root", qtrue );
	ent->lowerLumbarBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "cannon_Yrot", qtrue );
	ent->upperLumbarBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "cannon_Xrot", qtrue );
	gi.G2API_SetBoneAnglesIndex( &ent->ghoul2[ent->playerModel], ent->lowerLumbarBone, vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_X, NEGATIVE_Y, NULL, 0, 0); 
	gi.G2API_SetBoneAnglesIndex( &ent->ghoul2[ent->playerModel], ent->upperLumbarBone, vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_X, NEGATIVE_Y, NULL, 0, 0); 
	//gi.G2API_SetBoneAngles( &ent->ghoul2[0], "cannon_Yrot", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL); 
	//set the constraints for this guy as an emplaced weapon, and his constraint angles
	//ent->s.origin2[0] = 60.0f; //60 degrees in either direction

	RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN ));
	ent->s.weapon = WP_EMPLACED_GUN;

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );
	VectorCopy( ent->s.angles, ent->lastAngles );

	// store base angles for later
	VectorClear( ent->pos1 );

	ent->e_UseFunc = useF_eweb_use;
	ent->bounceCount = 1;//to distinguish it from the emplaced gun

	gi.linkentity (ent);
}
Пример #22
0
//----------------------------------------------------------
void eweb_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc )
{
	vec3_t org;

	// turn off any firing animations it may have been doing
	self->s.frame = self->startFrame = self->endFrame = 0;
	self->svFlags &= ~(SVF_ANIMATING|SVF_PLAYER_USABLE);
	
			
	self->health = 0;
//	self->s.weapon = WP_EMPLACED_GUN; // we need to be able to switch back to the old weapon

	self->takedamage = qfalse;
	self->lastEnemy = attacker;

	if ( self->activator && self->activator->client )
	{
		if ( self->activator->NPC )
		{
			vec3_t right;

			// radius damage seems to throw them, but add an extra bit to throw them away from the weapon
			AngleVectors( self->currentAngles, NULL, right, NULL );
			VectorMA( self->activator->client->ps.velocity, 140, right, self->activator->client->ps.velocity );
			self->activator->client->ps.velocity[2] = -100;

			// kill them
			self->activator->health = 0;
			self->activator->client->ps.stats[STAT_HEALTH] = 0;
		}

		// kill the players emplaced ammo, cheesy way to keep the gun from firing
		self->activator->client->ps.ammo[weaponData[WP_EMPLACED_GUN].ammoIndex] = 0;
	}

	self->e_PainFunc = painF_NULL;

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

	G_RadiusDamage( self->currentOrigin, self, self->splashDamage, self->splashRadius, self, MOD_UNKNOWN );

	VectorCopy( self->currentOrigin,  org );
	org[2] += 20;

	G_PlayEffect( "emplaced/explode", org );

	// Turn the top of the eweb off.
#define TURN_OFF			0x00000100//G2SURFACEFLAG_NODESCENDANTS
	gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "eweb_damage", TURN_OFF );

	// create some persistent smoke by using a dynamically created fx runner
	gentity_t *ent = G_Spawn();

	if ( ent )
	{
		ent->delay = 200;
		ent->random = 100;

		ent->fxID = G_EffectIndex( "emplaced/dead_smoke" );

		ent->e_ThinkFunc = thinkF_fx_runner_think; 
		ent->nextthink = level.time + 50;

		// move up above the gun origin
		VectorCopy( self->currentOrigin, org );
		org[2] += 35;
		G_SetOrigin( ent, org );
		VectorCopy( org, ent->s.origin );

		VectorSet( ent->s.angles, -90, 0, 0 ); // up
		G_SetAngles( ent, ent->s.angles );

		gi.linkentity( ent );
	}

	G_ActivateBehavior( self, BSET_DEATH );
}
Пример #23
0
//-----------------------------------------------------
void finish_spawning_turretG2( gentity_t *base )
{
    vec3_t		fwd;
    int			t;

    if ( (base->spawnflags&2) )
    {
        base->s.angles[ROLL] += 180;
        base->s.origin[2] -= 22.0f;
    }

    G_SetAngles( base, base->s.angles );
    AngleVectors( base->r.currentAngles, fwd, NULL, NULL );

    G_SetOrigin(base, base->s.origin);

    base->s.eType = ET_GENERAL;

    if ( base->team && base->team[0] && //g_gametype.integer == GT_SIEGE &&
            !base->teamnodmg)
    {
        base->teamnodmg = atoi(base->team);
    }
    base->team = NULL;

    // Set up our explosion effect for the ExplodeDeath code....
    G_EffectIndex( "turret/explode" );
    G_EffectIndex( "sparks/spark_exp_nosnd" );

    base->use = turretG2_base_use;
    base->pain = TurretG2Pain;

    // don't start working right away
    base->think = turretG2_base_think;
    base->nextthink = level.time + FRAMETIME * 5;

    // this is really the pitch angle.....
    base->speed = 0;

    // respawn time defaults to 20 seconds
    if ( (base->spawnflags&SPF_TURRETG2_CANRESPAWN) && !base->count )
    {
        base->count = 20000;
    }

    G_SpawnFloat( "shotspeed", "0", &base->mass );
    if ( (base->spawnflags&SPF_TURRETG2_TURBO) )
    {
        if ( !base->random )
        {   //error worked into projectile direction
            base->random = 2.0f;
        }

        if ( !base->mass )
        {   //misnomer: speed of projectile
            base->mass = 20000;
        }

        if ( !base->health )
        {
            base->health = 2000;
        }

        // search radius
        if ( !base->radius )
        {
            base->radius = 32768;
        }

        // How quickly to fire
        if ( !base->wait )
        {
            base->wait = 1000;// + random() * 500;
        }

        if ( !base->splashDamage )
        {
            base->splashDamage = 200;
        }

        if ( !base->splashRadius )
        {
            base->splashRadius = 500;
        }

        // how much damage each shot does
        if ( !base->damage )
        {
            base->damage = 500;
        }

        if ( (base->spawnflags&SPF_TURRETG2_TURBO) )
        {
            VectorSet( base->r.maxs, 64.0f, 64.0f, 30.0f );
            VectorSet( base->r.mins, -64.0f, -64.0f, -30.0f );
        }
        //start in "off" anim
        TurboLaser_SetBoneAnim( base, 4, 5 );
        if ( g_gametype.integer == GT_SIEGE )
        {   //FIXME: designer-specified?
            //FIXME: put on other entities, too, particularly siege objectives and bbrushes...
            base->s.eFlags2 |= EF2_BRACKET_ENTITY;
        }
    }
    else
    {
        if ( !base->random )
        {   //error worked into projectile direction
            base->random = 2.0f;
        }

        if ( !base->mass )
        {   //misnomer: speed of projectile
            base->mass = 1100;
        }

        if ( !base->health )
        {
            base->health = 100;
        }

        // search radius
        if ( !base->radius )
        {
            base->radius = 512;
        }

        // How quickly to fire
        if ( !base->wait )
        {
            base->wait = 150 + random() * 55;
        }

        if ( !base->splashDamage )
        {
            base->splashDamage = 10;
        }

        if ( !base->splashRadius )
        {
            base->splashRadius = 25;
        }

        // how much damage each shot does
        if ( !base->damage )
        {
            base->damage = 5;
        }

        if ( base->spawnflags & 2 )
        {   //upside-down, invert r.mins and maxe
            VectorSet( base->r.maxs, 10.0f, 10.0f, 30.0f );
            VectorSet( base->r.mins, -10.0f, -10.0f, 0.0f );
        }
        else
        {
            VectorSet( base->r.maxs, 10.0f, 10.0f, 0.0f );
            VectorSet( base->r.mins, -10.0f, -10.0f, -30.0f );
        }
    }

    //stash health off for respawn.  NOTE: cannot use maxhealth because that might not be set if not showing the health bar
    base->genericValue6 = base->health;

    G_SpawnInt( "showhealth", "0", &t );
    if (t)
    {   //a non-0 maxhealth value will mean we want to show the health on the hud
        base->maxHealth = base->health;
        G_ScaleNetHealth(base);
        base->s.shouldtarget = qtrue;
        //base->s.owner = MAX_CLIENTS; //not owned by any client
    }

    if (base->s.iModelScale)
    {   //let's scale the bbox too...
        float fScale = base->s.iModelScale/100.0f;
        VectorScale(base->r.mins, fScale, base->r.mins);
        VectorScale(base->r.maxs, fScale, base->r.maxs);
    }

    // Precache special FX and moving sounds
    if ( (base->spawnflags&SPF_TURRETG2_TURBO) )
    {
        base->genericValue13 = G_EffectIndex( "turret/turb_muzzle_flash" );
        base->genericValue14 = G_EffectIndex( "turret/turb_shot" );
        base->genericValue15 = G_EffectIndex( "turret/turb_impact" );
        //FIXME: Turbo Laser Cannon sounds!
        G_SoundIndex( "sound/vehicles/weapons/turbolaser/turn.wav" );
    }
    else
    {
        G_SoundIndex( "sound/chars/turret/startup.wav" );
        G_SoundIndex( "sound/chars/turret/shutdown.wav" );
        G_SoundIndex( "sound/chars/turret/ping.wav" );
        G_SoundIndex( "sound/chars/turret/move.wav" );
    }

    base->r.contents = CONTENTS_BODY|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_SHOTCLIP;

    //base->max_health = base->health;
    base->takedamage = qtrue;
    base->die  = turretG2_die;

    base->material = MAT_METAL;
    //base->r.svFlags |= SVF_NO_TELEPORT|SVF_NONNPC_ENEMY|SVF_SELF_ANIMATING;

    // Register this so that we can use it for the missile effect
    RegisterItem( BG_FindItemForWeapon( WP_BLASTER ));

    // But set us as a turret so that we can be identified as a turret
    base->s.weapon = WP_TURRET;

    trap_LinkEntity( base );
}
Пример #24
0
/*
================
G_BounceItem

================
*/
void G_BounceItem( gentity_t *ent, trace_t *trace ) {
	vec3_t	velocity;
	float	dot;
	int		hitTime;
	qboolean droppedSaber = qtrue;

	if ( ent->item
		&& ent->item->giType == IT_WEAPON
		&& ent->item->giTag == WP_SABER 
		&& (ent->flags&FL_DROPPED_ITEM) )
	{
		droppedSaber = qtrue;
	}

	// reflect the velocity on the trace plane
	hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
	EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
	dot = DotProduct( velocity, trace->plane.normal );
	VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );

	// cut the velocity to keep from bouncing forever
	VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta );

	if ( droppedSaber )
	{//a dropped saber item
		//FIXME: use NPC_type (as saberType) to get proper bounce sound?
		WP_SaberFallSound( NULL, ent );
	}

	// check for stop
	if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) 
	{//stop
		G_SetOrigin( ent, trace->endpos );
		ent->s.groundEntityNum = trace->entityNum;
		if ( droppedSaber )
		{//a dropped saber item
			//stop rotation
			VectorClear( ent->s.apos.trDelta );
			ent->currentAngles[PITCH] = SABER_PITCH_HACK;
			ent->currentAngles[ROLL] = 0;
			if ( ent->NPC_type 
				&& ent->NPC_type[0] )
			{//we have a valid saber for this
				saberInfo_t saber;
				if ( WP_SaberParseParms( ent->NPC_type, &saber ) )
				{
					if ( (saber.saberFlags&SFL_BOLT_TO_WRIST) )
					{
						ent->currentAngles[PITCH] = 0;
					}
				}
			}
			pitch_roll_for_slope( ent, trace->plane.normal, ent->currentAngles, qtrue );
			G_SetAngles( ent, ent->currentAngles );
		}
		return;
	}
	//bounce
	if ( droppedSaber )
	{//a dropped saber item
		//change rotation
		VectorCopy( ent->currentAngles, ent->s.apos.trBase );
		ent->s.apos.trType = TR_LINEAR;
		ent->s.apos.trTime = level.time;
		VectorSet( ent->s.apos.trDelta, Q_irand( -300, 300 ), Q_irand( -300, 300 ), Q_irand( -300, 300 ) );
	}

	VectorAdd( ent->currentOrigin, trace->plane.normal, ent->currentOrigin);
	VectorCopy( ent->currentOrigin, ent->s.pos.trBase );
	ent->s.pos.trTime = level.time;
}
Пример #25
0
/*
================
LaunchItem

Spawns an item and tosses it forward
================
*/
gentity_t *LaunchItem( gitem_t *item, const vec3_t origin, const vec3_t velocity, char *target ) {
	gentity_t	*dropped;

	dropped = G_Spawn();

	dropped->s.eType = ET_ITEM;
	dropped->s.modelindex = item - bg_itemlist;	// store item number in modelindex
	dropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item

	dropped->classname = G_NewString(item->classname);	//copy it so it can be freed safely
	dropped->item = item;

	// try using the "correct" mins/maxs first
	VectorSet( dropped->mins, item->mins[0], item->mins[1], item->mins[2] );
	VectorSet( dropped->maxs, item->maxs[0], item->maxs[1], item->maxs[2] );

	if ((!dropped->mins[0] && !dropped->mins[1] && !dropped->mins[2]) && 
		(!dropped->maxs[0] && !dropped->maxs[1] && !dropped->maxs[2]))
	{
		VectorSet( dropped->maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS );
		VectorScale( dropped->maxs, -1, dropped->mins );
	}

	dropped->contents = CONTENTS_TRIGGER|CONTENTS_ITEM;//CONTENTS_TRIGGER;//not CONTENTS_BODY for dropped items, don't need to ID them

	if ( target && target[0] )
	{
		dropped->target = G_NewString( target );
	}
	else
	{
		// if not targeting something, auto-remove after 30 seconds
		// only if it's NOT a security or goodie key
		if (dropped->item->giTag != INV_SECURITY_KEY )
		{
			dropped->e_ThinkFunc = thinkF_G_FreeEntity;
			dropped->nextthink = level.time + 30000;
		}

		if ( dropped->item->giType == IT_AMMO && dropped->item->giTag == AMMO_FORCE )
		{
			dropped->nextthink = -1;
			dropped->e_ThinkFunc = thinkF_NULL;
		}
	}

	dropped->e_TouchFunc = touchF_Touch_Item;

	if ( item->giType == IT_WEAPON )
	{
		// give weapon items zero pitch, a random yaw, and rolled onto their sides...but would be bad to do this for a bowcaster
		if ( item->giTag != WP_BOWCASTER
			&& item->giTag != WP_THERMAL
			&& item->giTag != WP_TRIP_MINE
			&& item->giTag != WP_DET_PACK )
		{
			VectorSet( dropped->s.angles, 0, crandom() * 180, 90.0f );
			G_SetAngles( dropped, dropped->s.angles );
		}
	}

	G_SetOrigin( dropped, origin );
	dropped->s.pos.trType = TR_GRAVITY;
	dropped->s.pos.trTime = level.time;
	VectorCopy( velocity, dropped->s.pos.trDelta );

	dropped->s.eFlags |= EF_BOUNCE_HALF;

	dropped->flags = FL_DROPPED_ITEM;

	gi.linkentity (dropped);

	return dropped;
}
Пример #26
0
void SP_misc_model_ghoul( gentity_t *ent )
{
#if 1
	ent->s.modelindex = G_ModelIndex( ent->model );
	gi.G2API_InitGhoul2Model(ent->ghoul2, ent->model, ent->s.modelindex, NULL_HANDLE, NULL_HANDLE, 0, 0);
	ent->s.radius = 50;

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );

	qboolean bHasScale = G_SpawnVector( "modelscale_vec", "1 1 1", ent->s.modelScale );
	if ( !bHasScale ) {
		float temp;
		G_SpawnFloat( "modelscale", "0", &temp );
		if ( temp != 0.0f ) {
			ent->s.modelScale[0] = ent->s.modelScale[1] = ent->s.modelScale[2] = temp;
			bHasScale = qtrue;
		}
	}
	if ( bHasScale ) {
		//scale the x axis of the bbox up.
		ent->maxs[0] *= ent->s.modelScale[0];
		ent->mins[0] *= ent->s.modelScale[0];

		//scale the y axis of the bbox up.
		ent->maxs[1] *= ent->s.modelScale[1];
		ent->mins[1] *= ent->s.modelScale[1];

		//scale the z axis of the bbox up and adjust origin accordingly
		ent->maxs[2] *= ent->s.modelScale[2];
		float oldMins2 = ent->mins[2];
		ent->mins[2] *= ent->s.modelScale[2];
		ent->s.origin[2] += (oldMins2 - ent->mins[2]);
	}

	gi.linkentity (ent);
#else
	char name1[200] = "models/players/kyle/model.glm";
	ent->s.modelindex = G_ModelIndex( name1 );

	gi.G2API_InitGhoul2Model(ent->ghoul2, name1, ent->s.modelindex);
	ent->s.radius = 150;

			// we found the model ok - load it's animation config
	temp_animFileIndex = G_ParseAnimFileSet("_humanoid", "kyle");
 	if ( temp_animFileIndex<0 ) 
 	{
 		Com_Printf( S_COLOR_RED"Failed to load animation file set models/players/jedi/animation.cfg\n");
 	}
 

	ent->s.angles[0] = 0;
	ent->s.angles[1] = 90;
	ent->s.angles[2] = 0;

	ent->s.origin[2] = 20;
	ent->s.origin[1] = 80;
//	ent->s.modelScale[0] = ent->s.modelScale[1] = ent->s.modelScale[2] = 0.8f;

	VectorSet (ent->mins, -16, -16, -37);
	VectorSet (ent->maxs, 16, 16, 32);
//#if _DEBUG
//loadsavecrash
//	VectorCopy(ent->mins, ent->s.mins);
//	VectorCopy(ent->maxs, ent->s.maxs);
//#endif
	ent->contents = CONTENTS_BODY;
	ent->clipmask = MASK_NPCSOLID;

	G_SetOrigin( ent, ent->s.origin );
	VectorCopy( ent->s.angles, ent->s.apos.trBase );
	ent->health = 1000;

//	ent->s.modelindex = G_ModelIndex( "models/weapons2/blaster_r/g2blaster_w.glm" );
//	gi.G2API_InitGhoul2Model(ent->ghoul2, "models/weapons2/blaster_r/g2blaster_w.glm", ent->s.modelindex);
//	gi.G2API_AddBolt(&ent->ghoul2[0], "*weapon");
//	gi.G2API_AttachG2Model(&ent->ghoul2[1],&ent->ghoul2[0], 0, 0);

	gi.linkentity (ent);

	animation_t *animations = level.knownAnimFileSets[temp_animFileIndex].animations;
	int anim = BOTH_STAND3;
	float animSpeed = 50.0f / animations[anim].frameLerp;
	gi.G2API_SetBoneAnim(&ent->ghoul2[0], "model_root", animations[anim].firstFrame, 
					(animations[anim].numFrames -1 )+ animations[anim].firstFrame,
					BONE_ANIM_OVERRIDE_FREEZE , animSpeed, cg.time);

//	int test = gi.G2API_GetSurfaceRenderStatus(&ent->ghoul2[0], "l_hand");
//	gi.G2API_SetSurfaceOnOff(&ent->ghoul2[0], "l_arm",0x00000100);
//	test = gi.G2API_GetSurfaceRenderStatus(&ent->ghoul2[0], "l_hand");

//	gi.G2API_SetNewOrigin(&ent->ghoul2[0], gi.G2API_AddBolt(&ent->ghoul2[0], "rhang_tag_bone"));
//	ent->s.apos.trDelta[1] = 10;
//	ent->s.apos.trType = TR_LINEAR;


	ent->nextthink = level.time + 1000;
	ent->e_ThinkFunc = thinkF_set_MiscAnim;
#endif
}
Пример #27
0
// AMMO RACK!!
void spawn_rack_goods( gentity_t *ent )
{
	float		v_off = 0;
	gitem_t		*blaster = NULL, *metal_bolts = NULL, *rockets = NULL, *it = NULL;
	gitem_t		*am_blaster = NULL, *am_metal_bolts = NULL, *am_rockets = NULL, *am_pwr_cell = NULL;
	gitem_t		*health = NULL;
	int			pos = 0, ct = 0;
	gitem_t		*itemList[4]; // allocating 4, but we only use 3.  done so I don't have to validate that the array isn't full before I add another

	gi.unlinkentity( ent );

	// If BLASTER is checked...or nothing is checked then we'll do blasters
	if (( ent->spawnflags & RACK_BLASTER ) || !(ent->spawnflags & ( RACK_BLASTER | RACK_METAL_BOLTS | RACK_ROCKETS | RACK_PWR_CELL )))
	{
		if ( ent->spawnflags & RACK_WEAPONS )
		{
			blaster	= FindItemForWeapon( WP_BLASTER );
		}
		am_blaster	= FindItemForAmmo( AMMO_BLASTER );
	}

	if (( ent->spawnflags & RACK_METAL_BOLTS ))
	{
		if ( ent->spawnflags & RACK_WEAPONS )
		{
			metal_bolts = FindItemForWeapon( WP_REPEATER );
		}
		am_metal_bolts = FindItemForAmmo( AMMO_METAL_BOLTS );
	}

	if (( ent->spawnflags & RACK_ROCKETS ))
	{
		if ( ent->spawnflags & RACK_WEAPONS )
		{
			rockets = FindItemForWeapon( WP_ROCKET_LAUNCHER );
		}
		am_rockets = FindItemForAmmo( AMMO_ROCKETS );
	}

	if (( ent->spawnflags & RACK_PWR_CELL ))
	{
		am_pwr_cell = FindItemForAmmo( AMMO_POWERCELL );
	}

	if (( ent->spawnflags & RACK_HEALTH ))
	{
		health = FindItem( "item_medpak_instant" );
		RegisterItem( health );
	}

	//---------Ammo types
	if ( am_blaster )
	{
		itemList[ct++] = am_blaster;
	}

	if ( am_metal_bolts )
	{
		itemList[ct++] = am_metal_bolts;
	}

	if ( am_pwr_cell )
	{
		itemList[ct++] = am_pwr_cell;
	}

	if ( am_rockets )
	{
		itemList[ct++] = am_rockets;
	}

	if ( !(ent->spawnflags & RACK_NO_FILL) && ct ) //double negative..should always have at least one item on there, but just being safe
	{
		for ( ; ct < 3 ; ct++ )
		{
			itemList[ct] = itemList[0]; // first item ALWAYS propagates to fill up the shelf
		}
	}

	// now actually add the items to the shelf...validate that we have a list to add
	if ( ct )
	{
		for ( int i = 0; i < ct; i++ )
		{
			GunRackAddItem( itemList[i], ent->s.origin, ent->s.angles, crandom() * 0.5f, (i-1)* 8, 7.0f );
		}
	}

	// -----Weapon option
	if ( ent->spawnflags & RACK_WEAPONS )
	{
		if ( !(ent->spawnflags & ( RACK_BLASTER | RACK_METAL_BOLTS | RACK_ROCKETS | RACK_PWR_CELL )))
		{
			// nothing was selected, so we assume blaster pack
			it = blaster;
		}
		else
		{
			// if weapon is checked...and so are one or more ammo types, then pick a random weapon to display..always give weaker weapons first
			if ( blaster )
			{
				it = blaster;
				v_off = 25.5f;
			}
			else if ( metal_bolts )
			{
				it = metal_bolts;
				v_off = 27.0f;
			}
			else if ( rockets )
			{
				it = rockets;
				v_off = 28.0f;
			}
		}

		if ( it )
		{
			// since we may have to put up a health pack on the shelf, we should know where we randomly put
			//	the gun so we don't put the pack on the same spot..so pick either the left or right side
			pos = ( random() > .5 ) ? -1 : 1;

			GunRackAddItem( it, ent->s.origin, ent->s.angles, crandom() * 2, ( random() * 6 + 4 ) * pos, v_off );
		}
	}

	// ------Medpack
	if (( ent->spawnflags & RACK_HEALTH ) && health )
	{
		if ( !pos )
		{
			// we haven't picked a side already...
			pos = ( random() > .5 ) ? -1 : 1;
		}
		else
		{
			// switch to the opposite side
			pos *= -1;
		}

		GunRackAddItem( health, ent->s.origin, ent->s.angles, crandom() * 0.5f, ( random() * 4 + 4 ) * pos, 24 );
	}

	ent->s.modelindex = G_ModelIndex( "models/map_objects/kejim/weaponsrung.md3" );

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );

	gi.linkentity( ent );
}
Пример #28
0
//----------------------------------------------------------
void SP_emplaced_gun( gentity_t *ent )
{
	char name[] = "models/map_objects/imp_mine/turret_chair.glm";

	ent->svFlags |= SVF_PLAYER_USABLE;
	ent->contents = CONTENTS_BODY;//CONTENTS_SHOTCLIP|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP;//CONTENTS_SOLID;

	if ( ent->spawnflags & EMPLACED_INACTIVE )
	{
		ent->svFlags |= SVF_INACTIVE;
	}

	VectorSet( ent->mins, -30, -30, -5 );
	VectorSet( ent->maxs, 30, 30, 60 );

	ent->takedamage = qtrue;

	if ( !( ent->spawnflags & EMPLACED_VULNERABLE ))
	{
		ent->flags |= FL_GODMODE;
	}

	ent->s.radius = 110;
	ent->spawnflags |= 4; // deadsolid

	//ent->e_ThinkFunc = thinkF_NULL;
	ent->e_PainFunc = painF_emplaced_gun_pain;
	ent->e_DieFunc  = dieF_emplaced_gun_die;

	G_EffectIndex( "emplaced/explode" );
	G_EffectIndex( "emplaced/dead_smoke" );

	G_SoundIndex( "sound/weapons/emplaced/emplaced_mount.mp3" );
	G_SoundIndex( "sound/weapons/emplaced/emplaced_dismount.mp3" );
	G_SoundIndex( "sound/weapons/emplaced/emplaced_move_lp.wav" );

	// Set up our defaults and override with custom amounts as necessary
	G_SpawnInt( "count", "999", &ent->count );
	G_SpawnInt( "health", "250", &ent->health );
	G_SpawnInt( "splashDamage", "80", &ent->splashDamage );
	G_SpawnInt( "splashRadius", "128", &ent->splashRadius );
	G_SpawnFloat( "delay", "200", &ent->random ); // NOTE: spawning into a different field!!
	G_SpawnFloat( "wait", "800", &ent->wait );

	ent->max_health = ent->health;
	ent->dflags |= DAMAGE_CUSTOM_HUD; // dumb, but we draw a custom hud

	ent->s.modelindex = G_ModelIndex( name );
	ent->playerModel = gi.G2API_InitGhoul2Model( ent->ghoul2, name, ent->s.modelindex, NULL, NULL, 0, 0 );

	// Activate our tags and bones
	ent->headBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*seat" );
	ent->handLBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*flash01" );
	ent->handRBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*flash02" );
	ent->rootBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "base_bone", qtrue );
	ent->lowerLumbarBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "swivel_bone", qtrue );
	gi.G2API_SetBoneAnglesIndex( &ent->ghoul2[ent->playerModel], ent->lowerLumbarBone, vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL, 0, 0); 

	RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN ));
	ent->s.weapon = WP_EMPLACED_GUN;

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );
	VectorCopy( ent->s.angles, ent->lastAngles );

	// store base angles for later
	VectorCopy( ent->s.angles, ent->pos1 );

	ent->e_UseFunc = useF_emplaced_gun_use;
	ent->bounceCount = 0;//to distinguish it from the eweb

	gi.linkentity (ent);
}
Пример #29
0
void ExitEmplacedWeapon( gentity_t *ent )
{
	// requesting to unlock from the weapon
	// We'll leave the gun pointed in the direction it was last facing, though we'll cut out the pitch
	if ( ent->client )
	{
		// if we are the player we will have put down a brush that blocks NPCs so that we have a clear spot to get back out.
		//gentity_t *place = G_Find( NULL, FOFS(classname), "emp_placeholder" );

		if ( ent->health > 0 )
		{//he's still alive, and we have a placeholder, so put him back
			if ( ent->owner->nextTrain )
			{
				// reset the players position
				VectorCopy( ent->owner->nextTrain->currentOrigin, ent->client->ps.origin );
				//reset ent's size to normal
				VectorCopy( ent->owner->nextTrain->mins, ent->mins );
				VectorCopy( ent->owner->nextTrain->maxs, ent->maxs );
				//free the placeholder
				G_FreeEntity( ent->owner->nextTrain );
				//re-link the ent
				gi.linkentity( ent );
			}
			else if ( ent->owner->e_UseFunc == useF_eweb_use )//yeah, crappy way to check this, but...
			{
				// so give 'em a push away from us
				vec3_t backDir, start, end;
				trace_t trace;
				gentity_t *eweb = ent->owner;
				float curRadius = 0.0f;
				float minRadius, maxRadius;
				qboolean safeExit = qfalse;

				VectorSubtract( ent->currentOrigin, eweb->currentOrigin, backDir );
				backDir[2] = 0;
				minRadius = VectorNormalize( backDir )-8.0f;

				maxRadius = (ent->maxs[0]+ent->maxs[1])*0.5f;
				maxRadius += (eweb->maxs[0]+eweb->maxs[1])*0.5f;
				maxRadius *= 1.5f;

				if ( minRadius >= maxRadius - 1.0f )
				{
					maxRadius = minRadius + 8.0f;
				}

				ent->owner = NULL;//so his trace hits me

				for ( curRadius = minRadius; curRadius <= maxRadius; curRadius += 4.0f )
				{
					VectorMA( ent->currentOrigin, curRadius, backDir, start );
					//make sure they're not in the ground
					VectorCopy( start, end );
					start[2] += 18;
					end[2] -= 18;
					gi.trace(&trace, start, ent->mins, ent->maxs, end, ent->s.number, ent->clipmask, (EG2_Collision)0, 0);
					if ( !trace.allsolid && !trace.startsolid )
					{
						G_SetOrigin( ent, trace.endpos );
						gi.linkentity( ent );
						safeExit = qtrue;
						break;
					}
				}
				//Hmm... otherwise, don't allow them to get off?
				ent->owner = eweb;
				if ( !safeExit )
				{//don't try again for a second
					ent->owner->delay = level.time + 500;
					return;
				}
			}
		}
		else if ( ent->health <= 0 )
		{
			// dead, so give 'em a push out of the chair
			vec3_t dir;
			AngleVectors( ent->owner->s.angles, NULL, dir, NULL );

			if ( rand() & 1 )
			{
				VectorScale( dir, -1, dir );
			}

			VectorMA( ent->client->ps.velocity, 75, dir, ent->client->ps.velocity );
		}
		//don't let them move towards me for a couple frames so they don't step back into me while I'm becoming solid to them
		if ( ent->s.number < MAX_CLIENTS )
		{
			if ( ent->client->ps.pm_time < 100 )
			{
				ent->client->ps.pm_time = 100;
			}
			ent->client->ps.pm_flags |= (PMF_TIME_NOFRICTION|PMF_TIME_KNOCKBACK);
		}

		if ( !ent->owner->bounceCount )
		{//not an EWeb - the overridden bone angles will remember the angle we left it at
			VectorCopy( ent->client->ps.viewangles, ent->owner->s.angles );
			ent->owner->s.angles[PITCH] = 0;
			G_SetAngles( ent->owner, ent->owner->s.angles );
			VectorCopy( ent->owner->s.angles, ent->owner->pos1 );
		}
	}

	// Remove the emplaced gun from our inventory
	ent->client->ps.stats[STAT_WEAPONS] &= ~( 1 << WP_EMPLACED_GUN );

extern void ChangeWeapon( gentity_t *ent, int newWeapon );
extern void CG_ChangeWeapon( int num );
	if ( ent->health <= 0 ) 
	{//when die, don't set weapon back on when ejected from emplaced/eweb
		//empty hands
		ent->client->ps.weapon = WP_NONE;
		if ( ent->NPC )
		{
			ChangeWeapon( ent, ent->client->ps.weapon );	// should be OK actually.
		}
		else
		{
			CG_ChangeWeapon( ent->client->ps.weapon );
		}
		if ( ent->s.number < MAX_CLIENTS )
		{
			gi.cvar_set( "cg_thirdperson", "1" );
		}
	}
	else
	{
		// when we lock or unlock from the the gun, we get our old weapon back
		ent->client->ps.weapon = ent->owner->s.weapon;

		if ( ent->NPC )
		{//BTW, if a saber-using NPC ever gets off of an emplaced gun/eweb, this will not work, look at NPC_ChangeWeapon for the proper way
			ChangeWeapon( ent, ent->client->ps.weapon );
		}
		else
		{
			G_RemoveWeaponModels( ent );
			CG_ChangeWeapon( ent->client->ps.weapon );
			if ( ent->client->ps.weapon == WP_SABER )
			{
				WP_SaberAddG2SaberModels( ent );
			}
			else
			{
				G_CreateG2AttachedWeaponModel( ent, weaponData[ent->client->ps.weapon].weaponMdl, ent->handRBolt, 0 );
			}

			if ( ent->s.number < MAX_CLIENTS )
			{
				if ( ent->client->ps.weapon == WP_SABER )
				{
					gi.cvar_set( "cg_thirdperson", "1" );
				}
				else if ( ent->client->ps.weapon != WP_SABER && cg_gunAutoFirst.integer )
				{
					gi.cvar_set( "cg_thirdperson", "0" );
				}
			}
		}

		if ( ent->client->ps.weapon == WP_SABER )
		{
			if ( ent->owner->alt_fire )
			{
				ent->client->ps.SaberActivate();
			}
			else
			{
				ent->client->ps.SaberDeactivate();
			}
		}
	}
	//set the emplaced gun/eweb's weapon back to the emplaced gun
	ent->owner->s.weapon = WP_EMPLACED_GUN;
//	gi.G2API_DetachG2Model( &ent->ghoul2[ent->playerModel] );

	ent->s.eFlags &= ~EF_LOCKED_TO_WEAPON;
	ent->client->ps.eFlags &= ~EF_LOCKED_TO_WEAPON;

	ent->owner->noDamageTeam = TEAM_FREE;
	ent->owner->svFlags &= ~SVF_NONNPC_ENEMY;
	ent->owner->delay = level.time;
	ent->owner->activator = NULL;

	if ( !ent->NPC )
	{
		// by keeping the owner, a dead npc can be pushed out of the chair without colliding with it
		ent->owner = NULL;
	}
}
Пример #30
0
/*
================
G_RunItem

================
*/
void G_RunItem( gentity_t *ent ) {
	vec3_t		origin;
	trace_t		tr;
	int			contents;
	int			mask;

	// if groundentity has been set to -1, it may have been pushed off an edge
	if ( ent->s.groundEntityNum == ENTITYNUM_NONE ) 
	{
		if ( ent->s.pos.trType != TR_GRAVITY ) 
		{
			ent->s.pos.trType = TR_GRAVITY;
			ent->s.pos.trTime = level.time;
		}
	}

	if ( ent->s.pos.trType == TR_STATIONARY ) 
	{
		// check think function
		G_RunThink( ent );
		if ( !g_gravity->value )
		{
			ent->s.pos.trType = TR_GRAVITY;
			ent->s.pos.trTime = level.time;
			ent->s.pos.trDelta[0] += crandom() * 40.0f; // I dunno, just do this??
			ent->s.pos.trDelta[1] += crandom() * 40.0f;
			ent->s.pos.trDelta[2] += random() * 20.0f;
		}
		else if ( (ent->flags&FL_DROPPED_ITEM) 
			&& ent->item
			&& ent->item->giType == IT_WEAPON
			&& ent->item->giTag == WP_SABER )
		{//a dropped saber item, check below, just in case
			int ignore = ENTITYNUM_NONE;
			if ( ent->clipmask ) 
			{
				mask = ent->clipmask;
			} 
			else 
			{
				mask = MASK_SOLID|CONTENTS_PLAYERCLIP;//shouldn't be able to get anywhere player can't
			}
			if ( ent->owner )
			{
				ignore = ent->owner->s.number;
			}
			else if ( ent->activator )
			{
				ignore = ent->activator->s.number;
			}
			VectorSet( origin, ent->currentOrigin[0], ent->currentOrigin[1], ent->currentOrigin[2]-1 ); 
			gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, ignore, mask, (EG2_Collision)0, 0 );
			if ( !tr.allsolid
				&& !tr.startsolid
				&& tr.fraction > 0.001f )
			{//wha?  fall....
				ent->s.pos.trType = TR_GRAVITY;
				ent->s.pos.trTime = level.time;
			}
		}
		return;
	}

	// get current position
	EvaluateTrajectory( &ent->s.pos, level.time, origin );
	if ( ent->s.apos.trType != TR_STATIONARY ) 
	{
		EvaluateTrajectory( &ent->s.apos, level.time, ent->currentAngles );
		G_SetAngles( ent, ent->currentAngles );
	}

	// trace a line from the previous position to the current position
	if ( ent->clipmask ) 
	{
		mask = ent->clipmask;
	} 
	else 
	{
		mask = MASK_SOLID|CONTENTS_PLAYERCLIP;//shouldn't be able to get anywhere player can't
	}

	int ignore = ENTITYNUM_NONE;
	if ( ent->owner )
	{
		ignore = ent->owner->s.number;
	}
	else if ( ent->activator )
	{
		ignore = ent->activator->s.number;
	}
	gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, ignore, mask, (EG2_Collision)0, 0 );

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

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

	gi.linkentity( ent );	// FIXME: avoid this for stationary?

	// check think function
	G_RunThink( ent );

	if ( tr.fraction == 1 ) 
	{
		if ( g_gravity->value <= 0 )
		{
			if ( ent->s.apos.trType != TR_LINEAR )
			{
				VectorCopy( ent->currentAngles, ent->s.apos.trBase );
				ent->s.apos.trType = TR_LINEAR;
				ent->s.apos.trDelta[1] = Q_flrand( -300, 300 );
				ent->s.apos.trDelta[0] = Q_flrand( -10, 10 );
				ent->s.apos.trDelta[2] = Q_flrand( -10, 10 );
				ent->s.apos.trTime = level.time;
			}
		}
		//friction in zero-G
		if ( !g_gravity->value )
		{
			float friction = 0.975f;
			/*friction -= ent->mass/1000.0f;
			if ( friction < 0.1 )
			{
				friction = 0.1f;
			}
			*/
			VectorScale( ent->s.pos.trDelta, friction, ent->s.pos.trDelta );
			VectorCopy( ent->currentOrigin, ent->s.pos.trBase );
			ent->s.pos.trTime = level.time;
		}
		return;
	}

	// if it is in a nodrop volume, remove it
	contents = gi.pointcontents( ent->currentOrigin, -1 );
	if ( contents & CONTENTS_NODROP ) 
	{
		G_FreeEntity( ent );
		return;
	}

	if ( !tr.startsolid )
	{
		G_BounceItem( ent, &tr );
	}
}