Пример #1
0
/*QUAKED target_autosave (1 1 0) (-8 -8 -8) (8 8 8)
saves game to 'autosave.sav' when triggered then dies.
*/
void SP_target_autosave(gentity_t *ent)
{
//	ent->use = Use_Target_Autosave;
	G_FreeEntity(ent);
}
Пример #2
0
/*
==================
Cmd_Give_f

Give items to a client
==================
*/
void Cmd_Give_f (gentity_t *ent)
{
	char		*name;
	gitem_t		*it;
	int			i;
	qboolean	give_all;
	gentity_t		*it_ent;
	trace_t		trace;

	if ( !CheatsOk( ent ) ) {
		return;
	}

	name = ConcatArgs( 1 );

	if (Q_stricmp(name, "all") == 0)
		give_all = qtrue;
	else
		give_all = qfalse;

	if (give_all || Q_stricmp( name, "health") == 0)
	{
		ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
		if (!give_all)
			return;
	}

	if (give_all || Q_stricmp(name, "weapons") == 0)
	{
		ent->client->ps.stats[STAT_WEAPONS] = (1 << WP_NUM_WEAPONS) - 1 - 
			( 1 << WP_GRAPPLING_HOOK ) - ( 1 << WP_NONE );
		if (!give_all)
			return;
	}

	if (give_all || Q_stricmp(name, "ammo") == 0)
	{
		for ( i = 0 ; i < MAX_WEAPONS ; i++ ) {
			ent->client->ps.ammo[i] = 999;
		}
		if (!give_all)
			return;
	}

	if (give_all || Q_stricmp(name, "armor") == 0)
	{
		ent->client->ps.stats[STAT_ARMOR] = 200;

		if (!give_all)
			return;
	}

	if (Q_stricmp(name, "excellent") == 0) {
		ent->client->ps.persistant[PERS_EXCELLENT_COUNT]++;
		return;
	}
	if (Q_stricmp(name, "impressive") == 0) {
		ent->client->ps.persistant[PERS_IMPRESSIVE_COUNT]++;
		return;
	}
	if (Q_stricmp(name, "gauntletaward") == 0) {
		ent->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT]++;
		return;
	}
	if (Q_stricmp(name, "defend") == 0) {
		ent->client->ps.persistant[PERS_DEFEND_COUNT]++;
		return;
	}
	if (Q_stricmp(name, "assist") == 0) {
		ent->client->ps.persistant[PERS_ASSIST_COUNT]++;
		return;
	}

	// spawn a specific item right on the player
	if ( !give_all ) {
		it = BG_FindItem (name);
		if (!it) {
			return;
		}

		it_ent = G_Spawn();
		VectorCopy( ent->r.currentOrigin, it_ent->s.origin );
		it_ent->classname = it->classname;
		G_SpawnItem (it_ent, it);
		FinishSpawningItem(it_ent );
		memset( &trace, 0, sizeof( trace ) );
		Touch_Item (it_ent, ent, &trace);
		if (it_ent->inuse) {
			G_FreeEntity( it_ent );
		}
	}
}
Пример #3
0
/**
* @brief Run item.
*/
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 == -1)
	{
		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 || ent->s.pos.trType == TR_GRAVITY_PAUSED) // check think function
	{
		G_RunThink(ent);
		return;
	}

	if (ent->s.pos.trType == TR_LINEAR && (!ent->clipmask && !ent->r.contents))
	{
		// check think function
		G_RunThink(ent);
		return;
	}

	// get current position
	BG_EvaluateTrajectory(&ent->s.pos, level.time, origin, qfalse, ent->s.effect2Time);

	// trace a line from the previous position to the current position
	if (ent->clipmask)
	{
		mask = ent->clipmask;
	}
	else
	{
		mask = MASK_SOLID;
	}
	trap_Trace(&tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin,
	           ent->r.ownerNum, mask);

	if (ent->isProp && ent->takedamage)
	{
		G_RunItemProp(ent, origin);
	}

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

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

	trap_LinkEntity(ent);   // FIXME: avoid this for stationary?

	// check think function
	G_RunThink(ent);

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

	// if it is in a nodrop volume, remove it
	contents = trap_PointContents(ent->r.currentOrigin, -1);
	if (contents & CONTENTS_NODROP)
	{
		if (ent->item && ent->item->giType == IT_TEAM)
		{
			Team_ReturnFlag(ent);
		}
		else
		{
			G_FreeEntity(ent);
		}
		return;
	}

	G_BounceItem(ent, &tr);
}
Пример #4
0
void trigger_always_think(gentity_t *ent)
{
    G_UseTargets(ent, ent);
    G_FreeEntity(ent);
}
Пример #5
0
/*
==================
Cmd_Give_f

Give items to a client
==================
*/
void Cmd_Give_f (gentity_t *ent)
{
	char		*name;
	gitem_t		*it;
	int			i;
	qboolean	give_all;

	if ( !CheatsOk( ent ) ) {
		return;
	}

	name = ConcatArgs( 1 );

	if (Q_stricmp(name, "all") == 0)
		give_all = qtrue;
	else
		give_all = qfalse;

	if (give_all || Q_stricmp(name, "force") == 0)
	{
		if ( ent->client )
		{
			ent->client->ps.forcePower = FORCE_POWER_MAX;
		}
		if (!give_all)
			return;
	}

	if (give_all || Q_stricmp(gi.argv(1), "health") == 0)
	{
		if (gi.argc() == 3) {
			ent->health = atoi(gi.argv(2));
			if (ent->health > ent->client->ps.stats[STAT_MAX_HEALTH]) {
				ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
			}
		}
		else {
			ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
		}
		if (!give_all)
			return;
	}


/*	if (give_all || Q_stricmp(name, "inventory") == 0)
	{
		// Huh?  Was doing a INV_MAX+1 which was wrong because then you'd actually have every inventory item including INV_MAX
		ent->client->ps.stats[STAT_ITEMS] = (1 << (INV_MAX)) - ( 1 << INV_ELECTROBINOCULARS );

		ent->client->ps.inventory[INV_ELECTROBINOCULARS] = 1;
		//ent->client->ps.inventory[INV_BACTA_CANISTER] = 5;
		//ent->client->ps.inventory[INV_SEEKER] = 5;
		ent->client->ps.inventory[INV_LIGHTAMP_GOGGLES] = 1;
		//ent->client->ps.inventory[INV_SENTRY] = 5;
		//ent->client->ps.inventory[INV_GOODIE_KEY] = 5;
		//ent->client->ps.inventory[INV_SECURITY_KEY] = 5;

		if (!give_all)
		{
			return;
		}
	}
*/
	if (give_all || Q_stricmp(name, "weapons") == 0)
	{
		ent->client->ps.stats[STAT_WEAPONS] = (1 << (WP_MELEE)) - ( 1 << WP_NONE );
		if (!give_all)
			return;
	}

	if ( !give_all && Q_stricmp(gi.argv(1), "weaponnum") == 0 )
	{
		ent->client->ps.stats[STAT_WEAPONS] |= (1 << atoi(gi.argv(2)));
		return;
	}

	if ( Q_stricmp(name, "eweaps") == 0)	//for developing, gives you all the weapons, including enemy
	{
		ent->client->ps.stats[STAT_WEAPONS] = (unsigned)(1 << WP_NUM_WEAPONS) - ( 1 << WP_NONE ); // NOTE: this wasn't giving the last weapon in the list
		if (!give_all)
			return;
	}

	if (give_all || Q_stricmp(name, "ammo") == 0)
	{
		for ( i = 0 ; i < AMMO_MAX ; i++ ) {
			ent->client->ps.ammo[i] = ammoData[i].max;
		}
		if (!give_all)
			return;
	}

	if (give_all || Q_stricmp(gi.argv(1), "batteries") == 0)
	{
		if (gi.argc() == 3)
			ent->client->ps.batteryCharge = atoi(gi.argv(2));
		else
			ent->client->ps.batteryCharge = MAX_BATTERIES;

		if (!give_all)
			return;
	}

	if (give_all || Q_stricmp(gi.argv(1), "armor") == 0)
	{
		if (gi.argc() == 3)
			ent->client->ps.stats[STAT_ARMOR] = atoi(gi.argv(2));
		else
			ent->client->ps.stats[STAT_ARMOR] = ent->client->ps.stats[STAT_MAX_HEALTH];

		if ( ent->client->ps.stats[STAT_ARMOR] > 0 )
		{
			ent->client->ps.powerups[PW_BATTLESUIT] = Q3_INFINITE;
		}
		else
		{
			ent->client->ps.powerups[PW_BATTLESUIT] = 0;
		}

		if (!give_all)
			return;
	}

	// spawn a specific item right on the player
	if ( !give_all ) {
		gentity_t	*it_ent;
		trace_t		trace;
		it = FindItem (name);
		if (!it) {
			name = gi.argv(1);
			it = FindItem (name);
			if (!it) {
				gi.SendServerCommand( ent-g_entities, "print \"unknown item\n\"");
				return;
			}
		}

		it_ent = G_Spawn();
		VectorCopy( ent->currentOrigin, it_ent->s.origin );
		it_ent->classname = G_NewString(it->classname);
		G_SpawnItem (it_ent, it);
		FinishSpawningItem(it_ent );
		memset( &trace, 0, sizeof( trace ) );
		Touch_Item (it_ent, ent, &trace);
		if (it_ent->inuse) {
			G_FreeEntity( it_ent );
		}
	}
}
Пример #6
0
qboolean IsLegShot( gentity_t *targ, vec3_t dir, vec3_t point, int mod ) {
	float height;
	float theight;
	gentity_t *leg;

	if (!(targ->client))
		return qfalse;

	if (targ->health <= 0)
		return qfalse;

	if(!point) {
		return qfalse;
	}

	if(!IsHeadShotWeapon(mod)) {
		return qfalse;
	}

	leg = G_BuildLeg( targ );

	if( leg ) {
		gentity_t	*traceEnt;
		vec3_t		start, end;
		trace_t		tr;

		// trace another shot see if we hit the legs
		VectorCopy( point, start );
		VectorMA( start, 64, dir, end );
		trap_Trace( &tr, start, NULL, NULL, end, targ->s.number, MASK_SHOT );
			
		traceEnt = &g_entities[ tr.entityNum ];

		if( g_debugBullets.integer >= 3 ) {	// show hit player head bb
			gentity_t *tent;
			vec3_t b1, b2;
			VectorCopy( leg->r.currentOrigin, b1 );
			VectorCopy( leg->r.currentOrigin, b2 );
			VectorAdd( b1, leg->r.mins, b1 );
			VectorAdd( b2, leg->r.maxs, b2 );
			tent = G_TempEntity( b1, EV_RAILTRAIL );
			VectorCopy( b2, tent->s.origin2 );
			tent->s.dmgFlags = 1;

			// show headshot trace
			// end the headshot trace at the head box if it hits
			if( tr.fraction != 1 ) {
				VectorMA( start, (tr.fraction * 64), dir, end );
			}
			tent = G_TempEntity( start, EV_RAILTRAIL );
			VectorCopy( end, tent->s.origin2 );
			tent->s.dmgFlags = 0;
		}

		G_FreeEntity( leg );

		if( traceEnt == leg ) {
			return qtrue;
		}
	} else {
		height = point[2] - targ->r.absmin[2];
		theight = targ->r.absmax[2] - targ->r.absmin[2];

		if(height < (theight * 0.4f)) {
			return qtrue;
		}
	}

	return qfalse;
}
Пример #7
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 );
	}
}
Пример #8
0
/*
================
G_MissileImpact

================
*/
void G_MissileImpact( gentity_t *ent, trace_t *trace )
{
    gentity_t   *other, *attacker;
    qboolean    returnAfterDamage = qfalse;
    vec3_t      dir;

    other = &g_entities[ trace->entityNum ];
    attacker = &g_entities[ ent->r.ownerNum ];

    // check for bounce
    if( !other->takedamage &&
            ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) )
    {
        G_BounceMissile( ent, trace );

        //only play a sound if requested
        if( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
            G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );

        return;
    }

    if( !strcmp( ent->classname, "grenade" ) )
    {
        //grenade doesn't explode on impact
        G_BounceMissile( ent, trace );

        //only play a sound if requested
        if( !( ent->s.eFlags & EF_NO_BOUNCE_SOUND ) )
            G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );

        return;
    }
    else if( !strcmp( ent->classname, "lockblob" ) )
    {
        if( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
        {
            other->client->ps.stats[ STAT_STATE ] |= SS_BLOBLOCKED;
            other->client->lastLockTime = level.time;
            AngleVectors( other->client->ps.viewangles, dir, NULL, NULL );
            other->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir );
        }
    }
    else if( !strcmp( ent->classname, "slowblob" ) )
    {
        if( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
        {
            other->client->ps.stats[ STAT_STATE ] |= SS_SLOWLOCKED;
            other->client->lastSlowTime = level.time;
            AngleVectors( other->client->ps.viewangles, dir, NULL, NULL );
            other->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir );
        }
    }
    else if( !strcmp( ent->classname, "hive" ) )
    {
        if( other->s.eType == ET_BUILDABLE && other->s.modelindex == BA_A_HIVE )
        {
            if( !ent->parent )
                G_Printf( S_COLOR_YELLOW "WARNING: hive entity has no parent in G_MissileImpact\n" );
            else
                ent->parent->active = qfalse;

            G_FreeEntity( ent );
            return;
        }
        else
        {
            //prevent collision with the client when returning
            ent->r.ownerNum = other->s.number;

            ent->think = G_ExplodeMissile;
            ent->nextthink = level.time + FRAMETIME;

            //only damage humans
            if( other->client && other->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS )
                returnAfterDamage = qtrue;
            else
                return;
        }
    }

    // impact damage
    if( other->takedamage )
    {
        // FIXME: wrong damage direction?
        if( ent->damage )
        {
            vec3_t  velocity;

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

            G_Damage( other, ent, attacker, velocity, ent->s.origin, ent->damage,
                      DAMAGE_NO_LOCDAMAGE, ent->methodOfDeath );
        }
    }

    if( returnAfterDamage )
        return;

    // is it cheaper in bandwidth to just remove this ent and create a new
    // one, rather than changing the missile into the explosion?

    if( other->takedamage &&
            ( other->s.eType == ET_PLAYER || other->s.eType == ET_BUILDABLE ) )
    {
        G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
        ent->s.otherEntityNum = other->s.number;
    }
    else if( trace->surfaceFlags & SURF_METALSTEPS )
        G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
    else
        G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );

    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

    G_SetOrigin( ent, trace->endpos );

    // splash damage (doesn't apply to person directly hit)
    if( ent->splashDamage )
        G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
                        other, ent->splashMethodOfDeath );

    trap_LinkEntity( ent );
}
Пример #9
0
/*
================
G_RunMissile

================
*/
void G_RunMissile( gentity_t *ent )
{
    vec3_t    origin;
    trace_t   tr;
    int       passent;
    qboolean  impact = qfalse;

    // get current position
    BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );

    // ignore interactions with the missile owner
    passent = ent->r.ownerNum;

    // general trace to see if we hit anything at all
    trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs,
                origin, passent, ent->clipmask );

    if( tr.startsolid || tr.allsolid )
    {
        tr.fraction = 0.0f;
        VectorCopy( ent->r.currentOrigin, tr.endpos );
    }

    if( tr.fraction < 1.0f )
    {
        if( !ent->pointAgainstWorld || tr.contents & CONTENTS_BODY )
        {
            // We hit an entity or we don't care
            impact = qtrue;
        }
        else
        {
            trap_Trace( &tr, ent->r.currentOrigin, NULL, NULL, origin,
                        passent, ent->clipmask );

            if( tr.fraction < 1.0f )
            {
                // Hit the world with point trace
                impact = qtrue;
            }
            else
            {
                if( tr.contents & CONTENTS_BODY )
                {
                    // Hit an entity
                    impact = qtrue;
                }
                else
                {
                    trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs,
                                origin, passent, CONTENTS_BODY );

                    if( tr.fraction < 1.0f )
                        impact = qtrue;
                }
            }
        }
    }

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

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

        G_MissileImpact( ent, &tr );

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

    ent->r.contents = CONTENTS_SOLID; //trick trap_LinkEntity into...
    trap_LinkEntity( ent );
    ent->r.contents = 0; //...encoding bbox information

    // check think function after bouncing
    G_RunThink( ent );
}
Пример #10
0
// Set up snapshot merge based on this portal
qboolean G_smvRunCamera( gentity_t *ent ) {
	int id = ent->TargetFlag;
	int chargeTime, sprintTime, hintTime, weapHeat;
	playerState_t *tps, *ps;

	// Opt out if not a real MV portal
	if ( ent->tagParent == NULL || ent->tagParent->client == NULL ) {
		return( qfalse );
	}

	if ( ( ps = &ent->tagParent->client->ps ) == NULL ) {
		return( qfalse );
	}

	// If viewing client is no longer connected, delete this camera
	if ( ent->tagParent->client->pers.connected != CON_CONNECTED ) {
		G_FreeEntity( ent );
		return( qtrue );
	}

	// Also remove if the target player is no longer in the game playing
	if ( ent->target_ent->client->pers.connected != CON_CONNECTED ||
		 ent->target_ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
		G_smvLocateEntityInMVList( ent->tagParent, ent->target_ent - g_entities, qtrue );
		return( qtrue );
	}

	// Seems that depending on player's state, we pull from either r.currentOrigin, or s.origin
	//		if(!spec) then use: r.currentOrigin
	//		if(spec) then use:  s.origin
	//
	// This is true for both the portal origin and its target (origin2)
	//
	VectorCopy( ent->tagParent->s.origin, ent->s.origin );
	G_SetOrigin( ent, ent->s.origin );
	VectorCopy( ent->target_ent->r.currentOrigin, ent->s.origin2 );
	trap_LinkEntity( ent );

	// Only allow client ids 0 to (MAX_MVCLIENTS-1) to be updated with extra info
	if ( id >= MAX_MVCLIENTS ) {
		return( qtrue );
	}

	tps = &ent->target_ent->client->ps;

	if ( tps->stats[STAT_PLAYER_CLASS] == PC_ENGINEER ) {
		chargeTime = g_engineerChargeTime.value;
	} else if ( tps->stats[STAT_PLAYER_CLASS] == PC_MEDIC ) {
		chargeTime = g_medicChargeTime.value;
	} else if ( tps->stats[STAT_PLAYER_CLASS] == PC_FIELDOPS )                                                                                                {
		chargeTime = g_LTChargeTime.value;
	} else if ( tps->stats[STAT_PLAYER_CLASS] == PC_COVERTOPS )                                                                                                                                                                                               {
		chargeTime = g_covertopsChargeTime.value;
	} else { chargeTime = g_soldierChargeTime.value;}

	chargeTime = ( level.time - tps->classWeaponTime >= (int)chargeTime ) ? 0 : ( 1 + floor( 15.0f * (float)( level.time - tps->classWeaponTime ) / chargeTime ) );
	sprintTime = ( ent->target_ent->client->pmext.sprintTime >= 20000 ) ? 0.0f : ( 1 + floor( 7.0f * (float)ent->target_ent->client->pmext.sprintTime / 20000.0f ) );
	weapHeat   = floor( (float)tps->curWeapHeat * 15.0f / 255.0f );
	hintTime   = ( tps->serverCursorHint != HINT_BUILD && ( tps->serverCursorHintVal >= 255 || tps->serverCursorHintVal == 0 ) ) ?
				 0 : ( 1 + floor( 15.0f * (float)tps->serverCursorHintVal / 255.0f ) );

	// (Remaining bits)
	// ammo      : 0
	// ammo-1    : 0
	// ammiclip  : 0
	// ammoclip-1: 16
	id = MAX_WEAPONS - 1 - ( id * 2 );

	if ( tps->pm_flags & PMF_LIMBO ) {
		ps->ammo[id] = 0;
		ps->ammo[id - 1] = 0;
		ps->ammoclip[id - 1] = 0;
	} else {
		ps->ammo[id]  = ( ( ( ent->target_ent->health > 0 ) ? ent->target_ent->health : 0 ) & 0xFF ); // Meds up to 140 :(
		ps->ammo[id] |= ( hintTime & 0x0F ) << 8; // 4 bits for work on current item (dynamite, weapon repair, etc.)
		ps->ammo[id] |= ( weapHeat & 0x0F ) << 12; // 4 bits for weapon heat info

		ps->ammo[id - 1]  = tps->ammo[BG_FindAmmoForWeapon( tps->weapon )] & 0x3FF;   // 11 bits needed to cover 1500 Venom ammo
		ps->ammo[id - 1] |= ( BG_simpleWeaponState( tps->weaponstate ) & 0x03 ) << 11;  // 2 bits for current weapon state
		ps->ammo[id - 1] |= ( ( tps->persistant[PERS_HWEAPON_USE] ) ? 1 : 0 ) << 13;    // 1 bit for mg42 use
		ps->ammo[id - 1] |= ( BG_simpleHintsCollapse( tps->serverCursorHint, hintTime ) & 0x03 ) << 14; // 2 bits for cursor hints

//	G_Printf("tps->hint: %d, dr: %d, collapse: %d\n", tps->serverCursorHint, HINT_DOOR_ROTATING, G_simpleHintsCollapse(tps->serverCursorHint, hintTime));

		ps->ammoclip[id - 1]  = tps->ammoclip[BG_FindClipForWeapon( tps->weapon )] & 0x1FF;   // 9 bits to cover 500 Venom ammo clip
		ps->ammoclip[id - 1] |= ( chargeTime & 0x0F ) << 9;   // 4 bits for weapon charge time
		ps->ammoclip[id - 1] |= ( sprintTime & 0x07 ) << 13;  // 3 bits for fatigue
	}

	return( qtrue );
}
Пример #11
0
/*
QUAKED trigger_concussive_dust (.5 .5 .5) ?
Allows client side prediction of teleportation events.
Must point at a target_position, which will be the teleport destination.
*/
void SP_trigger_concussive_dust(gentity_t *self)
{
	G_Printf("trigger_concussive_dust is obsolete, please delete it.\n");
	G_FreeEntity(self);
}
Пример #12
0
void FinishSpawningItem( gentity_t *ent ) {
	trace_t		tr;
	vec3_t		dest;
	gitem_t		*item;
	int			itemNum;

	itemNum=1;
	for ( item = bg_itemlist + 1 ; item->classname ; item++,itemNum++) 
	{
		if (!strcmp(item->classname,ent->classname))
		{
			break;
		}
	}

	// Set bounding box for item
	VectorSet( ent->mins, item->mins[0],item->mins[1] ,item->mins[2]);
	VectorSet( ent->maxs, item->maxs[0],item->maxs[1] ,item->maxs[2]);

	if ((!ent->mins[0] && !ent->mins[1] && !ent->mins[2]) && 
		(!ent->maxs[0] && !ent->maxs[1] && !ent->maxs[2]))
	{
		VectorSet (ent->mins, -ITEM_RADIUS, -ITEM_RADIUS, -2);//to match the comments in the items.dat file!
		VectorSet (ent->maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
	}

	if ((item->quantity) && (item->giType == IT_AMMO))
	{
		ent->count = item->quantity;
	}

	if ((item->quantity) && (item->giType == IT_BATTERY))
	{
		ent->count = item->quantity; 
	}


//	if ( item->giType == IT_WEAPON ) // NOTE: james thought it was ok to just always do this?
	{
		ent->s.radius = 20;
		VectorSet( ent->s.modelScale, 1.0f, 1.0f, 1.0f );
		gi.G2API_InitGhoul2Model( ent->ghoul2, ent->item->world_model, G_ModelIndex( ent->item->world_model ), NULL, NULL, 0, 0);
	}

	// Set crystal ammo amount based on skill level
/*	if ((itemNum == ITM_AMMO_CRYSTAL_BORG) ||
		(itemNum == ITM_AMMO_CRYSTAL_DN) ||
		(itemNum == ITM_AMMO_CRYSTAL_FORGE) ||
		(itemNum == ITM_AMMO_CRYSTAL_SCAVENGER) ||
		(itemNum == ITM_AMMO_CRYSTAL_STASIS))
	{
		CrystalAmmoSettings(ent);
	}
*/
	ent->s.eType = ET_ITEM;
	ent->s.modelindex = ent->item - bg_itemlist;		// store item number in modelindex
	ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item

	ent->contents = CONTENTS_TRIGGER|CONTENTS_ITEM;//CONTENTS_BODY;//CONTENTS_TRIGGER|
	ent->e_TouchFunc = touchF_Touch_Item;
	// useing an item causes it to respawn
	ent->e_UseFunc = useF_Use_Item;
	ent->svFlags |= SVF_PLAYER_USABLE;//so player can pick it up

	// Hang in air?
	ent->s.origin[2] += 1;//just to get it off the damn ground because coplanar = insolid
	if ( ent->spawnflags & ITMSF_SUSPEND) 
	{
		// suspended
		G_SetOrigin( ent, ent->s.origin );
	} 
	else 
	{
		// drop to floor
		VectorSet( dest, ent->s.origin[0], ent->s.origin[1], MIN_WORLD_COORD );
		gi.trace( &tr, ent->s.origin, ent->mins, ent->maxs, dest, ent->s.number, MASK_SOLID|CONTENTS_PLAYERCLIP, G2_NOCOLLIDE, 0 );
		if ( tr.startsolid ) 
		{
			if ( &g_entities[tr.entityNum] != NULL )
			{
				gi.Printf (S_COLOR_RED"FinishSpawningItem: removing %s startsolid at %s (in a %s)\n", ent->classname, vtos(ent->s.origin), g_entities[tr.entityNum].classname );
			}
			else
			{
				gi.Printf (S_COLOR_RED"FinishSpawningItem: removing %s startsolid at %s (in a %s)\n", ent->classname, vtos(ent->s.origin) );
			}
			assert( 0 && "item starting in solid");
#ifndef FINAL_BUILD
			if (!g_entities[ENTITYNUM_WORLD].s.radius){	//not a region
				delayedShutDown = level.time + 100;
			}
#endif
			G_FreeEntity( ent );
			return;
		}

		// allow to ride movers
		ent->s.groundEntityNum = tr.entityNum;

		G_SetOrigin( ent, tr.endpos );
	}

/* ? don't need this
	// team slaves and targeted items aren't present at start
	if ( ( ent->flags & FL_TEAMSLAVE ) || ent->targetname ) {
		ent->s.eFlags |= EF_NODRAW;
		ent->contents = 0;
		return;
	}
*/
	if ( ent->spawnflags & ITMSF_INVISIBLE ) // invisible
	{
		ent->s.eFlags |= EF_NODRAW;
		ent->contents = 0;
	}

	if ( ent->spawnflags & ITMSF_NOTSOLID ) // not solid
	{
		ent->contents = 0;
	}

	gi.linkentity (ent);
}
Пример #13
0
void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) {
	int			respawn = 0;

	if (!other->client)
		return;
	if (other->health < 1)
		return;		// dead people can't pickup

	if ( other->client->ps.pm_time > 0 )
	{//cant pick up when out of control
		return;
	}

	// Only monsters can pick it up
	if ((ent->spawnflags &  ITMSF_MONSTER) && (other->client->playerTeam == TEAM_PLAYER))
	{
		return;
	}

	// Only starfleet can pick it up
	if ((ent->spawnflags &  ITMSF_TEAM) && (other->client->playerTeam != TEAM_PLAYER))
	{
		return;
	}

	
	if ( other->client->NPC_class == CLASS_ATST || 
		other->client->NPC_class == CLASS_GONK || 
		other->client->NPC_class == CLASS_MARK1 || 
		other->client->NPC_class == CLASS_MARK2 || 
		other->client->NPC_class == CLASS_MOUSE || 
		other->client->NPC_class == CLASS_PROBE || 
		other->client->NPC_class == CLASS_PROTOCOL || 
		other->client->NPC_class == CLASS_R2D2 || 
		other->client->NPC_class == CLASS_R5D2 || 
		other->client->NPC_class == CLASS_SEEKER || 
		other->client->NPC_class == CLASS_REMOTE || 
		other->client->NPC_class == CLASS_SENTRY )
	{//FIXME: some flag would be better
		//droids can't pick up items/weapons!
		return;
	}

	//FIXME: need to make them run toward a dropped weapon when fleeing without one?
	//FIXME: need to make them come out of flee mode when pick up their old weapon?
	if ( CheckItemCanBePickedUpByNPC( ent, other ) )
	{
		if ( other->NPC && other->NPC->goalEntity && other->NPC->goalEntity->enemy == ent )
		{//they were running to pick me up, they did, so clear goal
			other->NPC->goalEntity = NULL;
			other->NPC->squadState = SQUAD_STAND_AND_SHOOT;
		}
	}
	else if (!(ent->spawnflags &  ITMSF_TEAM) && !(ent->spawnflags &  ITMSF_MONSTER))
	{// Only player can pick it up
		if ( other->s.number != 0 )	// Not the player?
		{
			return;
		}
	}

	// the same pickup rules are used for client side and server side
	if ( !BG_CanItemBeGrabbed( &ent->s, &other->client->ps ) ) {
		return;
	}

	if ( other->client )
	{
		if ( other->client->ps.eFlags&EF_FORCE_GRIPPED )
		{//can't pick up anything while being gripped
			return;
		}
		if ( PM_InKnockDown( &other->client->ps ) && !PM_InGetUp( &other->client->ps ) )
		{//can't pick up while in a knockdown
			return;
		}
	}
	if (!ent->item) {		//not an item!
		gi.Printf( "Touch_Item: %s is not an item!\n", ent->classname);
		return;
	}
	qboolean bHadWeapon = qfalse;
	// call the item-specific pickup function
	switch( ent->item->giType ) 
	{
	case IT_WEAPON:
		if ( other->NPC && other->s.weapon == WP_NONE )
		{//Make them duck and sit here for a few seconds
			int pickUpTime = Q_irand( 1000, 3000 );
			TIMER_Set( other, "duck", pickUpTime );
			TIMER_Set( other, "roamTime", pickUpTime );
			TIMER_Set( other, "stick", pickUpTime );
			TIMER_Set( other, "verifyCP", pickUpTime );
			TIMER_Set( other, "attackDelay", 600 );
			respawn = 0;
		}
		if ( other->client->ps.stats[STAT_WEAPONS] & ( 1 << ent->item->giTag ) )
		{
			bHadWeapon = qtrue;
		}
		respawn = Pickup_Weapon(ent, other);
		break;
	case IT_AMMO:
		respawn = Pickup_Ammo(ent, other);
		break;
	case IT_ARMOR:
		respawn = Pickup_Armor(ent, other);
		break;
	case IT_HEALTH:
		respawn = Pickup_Health(ent, other);
		break;
	case IT_HOLDABLE:
		respawn = Pickup_Holdable(ent, other);
		break;
	case IT_BATTERY:
		respawn = Pickup_Battery( ent, other );
		break;
	case IT_HOLOCRON:
		respawn = Pickup_Holocron( ent, other );
		break;
	default:
		return;
	}

	if ( !respawn ) 
	{
		return;
	}

	// play the normal pickup sound
	if ( !other->s.number && g_timescale->value < 1.0f  )
	{//SIGH... with timescale on, you lose events left and right
extern void CG_ItemPickup( int itemNum, qboolean bHadItem );
		// but we're SP so we'll cheat
		cgi_S_StartSound( NULL, other->s.number, CHAN_AUTO,	cgi_S_RegisterSound( ent->item->pickup_sound ) );
		// show icon and name on status bar
		CG_ItemPickup( ent->s.modelindex, bHadWeapon );
	}
	else
	{
		if ( bHadWeapon )
		{
			G_AddEvent( other, EV_ITEM_PICKUP, -ent->s.modelindex );
		} 
		else
		{
			G_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex );
		}
	}

	// fire item targets
	G_UseTargets (ent, other);

	// wait of -1 will not respawn
