Beispiel #1
0
void
doppleganger_timeout(edict_t *self)
{
	if (self->teamchain)
	{
		BecomeExplosion1(self->teamchain);
	}

	BecomeExplosion1(self);
}
Beispiel #2
0
/*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST
Any brush that you want to explode or break apart.  If you want an
ex0plosion, set dmg and it will do a radius explosion of that amount
at the center of the bursh.

If targeted it will not be shootable.

health defaults to 100.

mass defaults to 75.  This determines how much debris is emitted when
it explodes.  You get one large chunk per 100 of mass (up to 8) and
one small chunk per 25 of mass (up to 16).  So 800 gives the most.
*/
void func_explosive_explode(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
    vec3_t  origin;
    vec3_t  chunkorigin;
    vec3_t  size;
    int     count;
    int     mass;

    // bmodel origins are (0 0 0), we need to adjust that here
    VectorScale(self->size, 0.5f, size);
    VectorAdd(self->absmin, size, origin);
    VectorCopy(origin, self->s.origin);

    self->takedamage = DAMAGE_NO;

    if (self->dmg)
        T_RadiusDamage(self, attacker, self->dmg, NULL, self->dmg + 40, MOD_EXPLOSIVE);

    VectorSubtract(self->s.origin, inflictor->s.origin, self->velocity);
    VectorNormalize(self->velocity);
    VectorScale(self->velocity, 150, self->velocity);

    // start chunks towards the center
    VectorScale(size, 0.5f, size);

    mass = self->mass;
    if (!mass)
        mass = 75;

    // big chunks
    if (mass >= 100) {
        count = mass / 100;
        if (count > 8)
            count = 8;
        while (count--) {
            chunkorigin[0] = origin[0] + crandom() * size[0];
            chunkorigin[1] = origin[1] + crandom() * size[1];
            chunkorigin[2] = origin[2] + crandom() * size[2];
            ThrowDebris(self, "models/objects/debris1/tris.md2", 1, chunkorigin);
        }
    }

    // small chunks
    count = mass / 25;
    if (count > 16)
        count = 16;
    while (count--) {
        chunkorigin[0] = origin[0] + crandom() * size[0];
        chunkorigin[1] = origin[1] + crandom() * size[1];
        chunkorigin[2] = origin[2] + crandom() * size[2];
        ThrowDebris(self, "models/objects/debris2/tris.md2", 2, chunkorigin);
    }

    G_UseTargets(self, attacker);

    if (self->dmg)
        BecomeExplosion1(self);
    else
        G_FreeEdict(self);
}
Beispiel #3
0
void model_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	edict_t	*e, *next;

	e = self->movewith_next;
	while(e) {
		next = e->movewith_next;
		if(e->solid == SOLID_NOT) {
			e->nextthink = 0;
			G_FreeEdict(e);
		} else
			BecomeExplosion1 (e);
		e = next;
	}

	BecomeExplosion1(self);
}
Beispiel #4
0
void fixbot_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
	BecomeExplosion1(self);

	// shards
	
}
Beispiel #5
0
// =================
// =================
void sphere_think_explode (edict_t *self)
{
	if(self->owner && self->owner->client && !(self->spawnflags & SPHERE_DOPPLEGANGER))
	{
		self->owner->client->owned_sphere = NULL;
	}
	BecomeExplosion1 (self);
}
Beispiel #6
0
void hover_deadthink(edict_t *self)
{
    if (!self->groundentity && level.time < self->timestamp) {
        self->nextthink = level.time + FRAMETIME;
        return;
    }
    BecomeExplosion1(self);
}
Beispiel #7
0
void supplystation_explode (edict_t *self, char *message)
{
	if (self->creator && self->creator->inuse)
	{
		safe_cprintf(self->creator, PRINT_HIGH, message);
		self->creator->supplystation = NULL;
		T_RadiusDamage(self, self->creator, 150, self, 150, MOD_SUPPLYSTATION);
	}
	BecomeExplosion1(self);
}
Beispiel #8
0
void base_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	if (self->creator && self->creator->inuse)
	{
		self->creator->num_sentries--;
		if (self->creator->num_sentries < 0)
			self->creator->num_sentries = 0;
	}
	BecomeExplosion1(self);
}
Beispiel #9
0
void base_think (edict_t *self)
{
	// make sure sentry has settled down
	if (!minisentry_checkposition(self))
	{
		BecomeExplosion1(self);
		return;
	}
	self->nextthink = level.time + FRAMETIME;
}
Beispiel #10
0
void model_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
    if(self->deathtarget)
    {
        self->target = self->deathtarget;
        G_UseTargets (self, attacker);
    }
    train_kill_children(self);
    BecomeExplosion1(self);
}
Beispiel #11
0
//mxd
void flyer_spawn_gibs(edict_t *self, int damage)
{
	for (int n = 0; n < 6; n++)
		ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
	for (int n = 0; n < 4; n++)
		ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
	ThrowGib(self, "models/objects/gibs/skull/tris.md2", damage, GIB_ORGANIC); //mxd

	gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
	BecomeExplosion1(self);
}
Beispiel #12
0
void flyer_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	int n;
	// Knightmare- gibs!
	for (n= 0; n < 4; n++)
		ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
	for (n= 0; n < 2; n++)
		ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
	gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
	BecomeExplosion1(self);
}
Beispiel #13
0
void
flyer_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
		int damage /* unused */, vec3_t point /* unused */)
{
	if (!self)
	{
		return;
	}

	gi.sound(self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
	BecomeExplosion1(self);
}
Beispiel #14
0
void
doppleganger_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker,
		int damage, vec3_t point)
{
	edict_t *sphere;
	float dist;
	vec3_t dir;

	if (!self || !attacker)
	{
		return;
	}

	if ((self->enemy) && (self->enemy != self->teammaster))
	{
		VectorSubtract(self->enemy->s.origin, self->s.origin, dir);
		dist = VectorLength(dir);

		if (dist > 768)
		{
			sphere = Sphere_Spawn(self, SPHERE_HUNTER | SPHERE_DOPPLEGANGER);
			sphere->pain(sphere, attacker, 0, 0);
		}
		else
		{
			sphere = Sphere_Spawn(self, SPHERE_VENGEANCE | SPHERE_DOPPLEGANGER);
			sphere->pain(sphere, attacker, 0, 0);
		}
	}

	if (self->teamchain)
	{
		BecomeExplosion1(self->teamchain);
	}

	BecomeExplosion1(self);
}
Beispiel #15
0
/*
==========
RemoveLaserDefense

removes all lasers for this entity
==========
*/
void RemoveLaserDefense (edict_t *ent)
{
	edict_t *e = NULL;

	while((e = G_Find(e, FOFS(classname), "laser_defense_gr")) != NULL) {
		if (e && (e->owner == ent))
		{
			// remove the linked laser
			if (e->creator)
				G_FreeEdict(e->creator);
			// remove the grenade
			BecomeExplosion1(e);
		}
	}
	ent->num_lasers = 0;
}
Beispiel #16
0
void Cmd_SpawnMagmine_f (edict_t *ent)
{
	int talentLevel,cost=MAGMINE_COST;
	float skill_mult=1.0, cost_mult=1.0, delay_mult=1.0;//Talent: Rapid Assembly & Precision Tuning
	char *opt = gi.argv(1);

	if (ent->myskills.abilities[MAGMINE].disable)
		return;

	//Talent: Rapid Assembly
	talentLevel = getTalentLevel(ent, TALENT_RAPID_ASSEMBLY);
	if (talentLevel > 0)
		delay_mult -= 0.1 * talentLevel;
	//Talent: Precision Tuning
	else if ((talentLevel = getTalentLevel(ent, TALENT_PRECISION_TUNING)) > 0)
	{
		cost_mult += PRECISION_TUNING_COST_FACTOR * talentLevel;
		delay_mult += PRECISION_TUNING_DELAY_FACTOR * talentLevel;
		skill_mult += PRECISION_TUNING_SKILL_FACTOR * talentLevel;
	}
	cost *= cost_mult;

	if (!G_CanUseAbilities(ent, ent->myskills.abilities[MAGMINE].current_level, cost))
		return;

	if (!strcmp(opt, "self"))
	{
		if (getTalentLevel(ent, TALENT_MAGMINESELF))
		{
			ent->automag = !ent->automag;
			safe_cprintf(ent, PRINT_HIGH, "Auto Magmine %s\n", ent->automag? "enabled" : "disabled");
		}else
			safe_cprintf(ent, PRINT_HIGH, "You haven't upgraded this talent.\n");

		return;
	}

	if (ent->magmine && ent->magmine->inuse)
	{
		safe_cprintf(ent, PRINT_HIGH, "Removed mag mine.\n");
		BecomeExplosion1(ent->magmine);
		ent->magmine = NULL;
		return;
	}

	magmine_spawn(ent, cost, skill_mult, delay_mult);
}
Beispiel #17
0
void door_secret_blocked  (edict_t *self, edict_t *other)
{
	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
	{
		// give it a chance to go away on it's own terms (like gibs)
		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
		// if it's still there, nuke it
		if (other)
			BecomeExplosion1 (other);
		return;
	}

	if (level.time < self->touch_debounce_time)
		return;
	self->touch_debounce_time = level.time + 0.5;

	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
}
Beispiel #18
0
void plat_blocked (edict_t *self, edict_t *other) {
	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
	{
		// give it a chance to go away on it's own terms (like gibs)
		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
		// if it's still there, nuke it
		if (other)
			BecomeExplosion1 (other);
		return;
	}

	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);

	if (self->moveinfo.state == STATE_UP)
		plat_go_down (self);
	else if (self->moveinfo.state == STATE_DOWN)
		plat_go_up (self);
}
void hover_deadthink (edict_t *self)
{
	int		n;

	if (!self->groundentity && level.time < self->timestamp)
	{
		self->nextthink = level.time + FRAMETIME;
		return;
	}
	// Knightmare- gibs!
	gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
	for (n= 0; n < 8; n++)
		ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", 200, GIB_METALLIC);
	for (n= 0; n < 2; n++)
		ThrowGib (self, "models/objects/gibs/gear/tris.md2", 200, GIB_METALLIC);
	for (n= 0; n < 2; n++)
		ThrowGib (self, "models/objects/gibs/bone/tris.md2", 200, GIB_ORGANIC);
	for (n= 0; n < 6; n++)
		ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", 200, GIB_ORGANIC);
	ThrowGib (self, "models/objects/gibs/head2/tris.md2", 200, GIB_ORGANIC);
	BecomeExplosion1(self);
}
Beispiel #20
0
void Crane_blocked (edict_t *self, edict_t *other)
{
	if ( (other->classname) && (other->movetype == MOVETYPE_PUSHABLE))
	{
		// treat func_pushable like a world brush - attempt to stop
		// crane
		// This *shouldn't* be necessary, but I'm a pessimist
		Crane_Stop(self->crane_control);
		return;

	}

	if (self->crane_control->crane_hook == other)
		return;

	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
	{
		// give it a chance to go away on it's own terms (like gibs)
		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
		// if it's still there, nuke it
		if (other)
		{
			// Lazarus: Some of our ents don't have origin near the model
			vec3_t save;
			VectorCopy(other->s.origin,save);
			VectorMA (other->absmin, 0.5, other->size, other->s.origin);
			BecomeExplosion1 (other);
		}
		return;
	}

	if (level.time < self->touch_debounce_time)
		return;

	if (!self->dmg)
		return;
	self->touch_debounce_time = level.time + 0.5;
	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
}
Beispiel #21
0
void flyer_detonate(edict_t *self) {
	int damage;

	if (self->radius_dmg)
		damage = (150 + 26 * self->monsterinfo.skill);
	else
		damage = (75 + 13 * self->monsterinfo.skill);
	if (self->radius_dmg && self->monsterinfo.ability & GIEX_MABILITY_DAMAGE) {
		damage *= 2;
	}

	T_RadiusDamage(NULL, self, self, damage, damage * 0.5, self, 120 + 5 * self->monsterinfo.skill, true, MOD_R_SPLASH);

	gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
	BecomeExplosion1(self);
	if (!(self->monsterinfo.aiflags & AI_GOOD_GUY)) {
		if (self->monsterinfo.ability & GIEX_MABILITY_STEALTH) {
			removeStealth();
		}
		level.killed_monsters++;
	}
}
void hover_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	int		n;

	self->s.skinnum |= 1;

