예제 #1
0
/*
=================
fire_lockblob
=================
*/
gentity_t *fire_lockblob( gentity_t *self, vec3_t start, vec3_t dir )
{
	gentity_t *bolt;

	bolt = G_NewEntity();
	bolt->classname = "lockblob";
	bolt->pointAgainstWorld = qtrue;
	bolt->nextthink = level.time + 15000;
	bolt->think = G_ExplodeMissile;
	bolt->s.eType = ET_MISSILE;
	bolt->s.weapon = WP_LOCKBLOB_LAUNCHER;
	bolt->s.generic1 = WPM_PRIMARY; //weaponMode
	bolt->r.ownerNum = self->s.number;
	bolt->parent = self;
	bolt->damage = 0;
	bolt->flightSplashDamage = 0;
	bolt->splashDamage = 0;
	bolt->splashRadius = 0;
	bolt->methodOfDeath = MOD_UNKNOWN; //doesn't do damage so will never kill
	bolt->clipmask = MASK_SHOT;
	bolt->target = NULL;

	bolt->s.pos.trType = TR_LINEAR;
	bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale( dir, LOCKBLOB_SPEED, bolt->s.pos.trDelta );
	SnapVector( bolt->s.pos.trDelta );  // save net bandwidth
	VectorCopy( start, bolt->r.currentOrigin );

	return bolt;
}
예제 #2
0
/*
=================
fire_bounceBall
=================
*/
gentity_t *fire_bounceBall( gentity_t *self, vec3_t start, vec3_t dir )
{
	gentity_t *bolt;

	bolt = G_NewEntity();
	bolt->classname = "bounceball";
	bolt->pointAgainstWorld = qtrue;
	bolt->nextthink = level.time + 3000;
	bolt->think = G_ExplodeMissile;
	bolt->s.eType = ET_MISSILE;
	bolt->s.weapon = WP_ALEVEL3_UPG;
	bolt->s.generic1 = self->s.generic1; //weaponMode
	bolt->r.ownerNum = self->s.number;
	bolt->parent = self;
	bolt->damage = LEVEL3_BOUNCEBALL_DMG;
	bolt->flightSplashDamage = 0;
	bolt->splashDamage = LEVEL3_BOUNCEBALL_DMG;
	bolt->splashRadius = LEVEL3_BOUNCEBALL_RADIUS;
	bolt->methodOfDeath = MOD_LEVEL3_BOUNCEBALL;
	bolt->splashMethodOfDeath = MOD_LEVEL3_BOUNCEBALL;
	bolt->clipmask = MASK_SHOT;
	bolt->target = NULL;

	bolt->s.pos.trType = TR_GRAVITY;
	bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale( dir, LEVEL3_BOUNCEBALL_SPEED, bolt->s.pos.trDelta );
	SnapVector( bolt->s.pos.trDelta );  // save net bandwidth
	VectorCopy( start, bolt->r.currentOrigin );

	return bolt;
}
예제 #3
0
/*
=================
fire_pulseRifle

=================
*/
gentity_t *fire_pulseRifle( gentity_t *self, vec3_t start, vec3_t dir )
{
	gentity_t *bolt;

	bolt = G_NewEntity();
	bolt->classname = "pulse";
	bolt->pointAgainstWorld = qtrue;
	bolt->nextthink = level.time + 10000;
	bolt->think = G_ExplodeMissile;
	bolt->s.eType = ET_MISSILE;
	bolt->s.weapon = WP_PULSE_RIFLE;
	bolt->s.generic1 = self->s.generic1; //weaponMode
	bolt->r.ownerNum = self->s.number;
	bolt->parent = self;
	bolt->damage = PRIFLE_DMG;
	bolt->flightSplashDamage = 0;
	bolt->splashDamage = 0;
	bolt->splashRadius = 0;
	bolt->methodOfDeath = MOD_PRIFLE;
	bolt->splashMethodOfDeath = MOD_PRIFLE;
	bolt->clipmask = MASK_SHOT;
	bolt->target = NULL;
	bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -PRIFLE_SIZE;
	bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = PRIFLE_SIZE;

	bolt->s.pos.trType = TR_LINEAR;
	bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale( dir, PRIFLE_SPEED, bolt->s.pos.trDelta );
	SnapVector( bolt->s.pos.trDelta );  // save net bandwidth

	VectorCopy( start, bolt->r.currentOrigin );

	return bolt;
}
예제 #4
0
/*
=================
fire_hive
=================
*/
gentity_t *fire_hive( gentity_t *self, vec3_t start, vec3_t dir )
{
	gentity_t *bolt;

	bolt = G_NewEntity();
	bolt->classname = "hive";
	bolt->pointAgainstWorld = qfalse;
	bolt->nextthink = level.time + HIVE_DIR_CHANGE_PERIOD;
	bolt->think = AHive_SearchAndDestroy;
	bolt->s.eType = ET_MISSILE;
	bolt->s.eFlags |= EF_BOUNCE | EF_NO_BOUNCE_SOUND;
	bolt->s.weapon = WP_HIVE;
	bolt->s.generic1 = WPM_PRIMARY; //weaponMode
	bolt->r.ownerNum = self->s.number;
	bolt->parent = self;
	bolt->damage = HIVE_DMG;
	bolt->flightSplashDamage = 0;
	bolt->splashDamage = 0;
	bolt->splashRadius = 0;
	bolt->methodOfDeath = MOD_SWARM;
	bolt->clipmask = MASK_SHOT;
	bolt->target = self->target;
	bolt->timestamp = level.time + HIVE_LIFETIME;

	bolt->s.pos.trType = TR_LINEAR;
	bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale( dir, HIVE_SPEED, bolt->s.pos.trDelta );
	SnapVector( bolt->s.pos.trDelta );  // save net bandwidth
	VectorCopy( start, bolt->r.currentOrigin );

	return bolt;
}
예제 #5
0
/*
=================
fire_luciferCannon

=================
*/
gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir,
                               int damage, int radius, int speed )
{
	gentity_t *bolt;
	float     charge;

	bolt = G_NewEntity();
	bolt->classname = "lcannon";
	bolt->pointAgainstWorld = qtrue;

	if ( damage == LCANNON_DAMAGE )
	{
		bolt->nextthink = level.time;
	}
	else
	{
		bolt->nextthink = level.time + 10000;
	}

	bolt->think = G_ExplodeMissile;
	bolt->s.eType = ET_MISSILE;
	bolt->s.weapon = WP_LUCIFER_CANNON;
	bolt->s.generic1 = self->s.generic1; //weaponMode
	bolt->r.ownerNum = self->s.number;
	bolt->parent = self;
	bolt->damage = damage;
	bolt->flightSplashDamage = 0;
	bolt->splashDamage = damage / 2;
	bolt->splashRadius = radius;
	bolt->methodOfDeath = MOD_LCANNON;
	bolt->splashMethodOfDeath = MOD_LCANNON_SPLASH;
	bolt->clipmask = MASK_SHOT;
	bolt->target = NULL;

	// Give the missile a small bounding box
	bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] =
	    -LCANNON_SIZE;
	bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] =
	    -bolt->r.mins[ 0 ];

	// Pass the missile charge through
	charge = ( float )( damage - LCANNON_SECONDARY_DAMAGE ) / LCANNON_DAMAGE;
	bolt->s.torsoAnim = charge * 255;

	if ( bolt->s.torsoAnim < 0 )
	{
		bolt->s.torsoAnim = 0;
	}

	bolt->s.pos.trType = TR_LINEAR;
	bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale( dir, speed, bolt->s.pos.trDelta );
	SnapVector( bolt->s.pos.trDelta );  // save net bandwidth

	VectorCopy( start, bolt->r.currentOrigin );