//	if ( ent->wait == -1 ) 
	{
		//why not just remove me?
		G_FreeEntity( ent );
		/*
		//NOTE: used to do this:  (for respawning?)
		ent->svFlags |= SVF_NOCLIENT;
		ent->s.eFlags |= EF_NODRAW;
		ent->contents = 0;
		ent->unlinkAfterEvent = qtrue;
		*/
		return;
	}
}
Пример #14
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;
		}
		return;
	}

	// get current position
	EvaluateTrajectory( &ent->s.pos, level.time, origin );

	// 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, G2_NOCOLLIDE, 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 );
	}
}
Пример #15
0
/*
===================
G_SpawnGEntityFromSpawnVars

Spawn an entity and fill in all of the level fields from
level.spawnVars[], then call the class specfic spawn function
===================
*/
void G_SpawnGEntityFromSpawnVars( void ) {
	int			i;
	gentity_t	*ent;
	char		*s, *value, *gametypeName;
	static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester"};
	int spawnVarsOffset[MAX_SPAWN_VARS][2];	// key / value pairs offsets

	// Convert to offsets.
	for (i = 0; i < level.numSpawnVars; ++i) {
		spawnVarsOffset[i][0] = level.spawnVars[i][0] - level.spawnVarChars;
		spawnVarsOffset[i][1] = level.spawnVars[i][1] - level.spawnVarChars;
	}

	// Early out if spawn is not required.
	if (!dmlab_update_spawn_vars(
			level.spawnVarChars,
			&level.numSpawnVarChars,
			spawnVarsOffset,
			&level.numSpawnVars)) {
		return;
	}

	// Convert from offsets.
	for (i = 0; i < level.numSpawnVars; ++i) {
		level.spawnVars[i][0] = level.spawnVarChars + spawnVarsOffset[i][0];
		level.spawnVars[i][1] = level.spawnVarChars + spawnVarsOffset[i][1];
	}

	// get the next free entity
	ent = G_Spawn();

	for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
		G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );
	}

	// check for "notsingle" flag
	if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
		G_SpawnInt( "notsingle", "0", &i );
		if ( i ) {
			ADJUST_AREAPORTAL();
			G_FreeEntity( ent );
			return;
		}
	}
	// check for "notteam" flag (GT_FFA, GT_TOURNAMENT, GT_SINGLE_PLAYER)
	if ( g_gametype.integer >= GT_TEAM ) {
		G_SpawnInt( "notteam", "0", &i );
		if ( i ) {
			ADJUST_AREAPORTAL();
			G_FreeEntity( ent );
			return;
		}
	} else {
		G_SpawnInt( "notfree", "0", &i );
		if ( i ) {
			ADJUST_AREAPORTAL();
			G_FreeEntity( ent );
			return;
		}
	}

