示例#1
0
static gentity_t *FireLcannonHelper( gentity_t *self, vec3_t start, vec3_t dir,
                                     int damage, int radius, int speed )
{
	// TODO: Tidy up this and lcannonFire

	gentity_t *m;
	int       nextthink;
	float     charge;

	// explode in front of player when overcharged
	if ( damage == LCANNON_DAMAGE )
	{
		nextthink = level.time;
	}
	else
	{
		nextthink = level.time + 10000;
	}

	if ( self->s.generic1 == WPM_PRIMARY )
	{
		m = G_SpawnMissile( MIS_LCANNON, self, start, dir, NULL, G_ExplodeMissile, nextthink );

		// some values are set in the code
		m->damage       = damage;
		m->splashDamage = damage / 2;
		m->splashRadius = radius;
		VectorScale( dir, speed, m->s.pos.trDelta );
		SnapVector( m->s.pos.trDelta ); // save net bandwidth

		// pass the missile charge through
		charge = ( float )( damage - LCANNON_SECONDARY_DAMAGE ) / LCANNON_DAMAGE;

		m->s.torsoAnim = charge * 255;

		if ( m->s.torsoAnim < 0 )
		{
			m->s.torsoAnim = 0;
		}
	}
	else
	{
		m = G_SpawnMissile( MIS_LCANNON2, self, start, dir, NULL, G_ExplodeMissile, nextthink );
	}

	return m;
}
示例#2
0
static void FireHive( gentity_t *self )
{
	vec3_t    origin;
	gentity_t *m;

	// fire from the hive tip, not the center
	VectorMA( muzzle, self->r.maxs[ 2 ], self->s.origin2, origin );

	m = G_SpawnMissile( MIS_HIVE, self, origin, forward, self->target,
	                    HiveMissileThink, level.time + HIVE_DIR_CHANGE_PERIOD );

	m->timestamp = level.time + HIVE_LIFETIME;
}
示例#3
0
static void FirebombMissileThink( gentity_t *self )
{
	gentity_t *neighbor, *m;
	int       subMissileNum;
	vec3_t    dir, upwards = { 0.0f, 0.0f, 1.0f };

	// ignite alien buildables in range
	neighbor = NULL;
	while ( ( neighbor = G_IterateEntitiesWithinRadius( neighbor, self->s.origin, FIREBOMB_IGNITE_RANGE ) ) )
	{
		if ( neighbor->s.eType == ET_BUILDABLE && neighbor->buildableTeam == TEAM_ALIENS &&
		     G_LineOfSight( self, neighbor ) )
		{
				G_IgniteBuildable( neighbor, self->parent );
		}
	}

	// set floor below on fire (assumes the firebomb lays on the floor!)
	G_SpawnFire( self->s.origin, upwards, self->parent );

	// spam fire
	for ( subMissileNum = 0; subMissileNum < FIREBOMB_SUBMISSILE_COUNT; subMissileNum++ )
	{
		dir[ 0 ] = ( rand() / ( float )RAND_MAX ) - 0.5f;
		dir[ 1 ] = ( rand() / ( float )RAND_MAX ) - 0.5f;
		dir[ 2 ] = ( rand() / ( float )RAND_MAX ) * 0.5f;

		VectorNormalize( dir );

		// the submissile's parent is the attacker
		m = G_SpawnMissile( MIS_FIREBOMB_SUB, self->parent, self->s.origin, dir, NULL, G_FreeEntity, level.time + 10000 );

		// randomize missile speed
		VectorScale( m->s.pos.trDelta, ( rand() / ( float )RAND_MAX ) + 0.5f, m->s.pos.trDelta );
	}

	// explode
	G_ExplodeMissile( self );
}
示例#4
0
void FireFirebomb( gentity_t *self )
{
	G_SpawnMissile( MIS_FIREBOMB, self, muzzle, forward, NULL, FirebombMissileThink, level.time + FIREBOMB_TIMER );
}
示例#5
0
static void FireGrenade( gentity_t *self )
{
	G_SpawnMissile( MIS_GRENADE, self, muzzle, forward, NULL, G_ExplodeMissile, level.time + 5000 );
}
示例#6
0
static void FireFlamer( gentity_t *self )
{
	G_SpawnMissile( MIS_FLAMER, self, muzzle, forward, NULL, G_FreeEntity, level.time + FLAMER_LIFETIME );
}
示例#7
0
static void FirePrifle( gentity_t *self )
{
	G_SpawnMissile( MIS_PRIFLE, self, muzzle, forward, NULL, G_ExplodeMissile, level.time + 10000 );
}
示例#8
0
static void FireBlaster( gentity_t *self )
{
	G_SpawnMissile( MIS_BLASTER, self, muzzle, forward, NULL, G_ExplodeMissile, level.time + 10000 );
}
示例#9
0
static void FireLockblob( gentity_t *self )
{
	G_SpawnMissile( MIS_LOCKBLOB, self, muzzle, forward, NULL, G_ExplodeMissile, level.time + 15000 );
}
示例#10
0
static void FireBounceball( gentity_t *self )
{
	G_SpawnMissile( MIS_BOUNCEBALL, self, muzzle, forward, NULL, G_ExplodeMissile, level.time + 3000 );
}
示例#11
0
static void FireRocket( gentity_t *self )
{
	G_SpawnMissile( MIS_ROCKET, self, muzzle, forward, self->target, RocketThink,
	                level.time + ROCKET_TURN_PERIOD )->timestamp = level.time + ROCKET_LIFETIME;
}
示例#12
0
static void FireSlowblob( gentity_t *self )
{
	G_SpawnMissile( MIS_SLOWBLOB, self, muzzle, forward, nullptr, G_ExplodeMissile, level.time + 15000 );
}
示例#13
0
bool SpikerComponent::Fire() {
	gentity_t *self = entity.oldEnt;
	// Check if still resting.
	if (restUntil > level.time) {
		logger.Verbose("Spiker #%i wanted to fire but wasn't ready.", entity.oldEnt->s.number);

		return false;
	} else {
		logger.Verbose("Spiker #%i is firing!", entity.oldEnt->s.number);
	}

	// Play shooting animation.
	G_SetBuildableAnim(self, BANIM_ATTACK1, false);
	GetBuildableComponent().ProtectAnimation(5000);

	// TODO: Add a particle effect.
	//G_AddEvent(self, EV_ALIEN_SPIKER, DirToByte(self->s.origin2));

	// Calculate total perimeter of all spike rows to allow for a more even spike distribution.
	// A "row" is a group of missile launch directions with a common base altitude (angle measured
	// from the Spiker's horizon to its zenith) which is slightly adjusted for each new missile in
	// the row (at most halfway to the base altitude of a neighbouring row).
	float totalPerimeter = 0.0f;
	for (int row = 0; row < MISSILEROWS; row++) {
		float rowAltitude = (((float)row + 0.5f) * M_PI_2) / (float)MISSILEROWS;
		float rowPerimeter = 2.0f * M_PI * cos(rowAltitude);
		totalPerimeter += rowPerimeter;
	}

	// TODO: Use new vector library.
	vec3_t dir, zenith, rotAxis;

	// As rotation axis for setting the altitude, any vector perpendicular to the zenith works.
	VectorCopy(self->s.origin2, zenith);
	PerpendicularVector(rotAxis, zenith);

	// Distribute and launch missiles.
	for (int row = 0; row < MISSILEROWS; row++) {
		// Set the base altitude and get the perimeter for the current row.
		float rowAltitude = (((float)row + 0.5f) * M_PI_2) / (float)MISSILEROWS;
		float rowPerimeter = 2.0f * M_PI * cos(rowAltitude);

		// Attempt to distribute spikes with equal expected angular distance on all rows.
		int spikes = (int)round(((float)MISSILES * rowPerimeter) / totalPerimeter);

		// Launch missiles in the current row.
		for (int spike = 0; spike < spikes; spike++) {
			float spikeAltitude = rowAltitude + (0.5f * crandom() * M_PI_2 / (float)MISSILEROWS);
			float spikeAzimuth = 2.0f * M_PI * (((float)spike + 0.5f * crandom()) / (float)spikes);

			// Set launch direction altitude.
			RotatePointAroundVector(dir, rotAxis, zenith, RAD2DEG(M_PI_2 - spikeAltitude));

			// Set launch direction azimuth.
			RotatePointAroundVector(dir, zenith, dir, RAD2DEG(spikeAzimuth));

			// Trace in the shooting direction and do not shoot spikes that are likely to harm
			// friendly entities.
			bool fire = SafeToShoot(Vec3::Load(dir));

			logger.Debug("Spiker #%d %s: Row %d/%d: Spike %2d/%2d: "
				"( Alt %2.0f°, Az %3.0f° → %.2f, %.2f, %.2f )", self->s.number,
				fire ? "fires" : "skips", row + 1, MISSILEROWS, spike + 1, spikes,
				RAD2DEG(spikeAltitude), RAD2DEG(spikeAzimuth), dir[0], dir[1], dir[2]);

			if (!fire) {
				continue;
			}

			G_SpawnMissile(
				MIS_SPIKER, self, self->s.origin, dir, nullptr, G_FreeEntity,
				level.time + (int)(1000.0f * SPIKE_RANGE / (float)BG_Missile(MIS_SPIKER)->speed));
		}
	}

	restUntil = level.time + COOLDOWN;
	RegisterSlowThinker();

	return true;
}