//	Com_Printf("Luciball power = %d, speed = %d/s.\n", damage, speed);
	return bolt;
}
예제 #6
0
static void CreateNewZap( gentity_t *creator, gentity_t *target )
{
	int   i;
	zap_t *zap;

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

		if ( zap->used )
		{
			continue;
		}

		zap->used = qtrue;
		zap->timeToLive = LEVEL2_AREAZAP_TIME;

		zap->creator = creator;
		zap->targets[ 0 ] = target;
		zap->numTargets = 1;

		// the zap chains only through living entities
		if ( target->health > 0 )
		{
			G_Damage( target, creator, creator, forward,
			          target->s.origin, LEVEL2_AREAZAP_DMG,
			          DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE,
			          MOD_LEVEL2_ZAP );

			FindZapChainTargets( zap );

			for ( i = 1; i < zap->numTargets; i++ )
			{
				G_Damage( zap->targets[ i ], target, zap->creator, forward, target->s.origin,
				          LEVEL2_AREAZAP_DMG * ( 1 - powf( ( zap->distances[ i ] /
				                                 LEVEL2_AREAZAP_CHAIN_RANGE ), LEVEL2_AREAZAP_CHAIN_FALLOFF ) ) + 1,
				          DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE,
				          MOD_LEVEL2_ZAP );
			}
		}

		zap->effectChannel = G_NewEntity();
		zap->effectChannel->s.eType = ET_LEV2_ZAP_CHAIN;
		zap->effectChannel->classname = "lev2zapchain";
		UpdateZapEffect( zap );

		return;
	}
}
예제 #7
0
void G_SpawnFakeEntities()
{
	level.fakeLocation = G_NewEntity();
	level.fakeLocation->s.origin[ 0 ] =
	level.fakeLocation->s.origin[ 1 ] =
	level.fakeLocation->s.origin[ 2 ] = 1.7e19f; // well out of range
	level.fakeLocation->message = nullptr;

	level.fakeLocation->s.eType = entityType_t::ET_LOCATION;
	level.fakeLocation->r.svFlags = SVF_BROADCAST;

	level.fakeLocation->nextPathSegment = level.locationHead;
	level.fakeLocation->s.generic1 = G_LocationIndex( "" );
	level.locationHead = level.fakeLocation;

	G_SetOrigin( level.fakeLocation, level.fakeLocation->s.origin );
}
예제 #8
0
static void CreateNewZap( gentity_t *creator, gentity_t *target )
{
	int   i;
	zap_t *zap;

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

		if ( zap->used )
		{
			continue;
		}

		zap->used = true;
		zap->timeToLive = LEVEL2_AREAZAP_TIME;

		zap->creator = creator;
		zap->targets[ 0 ] = target;
		zap->numTargets = 1;

		// Zap chains only originate from alive entities.
		if (target->entity->Damage((float)LEVEL2_AREAZAP_DMG, creator, Vec3::Load(target->s.origin),
		                           Vec3::Load(forward), DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP)) {
			FindZapChainTargets( zap );

			for ( i = 1; i < zap->numTargets; i++ )
			{
				float damage = LEVEL2_AREAZAP_DMG * ( 1 - powf( ( zap->distances[ i ] /
				               LEVEL2_AREAZAP_CHAIN_RANGE ), LEVEL2_AREAZAP_CHAIN_FALLOFF ) ) + 1;

				target->entity->Damage(damage, zap->creator, Vec3::Load(target->s.origin),
				                       Vec3::Load(forward), DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP);
			}
		}

		zap->effectChannel = G_NewEntity();
		zap->effectChannel->s.eType = ET_LEV2_ZAP_CHAIN;
		zap->effectChannel->classname = "lev2zapchain";
		UpdateZapEffect( zap );

		return;
	}
}
예제 #9
0
/*
=================
G_NewTempEntity

Spawns an event entity that will be auto-removed
The origin will be snapped to save net bandwidth, so care
must be taken if the origin is right on a surface (snap towards start vector first)
=================
*/
gentity_t *G_NewTempEntity( const vec3_t origin, int event )
{
	gentity_t *newEntity;
	vec3_t    snapped;

	newEntity = G_NewEntity();
	newEntity->s.eType = (entityType_t) ( ET_EVENTS + event );

	newEntity->classname = "tempEntity";
	newEntity->eventTime = level.time;
	newEntity->freeAfterEvent = true;

	VectorCopy( origin, snapped );
	SnapVector( snapped );  // save network bandwidth
	G_SetOrigin( newEntity, snapped );

	// find cluster for PVS
	trap_LinkEntity( newEntity );

	return newEntity;
}
예제 #10
0
	/**
	 * @brief Create a new ET_BEACON entity.
	 * @param conflictHandler How to handle existing similiar beacons.
	 * @return A pointer to the new entity.
	 */
	gentity_t *New( const vec3_t origin, beaconType_t type, int data,
	                team_t team, int owner, beaconConflictHandler_t conflictHandler )
	{
		gentity_t *ent;
		int decayTime;

		switch( conflictHandler )
		{
			case BCH_MOVE:
				return MoveSimilar( origin, origin, type, data, team, owner );

			case BCH_REMOVE:
				RemoveSimilar( origin, type, data, team, owner );
				break;

			default:
				break;
		}

		ent = G_NewEntity( );
		ent->s.eType = ET_BEACON;
		ent->classname = "beacon";

		ent->s.bc_type = type;
		ent->s.bc_data = data;
		ent->s.bc_team = team;
		ent->s.bc_owner = owner;
		ent->think = Think;
		ent->nextthink = level.time;

		ent->s.bc_ctime = level.time;
		ent->s.bc_mtime = level.time;
		decayTime = BG_Beacon( type )->decayTime;
		ent->s.bc_etime = ( decayTime ? level.time + decayTime : 0 );

		ent->s.pos.trType = TR_INTERPOLATE;
		Move( ent, origin );

		return ent;
	}