#ifdef MISSIONPACK
	G_SpawnInt( "notta", "0", &i );
	if ( i ) {
		ADJUST_AREAPORTAL();
		G_FreeEntity( ent );
		return;
	}
#else
	G_SpawnInt( "notq3a", "0", &i );
	if ( i ) {
		ADJUST_AREAPORTAL();
		G_FreeEntity( ent );
		return;
	}
#endif

	if( G_SpawnString( "gametype", NULL, &value ) ) {
		if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {
			gametypeName = gametypeNames[g_gametype.integer];

			s = strstr( value, gametypeName );
			if( !s ) {
				ADJUST_AREAPORTAL();
				G_FreeEntity( ent );
				return;
			}
		}
	}

	// move editor origin to pos
	VectorCopy( ent->s.origin, ent->s.pos.trBase );
	VectorCopy( ent->s.origin, ent->r.currentOrigin );

	// if we didn't get a classname, don't bother spawning anything
	if ( !G_CallSpawn( ent ) ) {
		G_FreeEntity( ent );
	}
}
Пример #16
0
void G_delayPrint( gentity_t *dpent ) {
	int think_next = 0;
	bool fFree = true;

	switch ( dpent->spawnflags ) {
	case DP_PAUSEINFO:
	{
		if ( level.match_pause > PAUSE_UNPAUSING ) {
			int cSeconds = match_timeoutlength.integer * 1000 - ( level.time - dpent->timestamp );

			if ( cSeconds > 1000 ) {
				AP( va( "cp \"^3Match resuming in ^1%d^3 seconds!\n\"", cSeconds / 1000 ) );
				think_next = level.time + 15000;
				fFree = false;
			} else {
				level.match_pause = PAUSE_UNPAUSING;
				AP( "print \"^3Match resuming in 10 seconds!\n\"" );
				G_globalSound( "sound/osp/prepare.wav" );
				G_spawnPrintf( DP_UNPAUSING, level.time + 10, NULL );
			}
		}
		break;
	}

	case DP_UNPAUSING:
	{
		if ( level.match_pause == PAUSE_UNPAUSING ) {
			int cSeconds = 11 * 1000 - ( level.time - dpent->timestamp );

			if ( cSeconds > 1000 ) {
				AP( va( "cp \"^3Match resuming in ^1%d^3 seconds!\n\"", cSeconds / 1000 ) );
				think_next = level.time + 1000;
				fFree = false;
			} else {
				level.match_pause = PAUSE_NONE;
				G_globalSound( "sound/osp/fight.wav" );
				G_printFull( "^1FIGHT!", NULL );
				trap_SetConfigstring( CS_LEVEL_START_TIME, va( "%i", level.startTime + level.timeDelta ) );
				level.server_settings &= ~CV_SVS_PAUSE;
				trap_SetConfigstring( CS_SERVERTOGGLES, va( "%d", level.server_settings ) );
			}
		}
		break;
	}

	case DP_MVSPAWN:
	{
		int i;
		gentity_t *ent;

		for ( i = 0; i < level.numConnectedClients; i++ ) {
			ent = g_entities + level.sortedClients[i];

			if ( ent->client->pers.mvReferenceList == 0 ) {
				continue;
			}
			if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) {
				continue;
			}
			G_smvRegenerateClients( ent, ent->client->pers.mvReferenceList );
		}

		break;
	}

	default:
		break;
	}

	dpent->nextthink = think_next;
	if ( fFree ) {
		dpent->think = 0;
		G_FreeEntity( dpent );
	}
}
Пример #17
0
/*
================
G_RunFrame

Advances the non-player objects in the world
================
*/
void G_RunFrame( int levelTime ) {
	int			i;
	gentity_t	*ent;
	int			msec;
int start, end;

	// if we are waiting for the level to restart, do nothing
	if ( level.restarted ) {
		return;
	}

	level.framenum++;
	level.previousTime = level.time;
	level.time = levelTime;
	msec = level.time - level.previousTime;

	// get any cvar changes
	G_UpdateCvars();

	//
	// go through all allocated objects
	//
	start = trap_Milliseconds();
	ent = &g_entities[0];
	for (i=0 ; i<level.num_entities ; i++, ent++) {
		if ( !ent->inuse ) {
			continue;
		}

		// clear events that are too old
		if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) {
			if ( ent->s.event ) {
				ent->s.event = 0;	// &= EV_EVENT_BITS;
				if ( ent->client ) {
					ent->client->ps.externalEvent = 0;
					// predicted events should never be set to zero
					//ent->client->ps.events[0] = 0;
					//ent->client->ps.events[1] = 0;
				}
			}
			if ( ent->freeAfterEvent ) {
				// tempEntities or dropped items completely go away after their event
				G_FreeEntity( ent );
				continue;
			} else if ( ent->unlinkAfterEvent ) {
				// items that will respawn will hide themselves after their pickup event
				ent->unlinkAfterEvent = qfalse;
				trap_UnlinkEntity( ent );
			}
		}

		// temporary entities don't think
		if ( ent->freeAfterEvent ) {
			continue;
		}

		if ( !ent->r.linked && ent->neverFree ) {
			continue;
		}

		if ( ent->s.eType == ET_MISSILE ) {
			G_RunMissile( ent );
			continue;
		}

		if ( ent->s.eType == ET_ITEM || ent->physicsObject ) {
			G_RunItem( ent );
			continue;
		}

		if ( ent->s.eType == ET_MOVER ) {
			G_RunMover( ent );
			continue;
		}

		if ( i < MAX_CLIENTS ) {
			G_RunClient( ent );
			continue;
		}

		G_RunThink( ent );
	}