// check for gib
	if (self->health <= self->gib_health && !(self->spawnflags & SF_MONSTER_NOGIB))
	{	// Knightmare- more gibs!
		gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
		for (n= 0; n < 8; n++)
			ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
		for (n= 0; n < 2; n++)
			ThrowGib (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
		for (n= 0; n < 2; n++)
			ThrowGib (self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
		for (n= 0; n < 6; n++)
			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
		ThrowGib (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
		BecomeExplosion1(self);
		//ThrowHead (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
		//self->deadflag = DEAD_DEAD;
		return;
	}

	if (self->deadflag == DEAD_DEAD)
		return;

// regular death
	if (random() < 0.5)
		gi.sound (self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
	else
		gi.sound (self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0);
	self->deadflag = DEAD_DEAD;
	self->takedamage = DAMAGE_YES;
	self->monsterinfo.currentmove = &hover_move_death1;
}
Beispiel #23
0
void door_blocked  (edict_t *self, edict_t *other)
{
	edict_t	*ent;

	if (!(other->svflags & SVF_MONSTER) && (!other->client) )
	{
		// give it a chance to go away on it's own terms (like gibs)
		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
		// if it's still there, nuke it
		if (other)
			BecomeExplosion1 (other);
		return;
	}

	T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);

	if (self->spawnflags & DOOR_CRUSHER)
		return;


// if a door has a negative wait, it would never come back if blocked,
// so let it just squash the object to death real fast
	if (self->moveinfo.wait >= 0)
	{
		if (self->moveinfo.state == STATE_DOWN)
		{
			for (ent = self->teammaster ; ent ; ent = ent->teamchain)
				door_go_up (ent, ent->activator);
		}
		else
		{
			for (ent = self->teammaster ; ent ; ent = ent->teamchain)
				door_go_down (ent);
		}
	}
}
Beispiel #24
0
void barrel_explode (edict_t *self)
{
	vec3_t	org;
	float	spd;
	vec3_t	save;

	T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_BARREL);

	VectorCopy (self->s.origin, save);
	VectorMA (self->absmin, 0.5, self->size, self->s.origin);

	// a few big chunks
	spd = 1.5 * (float)self->dmg / 200.0;
	org[0] = self->s.origin[0] + crandom() * self->size[0];
	org[1] = self->s.origin[1] + crandom() * self->size[1];
	org[2] = self->s.origin[2] + crandom() * self->size[2];
	ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org);
	org[0] = self->s.origin[0] + crandom() * self->size[0];
	org[1] = self->s.origin[1] + crandom() * self->size[1];
	org[2] = self->s.origin[2] + crandom() * self->size[2];
	ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org);

	// bottom corners
	spd = 1.75 * (float)self->dmg / 200.0;
	VectorCopy (self->absmin, org);
	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
	VectorCopy (self->absmin, org);
	org[0] += self->size[0];
	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
	VectorCopy (self->absmin, org);
	org[1] += self->size[1];
	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
	VectorCopy (self->absmin, org);
	org[0] += self->size[0];
	org[1] += self->size[1];
	ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);

	// a bunch of little chunks
	spd = 2 * self->dmg / 200;
	org[0] = self->s.origin[0] + crandom() * self->size[0];
	org[1] = self->s.origin[1] + crandom() * self->size[1];
	org[2] = self->s.origin[2] + crandom() * self->size[2];
	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
	org[0] = self->s.origin[0] + crandom() * self->size[0];
	org[1] = self->s.origin[1] + crandom() * self->size[1];
	org[2] = self->s.origin[2] + crandom() * self->size[2];
	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
	org[0] = self->s.origin[0] + crandom() * self->size[0];
	org[1] = self->s.origin[1] + crandom() * self->size[1];
	org[2] = self->s.origin[2] + crandom() * self->size[2];
	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
	org[0] = self->s.origin[0] + crandom() * self->size[0];
	org[1] = self->s.origin[1] + crandom() * self->size[1];
	org[2] = self->s.origin[2] + crandom() * self->size[2];
	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
	org[0] = self->s.origin[0] + crandom() * self->size[0];
	org[1] = self->s.origin[1] + crandom() * self->size[1];
	org[2] = self->s.origin[2] + crandom() * self->size[2];
	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
	org[0] = self->s.origin[0] + crandom() * self->size[0];
	org[1] = self->s.origin[1] + crandom() * self->size[1];
	org[2] = self->s.origin[2] + crandom() * self->size[2];
	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
	org[0] = self->s.origin[0] + crandom() * self->size[0];
	org[1] = self->s.origin[1] + crandom() * self->size[1];
	org[2] = self->s.origin[2] + crandom() * self->size[2];
	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
	org[0] = self->s.origin[0] + crandom() * self->size[0];
	org[1] = self->s.origin[1] + crandom() * self->size[1];
	org[2] = self->s.origin[2] + crandom() * self->size[2];
	ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);

	VectorCopy (save, self->s.origin);
	if (self->groundentity)
		BecomeExplosion2 (self);
	else
		BecomeExplosion1 (self);
}
Beispiel #25
0
/*
========================
func_explosive_objective
========================
*/
void func_explosive_objective_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	vec3_t	origin;
	vec3_t	chunkorigin;
	vec3_t	size;
	int		count;
	int		mass;
	int		enemy;
	int		otherteam;

	//gi.dprintf(DEVELOPER_MSG_GAME, "self: %s\ninflictor: %s\n attacker: %s\n",
	//	self->classname, inflictor->classname, attacker->classname);

	if (!attacker->client ||
		!attacker->client->resp.mos)
		return;

	// bmodel origins are (0 0 0), we need to adjust that here
	VectorScale (self->size, 0.5, size);
	VectorAdd (self->absmin, size, origin);
	VectorCopy (origin, self->s.origin);

	self->takedamage = DAMAGE_NO;

	if (self->dmg)
		T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);

	VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity);
	VectorNormalize (self->velocity);
	VectorScale (self->velocity, 150, self->velocity);

	// start chunks towards the center
	VectorScale (size, 0.5, size);

	mass = self->mass;
	if (!mass)
		mass = 75;

	// big chunks
	if (mass >= 100)
	{
		count = mass / 100;
		if (count > 8)
			count = 8;
		while(count--)
		{
			chunkorigin[0] = origin[0] + crandom() * size[0];
			chunkorigin[1] = origin[1] + crandom() * size[1];
			chunkorigin[2] = origin[2] + crandom() * size[2];
			ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin);
		}
	}

	// small chunks
	count = mass / 25;
	if (count > 16)
		count = 16;
	while(count--)
	{
		chunkorigin[0] = origin[0] + crandom() * size[0];
		chunkorigin[1] = origin[1] + crandom() * size[1];
		chunkorigin[2] = origin[2] + crandom() * size[2];
		ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin);
	}

	G_UseTargets (self, attacker);

	// hack for 2 team games

	if (self->obj_owner != 99) {
		team_list[self->obj_owner]->score -= self->obj_loss;
		enemy = (self->obj_owner) ? 0 : 1;
	} else
		enemy = 99;

	if (self->obj_owner != attacker->client->resp.team_on->index)
		team_list[attacker->client->resp.team_on->index]->score += self->obj_gain;
	else if (self->obj_owner == attacker->client->resp.team_on->index && enemy != 99)
		team_list[enemy]->score += self->obj_gain;

	if (dedicated->value)
		safe_cprintf(NULL, PRINT_HIGH, "%s destroyed by %s [%s]\n", 
			self->obj_name, 
			attacker->client->pers.netname,
			team_list[attacker->client->resp.team_on->index]->teamname);

	centerprintall("%s destroyed by:\n\n%s\n%s",
		self->obj_name, 
		attacker->client->pers.netname,
		team_list[attacker->client->resp.team_on->index]->teamname);

	otherteam = (self->obj_owner+1)%2;
	if ((!team_list[otherteam]->kills_and_points && team_list[otherteam]->score < team_list[otherteam]->need_points) ||
	    (team_list[otherteam]->kills_and_points && team_list[otherteam]->kills < team_list[otherteam]->need_kills))
	  gi.sound(self, CHAN_NO_PHS_ADD, gi.soundindex(va("%s/objectives/touch_cap.wav", team_list[otherteam]->teamid)), 1, 0, 0);