예제 #11
0
/*
=================
launch_grenade

=================
*/
gentity_t *launch_grenade( gentity_t *self, vec3_t start, vec3_t dir )
{
	gentity_t *bolt;

	bolt = G_NewEntity();
	bolt->classname = "grenade";
	bolt->pointAgainstWorld = qfalse;
	bolt->nextthink = level.time + 5000;
	bolt->think = G_ExplodeMissile;
	bolt->s.eType = ET_MISSILE;
	bolt->s.weapon = WP_GRENADE;
	bolt->s.eFlags = EF_BOUNCE_HALF;
	bolt->s.generic1 = WPM_PRIMARY; //weaponMode
	bolt->r.ownerNum = self->s.number;
	bolt->parent = self;
	bolt->damage = GRENADE_DAMAGE;
	bolt->flightSplashDamage = 0;
	bolt->splashDamage = GRENADE_DAMAGE;
	bolt->splashRadius = GRENADE_RANGE;
	bolt->methodOfDeath = MOD_GRENADE;
	bolt->splashMethodOfDeath = MOD_GRENADE;
	bolt->clipmask = MASK_SHOT;
	bolt->target = NULL;
	bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -3.0f;
	bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = 3.0f;
	bolt->s.time = level.time;

	bolt->s.pos.trType = TR_GRAVITY;
	bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale( dir, GRENADE_SPEED, bolt->s.pos.trDelta );
	SnapVector( bolt->s.pos.trDelta );  // save net bandwidth

	VectorCopy( start, bolt->r.currentOrigin );

	trap_SendServerCommand( self - g_entities, "vcommand grenade" );

	return bolt;
}
예제 #12
0
/*
=================
fire_flamer

=================
*/
gentity_t *fire_flamer( gentity_t *self, vec3_t start, vec3_t dir )
{
	gentity_t *bolt;
	vec3_t    pvel;

	bolt = G_NewEntity();
	bolt->classname = "flame";
	bolt->pointAgainstWorld = qfalse;
	bolt->nextthink = level.time + FLAMER_LIFETIME;
	bolt->think = G_ExplodeMissile;
	bolt->s.eType = ET_MISSILE;
	bolt->s.weapon = WP_FLAMER;
	bolt->s.generic1 = self->s.generic1; //weaponMode
	bolt->r.ownerNum = self->s.number;
	bolt->parent = self;
	bolt->damage = FLAMER_DMG;
	bolt->flightSplashDamage = FLAMER_FLIGHTSPLASHDAMAGE;
	bolt->splashDamage = FLAMER_SPLASHDAMAGE;
	bolt->splashRadius = FLAMER_RADIUS;
	bolt->methodOfDeath = MOD_FLAMER;
	bolt->splashMethodOfDeath = MOD_FLAMER_SPLASH;
	bolt->clipmask = MASK_SHOT;
	bolt->target = NULL;
	bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -FLAMER_SIZE;
	bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = FLAMER_SIZE;

	bolt->s.pos.trType = TR_LINEAR;
	bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale( self->client->ps.velocity, FLAMER_LAG, pvel );
	VectorMA( pvel, FLAMER_SPEED, dir, bolt->s.pos.trDelta );
	SnapVector( bolt->s.pos.trDelta );  // save net bandwidth

	VectorCopy( start, bolt->r.currentOrigin );

	return bolt;
}
예제 #13
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, j;
	gentity_t *spawningEntity;

	// get the next free entity
	spawningEntity = G_NewEntity();

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

	if(G_SpawnBoolean( "nop", qfalse ) || G_SpawnBoolean( "notunv", qfalse ))
	{
		G_FreeEntity( spawningEntity );
		return;
	}

	/*
	 * will have only the classname or missing it…
	 * both aren't helping us and might even create a error later
	 * in the server, where we dont know as much anymore about it,
	 * so we fail rather here, so mappers have a chance to remove it
	 */
	if( level.numSpawnVars <= 1 )
	{
		G_Error( S_ERROR "encountered ghost-entity #%i with only one field: %s = %s\n", spawningEntity->s.number, level.spawnVars[ 0 ][ 0 ], level.spawnVars[ 0 ][ 1 ] );
	}

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

	// don't leave any "gaps" between multiple names
	j = 0;
	for (i = 0; i < MAX_ENTITY_ALIASES; ++i)
	{
		if (spawningEntity->names[i])
			spawningEntity->names[j++] = spawningEntity->names[i];
	}
	spawningEntity->names[ j ] = NULL;

	/*
	 * for backward compatbility, since before targets were used for calling,
	 * we'll have to copy them over to the called-targets as well for now
	 */
	if(!spawningEntity->callTargetCount)
	{
		for (i = 0; i < MAX_ENTITY_TARGETS && i < MAX_ENTITY_CALLTARGETS; i++)
		{
			if (!spawningEntity->targets[i])
				continue;

			spawningEntity->calltargets[i].event = "target";
			spawningEntity->calltargets[i].eventType = ON_DEFAULT;
			spawningEntity->calltargets[i].actionType = ECA_DEFAULT;
			spawningEntity->calltargets[i].name = spawningEntity->targets[i];
			spawningEntity->callTargetCount++;
		}
	}

	// don't leave any "gaps" between multiple targets
	j = 0;
	for (i = 0; i < MAX_ENTITY_TARGETS; ++i)
	{
		if (spawningEntity->targets[i])
			spawningEntity->targets[j++] = spawningEntity->targets[i];
	}
	spawningEntity->targets[ j ] = NULL;

	// if we didn't get necessary fields (like the classname), don't bother spawning anything
	if ( !G_CallSpawnFunction( spawningEntity ) )
	{
		G_FreeEntity( spawningEntity );
	}
}
예제 #14
0
/*
=============
SpawnCorpse

A player is respawning, so make an entity that looks
just like the existing corpse to leave behind.
=============
*/
static void SpawnCorpse( gentity_t *ent )
{
	gentity_t *body;
	int       contents;
	vec3_t    origin, mins;

	VectorCopy( ent->r.currentOrigin, origin );

	trap_UnlinkEntity( ent );

	// if client is in a nodrop area, don't leave the body
	contents = trap_PointContents( origin, -1 );

	if ( contents & CONTENTS_NODROP )
	{
		return;
	}

	body = G_NewEntity();

	VectorCopy( ent->s.apos.trBase, body->s.angles );
	body->s.eFlags = EF_DEAD;
	body->s.eType = entityType_t::ET_CORPSE;
	body->timestamp = level.time;
	body->s.event = 0;
	body->r.contents = CONTENTS_CORPSE;
	body->clipmask = MASK_DEADSOLID;
	body->s.clientNum = ent->client->ps.stats[ STAT_CLASS ];
	body->nonSegModel = ent->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL;

	if ( ent->client->pers.team == TEAM_HUMANS )
	{
		body->classname = "humanCorpse";
	}
	else
	{
		body->classname = "alienCorpse";
	}

	body->s.misc = MAX_CLIENTS;

	body->think = BodySink;
	body->nextthink = level.time + 20000;

	body->s.legsAnim = ent->s.legsAnim;

	if ( !body->nonSegModel )
	{
		switch ( body->s.legsAnim & ~ANIM_TOGGLEBIT )
		{
			case BOTH_DEATH1:
			case BOTH_DEAD1:
				body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD1;
				break;

			case BOTH_DEATH2:
			case BOTH_DEAD2:
				body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD2;
				break;

			case BOTH_DEATH3:
			case BOTH_DEAD3:
			default:
				body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD3;
				break;
		}
	}
	else
	{
		switch ( body->s.legsAnim & ~ANIM_TOGGLEBIT )
		{
			case NSPA_DEATH1:
			case NSPA_DEAD1:
				body->s.legsAnim = NSPA_DEAD1;
				break;

			case NSPA_DEATH2:
			case NSPA_DEAD2:
				body->s.legsAnim = NSPA_DEAD2;
				break;

			case NSPA_DEATH3:
			case NSPA_DEAD3:
			default:
				body->s.legsAnim = NSPA_DEAD3;
				break;
		}
	}

	//change body dimensions
	BG_ClassBoundingBox( ent->client->ps.stats[ STAT_CLASS ], mins, nullptr, nullptr, body->r.mins, body->r.maxs );

	//drop down to match the *model* origins of ent and body
	origin[2] += mins[ 2 ] - body->r.mins[ 2 ];

	G_SetOrigin( body, origin );
	body->s.pos.trType = trType_t::TR_GRAVITY;
	body->s.pos.trTime = level.time;
	VectorCopy( ent->client->ps.velocity, body->s.pos.trDelta );

	trap_LinkEntity( body );
}
예제 #15
0
gentity_t *G_SpawnMissile( missile_t missile, gentity_t *parent, vec3_t start, vec3_t dir,
                           gentity_t *target, void ( *think )( gentity_t *self ), int nextthink )
{
	gentity_t                 *m;
	const missileAttributes_t *ma;
	vec3_t                    velocity;

	if ( !parent )
	{
		return nullptr;
	}

	ma = BG_Missile( missile );

	m = G_NewEntity();

	// generic
	m->s.eType             = ET_MISSILE;
	m->s.modelindex        = missile;
	m->r.ownerNum          = parent->s.number;
	m->parent              = parent;
	m->target              = target;
	m->think               = think;
	m->nextthink           = nextthink;

	// from attribute config file
	m->s.weapon            = ma->number;
	m->classname           = ma->name;
	m->pointAgainstWorld   = ma->pointAgainstWorld;
	m->damage              = ma->damage;
	m->methodOfDeath       = ma->meansOfDeath;
	m->splashDamage        = ma->splashDamage;
	m->splashRadius        = ma->splashRadius;
	m->splashMethodOfDeath = ma->splashMeansOfDeath;
	m->clipmask            = ma->clipmask;
	m->r.mins[ 0 ]         =
	m->r.mins[ 1 ]         =
	m->r.mins[ 2 ]         = -ma->size;
	m->r.maxs[ 0 ]         =
	m->r.maxs[ 1 ]         =
	m->r.maxs[ 2 ]         = ma->size;
	m->s.eFlags            = ma->flags;

	// not yet implemented / deprecated
	m->flightSplashDamage  = 0;
	m->flightSplashRadius  = 0;

	// trajectory
	{
		// set trajectory type
		m->s.pos.trType = ma->trajectoryType;

		// move a bit on the first frame
		m->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;

		// set starting point
		VectorCopy( start, m->s.pos.trBase );
		VectorCopy( start, m->r.currentOrigin );

		// set speed
		VectorScale( dir, ma->speed, velocity );

		// add lag
		if ( ma->lag && parent->client )
		{
			VectorMA( velocity, ma->lag, parent->client->ps.velocity, velocity );
		}

		// copy velocity
		VectorCopy( velocity, m->s.pos.trDelta );

		// save net bandwidth
		SnapVector( m->s.pos.trDelta );
	}

	return m;
}