end = trap_Milliseconds();

start = trap_Milliseconds();
	// perform final fixups on the players
	ent = &g_entities[0];
	for (i=0 ; i < level.maxclients ; i++, ent++ ) {
		if ( ent->inuse ) {
			ClientEndFrame( ent );
		}
	}
end = trap_Milliseconds();

	// see if it is time to do a tournement restart
	CheckTournament();

	// see if it is time to end the level
	CheckExitRules();

	// update to team status?
	CheckTeamStatus();

	// cancel vote if timed out
	CheckVote();

	// check team votes
	CheckTeamVote( TEAM_RED );
	CheckTeamVote( TEAM_BLUE );

	// for tracking changes
	CheckCvars();

	if (g_listEntity.integer) {
		for (i = 0; i < MAX_GENTITIES; i++) {
			G_Printf("%4i: %s\n", i, g_entities[i].classname);
		}
		trap_Cvar_Set("g_listEntity", "0");
	}
}
Пример #18
0
/*QUAKED bot_jump_dest (0.5 0.8 0) (-18 -18 -24) (18 18 40) NODROP
Bots will use this spot to jump to

Must recompile .AAS file after adding/changing these entities

NOTE: MUST HAVE A MATCHING BOT_JUMP_SOURCE

NODROP means dont drop it to the ground
*/
void SP_bot_jump_dest(gentity_t *ent)
{
	// only used for bspc process
	G_FreeEntity(ent);
}
Пример #19
0
/**
 * @brief SP_target_location
 * @details QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)
 * Set "message" to the name of this location.
 * Set "count" to 0-7 for color.
 * 0:white 1:red 2:green 3:yellow 4:blue 5:cyan 6:magenta 7:white
 *
 * Closest target_location in sight used for the location, if none
 * in site, closest in distance
 * @param self
 */