//		gi.dprintf(DEVELOPER_MSG_GAME, "pts:%i  ndpts:%i  kills:%i  ndkills:%i\n",team_list[(self->obj_owner+1)%2]->score,team_list[(self->obj_owner+1)%2]->need_points,
//team_list[(self->obj_owner+1)%2]->kills,team_list[(self->obj_owner+1)%2]->need_kills);

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

	if (self->dmg)
		BecomeExplosion1 (self);
	else
		G_FreeEdict (self);
}
Beispiel #26
0
void floater_die(edict_t * self, edict_t * inflictor, edict_t * attacker,
		 int damage, vec3_t point)
{
	gi.sound(self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
	BecomeExplosion1(self);
}
Beispiel #27
0
void pendulum_blocked (edict_t *self, edict_t *other)
{
	trace_t	trace;
	vec3_t	angles;
	vec3_t	forward, left, up;
	vec3_t	dir;
	vec3_t	f1, l1, u1;
	vec3_t	point;
	vec3_t	origin;
	vec3_t	new_velocity;
	vec3_t	new_origin;
	float	speed;
	int		damage;

	// Since this routine is called in response to being blocked, 
	// the current s.angles is for the LAST frame, not the proposed
	// angles for the current frame. Since we're basically overriding
	// normal physics here, go ahead and move to new location. This
	// means that later on we have to move blocker NOW rather than
	// relying on its velocity to get it out of the way.
	// BUT... trouble is doing this with players ends up giving
	// goofy direction in some cases. For players/monsters, use old
	// angles but STILL move 'em out of the way immediately
	if(other->client || (other->svflags & SVF_MONSTER))
		VectorCopy(self->s.angles,angles);
	else
		VectorMA(self->s.angles,FRAMETIME,self->avelocity,angles);

	AngleVectors(angles,forward,left,up);

	speed = fabs(self->avelocity[ROLL]) * M_PI / 180. * self->radius;
	if( (level.time > self->touch_debounce_time) && (speed > 200) )
	{
		damage = (int)( self->dmg * (speed-200)/100 );
		self->touch_debounce_time = level.time + 0.5;
	}
	else
		damage = 0;

	VectorAdd(other->s.origin,other->origin_offset,origin);
	VectorCopy(left,dir);
	if(self->avelocity[ROLL] > 0)
		VectorNegate(dir,dir);

	VectorScale(forward,self->move_origin[0],f1);
	VectorScale(left,-self->move_origin[1],l1);
	VectorScale(up,self->move_origin[2],u1);
	VectorAdd(self->s.origin,f1,point);
	VectorAdd(point,l1,point);
	VectorAdd(point,u1,point);
	VectorSubtract(origin,point,point);
	VectorNormalize(point);

	if(other->client || (other->svflags & SVF_MONSTER))
	{
		if((point[2] < -0.7) && other->groundentity)
		{
			T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, DAMAGE_NO_PROTECTION, MOD_CRUSH);
			return;
		}

		dir[2] = max(1.0,fabs(dir[2]));
		VectorNormalize(dir);
		// Normal kickback takes too long to take effect and allows embedment. Move
		// the blocker NOW.
		// Give a minimum speed so we can get the poor fool out of the way
		speed = max(100,speed);
		VectorScale(dir,speed,new_velocity);
		VectorMA(other->s.origin,FRAMETIME,new_velocity,new_origin);
		other->solid = SOLID_NOT;
		gi.linkentity(other);
		trace = gi.trace(other->s.origin,other->mins,other->maxs,new_origin,self,other->clipmask);
		VectorCopy(trace.endpos,other->s.origin);
		VectorCopy(new_velocity,other->velocity);
		other->solid = SOLID_BBOX;
		gi.linkentity(other);
		T_Damage (other, self, self, dir, other->s.origin, vec3_origin, damage, 0, 0, MOD_CRUSH);
	}
	else if(other->solid == SOLID_BSP)
	{
		// Other is most likely a func_pushable, since almost all other bmodels aren't
		// clipped to MOVETYPE_PUSH

		vec3_t		org, mins, maxs;
		vec3_t		vn2;
		qboolean	block;
		float		e=self->attenuation;	// coefficient of restitution
		float		m=(float)(other->mass)/(float)(self->mass);
		float		v11 = speed;
		float		v21;		// Initial speed of other in the impact direction
		float		v12, v22;
		float		new_rspeed;
		float		sgor, time, wave;

		if(v11 >= 100)
			gi.sound (self, 0, self->noise_index, 1, 1, 0);

		// If other is on the ground, push it UP regardless of dir
		if(other->groundentity)
			dir[2] = max(1.0,fabs(dir[2]));
		VectorNormalize(dir);

		// If pendulum hits crate from above and crate is on the ground,
		// destroy the crate. This may not be realistic, but there's really
		// no other way since if we stop the pendulum we'd then have to 
		// continously monitor whether the crate moved away or not.
		if((point[2] < -0.7) && (other->velocity[2] == 0))
		{
			box_die (other, self, self, 100000, point);
			return;
		}
		if(e > 0)
		{
			v21 = VectorLength(other->velocity);
			if(v21 > 0)
			{
				VectorCopy(other->velocity,vn2);
				VectorNormalize(vn2);
				v21 *= DotProduct(dir,vn2);
			}

			v22 = ( e*(v11-v21) + v11 + m*v21 ) / (1.0 + m);
			v12 = v22 + e*(v21-v11);
//			gi.dprintf("v11=%g, v21=%g, v12=%g, v22=%g\n",v11,v21,v12,v22);
//			gi.dprintf("av[ROLL]=%g, roll=%g\n",self->avelocity[ROLL],angles[ROLL]);
		}
		else
		{
			v12 = v11;
			if(other->mass > self->mass)
			{
				block = true;
				VectorClear(self->avelocity);
				gi.linkentity(self);
				goto deadstop;
			}
			else
				v22 = v11 * (float)self->mass/(float)other->mass;
		}
		VectorScale(dir,v22,new_velocity);

		if(v12 < 0)
		{
			// Reverse rotation.
			new_rspeed = fabs(v12) / (M_PI / 180. * self->radius);
			if(self->avelocity[ROLL] > 0)
				self->avelocity[ROLL] = -new_rspeed;
			else
				self->avelocity[ROLL] = new_rspeed;
		}
		else
		{
			// Continuing to move in same direction, though slower.
			new_rspeed = v12 / (M_PI / 180. * self->radius);
			if(self->avelocity[ROLL] > 0)
				self->avelocity[ROLL] = new_rspeed;
			else
				self->avelocity[ROLL] = -new_rspeed;
		}
		sgor = sqrt( (float)sv_gravity->value / self->radius );
		wave = fabs( self->avelocity[ROLL] / (angles[ROLL] * sgor) );
		wave = atan(wave);
		if(self->avelocity[ROLL] >= 0)
		{
			if(angles[ROLL] > 0)
				wave = M_PI - wave;
		}
		else
		{
			if(angles[ROLL] > 0)
				wave = M_PI + wave;
			else
				wave = 2*M_PI - wave;
		}
		time = wave/sgor;
		self->startframe = level.framenum - time*10.;
		self->moveinfo.start_angles[ROLL] = -fabs(angles[ROLL] / cos(wave));

		// Now we know the new pendulum velocity and crate velocity, *assuming*
		// nothing else is in the way. Now check to see if crate hits anything
		// else.

		VectorAdd(other->s.origin,other->origin_offset,org);
		VectorMA(org,FRAMETIME,new_velocity,new_origin);

		// Temporarily make crate nonsolid so we can ignore pendulum in our trace
		// (rather than crate)
		other->solid = SOLID_NOT;
		gi.linkentity(other);
		VectorSubtract(other->mins,other->origin_offset,mins);
		VectorSubtract(other->maxs,other->origin_offset,maxs);
		trace = gi.trace (org, mins, maxs, new_origin, self, other->clipmask);
		// restore solidity of crate
		other->solid = SOLID_BSP;
		if(trace.startsolid)
		{
			// Things are completely fouled up. Nuke other and go away.
			T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
			if (other)
				BecomeExplosion1 (other);
			return;
		}
		else if(trace.fraction < 1.0)
		{
			vec3_t	vec;
			float	dist;
			VectorSubtract(trace.endpos,org,vec);
			dist = VectorLength(vec);

			if( (trace.ent->client) || (trace.ent->flags & SVF_MONSTER))
			{
				float	delta=FRAMETIME*VectorLength(new_velocity);

				// If a player or monster is in the way of the crate, AND
				// the pendulum speed is > 100, throw 'em out of the way.
				// If pendulum tangential speed is < 100, give up.
				if(speed < 100)
					block = true;
				else
				{
					if(dist < delta)
					{
						VectorScale(new_velocity,1.25,trace.ent->velocity);
						VectorMA(trace.ent->s.origin,FRAMETIME,trace.ent->velocity,trace.ent->s.origin);
						gi.linkentity(trace.ent);
					}
					block = false;
				}
			}
			else
			{
				if(dist < speed*FRAMETIME)
				{
					block = true;
					VectorScale(vec,10.,other->velocity);
					VectorMA(other->s.origin,FRAMETIME,other->velocity,other->s.origin);
				}
				else
					block = false;
			}
		}
		else
			block = false;

		if(!block)
		{
			VectorCopy(new_velocity,other->velocity);
			VectorMA(other->s.origin,FRAMETIME,other->velocity,other->s.origin);
		}
		gi.linkentity(other);

		// Final checks:
		// 1) If pendulum after-impact speed is < 100, that's too damn slow.
		//    Lie and say it's blocked
		// 2) If not blocked, in its new position test for intersection
		// of crate and pendulum. If they intersect, then most likely pendulum is
		// moving VERY slowly and we need to reverse direction NOW to prevent
		// embedment.
		if(!block)
		{
			if(fabs(v12) < 100)
				block = true;
			else
			{
				VectorAdd(other->s.origin,other->origin_offset,org);
				trace = gi.trace(org,mins,maxs,org,other,MASK_SOLID);
				if(trace.startsolid)
					block = true;
			}
		}
deadstop:
		T_Damage (other, self, self, dir, other->s.origin, vec3_origin, damage, 0, 0, MOD_CRUSH);
		if( block )
		{
			// Then this sucker will still be in the way. Reverse rotation, slow, or stop
			if(fabs(angles[ROLL]) > 2)
			{
				if(fabsf(angles[ROLL]) < 10)
					self->spawnflags |= SF_PENDULUM_SLOW;
				self->moveinfo.start_angles[ROLL] = angles[ROLL];
				VectorClear(self->avelocity);
				self->startframe = 0;
			}
			else
			{
				self->spawnflags &= ~SF_PENDULUM_STARTON;
				self->moveinfo.start_angles[ROLL] = 0;
				VectorClear(self->s.angles);
				VectorClear(self->avelocity);
			}
			gi.linkentity(self);
		}
		else if((fabs(self->avelocity[ROLL]) < 10) && (fabs(self->s.angles[ROLL]) < 10))
		{
			self->spawnflags |= SF_PENDULUM_SLOW;
			self->moveinfo.start_angles[ROLL] = angles[ROLL];
			VectorClear(self->avelocity);
			self->startframe = 0;
		}
	}
	else
	{
		T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH);
		// if it's still there, nuke it
		if (other)
			BecomeExplosion1 (other);
	}
}
Beispiel #28
0
void base_createturret (edict_t *self)
{
	edict_t		*sentry;
	vec3_t		end;
	trace_t		tr;
	int			casterlevel, talentLevel;
	float		ammo_mult=1.0;

	// make sure sentry has settled down
	if (!G_EntIsAlive(self->creator) || !minisentry_checkposition(self))
	{
		if (self->creator)
		{
			self->creator->num_sentries--;
			if (self->creator->num_sentries < 0)
				self->creator->num_sentries = 0;
		}
		BecomeExplosion1(self);
		return;
	}
	self->movetype = MOVETYPE_NONE; // lock down base
	self->takedamage = DAMAGE_NO; // the base is invulnerable

	// 3.8 base bbox no longer necessary, turret takes over
	VectorClear(self->mins);
	VectorClear(self->maxs);
	self->solid = SOLID_NOT;

	// create basic ent for sentry
	sentry = G_Spawn();
	sentry->creator = self->creator;
	sentry->owner = self; // the base becomes the owner
	VectorCopy(self->s.angles, sentry->s.angles);
	sentry->think = minisentry_think;
	sentry->nextthink = level.time + FRAMETIME;
	sentry->s.modelindex = gi.modelindex ("models/weapons/g_bfg/tris.md2");
	sentry->s.renderfx |= RF_IR_VISIBLE;
	// who really wanted to chase sentries anyway
	// sentry->flags |= FL_CHASEABLE; // 3.65 indicates entity can be chase cammed
	sentry->solid = SOLID_BBOX;
	sentry->movetype = MOVETYPE_NONE;
	sentry->clipmask = MASK_MONSTERSOLID;
	sentry->mass = 100;
	sentry->classname = "msentrygun";
	//sentry->viewheight = 16;
	sentry->takedamage = DAMAGE_AIM;
	sentry->mtype = M_MINISENTRY;
	sentry->touch = minisentry_touch;
	
	sentry->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD;

	//Talent: Storage Upgrade
	talentLevel = getTalentLevel(self->creator, TALENT_STORAGE_UPGRADE);
	ammo_mult += 0.2 * talentLevel;

	// set ammo
	sentry->monsterinfo.jumpdn = SENTRY_MAX_AMMO * ammo_mult; // max ammo
	sentry->light_level = sentry->monsterinfo.jumpdn; // current ammo

	//get player's current_level for BUILD_SENTRY
	casterlevel = self->monsterinfo.level;
	sentry->monsterinfo.level = casterlevel; // used for adding monster exp
	sentry->monsterinfo.control_cost = 20; // used for adding monster exp

	//set health
	sentry->health = MINISENTRY_INITIAL_HEALTH + (MINISENTRY_ADDON_HEALTH * casterlevel);
	sentry->monsterinfo.power_armor_power = MINISENTRY_INITIAL_ARMOR + (MINISENTRY_ADDON_ARMOR * casterlevel);
//	if (sentry->health > MINISENTRY_MAX_HEALTH)
//		sentry->health = MINISENTRY_MAX_HEALTH;
	//if (sentry->monsterinfo.power_armor_power > MINISENTRY_MAX_ARMOR)
	//	sentry->monsterinfo.power_armor_power = MINISENTRY_MAX_ARMOR;
	sentry->max_health = sentry->health;
	sentry->monsterinfo.max_armor = sentry->monsterinfo.power_armor_power;

	//set damage
	sentry->dmg = MINISENTRY_INITIAL_BULLET + (MINISENTRY_ADDON_BULLET * casterlevel);// bullet damage
	sentry->radius_dmg = MINISENTRY_INITIAL_ROCKET + (MINISENTRY_ADDON_ROCKET * casterlevel); // rocket damage
	if (sentry->dmg > MINISENTRY_MAX_BULLET)
		sentry->dmg = MINISENTRY_MAX_BULLET;
	if (sentry->radius_dmg > MINISENTRY_MAX_ROCKET)
		sentry->radius_dmg = MINISENTRY_MAX_ROCKET;

	sentry->die = minisentry_die;
	sentry->pain = minisentry_pain;
	sentry->yaw_speed = 5;

	if (self->style == SENTRY_UPRIGHT)
	{
		VectorSet(sentry->mins, -28, -28, -12);
		VectorSet(sentry->maxs, 28, 28, 24);
		VectorCopy(self->s.origin, end);
		//end[2] += self->maxs[2] + sentry->mins[2] + 1;
		end[2] += abs(sentry->mins[2])+1;
	}
	else
	{
		VectorSet(sentry->mins, -28, -28, -24);
		VectorSet(sentry->maxs, 28, 28, 12);
		VectorCopy(self->s.origin, end);
		//end[2] -= abs(self->mins[2]) + sentry->maxs[2] + 1;
		end[2] -= sentry->maxs[2]+1;
	}

	// make sure position is valid
	tr = gi.trace(end, sentry->mins, sentry->maxs, end, sentry, MASK_SHOT);
	if (tr.contents & MASK_SHOT)
	{
		if (self->creator)
		{
			self->creator->num_sentries--;
			if (self->creator->num_sentries < 0)
				self->creator->num_sentries = 0;
		}
		//gi.dprintf("%s\n", tr.ent?tr.ent->classname:"null");
		BecomeExplosion1(self);
		BecomeExplosion1(sentry);
		return;
	}
	VectorCopy(tr.endpos, sentry->s.origin);
	VectorCopy(sentry->s.angles, sentry->move_angles);// save for idle animation
	gi.linkentity(sentry);
	
	gi.sound(sentry, CHAN_VOICE, gi.soundindex("weapons/turrset.wav"), 1, ATTN_NORM, 0);
	self->think = base_think; // base is done creating gun
	self->nextthink = level.time + FRAMETIME;
}
Beispiel #29
0
static void func_explosive_explode( edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t point )
{
	vec3_t origin, bakorigin;
	vec3_t chunkorigin;
	vec3_t size;
	int count;
	int mass;

	// do not explode unless visible
	if( self->r.svflags & SVF_NOCLIENT )
		return;

	self->takedamage = DAMAGE_NO;

	// bmodel origins are (0 0 0), we need to adjust that here
	VectorCopy( self->s.origin, bakorigin );
	VectorScale( self->r.size, 0.5, size );
	VectorAdd( self->r.absmin, size, origin );
	VectorCopy( origin, self->s.origin );

	if( self->projectileInfo.maxDamage )
		G_RadiusDamage( self, attacker, NULL, NULL, MOD_EXPLOSIVE );

	VectorSubtract( self->s.origin, inflictor->s.origin, self->velocity );
	VectorNormalize( self->velocity );
	VectorScale( self->velocity, 150, self->velocity );

	// start chunks towards the center
	VectorScale( size, 0.5, size );
	mass = self->projectileInfo.radius * 0.75;
	if( !mass )
		mass = 75;

	// big chunks
	if( self->count > 0 )
	{
		if( mass >= 100 )
		{
			count = mass / 100;
			if( count > 8 )
				count = 8;
			while( count-- )
			{
				chunkorigin[0] = origin[0] + crandom() * size[0];
				chunkorigin[1] = origin[1] + crandom() * size[1];
				chunkorigin[2] = origin[2] + crandom() * size[2];
				ThrowDebris( self, self->count, 1, chunkorigin );
			}
		}
	}

	// small chunks
	if( self->viewheight > 0 )
	{
		count = mass / 25;
		if( count > 16 )
			count = 16;
		if( count < 1 ) count = 1;
		while( count-- )
		{
			chunkorigin[0] = origin[0] + crandom() * size[0];
			chunkorigin[1] = origin[1] + crandom() * size[1];
			chunkorigin[2] = origin[2] + crandom() * size[2];
			ThrowDebris( self, self->viewheight, 2, chunkorigin );
		}
	}

	G_UseTargets( self, attacker );

	if( self->projectileInfo.maxDamage )
	{
		edict_t *explosion;

		explosion = G_Spawn();
		VectorCopy( self->s.origin, explosion->s.origin );
		explosion->projectileInfo = self->projectileInfo;
		BecomeExplosion1( explosion );
	}

	if( self->use == NULL )
	{
		G_FreeEdict( self );
		return;
	}

	self->health = self->max_health;
	self->r.solid = SOLID_NOT;
	self->r.svflags |= SVF_NOCLIENT;
	VectorCopy( bakorigin, self->s.origin );
	VectorClear( self->velocity );
	GClip_LinkEntity( self );
}
Beispiel #30
0
void
Trap_Think(edict_t *ent)
{
	edict_t *target = NULL;
	edict_t *best = NULL;
	vec3_t vec;
	int len, i;
	int oldlen = 8000;
	vec3_t forward, right, up;

	if (!ent)
	{
		return;
	}

	if (ent->timestamp < level.time)
	{
		BecomeExplosion1(ent);
		return;
	}

	ent->nextthink = level.time + 0.1;

	if (!ent->groundentity)
	{
		return;
	}

	/* ok lets do the blood effect */
	if (ent->s.frame > 4)
	{
		if (ent->s.frame == 5)
		{
			if (ent->wait == 64)
			{
				gi.sound(ent, CHAN_VOICE, gi.soundindex("weapons/trapdown.wav"),
					   	1, ATTN_IDLE, 0);
			}

			ent->wait -= 2;
			ent->delay += level.time;

			for (i = 0; i < 3; i++)
			{
				best = G_Spawn();

				if (strcmp(ent->enemy->classname, "monster_gekk") == 0)
				{
					best->s.modelindex = gi.modelindex("models/objects/gekkgib/torso/tris.md2");
					best->s.effects |= TE_GREENBLOOD;
				}
				else if (ent->mass > 200)
				{
					best->s.modelindex = gi.modelindex("models/objects/gibs/chest/tris.md2");
					best->s.effects |= TE_BLOOD;
				}
				else
				{
					best->s.modelindex = gi.modelindex("models/objects/gibs/sm_meat/tris.md2");
					best->s.effects |= TE_BLOOD;
				}

				AngleVectors(ent->s.angles, forward, right, up);

				RotatePointAroundVector(vec, up, right, ((360.0 / 3) * i) + ent->delay);
				VectorMA(vec, ent->wait / 2, vec, vec);
				VectorAdd(vec, ent->s.origin, vec);
				VectorAdd(vec, forward, best->s.origin);

				best->s.origin[2] = ent->s.origin[2] + ent->wait;

				VectorCopy(ent->s.angles, best->s.angles);

				best->solid = SOLID_NOT;
				best->s.effects |= EF_GIB;
				best->takedamage = DAMAGE_YES;

				best->movetype = MOVETYPE_TOSS;
				best->svflags |= SVF_MONSTER;
				best->deadflag = DEAD_DEAD;

				VectorClear(best->mins);
				VectorClear(best->maxs);

				best->watertype = gi.pointcontents(best->s.origin);

				if (best->watertype & MASK_WATER)
				{
					best->waterlevel = 1;
				}

				best->nextthink = level.time + 0.1;
				best->think = G_FreeEdict;
				gi.linkentity(best);
			}

			if (ent->wait < 19)
			{
				ent->s.frame++;
			}

			return;
		}

		ent->s.frame++;

		if (ent->s.frame == 8)
		{
			ent->nextthink = level.time + 1.0;
			ent->think = G_FreeEdict;

			best = G_Spawn();
			SP_item_foodcube(best);
			VectorCopy(ent->s.origin, best->s.origin);
			best->s.origin[2] += 16;
			best->velocity[2] = 400;
			best->count = ent->mass;
			gi.linkentity(best);
			return;
		}

		return;
	}

	ent->s.effects &= ~EF_TRAP;

	if (ent->s.frame >= 4)
	{
		ent->s.effects |= EF_TRAP;
		VectorClear(ent->mins);
		VectorClear(ent->maxs);
	}

	if (ent->s.frame < 4)
	{
		ent->s.frame++;
	}

	while ((target = findradius(target, ent->s.origin, 256)) != NULL)
	{
		if (target == ent)
		{
			continue;
		}

		if (!(target->svflags & SVF_MONSTER) && !target->client)
		{
			continue;
		}

		if (target->health <= 0)
		{
			continue;
		}

		if (!visible(ent, target))
		{
			continue;
		}

		if (!best)
		{
			best = target;
			continue;
		}

		VectorSubtract(ent->s.origin, target->s.origin, vec);
		len = VectorLength(vec);

		if (len < oldlen)
		{
			oldlen = len;
			best = target;
		}
	}

	/* pull the enemy in */
	if (best)
	{
		vec3_t forward;

		if (best->groundentity)
		{
			best->s.origin[2] += 1;
			best->groundentity = NULL;
		}

		VectorSubtract(ent->s.origin, best->s.origin, vec);
		len = VectorLength(vec);

		if (best->client)
		{
			VectorNormalize(vec);
			VectorMA(best->velocity, 250, vec, best->velocity);
		}
		else
		{
			best->ideal_yaw = vectoyaw(vec);
			M_ChangeYaw(best);
			AngleVectors(best->s.angles, forward, NULL, NULL);
			VectorScale(forward, 256, best->velocity);
		}

		gi.sound(ent, CHAN_VOICE, gi.soundindex(
						"weapons/trapsuck.wav"), 1, ATTN_IDLE, 0);

		if (len < 32)
		{
			if (best->mass < 400)
			{
				T_Damage(best, ent, ent->owner, vec3_origin, best->s.origin,
						vec3_origin, 100000, 1, 0, MOD_TRAP);
				ent->enemy = best;
				ent->wait = 64;
				VectorCopy(ent->s.origin, ent->s.old_origin);
				ent->timestamp = level.time + 30;

				if (deathmatch->value)
				{
					ent->mass = best->mass / 4;
				}
				else
				{
					ent->mass = best->mass / 10;
				}

				/* ok spawn the food cube */
				ent->s.frame = 5;
			}
			else
			{
				BecomeExplosion1(ent);
				return;
			}
		}
	}
}