void SP_target_location(gentity_t *self)
{
	G_Printf(S_COLOR_YELLOW "WARNING: target_location entities are now obsolete. Please remove ASAP\n");

	G_FreeEntity(self);
}
Пример #20
0
static void PortalDie(gentity_t * self, gentity_t * inflictor, gentity_t * attacker, int damage, int mod)
{
	G_FreeEntity(self);
	//FIXME do something more interesting
}
Пример #21
0
/*QUAKED target_autosave (1 1 0) (-8 -8 -8) (8 8 8)
saves game to 'autosave.svg' when triggered then dies.
*/
void SP_target_autosave( gentity_t *ent ) {
	G_FreeEntity(ent);
}
Пример #22
0
/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
*/
void SP_info_null(gentity_t * self)
{
	G_FreeEntity(self);
}
/*
================
FinishSpawningItem

Traces down to find where an item should rest, instead of letting them
free fall from their spawn points
================
*/
void FinishSpawningItem( gentity_t *ent ) {
	trace_t		tr;
	vec3_t		dest;

	VectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS );
	VectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS );

	ent->s.eType = ET_ITEM;
	ent->s.modelindex = ent->item - bg_itemlist;		// store item number in modelindex
	ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item

	ent->r.contents = CONTENTS_TRIGGER;
	ent->touch = Touch_Item;
	// useing an item causes it to respawn
	ent->use = Use_Item;

	if ( ent->spawnflags & 1 ) {
		// suspended
		G_SetOrigin( ent, ent->s.origin );
	} else {
		// drop to floor
		VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
		trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
		if ( tr.startsolid ) {
			G_Printf ("FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
			G_FreeEntity( ent );
			return;
		}

		// allow to ride movers
		ent->s.groundEntityNum = tr.entityNum;

		G_SetOrigin( ent, tr.endpos );
	}

	// team slaves and targeted items aren't present at start
	if ( ( ent->flags & FL_TEAMSLAVE ) || ent->targetname ) {
		ent->s.eFlags |= EF_NODRAW;
		ent->r.contents = 0;
		return;
	}

	// powerups don't spawn in for a while
	if ( ent->item->giType == IT_POWERUP ) {
		float	respawn;

		respawn = 45 + crandom() * 15;
		ent->s.eFlags |= EF_NODRAW;
		ent->r.contents = 0;
		ent->nextthink = level.time + respawn * 1000;
		ent->think = RespawnItem;
		return;
	}

	if ( ent->item->giType == IT_HOLDABLE ) {
		if ( ( ent->item->giTag == HI_BAMBAM ) && ( g_gametype.integer != GT_CTF ) ) {
			return;
		}
		else if ( ( ent->item->giTag == HI_BOOMIES ) &&
		          ( ( g_gametype.integer != GT_CTF ) && ( g_gametype.integer != GT_BALLOON ) ) ) {
			return;
		}
	}


	trap_LinkEntity (ent);
}
Пример #24
0
/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear
Non-displayed light.
"light" overrides the default 300 intensity.
Linear checbox gives linear falloff instead of inverse square
Lights pointed at a target will be spotlights.
"radius" overrides the default 64 unit radius of a spotlight at the target point.
*/
void SP_light(gentity_t * self)
{
	G_FreeEntity(self);
}
Пример #25
0
//------------------
void Cmd_Fx( gentity_t *ent )
{
	vec3_t		dir;
	gentity_t	*fx_ent = NULL;

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

			fx_ent = G_Spawn();

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

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

extern void SP_fx_runner( gentity_t *ent );

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

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

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

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

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

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

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

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

			return;
		}
	}

	gi.Printf( S_COLOR_CYAN"Fx--------------------------------------------------------\n" );
	gi.Printf( S_COLOR_CYAN"commands:              sample usage:\n" );
	gi.Printf( S_COLOR_CYAN"----------------------------------------------------------\n" );
	gi.Printf( S_COLOR_CYAN"fx play <filename>     fx play sparks, fx play env/fire\n" );
	gi.Printf( S_COLOR_CYAN"fx stop                fx stop\n" );		
	gi.Printf( S_COLOR_CYAN"fx delay <#>           fx delay 1000\n" );
	gi.Printf( S_COLOR_CYAN"fx random <#>          fx random 200\n" );
	gi.Printf( S_COLOR_CYAN"fx origin <#><#><#>    fx origin 10 20 30\n" );
	gi.Printf( S_COLOR_CYAN"fx dir <#><#><#>       fx dir 0 0 -1\n\n" );
}
Пример #26
0
/*
=================
AimAtTarget

Calculate origin2 so the target apogee will be hit
=================
*/
void AimAtTarget( gentity_t *self ) 
{
	gentity_t	*ent;
	vec3_t		origin;
	float		height, gravity, time, forward;
	float		dist;

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

	ent = G_PickTarget( self->target );
	if ( !ent ) 
	{
		G_FreeEntity( self );
		return;
	}

	if ( self->classname && !Q_stricmp( "trigger_push", self->classname ) )
	{
		if ( (self->spawnflags&2) )
		{//check once a second to see if we should activate or deactivate ourselves
			self->e_ThinkFunc = thinkF_trigger_push_checkclear;
			self->nextthink = level.time + FRAMETIME;
		}

		if ( (self->spawnflags&16) )
		{//relative, not an arc or linear
			VectorCopy( ent->currentOrigin, self->s.origin2 );
			return;
		}
		else if ( (self->spawnflags&4) )
		{//linear, not an arc
			VectorSubtract( ent->currentOrigin, origin, self->s.origin2 );
			VectorNormalize( self->s.origin2 );
			return;
		}
	}

	if ( self->classname && !Q_stricmp( "target_push", self->classname ) )
	{
		if( self->spawnflags & PUSH_CONSTANT )
		{
			VectorSubtract ( ent->s.origin, self->s.origin, self->s.origin2 );
			VectorNormalize( self->s.origin2);
			VectorScale (self->s.origin2, self->speed, self->s.origin2);
			return;
		}
	}
	height = ent->s.origin[2] - origin[2];
	if ( height < 0 )
	{//sqrt of negative is bad!
		height = 0;
	}
	gravity = g_gravity->value;
	if ( gravity < 0 )
	{
		gravity = 0;
	}
	time = sqrt( height / ( .5 * gravity ) );
	if ( !time ) {
		G_FreeEntity( self );
		return;
	}

	// set s.origin2 to the push velocity
	VectorSubtract ( ent->s.origin, origin, self->s.origin2 );
	self->s.origin2[2] = 0;
	dist = VectorNormalize( self->s.origin2);

	forward = dist / time;
	VectorScale( self->s.origin2, forward, self->s.origin2 );

	self->s.origin2[2] = time * gravity;
}
Пример #27
0
/*
===================
G_SpawnGEntityFromSpawnVars

Spawn an entity and fill in all of the level fields from
level.spawnVars[], then call the class specfic spawn function
===================
*/
void G_SpawnGEntityFromSpawnVars( void ) {
	int			i;
	gentity_t	*ent;
	char		*s, *value, *gametypeName;
	static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester"};

	// get the next free entity
	ent = G_Spawn();

	for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
		G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );
	}

	// check for "notsingle" flag
	if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
		G_SpawnInt( "notsingle", "0", &i );
		if ( i ) {
			ADJUST_AREAPORTAL();
			G_FreeEntity( ent );
			return;
		}
	}
	// check for "notteam" flag (GT_FFA, GT_TOURNAMENT, GT_SINGLE_PLAYER)
	if ( g_gametype.integer >= GT_TEAM ) {
		G_SpawnInt( "notteam", "0", &i );
		if ( i ) {
			ADJUST_AREAPORTAL();
			G_FreeEntity( ent );
			return;
		}
	} else {
		G_SpawnInt( "notfree", "0", &i );
		if ( i ) {
			ADJUST_AREAPORTAL();
			G_FreeEntity( ent );
			return;
		}
	}

#ifdef MISSIONPACK
	G_SpawnInt( "notta", "0", &i );
	if ( i ) {
		ADJUST_AREAPORTAL();
		G_FreeEntity( ent );
		return;
	}
#else
	G_SpawnInt( "notq3a", "0", &i );
	if ( i ) {
		ADJUST_AREAPORTAL();
		G_FreeEntity( ent );
		return;
	}
#endif

	if( G_SpawnString( "gametype", NULL, &value ) ) {
		if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {
			gametypeName = gametypeNames[g_gametype.integer];

			s = strstr( value, gametypeName );
			if( !s ) {
				ADJUST_AREAPORTAL();
				G_FreeEntity( ent );
				return;
			}
		}
	}

	// move editor origin to pos
	VectorCopy( ent->s.origin, ent->s.pos.trBase );
	VectorCopy( ent->s.origin, ent->r.currentOrigin );

	// if we didn't get a classname, don't bother spawning anything
	if ( !G_CallSpawn( ent ) ) {
		G_FreeEntity( ent );
	}
}
Пример #28
0
/*
================
G_SetEntState

  sets the entstate of an entity.
================
*/
void G_SetEntState(gentity_t *ent, entState_t state)
{
	if (ent->entstate == state)
	{
		G_DPrintf("G_SetEntState: entity %i already in desired state [%i]\n", ent->s.number, state);
		return;
	}

	switch (state)
	{
	case STATE_DEFAULT:
		if (ent->entstate == STATE_UNDERCONSTRUCTION)
		{
			ent->clipmask   = ent->realClipmask;
			ent->r.contents = ent->realContents;
			if (!ent->realNonSolidBModel)
			{
				ent->s.eFlags &= ~EF_NONSOLID_BMODEL;
			}
		}

		ent->entstate   = STATE_DEFAULT;
		ent->s.powerups = STATE_DEFAULT;

		if (ent->s.eType == ET_WOLF_OBJECTIVE)
		{
			char cs[MAX_STRING_CHARS];

			trap_GetConfigstring(ent->count, cs, sizeof(cs));
			ent->count2 &= ~256;
			Info_SetValueForKey(cs, "t", va("%i", ent->count2));
			trap_SetConfigstring(ent->count, cs);
		}

		if (ent->s.eType != ET_COMMANDMAP_MARKER)
		{
			trap_LinkEntity(ent);
		}

		// deal with any entities in the solid
		{
			int       listedEntities, e;
			int       entityList[MAX_GENTITIES];
			gentity_t *check, *block;

			listedEntities = trap_EntitiesInBox(ent->r.absmin, ent->r.absmax, entityList, MAX_GENTITIES);

			for (e = 0; e < listedEntities; e++)
			{
				check = &g_entities[entityList[e]];

				// ignore everything but items, players and missiles (grenades too)
				if (check->s.eType != ET_MISSILE && check->s.eType != ET_ITEM && check->s.eType != ET_PLAYER && !check->physicsObject)
				{
					continue;
				}

				if ((block = G_TestEntityPosition(check)) == NULL)
				{
					continue;
				}

				if (block != ent)
				{
					// the entity is blocked by another entity - that block this should take care of this itself
					continue;
				}

				if (check->client || check->s.eType == ET_CORPSE)
				{
					// gibs anything player like
					G_Damage(check, ent, ent, NULL, NULL, 9999, DAMAGE_NO_PROTECTION, MOD_CRUSH_CONSTRUCTIONDEATH_NOATTACKER);
				}
				else if (check->s.eType == ET_ITEM && check->item->giType == IT_TEAM)
				{
					// see if it's a critical entity, one that we can't just simply kill (basically flags)
					Team_DroppedFlagThink(check);
				}
				else
				{
					// remove the landmine from both teamlists
					if (check->s.eType == ET_MISSILE && check->methodOfDeath == MOD_LANDMINE)
					{
						mapEntityData_t *mEnt;

						if ((mEnt = G_FindMapEntityData(&mapEntityData[0], check - g_entities)) != NULL)
						{
							G_FreeMapEntityData(&mapEntityData[0], mEnt);
						}

						if ((mEnt = G_FindMapEntityData(&mapEntityData[1], check - g_entities)) != NULL)
						{
							G_FreeMapEntityData(&mapEntityData[1], mEnt);
						}
					}

					// just get rid of it
					G_FreeEntity(check);
				}
			}
		}

		break;
	case STATE_UNDERCONSTRUCTION:
		ent->entstate     = STATE_UNDERCONSTRUCTION;
		ent->s.powerups   = STATE_UNDERCONSTRUCTION;
		ent->realClipmask = ent->clipmask;
		if (ent->s.eType != ET_CONSTRUCTIBLE)                               // don't make nonsolid as we want to make them partially solid for staged construction
		{
			ent->clipmask = 0;
		}
		ent->realContents = ent->r.contents;
		if (ent->s.eType != ET_CONSTRUCTIBLE)
		{
			ent->r.contents = 0;
		}
		if (ent->s.eFlags & EF_NONSOLID_BMODEL)
		{
			ent->realNonSolidBModel = qtrue;
		}
		else if (ent->s.eType != ET_CONSTRUCTIBLE)
		{
			ent->s.eFlags |= EF_NONSOLID_BMODEL;
		}

		if (!Q_stricmp(ent->classname, "misc_mg42"))
		{
			// stop using the mg42
			mg42_stopusing(ent);
		}

		if (ent->s.eType == ET_COMMANDMAP_MARKER)
		{
			mapEntityData_t *mEnt;

			if ((mEnt = G_FindMapEntityData(&mapEntityData[0], ent - g_entities)) != NULL)
			{
				G_FreeMapEntityData(&mapEntityData[0], mEnt);
			}
			if ((mEnt = G_FindMapEntityData(&mapEntityData[1], ent - g_entities)) != NULL)
			{
				G_FreeMapEntityData(&mapEntityData[1], mEnt);
			}
		}

		trap_LinkEntity(ent);
		break;
	case STATE_INVISIBLE:
		if (ent->entstate == STATE_UNDERCONSTRUCTION)
		{
			ent->clipmask   = ent->realClipmask;
			ent->r.contents = ent->realContents;
			if (!ent->realNonSolidBModel)
			{
				ent->s.eFlags &= ~EF_NONSOLID_BMODEL;
			}
		}

		ent->entstate   = STATE_INVISIBLE;
		ent->s.powerups = STATE_INVISIBLE;

		if (!Q_stricmp(ent->classname, "misc_mg42"))
		{
			mg42_stopusing(ent);
		}
		else if (ent->s.eType == ET_WOLF_OBJECTIVE)
		{
			char cs[MAX_STRING_CHARS];

			trap_GetConfigstring(ent->count, cs, sizeof(cs));
			ent->count2 |= 256;
			Info_SetValueForKey(cs, "t", va("%i", ent->count2));
			trap_SetConfigstring(ent->count, cs);
		}

		if (ent->s.eType == ET_COMMANDMAP_MARKER)
		{
			mapEntityData_t *mEnt;

			if ((mEnt = G_FindMapEntityData(&mapEntityData[0], ent - g_entities)) != NULL)
			{
				G_FreeMapEntityData(&mapEntityData[0], mEnt);
			}
			if ((mEnt = G_FindMapEntityData(&mapEntityData[1], ent - g_entities)) != NULL)
			{
				G_FreeMapEntityData(&mapEntityData[1], mEnt);
			}
		}

		trap_UnlinkEntity(ent);
		break;
	}
}
Пример #29
0
/**
* @brief Traces down to find where an item should rest, instead of letting them
free fall from their spawn points.
*/
void FinishSpawningItem(gentity_t *ent)
{
	trace_t tr;
	vec3_t  dest;
	vec3_t  maxs;

	if (ent->spawnflags & 1)     // suspended
	{
		VectorSet(ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
		VectorSet(ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
		VectorCopy(ent->r.maxs, maxs);
	}
	else
	{
		// had to modify this so that items would spawn in shelves
		VectorSet(ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, 0);
		VectorSet(ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
		VectorCopy(ent->r.maxs, maxs);
		maxs[2] /= 2;
	}

	ent->r.contents   = CONTENTS_TRIGGER | CONTENTS_ITEM;
	ent->touch        = Touch_Item_Auto;
	ent->s.eType      = ET_ITEM;
	ent->s.modelindex = ent->item - bg_itemlist;        // store item number in modelindex

	ent->s.otherEntityNum2 = 0;     // takes modelindex2's place in signaling a dropped item
	// we don't use this (yet, anyway) so I'm taking it so you can specify a model for treasure items and clipboards
	//ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item
	if (ent->model)
	{
		ent->s.modelindex2 = G_ModelIndex(ent->model);
	}

	// using an item causes it to respawn
	ent->use = Use_Item;

	// moved this up so it happens for suspended items too (and made it a function)
	G_SetAngle(ent, ent->s.angles);

	if (ent->spawnflags & 1)        // suspended
	{
		G_SetOrigin(ent, ent->s.origin);
	}
	else
	{
		VectorSet(dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096);
		trap_Trace(&tr, ent->s.origin, ent->r.mins, maxs, dest, ent->s.number, MASK_SOLID);

		if (tr.startsolid)
		{
			vec3_t temp;

			VectorCopy(ent->s.origin, temp);
			temp[2] -= ITEM_RADIUS;

			VectorSet(dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096);
			trap_Trace(&tr, temp, ent->r.mins, maxs, dest, ent->s.number, MASK_SOLID);
		}

		if (tr.startsolid)
		{
			G_Printf("FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
			G_FreeEntity(ent);
			return;
		}

		// allow to ride movers
		ent->s.groundEntityNum = tr.entityNum;

		G_SetOrigin(ent, tr.endpos);
	}

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

	// team slaves and targeted items aren't present at start
	if ((ent->flags & FL_TEAMSLAVE) || ent->targetname)
	{
		ent->flags |= FL_NODRAW;
		//ent->s.eFlags |= EF_NODRAW;
		ent->r.contents = 0;
		return;
	}

	// health/ammo can potentially be multi-stage (multiple use)
	if (ent->item->giType == IT_HEALTH || ent->item->giType == IT_AMMO)
	{
		int i;

		// having alternate models defined in bg_misc.c for a health or ammo item specify it as "multi-stage"
		// - left-hand operand of comma expression has no effect
		// initial line: for(i=0;i<4,ent->item->world_model[i];i++) {}
		for (i = 0; i < 4 && ent->item->world_model[i] ; i++)
		{
		}

		ent->s.density = i - 1;   // store number of stages in 'density' for client (most will have '1')
	}

	trap_LinkEntity(ent);
}
Пример #30
0
/*
================
G_RunMissile
================
*/
void G_RunMissile( gentity_t *ent ) {
	vec3_t		origin, groundSpot;
	trace_t		tr;
	int			passent;
	qboolean	isKnockedSaber = qfalse;

	if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
	{
		isKnockedSaber = qtrue;
		ent->s.pos.trType = TR_GRAVITY;
	}

	// get current position
	BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );

	// if this missile bounced off an invulnerability sphere
	if ( ent->target_ent ) {
		passent = ent->target_ent->s.number;
	}
	else {
		// ignore interactions with the missile owner
		if ( (ent->r.svFlags&SVF_OWNERNOTSHARED) 
			&& (ent->s.eFlags&EF_JETPACK_ACTIVE) )
		{//A vehicle missile that should be solid to its owner
			//I don't care about hitting my owner
			passent = ent->s.number;
		}
		else
		{
			passent = ent->r.ownerNum;
		}
	}
	// trace a line from the previous position to the current position
	if (d_projectileGhoul2Collision.integer)
	{
		trap_G2Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, G2TRFLAG_DOGHOULTRACE|G2TRFLAG_GETSURFINDEX|G2TRFLAG_THICK|G2TRFLAG_HITCORPSES, g_g2TraceLod.integer );

		if (tr.fraction != 1.0 && tr.entityNum < ENTITYNUM_WORLD)
		{
			gentity_t *g2Hit = &g_entities[tr.entityNum];

			if (g2Hit->inuse && g2Hit->client && g2Hit->ghoul2)
			{ //since we used G2TRFLAG_GETSURFINDEX, tr.surfaceFlags will actually contain the index of the surface on the ghoul2 model we collided with.
				g2Hit->client->g2LastSurfaceHit = tr.surfaceFlags;
				g2Hit->client->g2LastSurfaceTime = level.time;
			}

			if (g2Hit->ghoul2)
			{
				tr.surfaceFlags = 0; //clear the surface flags after, since we actually care about them in here.
			}
		}
	}
	else
	{
		trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
	}

	if ( tr.startsolid || tr.allsolid ) {
		// make sure the tr.entityNum is set to the entity we're stuck in
		trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
		tr.fraction = 0;
	}
	else {
		VectorCopy( tr.endpos, ent->r.currentOrigin );
	}

	if (ent->passThroughNum && tr.entityNum == (ent->passThroughNum-1))
	{
		VectorCopy( origin, ent->r.currentOrigin );
		trap_LinkEntity( ent );
		goto passthrough;
	}

	trap_LinkEntity( ent );

	if (ent->s.weapon == G2_MODEL_PART && !ent->bounceCount)
	{
		vec3_t lowerOrg;
		trace_t trG;

		VectorCopy(ent->r.currentOrigin, lowerOrg);
		lowerOrg[2] -= 1;
		trap_Trace( &trG, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, lowerOrg, passent, ent->clipmask );

		VectorCopy(trG.endpos, groundSpot);

		if (!trG.startsolid && !trG.allsolid && trG.entityNum == ENTITYNUM_WORLD)
		{
			ent->s.groundEntityNum = trG.entityNum;
		}
		else
		{
			ent->s.groundEntityNum = ENTITYNUM_NONE;
		}
	}

	if ( tr.fraction != 1) {
		// never explode or bounce on sky
		if ( tr.surfaceFlags & SURF_NOIMPACT ) {
			// If grapple, reset owner
			if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
				ent->parent->client->hook = NULL;
			}

			if ((ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber)
			{
				G_RunThink( ent );
				return;
			}
			else if (ent->s.weapon != G2_MODEL_PART)
			{
				G_FreeEntity( ent );
				return;
			}
		}

#if 0 //will get stomped with missile impact event...
		if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
			(tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
		{ //player or NPC, try making a mark on him
			/*
			gentity_t *evEnt = G_TempEntity(ent->r.currentOrigin, EV_GHOUL2_MARK);

			evEnt->s.owner = tr.entityNum; //the entity the mark should be placed on
			evEnt->s.weapon = ent->s.weapon; //the weapon used (to determine mark type)
			VectorCopy(ent->r.currentOrigin, evEnt->s.origin); //the point of impact

			//origin2 gets the predicted trajectory-based position.
			BG_EvaluateTrajectory( &ent->s.pos, level.time, evEnt->s.origin2 );

			//If they are the same, there will be problems.
			if (VectorCompare(evEnt->s.origin, evEnt->s.origin2))
			{
				evEnt->s.origin2[2] += 2; //whatever, at least it won't mess up.
			}
			*/
			//ok, let's try adding it to the missile ent instead (tempents bad!)
			G_AddEvent(ent, EV_GHOUL2_MARK, 0);

			//copy current pos to s.origin, and current projected traj to origin2
			VectorCopy(ent->r.currentOrigin, ent->s.origin);
			BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );

			//the index for whoever we are hitting
			ent->s.otherEntityNum = tr.entityNum;

			if (VectorCompare(ent->s.origin, ent->s.origin2))
			{
				ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up.
			}
		}
#else
		if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
			(tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
		{ //player or NPC, try making a mark on him
			//copy current pos to s.origin, and current projected traj to origin2
			VectorCopy(ent->r.currentOrigin, ent->s.origin);
			BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );

			if (VectorCompare(ent->s.origin, ent->s.origin2))
			{
				ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up.
			}
		}
#endif

		G_MissileImpact( ent, &tr );

		if (tr.entityNum == ent->s.otherEntityNum)
		{ //if the impact event other and the trace ent match then it's ok to do the g2 mark
			ent->s.trickedentindex = 1;
		}

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

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

	if (ent->s.weapon == G2_MODEL_PART)
	{
		if (ent->s.groundEntityNum == ENTITYNUM_WORLD)
		{
			ent->s.pos.trType = TR_LINEAR;
			VectorClear(ent->s.pos.trDelta);
			ent->s.pos.trTime = level.time;

			VectorCopy(groundSpot, ent->s.pos.trBase);
			VectorCopy(groundSpot, ent->r.currentOrigin);

			if (ent->s.apos.trType != TR_STATIONARY)
			{
				ent->s.apos.trType = TR_STATIONARY;
				ent->s.apos.trTime = level.time;

				ent->s.apos.trBase[ROLL] = 0;
				ent->s.apos.trBase[PITCH] = 0;
			}
		}
	}

	// check think function after bouncing
	G_RunThink( ent );
}