3680 lines
86 KiB
C
3680 lines
86 KiB
C
|
// g_misc.c
|
||
|
|
||
|
#include "g_local.h"
|
||
|
|
||
|
|
||
|
/*QUAKED func_group (0 0 0) ?
|
||
|
Used to group brushes together just for editor convenience.
|
||
|
*/
|
||
|
|
||
|
//=====================================================
|
||
|
|
||
|
void Use_Areaportal (edict_t *ent, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
ent->count ^= 1; // toggle state
|
||
|
// gi.dprintf ("portalstate: %i = %i\n", ent->style, ent->count);
|
||
|
gi.SetAreaPortalState (ent->style, ent->count);
|
||
|
}
|
||
|
|
||
|
/*QUAKED func_areaportal (0 0 0) ?
|
||
|
|
||
|
This is a non-visible object that divides the world into
|
||
|
areas that are seperated when this portal is not activated.
|
||
|
Usually enclosed in the middle of a door.
|
||
|
*/
|
||
|
void SP_func_areaportal (edict_t *ent)
|
||
|
{
|
||
|
ent->use = Use_Areaportal;
|
||
|
ent->count = 0; // always start closed;
|
||
|
}
|
||
|
|
||
|
//=====================================================
|
||
|
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
Misc functions
|
||
|
=================
|
||
|
*/
|
||
|
void VelocityForDamage (int damage, vec3_t v)
|
||
|
{
|
||
|
v[0] = 300.0 * crandom();
|
||
|
v[1] = 300.0 * crandom();
|
||
|
v[2] = 200.0 + 400.0 * random();
|
||
|
|
||
|
if (damage < 50)
|
||
|
VectorScale (v, 0.7, v);
|
||
|
else
|
||
|
VectorScale (v, 1.2, v);
|
||
|
}
|
||
|
|
||
|
void ClipGibVelocity (edict_t *ent)
|
||
|
{
|
||
|
if (ent->velocity[0] < -400)
|
||
|
ent->velocity[0] = -400;
|
||
|
else if (ent->velocity[0] > 400)
|
||
|
ent->velocity[0] = 400;
|
||
|
if (ent->velocity[1] < -400)
|
||
|
ent->velocity[1] = -400;
|
||
|
else if (ent->velocity[1] > 400)
|
||
|
ent->velocity[1] = 400;
|
||
|
if (ent->velocity[2] < 200)
|
||
|
ent->velocity[2] = 200; // always some upwards
|
||
|
else if (ent->velocity[2] > 500)
|
||
|
ent->velocity[2] = 500;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
gibs
|
||
|
=================
|
||
|
*/
|
||
|
void gib_think (edict_t *self)
|
||
|
{
|
||
|
self->s.frame++;
|
||
|
self->nextthink = level.time + FRAMETIME;
|
||
|
|
||
|
if (self->s.frame == 10)
|
||
|
{
|
||
|
self->think = G_FreeEdict;
|
||
|
self->nextthink = level.time + 8 + random()*10;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gib_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
|
{
|
||
|
vec3_t normal_angles, right;
|
||
|
|
||
|
if (!self->groundentity)
|
||
|
return;
|
||
|
|
||
|
self->touch = NULL;
|
||
|
|
||
|
if (plane)
|
||
|
{
|
||
|
// JOSEPH 29-MAR-99
|
||
|
//gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0);
|
||
|
// END JOSEPH
|
||
|
|
||
|
vectoangles (plane->normal, normal_angles);
|
||
|
AngleVectors (normal_angles, NULL, right, NULL);
|
||
|
vectoangles (right, self->s.angles);
|
||
|
|
||
|
if (self->s.modelindex == sm_meat_index)
|
||
|
{
|
||
|
self->s.frame++;
|
||
|
self->think = gib_think;
|
||
|
self->nextthink = level.time + FRAMETIME;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RAFAEL
|
||
|
/* Ridah, this has been diasabled in the latest code
|
||
|
void gib_touchacid (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
|
{
|
||
|
vec3_t normal_angles, right;
|
||
|
|
||
|
if (other->takedamage)
|
||
|
{
|
||
|
// T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0);
|
||
|
T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
|
||
|
G_FreeEdict (self);
|
||
|
}
|
||
|
|
||
|
if (!self->groundentity)
|
||
|
return;
|
||
|
|
||
|
if (plane)
|
||
|
{
|
||
|
// JOSEPH 29-MAR-99
|
||
|
gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0);
|
||
|
// END JOSEPH
|
||
|
|
||
|
vectoangles (plane->normal, normal_angles);
|
||
|
AngleVectors (normal_angles, NULL, right, NULL);
|
||
|
vectoangles (right, self->s.angles);
|
||
|
|
||
|
if (self->s.modelindex == sm_meat_index)
|
||
|
{
|
||
|
self->s.frame++;
|
||
|
self->think = gib_think;
|
||
|
self->nextthink = level.time + FRAMETIME;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
void gib_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mdx_part, int mdx_subobject)
|
||
|
{
|
||
|
G_FreeEdict (self);
|
||
|
}
|
||
|
|
||
|
edict_t *ThrowGib (edict_t *self, char *gibname, int damage, int type)
|
||
|
{
|
||
|
edict_t *gib;
|
||
|
vec3_t vd;
|
||
|
vec3_t origin;
|
||
|
vec3_t size;
|
||
|
float vscale;
|
||
|
|
||
|
gib = G_Spawn();
|
||
|
|
||
|
VectorScale (self->size, 0.5, size);
|
||
|
VectorAdd (self->absmin, size, origin);
|
||
|
gib->s.origin[0] = origin[0] + crandom() * size[0];
|
||
|
gib->s.origin[1] = origin[1] + crandom() * size[1];
|
||
|
gib->s.origin[2] = origin[2] + crandom() * size[2];
|
||
|
|
||
|
gi.setmodel (gib, gibname);
|
||
|
gib->solid = SOLID_NOT;
|
||
|
gib->s.effects |= EF_GIB;
|
||
|
gib->flags |= FL_NO_KNOCKBACK;
|
||
|
gib->takedamage = DAMAGE_YES;
|
||
|
gib->s.renderfx2 |= RF2_NOSHADOW;
|
||
|
gib->die = gib_die;
|
||
|
|
||
|
if (type == GIB_ORGANIC)
|
||
|
{
|
||
|
gib->movetype = MOVETYPE_TOSS;
|
||
|
gib->touch = gib_touch;
|
||
|
vscale = 0.5;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gib->movetype = MOVETYPE_BOUNCE;
|
||
|
vscale = 1.0;
|
||
|
}
|
||
|
|
||
|
VelocityForDamage (damage, vd);
|
||
|
VectorMA (self->velocity, vscale, vd, gib->velocity);
|
||
|
ClipGibVelocity (gib);
|
||
|
gib->avelocity[0] = random()*600;
|
||
|
gib->avelocity[1] = random()*600;
|
||
|
gib->avelocity[2] = random()*600;
|
||
|
|
||
|
gib->think = G_FreeEdict;
|
||
|
gib->nextthink = level.time + 10 + random()*10;
|
||
|
|
||
|
gi.linkentity (gib);
|
||
|
|
||
|
return gib;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void ThrowHead (edict_t *self, char *gibname, int damage, int type)
|
||
|
{
|
||
|
vec3_t vd;
|
||
|
float vscale;
|
||
|
|
||
|
self->s.skinnum = 0;
|
||
|
self->s.frame = 0;
|
||
|
VectorClear (self->mins);
|
||
|
VectorClear (self->maxs);
|
||
|
|
||
|
// self->s.modelindex2 = 0;
|
||
|
gi.setmodel (self, gibname);
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->s.effects |= EF_GIB;
|
||
|
self->s.effects &= ~EF_FLIES;
|
||
|
self->s.sound = 0;
|
||
|
self->flags |= FL_NO_KNOCKBACK;
|
||
|
self->svflags &= ~SVF_MONSTER;
|
||
|
self->takedamage = DAMAGE_YES;
|
||
|
self->die = gib_die;
|
||
|
|
||
|
if (type == GIB_ORGANIC)
|
||
|
{
|
||
|
self->movetype = MOVETYPE_TOSS;
|
||
|
self->touch = gib_touch;
|
||
|
vscale = 0.5;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self->movetype = MOVETYPE_BOUNCE;
|
||
|
vscale = 1.0;
|
||
|
}
|
||
|
|
||
|
VelocityForDamage (damage, vd);
|
||
|
VectorMA (self->velocity, vscale, vd, self->velocity);
|
||
|
ClipGibVelocity (self);
|
||
|
|
||
|
self->avelocity[YAW] = crandom()*600;
|
||
|
|
||
|
self->think = G_FreeEdict;
|
||
|
self->nextthink = level.time + 10 + random()*10;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void ThrowClientHead (edict_t *self, int damage)
|
||
|
{
|
||
|
vec3_t vd;
|
||
|
char *gibname;
|
||
|
/*
|
||
|
if (rand()&1)
|
||
|
{
|
||
|
gibname = "models/objects/gibs/head2/tris.md2";
|
||
|
self->s.skinnum = 1; // second skin is player
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gibname = "models/objects/gibs/skull/tris.md2";
|
||
|
self->s.skinnum = 0;
|
||
|
}
|
||
|
*/
|
||
|
gibname = "models/props/gibs/gib3.mdx";
|
||
|
self->s.skinnum = 0;
|
||
|
|
||
|
self->s.origin[2] += 32;
|
||
|
self->s.frame = 0;
|
||
|
|
||
|
// gi.setmodel (self, gibname);
|
||
|
self->s.num_parts = 0;
|
||
|
self->s.modelindex = gi.modelindex( gibname );
|
||
|
|
||
|
VectorSet (self->mins, -16, -16, 0);
|
||
|
VectorSet (self->maxs, 16, 16, 16);
|
||
|
|
||
|
self->takedamage = DAMAGE_NO;
|
||
|
self->solid = SOLID_NOT;
|
||
|
// self->s.effects |= EF_GIB;
|
||
|
self->s.sound = 0;
|
||
|
self->flags |= FL_NO_KNOCKBACK;
|
||
|
|
||
|
self->movetype = MOVETYPE_BOUNCE;
|
||
|
VelocityForDamage (damage, vd);
|
||
|
VectorAdd (self->velocity, vd, self->velocity);
|
||
|
|
||
|
if (self->client) // bodies in the queue don't have a client anymore
|
||
|
{
|
||
|
self->client->anim_priority = ANIM_DEATH;
|
||
|
self->client->anim_end = self->s.frame;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self->think = NULL;
|
||
|
self->nextthink = 0;
|
||
|
}
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=============
|
||
|
GibEntity
|
||
|
|
||
|
Gibs an entity.. can be used for client's or AI
|
||
|
=============
|
||
|
*/
|
||
|
void GibEntity( edict_t *self, edict_t *inflictor, float damage )
|
||
|
{
|
||
|
vec3_t dir, vel;
|
||
|
int m, n;
|
||
|
|
||
|
// turn off flames
|
||
|
if (self->onfiretime)
|
||
|
self->onfiretime = 0;
|
||
|
|
||
|
if (inflictor->client || VectorCompare( inflictor->velocity, vec3_origin) )
|
||
|
VectorSubtract( self->s.origin, inflictor->s.origin, dir );
|
||
|
else
|
||
|
VectorCopy( inflictor->velocity, dir );
|
||
|
|
||
|
VectorNormalize( dir );
|
||
|
|
||
|
// JOSEPH 12-MAY-99-B
|
||
|
// send the client-side gib message
|
||
|
gi.WriteByte (svc_temp_entity);
|
||
|
gi.WriteByte (TE_GIBS);
|
||
|
gi.WritePosition (self->s.origin);
|
||
|
gi.WriteDir (dir);
|
||
|
gi.WriteByte ( 16 ); // number of gibs
|
||
|
gi.WriteByte ( (damage*2 > 128 ? 128 : (int)(damage*2)) ); // scale of direction to add to velocity
|
||
|
gi.WriteByte ( 16 ); // random origin offset scale
|
||
|
gi.WriteByte ( 100 ); // random velocity scale
|
||
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||
|
// END JOSEPH
|
||
|
|
||
|
for (n= 0; n < 6; n++)
|
||
|
{
|
||
|
|
||
|
VelocityForDamage (damage, vel);
|
||
|
|
||
|
// spawn a decal in this direction
|
||
|
for (m=0; m<4; m++) // try 4 times with a different Z value
|
||
|
{
|
||
|
vec3_t bdir;
|
||
|
vec3_t dorg;
|
||
|
trace_t tr;
|
||
|
|
||
|
VectorCopy( vel, bdir );
|
||
|
bdir[2] -= random()*bdir[2]*(1+4*random());
|
||
|
|
||
|
VectorAdd( self->s.origin, bdir, dorg );
|
||
|
|
||
|
tr = gi.trace( self->s.origin, NULL, NULL, dorg, self, MASK_SOLID );
|
||
|
|
||
|
if (tr.fraction < 1 && tr.ent == &g_edicts[0] && !(tr.surface->flags & SURF_SKY))
|
||
|
{
|
||
|
float rnd;
|
||
|
|
||
|
rnd = (1.5 + 5.0*random());
|
||
|
if (SurfaceSpriteEffect(SFX_SPRITE_SURF_BLOOD1, (unsigned char)(SFX_BLOOD_WIDTH*rnd), (unsigned char)(SFX_BLOOD_HEIGHT*rnd),
|
||
|
tr.ent, tr.endpos, tr.plane.normal))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!self->client) // Ridah, added this check, since in deathmatch, the body is left there, just only clients with parental lock ENABLEd will see them, since they don't see the gibs
|
||
|
ThrowClientHead (self, damage);
|
||
|
|
||
|
self->takedamage = DAMAGE_NO;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
debris
|
||
|
=================
|
||
|
*/
|
||
|
void debris_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mdx_part, int mdx_subobject)
|
||
|
{
|
||
|
G_FreeEdict (self);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 22-FEB-99
|
||
|
void Think_Debris (edict_t *ent)
|
||
|
{
|
||
|
if (!ent->misstime--)
|
||
|
{
|
||
|
ent->nextthink = 0;
|
||
|
G_FreeEdict(ent);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (ent->misstime <= 15)
|
||
|
{
|
||
|
if (ent->misstime == 15)
|
||
|
{
|
||
|
ent->s.renderfx2 |= RF2_PASSALPHA;
|
||
|
ent->s.effects = 1; // this is full alpha now
|
||
|
}
|
||
|
|
||
|
ent->s.effects += (255/15);
|
||
|
|
||
|
if (ent->s.effects > 255)
|
||
|
ent->s.effects = 255;
|
||
|
}
|
||
|
|
||
|
//ent->s.angles[1] += ent->avelocity[1];
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin)
|
||
|
{
|
||
|
edict_t *chunk;
|
||
|
vec3_t v;
|
||
|
|
||
|
chunk = G_Spawn();
|
||
|
VectorCopy (origin, chunk->s.origin);
|
||
|
gi.setmodel (chunk, modelname);
|
||
|
v[0] = 50 * crandom();
|
||
|
v[1] = 50 * crandom();
|
||
|
v[2] = 50 + 50 * crandom();
|
||
|
VectorMA (self->velocity, speed, v, chunk->velocity);
|
||
|
chunk->movetype = MOVETYPE_BOUNCE;
|
||
|
chunk->solid = SOLID_NOT;
|
||
|
chunk->avelocity[0] = random()*600;
|
||
|
chunk->avelocity[1] = random()*600;
|
||
|
chunk->avelocity[2] = random()*600;
|
||
|
chunk->think = G_FreeEdict;
|
||
|
chunk->nextthink = level.time + 5 + random()*5;
|
||
|
chunk->s.frame = 0;
|
||
|
chunk->flags = 0;
|
||
|
chunk->classname = "debris";
|
||
|
chunk->takedamage = DAMAGE_YES;
|
||
|
chunk->die = debris_die;
|
||
|
|
||
|
chunk->think = Think_Debris;
|
||
|
chunk->misstime = 20;
|
||
|
chunk->nextthink = level.time + 0.1;
|
||
|
chunk->s.renderfx2 |= RF2_NOSHADOW;
|
||
|
chunk->avelocity[1] = ((rand()&15)-8);
|
||
|
//chunk->s.angles[0] = 90;
|
||
|
gi.linkentity (chunk);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
// JOSEPH 5-JUN-99-B
|
||
|
void ThrowDebris_stuff (edict_t *self, char *modelname, float speed, vec3_t origin)
|
||
|
{
|
||
|
edict_t *chunk;
|
||
|
vec3_t v;
|
||
|
|
||
|
chunk = G_Spawn();
|
||
|
VectorCopy (origin, chunk->s.origin);
|
||
|
gi.setmodel (chunk, modelname);
|
||
|
v[0] = 150 * crandom();
|
||
|
v[1] = 150 * crandom();
|
||
|
v[2] = 150 + 50 * crandom();
|
||
|
VectorMA (self->velocity, speed, v, chunk->velocity);
|
||
|
chunk->movetype = MOVETYPE_BOUNCE;
|
||
|
chunk->solid = SOLID_NOT;
|
||
|
chunk->avelocity[0] = random()*600;
|
||
|
chunk->avelocity[1] = random()*600;
|
||
|
chunk->avelocity[2] = random()*600;
|
||
|
chunk->think = G_FreeEdict;
|
||
|
chunk->nextthink = level.time + 5 + random()*5;
|
||
|
chunk->s.frame = 0;
|
||
|
chunk->flags = 0;
|
||
|
chunk->classname = "debris";
|
||
|
chunk->takedamage = DAMAGE_YES;
|
||
|
chunk->die = debris_die;
|
||
|
|
||
|
chunk->think = Think_Debris;
|
||
|
chunk->misstime = 40;
|
||
|
chunk->nextthink = level.time + 0.1;
|
||
|
chunk->s.renderfx2 |= RF2_NOSHADOW;
|
||
|
chunk->avelocity[1] = ((rand()&15)-8);
|
||
|
chunk->lightit = 30;
|
||
|
gi.linkentity (chunk);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
// JOSEPH 1-JUN-99
|
||
|
extern void rat_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mdx_part, int mdx_subobject);
|
||
|
|
||
|
void BecomeExplosion1 (edict_t *self)
|
||
|
{
|
||
|
if ((self->classname) && (!strcmp(self->classname, "props_rat")))
|
||
|
{
|
||
|
rat_die (self, NULL, NULL, 0, NULL, 0, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
vec3_t vec;
|
||
|
|
||
|
VectorClear(vec);
|
||
|
vec[2] = 1;
|
||
|
|
||
|
gi.WriteByte (svc_temp_entity);
|
||
|
gi.WriteByte (TE_EXPLOSION1);
|
||
|
gi.WritePosition (self->s.origin);
|
||
|
gi.WriteDir( vec );
|
||
|
gi.WriteByte( (int)(self->dmg / 2) );
|
||
|
gi.WriteByte (self->fxdensity);
|
||
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||
|
|
||
|
{
|
||
|
edict_t *breakit;
|
||
|
|
||
|
breakit = G_Spawn();
|
||
|
|
||
|
if (breakit)
|
||
|
{
|
||
|
VectorCopy (self->s.origin, breakit->s.origin);
|
||
|
gi.linkentity(breakit);
|
||
|
gi.sound (breakit, CHAN_VOICE, gi.soundindex("world/explosion1.wav"), 1, ATTN_NORM, 0);
|
||
|
breakit->think = G_FreeEdict;
|
||
|
breakit->nextthink = level.time + 5.0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
G_FreeEdict (self);
|
||
|
}
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
void BecomeExplosion2 (edict_t *self)
|
||
|
{
|
||
|
gi.WriteByte (svc_temp_entity);
|
||
|
gi.WriteByte (TE_EXPLOSION2);
|
||
|
gi.WritePosition (self->s.origin);
|
||
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
||
|
|
||
|
G_FreeEdict (self);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*QUAKED path_corner_cast (.5 .3 0) (-16 -16 -24) (16 16 42) TELEPORT
|
||
|
Target: next path corner
|
||
|
Scriptname: hard-coded script to call when reaching this marker
|
||
|
Pathtarget: gets used when an entity that has
|
||
|
this path_corner targeted touches it
|
||
|
Could be used to trigger a button, or a character
|
||
|
Combattarget: when the cast reaches this marker,
|
||
|
they'll take on this combattarget
|
||
|
*/
|
||
|
|
||
|
void path_corner_cast_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
|
{
|
||
|
vec3_t v;
|
||
|
edict_t *next;
|
||
|
|
||
|
if ((other->goal_ent != self) && (other->combat_goalent != self))
|
||
|
return;
|
||
|
|
||
|
if (other->health < 0)
|
||
|
return;
|
||
|
|
||
|
if (self->pathtarget)
|
||
|
{
|
||
|
char *savetarget;
|
||
|
|
||
|
savetarget = self->target;
|
||
|
self->target = self->pathtarget;
|
||
|
G_UseTargets (self, other);
|
||
|
self->target = savetarget;
|
||
|
}
|
||
|
|
||
|
// play a sound if there is one
|
||
|
if (self->name)
|
||
|
gi.sound( other, CHAN_VOICE, gi.soundindex( self->name ), 1.0, 1, 0 );
|
||
|
|
||
|
|
||
|
if (self->combattarget)
|
||
|
other->next_combattarget = self->combattarget;
|
||
|
|
||
|
if (self->target)
|
||
|
next = G_PickTarget(self->target);
|
||
|
else
|
||
|
next = NULL;
|
||
|
|
||
|
if ((next) && (next->spawnflags & 1))
|
||
|
{
|
||
|
VectorCopy (next->s.origin, v);
|
||
|
v[2] += next->mins[2];
|
||
|
v[2] -= other->mins[2];
|
||
|
VectorCopy (v, other->s.origin);
|
||
|
next = G_PickTarget(next->target);
|
||
|
}
|
||
|
|
||
|
if (other->goal_ent == self)
|
||
|
other->goal_ent = next;
|
||
|
else
|
||
|
other->combat_goalent = next;
|
||
|
|
||
|
if (self->wait)
|
||
|
{
|
||
|
other->cast_info.goal_ent_pausetime = level.time + self->wait;
|
||
|
other->cast_info.currentmove = other->cast_info.move_stand;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (!other->goal_ent && !other->combat_goalent)
|
||
|
{
|
||
|
// end of the line
|
||
|
other->target = NULL;
|
||
|
other->cast_info.currentmove = other->cast_info.move_stand;
|
||
|
}
|
||
|
else // remember this marker
|
||
|
{
|
||
|
if (other->goal_ent == self)
|
||
|
{
|
||
|
other->target = other->goal_ent->target;
|
||
|
VectorSubtract (other->goal_ent->s.origin, other->s.origin, v);
|
||
|
}
|
||
|
else // combattarget
|
||
|
{
|
||
|
|
||
|
if (!(other->combat_goalent))
|
||
|
{
|
||
|
other->target = other->goal_ent->target;
|
||
|
VectorSubtract (other->goal_ent->s.origin, other->s.origin, v);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
VectorSubtract (other->combat_goalent->s.origin, other->s.origin, v);
|
||
|
other->combat_goalent->cast_info.aiflags |= AI_GOAL_RUN;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
other->ideal_yaw = vectoyaw (v);
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
|
||
|
// Ridah, hard-coded scripting
|
||
|
if (self->scriptname)
|
||
|
EP_EventScript( other, self->scriptname );
|
||
|
|
||
|
}
|
||
|
|
||
|
void SP_path_corner_cast (edict_t *self)
|
||
|
{
|
||
|
if (!self->targetname)
|
||
|
{
|
||
|
gi.dprintf ("path_corner_cast with no targetname at %s\n", vtos(self->s.origin));
|
||
|
G_FreeEdict (self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
strcpy(self->classname, "path_corner"); // so the existing code still works
|
||
|
|
||
|
VectorSet (self->mins, -16, -16, -24);
|
||
|
VectorSet (self->maxs, 16, 16, 42);
|
||
|
|
||
|
self->solid = SOLID_TRIGGER;
|
||
|
self->touch = path_corner_cast_touch;
|
||
|
self->svflags |= SVF_NOCLIENT;
|
||
|
|
||
|
M_droptofloor(self);
|
||
|
self->s.origin[2] += 4;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT
|
||
|
NOTE: Use path_corner_cast for character path's
|
||
|
Target: next path corner
|
||
|
Pathtarget: gets used when an entity that has
|
||
|
this path_corner targeted touches it
|
||
|
*/
|
||
|
|
||
|
void path_corner_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
|
{
|
||
|
vec3_t v;
|
||
|
edict_t *next;
|
||
|
|
||
|
if (other->movetarget != self)
|
||
|
return;
|
||
|
|
||
|
if (other->enemy)
|
||
|
return;
|
||
|
|
||
|
if (self->pathtarget)
|
||
|
{
|
||
|
char *savetarget;
|
||
|
|
||
|
savetarget = self->target;
|
||
|
self->target = self->pathtarget;
|
||
|
G_UseTargets (self, other);
|
||
|
self->target = savetarget;
|
||
|
}
|
||
|
|
||
|
if (self->target)
|
||
|
next = G_PickTarget(self->target);
|
||
|
else
|
||
|
next = NULL;
|
||
|
|
||
|
if ((next) && (next->spawnflags & 1))
|
||
|
{
|
||
|
VectorCopy (next->s.origin, v);
|
||
|
v[2] += next->mins[2];
|
||
|
v[2] -= other->mins[2];
|
||
|
VectorCopy (v, other->s.origin);
|
||
|
next = G_PickTarget(next->target);
|
||
|
}
|
||
|
|
||
|
other->goalentity = other->movetarget = next;
|
||
|
|
||
|
if (self->wait)
|
||
|
{
|
||
|
other->cast_info.pausetime = level.time + self->wait;
|
||
|
// other->cast_info.stand (other);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!other->movetarget)
|
||
|
{
|
||
|
other->cast_info.pausetime = level.time + 100000000;
|
||
|
// other->cast_info.stand (other);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
VectorSubtract (other->goalentity->s.origin, other->s.origin, v);
|
||
|
other->ideal_yaw = vectoyaw (v);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void SP_path_corner (edict_t *self)
|
||
|
{
|
||
|
if (!self->targetname)
|
||
|
{
|
||
|
gi.dprintf ("path_corner with no targetname at %s\n", vtos(self->s.origin));
|
||
|
G_FreeEdict (self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
self->solid = SOLID_TRIGGER;
|
||
|
self->touch = path_corner_touch;
|
||
|
VectorSet (self->mins, -8, -8, -8);
|
||
|
VectorSet (self->maxs, 8, 8, 8);
|
||
|
self->svflags |= SVF_NOCLIENT;
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 8-FEB-99
|
||
|
/*UAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8)
|
||
|
Just for the debugging level. Don't use
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void TH_viewthing(edict_t *ent)
|
||
|
{
|
||
|
ent->s.frame = (ent->s.frame + 1) % 7;
|
||
|
ent->nextthink = level.time + FRAMETIME;
|
||
|
}
|
||
|
|
||
|
void SP_viewthing(edict_t *ent)
|
||
|
{
|
||
|
gi.dprintf ("viewthing spawned\n");
|
||
|
|
||
|
ent->movetype = MOVETYPE_NONE;
|
||
|
ent->solid = SOLID_BBOX;
|
||
|
ent->s.renderfx = RF_FRAMELERP;
|
||
|
VectorSet (ent->mins, -16, -16, -24);
|
||
|
VectorSet (ent->maxs, 16, 16, 32);
|
||
|
ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2");
|
||
|
gi.linkentity (ent);
|
||
|
ent->nextthink = level.time + 0.5;
|
||
|
ent->think = TH_viewthing;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
|
||
|
Used as a positional target for spotlights, etc.
|
||
|
*/
|
||
|
void SP_info_null (edict_t *self)
|
||
|
{
|
||
|
if (!self->targetname) // Ridah, 5-7-99, had to add this or the info_null behind the radio gets deleted
|
||
|
G_FreeEdict (self);
|
||
|
};
|
||
|
|
||
|
|
||
|
/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
|
||
|
Used as a positional target for lightning.
|
||
|
*/
|
||
|
void SP_info_notnull (edict_t *self)
|
||
|
{
|
||
|
VectorCopy (self->s.origin, self->absmin);
|
||
|
VectorCopy (self->s.origin, self->absmax);
|
||
|
};
|
||
|
|
||
|
|
||
|
#define MIN_LIGHT_VALUE 128
|
||
|
#define MIN_LIGHT_INTENSITY 0.2
|
||
|
|
||
|
#define START_OFF 1
|
||
|
#define FLARE 2
|
||
|
#define DYNAMIC 8
|
||
|
|
||
|
|
||
|
void AddLightSource(edict_t *self)
|
||
|
{
|
||
|
if (!(self->spawnflags & DYNAMIC))
|
||
|
return;
|
||
|
|
||
|
if (level.num_light_sources >= MAX_LIGHT_SOURCES)
|
||
|
{
|
||
|
gi.dprintf("Warning: MAX_LIGHT_SOURCES exceeded\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (self->dmg_radius <= 0.0)
|
||
|
self->dmg_radius = 1.0;
|
||
|
|
||
|
if (self->light_level < MIN_LIGHT_VALUE)
|
||
|
self->light_level = MIN_LIGHT_VALUE;
|
||
|
|
||
|
VectorCopy( self->s.origin, level.light_orgs[level.num_light_sources] );
|
||
|
VectorCopy( self->rotate, level.light_colors[level.num_light_sources] );
|
||
|
// light_values[num_light_sources] = ((float) self->light_level) * 3.0;
|
||
|
level.light_values[level.num_light_sources] = ((float) self->light_level * 1.5);
|
||
|
// level.light_radius[level.num_light_sources] = self->dmg_radius;
|
||
|
level.light_styles[level.num_light_sources] = self->style;
|
||
|
|
||
|
level.num_light_sources++;
|
||
|
|
||
|
self->svflags |= SVF_NOCLIENT;
|
||
|
}
|
||
|
|
||
|
void LightConfigstrings ()
|
||
|
{
|
||
|
char str[256];
|
||
|
char fullstr[256];
|
||
|
int i, inc, j;
|
||
|
|
||
|
fullstr[0] = str[0] = '\0';
|
||
|
inc = 0;
|
||
|
j = 0;
|
||
|
|
||
|
for (i=0; i<level.num_light_sources; i++)
|
||
|
{
|
||
|
|
||
|
sprintf( str,
|
||
|
"%5i %5i %5i %1.1f %1.1f %1.1f %4i %3i", // "99999 99999 99999 9.9 9.9 9.9 9999 999"
|
||
|
(int)level.light_orgs[i][0], (int)level.light_orgs[i][1], (int)level.light_orgs[i][2],
|
||
|
level.light_colors[i][0], level.light_colors[i][1], level.light_colors[i][2],
|
||
|
(int)level.light_values[i],
|
||
|
(int)level.light_styles[i]);
|
||
|
|
||
|
strcat( fullstr, str );
|
||
|
|
||
|
// if (inc++)
|
||
|
{
|
||
|
gi.configstring (CS_JUNIORS + j++, fullstr );
|
||
|
|
||
|
fullstr[0] = '\0';
|
||
|
inc = 0;
|
||
|
}
|
||
|
// else // add the seperator
|
||
|
// {
|
||
|
// strcat( fullstr, " : " );
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
i -= 1;
|
||
|
|
||
|
if (inc)
|
||
|
gi.configstring (CS_JUNIORS + (int)floor(i/2), fullstr );
|
||
|
}
|
||
|
|
||
|
void UpdateDirLights( edict_t *self )
|
||
|
{
|
||
|
int i, ent_lights=0;
|
||
|
vec3_t vec;
|
||
|
int j;
|
||
|
|
||
|
|
||
|
for (i=0; i<level.num_light_sources; i++)
|
||
|
{
|
||
|
|
||
|
VectorSubtract( level.light_orgs[i], self->s.origin, vec );
|
||
|
|
||
|
// trivia reject
|
||
|
|
||
|
// lights less that 100 are rejected by default done in sp_light
|
||
|
|
||
|
{
|
||
|
float length;
|
||
|
|
||
|
length = VectorLength (vec);
|
||
|
|
||
|
if (((level.light_values[i]) - length) < 0)
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!gi.inPVS(self->s.origin, level.light_orgs[i]))
|
||
|
continue;
|
||
|
|
||
|
{
|
||
|
vec3_t spot1;
|
||
|
vec3_t spot2;
|
||
|
trace_t trace;
|
||
|
|
||
|
VectorCopy (self->s.origin, spot1);
|
||
|
spot1[2] += self->viewheight;
|
||
|
VectorCopy (level.light_orgs[i], spot2);
|
||
|
trace = gi.trace (spot1, vec3_origin, vec3_origin, spot2, self, MASK_OPAQUE);
|
||
|
|
||
|
if (trace.fraction != 1.0)
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// passed normal tests. if we've used all lights, look for one to replace
|
||
|
|
||
|
if (ent_lights >= MAX_MODEL_DIR_LIGHTS)
|
||
|
{
|
||
|
for (j=0; j<MAX_MODEL_DIR_LIGHTS; j++)
|
||
|
{
|
||
|
if ( (self->s.model_lighting.light_intensities[j] - VectorDistance( self->s.origin, self->s.model_lighting.light_orgs[j] ))
|
||
|
< (level.light_values[i] - VectorDistance( self->s.origin, level.light_orgs[i] )))
|
||
|
{
|
||
|
break; // replace this light
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (j == MAX_MODEL_DIR_LIGHTS)
|
||
|
continue; // no light to replace
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
j = ent_lights;
|
||
|
}
|
||
|
|
||
|
// end reject test
|
||
|
|
||
|
self->s.model_lighting.light_indexes[j] = i;
|
||
|
|
||
|
self->s.model_lighting.light_intensities[j] = level.light_values[i];
|
||
|
VectorCopy( level.light_colors[i], self->s.model_lighting.light_colors[j] );
|
||
|
VectorCopy( level.light_orgs[i], self->s.model_lighting.light_orgs[j] );
|
||
|
VectorNormalize( vec );
|
||
|
VectorCopy( vec, self->s.model_lighting.light_vecs[j] );
|
||
|
self->s.model_lighting.light_styles[j] = level.light_styles[i];
|
||
|
|
||
|
if (showlights->value)
|
||
|
NAV_DrawLine( self->s.origin, level.light_orgs[i] );
|
||
|
|
||
|
if (ent_lights < MAX_MODEL_DIR_LIGHTS)
|
||
|
ent_lights++;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (showlights->value)
|
||
|
gi.dprintf ("num lights %d\n", ent_lights);
|
||
|
|
||
|
self->s.model_lighting.num_dir_lights = ent_lights;
|
||
|
}
|
||
|
|
||
|
/*QUAKED junior (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
|
||
|
*/
|
||
|
|
||
|
static void junior_use (edict_t *self, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
if (self->spawnflags & START_OFF)
|
||
|
{
|
||
|
gi.configstring (CS_LIGHTS+self->style, "m");
|
||
|
self->spawnflags &= ~START_OFF;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gi.configstring (CS_LIGHTS+self->style, "a");
|
||
|
self->spawnflags |= START_OFF;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SP_junior (edict_t *self )
|
||
|
{
|
||
|
if (self->style >= 32)
|
||
|
{
|
||
|
self->use = junior_use;
|
||
|
if (self->spawnflags & START_OFF)
|
||
|
gi.configstring (CS_LIGHTS+self->style, "a");
|
||
|
else
|
||
|
gi.configstring (CS_LIGHTS+self->style, "m");
|
||
|
}
|
||
|
|
||
|
self->spawnflags |= DYNAMIC;
|
||
|
|
||
|
if (!(self->light_level))
|
||
|
self->light_level = 300;
|
||
|
|
||
|
AddLightSource(self);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// -----------------------------------------------------------------------------
|
||
|
|
||
|
/*QUAKED lightflare (0 1 0) (-2 -2 -2) (2 2 2) START_OFF FLARE NORESIZE DYNAMIC
|
||
|
Non-displayed light.
|
||
|
Default light value is 300.
|
||
|
Default style is 0.
|
||
|
If targeted, will toggle between on and off.
|
||
|
Default _cone value is 10 (used to set size of light for spotlights)
|
||
|
movedir will be the color of the flare
|
||
|
health is size for lightflare
|
||
|
dmg will specify the flare type
|
||
|
FLARE_NORMAL 0
|
||
|
FLARE_SUN 1
|
||
|
FLARE_AMBER 2
|
||
|
FLARE_RED 3
|
||
|
FLARE_BLUE 4
|
||
|
FLARE_GREEN 5
|
||
|
*/
|
||
|
|
||
|
/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF FLARE NORESIZE DYNAMIC
|
||
|
Non-displayed light.
|
||
|
Default light value is 300.
|
||
|
Default style is 0.
|
||
|
If targeted, will toggle between on and off.
|
||
|
Default _cone value is 10 (used to set size of light for spotlights)
|
||
|
movedir will be the color of the flare
|
||
|
health is size for lightflare
|
||
|
dmg will specify the flare type
|
||
|
FLARE_NORMAL 0
|
||
|
FLARE_SUN 1
|
||
|
FLARE_AMBER 2
|
||
|
FLARE_RED 3
|
||
|
FLARE_BLUE 4
|
||
|
FLARE_GREEN 5
|
||
|
*/
|
||
|
|
||
|
void SP_Flare (edict_t *self);
|
||
|
|
||
|
static void light_use (edict_t *self, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
if (self->spawnflags & START_OFF)
|
||
|
{
|
||
|
gi.configstring (CS_LIGHTS+self->style, "m");
|
||
|
self->spawnflags &= ~START_OFF;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gi.configstring (CS_LIGHTS+self->style, "a");
|
||
|
self->spawnflags |= START_OFF;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SP_light (edict_t *self)
|
||
|
{
|
||
|
if (self->style >= 32)
|
||
|
{
|
||
|
self->use = light_use;
|
||
|
if (self->spawnflags & START_OFF)
|
||
|
gi.configstring (CS_LIGHTS+self->style, "a");
|
||
|
else
|
||
|
gi.configstring (CS_LIGHTS+self->style, "m");
|
||
|
}
|
||
|
|
||
|
// RAFAEL
|
||
|
if (self->spawnflags & FLARE)
|
||
|
{
|
||
|
SP_Flare (self);
|
||
|
}
|
||
|
// flares will never be a level.light_source
|
||
|
else
|
||
|
{
|
||
|
if (!(self->light_level))
|
||
|
self->light_level = 300;
|
||
|
|
||
|
if (self->light_level > 100)
|
||
|
AddLightSource(self);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define RESIZE 2
|
||
|
|
||
|
void SP_Flare (edict_t *self)
|
||
|
{
|
||
|
lightflare_t lf;
|
||
|
// char lf_str[256], temp_str[256], zero_str[256];//, numstr[2];
|
||
|
// int i,j;
|
||
|
|
||
|
if (num_flares == MAX_LIGHTFLARES-1)
|
||
|
{
|
||
|
gi.dprintf("Too many light flares, num_flares == MAX_LIGHTFLARES\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!self->health) // size
|
||
|
self->health = 24;
|
||
|
|
||
|
if (!self->dmg) // type
|
||
|
self->dmg = FLARE_NORMAL;
|
||
|
|
||
|
if (self->dmg > 5)
|
||
|
{
|
||
|
gi.dprintf("Not a valid flare color 0,1,2,3,4,5 only\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
lf.lightstyle = (char)self->style;
|
||
|
|
||
|
if (self->spawnflags & 4)
|
||
|
lf.lightstyle |= RESIZE;
|
||
|
|
||
|
lf.type = (char) self->dmg;
|
||
|
|
||
|
lf.size = (float) self->health;
|
||
|
|
||
|
VectorCopy( self->s.origin, lf.pos );
|
||
|
|
||
|
// NOTE to Rafael this just shows what sort of values are required to define a Sun-Flare
|
||
|
/*
|
||
|
{
|
||
|
static int done_sun=0;
|
||
|
|
||
|
if (!done_sun)
|
||
|
{
|
||
|
lf.type = FLARE_SUN; // use self->dmg in editor
|
||
|
lf.size = 24;
|
||
|
|
||
|
VectorSet( lf.pos, 1000, 1000, 3000 ); // if the mappers place the sunflare out near the extremes of the map, in the position of the sun, these values will be set accordingly (no need to specify manually)
|
||
|
done_sun = true;
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
if (lf.type == FLARE_SUN)
|
||
|
VectorNormalize( lf.pos );
|
||
|
|
||
|
// just send it as a formatted string
|
||
|
{
|
||
|
char str[256];
|
||
|
|
||
|
sprintf( str,
|
||
|
"%3i %1i %4.1f %4.1f %4.1f %3.0f", // "999 9 9999.9 9999.9 9999.9 999" length = 30
|
||
|
(int)lf.lightstyle,
|
||
|
(int)lf.type,
|
||
|
lf.pos[0], lf.pos[1], lf.pos[2],
|
||
|
lf.size );
|
||
|
|
||
|
gi.configstring (CS_LIGHTFLARES + num_flares, str );
|
||
|
|
||
|
num_flares++;
|
||
|
|
||
|
//gi.dprintf( "game flares: %i\n", num_flares );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// JOSEPH 12-MAY-99-B
|
||
|
#define LIGHTB 16
|
||
|
#define LIGHTG 32
|
||
|
#define LIGHTR 64
|
||
|
#define LIGHTY 128
|
||
|
|
||
|
/*QUAKED light_sconce (1 1 1) (-4 -4 -8) (4 4 8) START_OFF FLARE NORESIZE DYNAMIC LIGHTB LIGHTG LIGHTR LIGHTY
|
||
|
|
||
|
A sconce??
|
||
|
|
||
|
Non-displayed light.
|
||
|
Default light value is 300.
|
||
|
Default style is 0.
|
||
|
If targeted, will toggle between on and off.
|
||
|
Default _cone value is 10 (used to set size of light for spotlights)
|
||
|
movedir will be the color of the flare
|
||
|
health is size for lightflare
|
||
|
dmg will specify the flare type
|
||
|
FLARE_NORMAL 0
|
||
|
FLARE_SUN 1
|
||
|
FLARE_AMBER 2
|
||
|
FLARE_RED 3
|
||
|
FLARE_BLUE 4
|
||
|
FLARE_GREEN 5
|
||
|
|
||
|
model="models\props\sconce\light.md2"
|
||
|
*/
|
||
|
|
||
|
void SP_light_sconce (edict_t *self)
|
||
|
{
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
self->svflags |= SVF_PROP;
|
||
|
|
||
|
if (self->style >= 32)
|
||
|
{
|
||
|
self->use = light_use;
|
||
|
if (self->spawnflags & START_OFF)
|
||
|
gi.configstring (CS_LIGHTS+self->style, "a");
|
||
|
else
|
||
|
gi.configstring (CS_LIGHTS+self->style, "m");
|
||
|
}
|
||
|
|
||
|
if (self->spawnflags & FLARE)
|
||
|
{
|
||
|
SP_Flare (self);
|
||
|
}
|
||
|
// flares will never be a level.light_source
|
||
|
else
|
||
|
{
|
||
|
if (!(self->light_level))
|
||
|
self->light_level = 300;
|
||
|
|
||
|
if (self->light_level > 100)
|
||
|
AddLightSource(self);
|
||
|
}
|
||
|
|
||
|
if (self->spawnflags & LIGHTB)
|
||
|
{
|
||
|
self->model = "models/props/sconce/lightb.md2";
|
||
|
}
|
||
|
else if (self->spawnflags & LIGHTG)
|
||
|
{
|
||
|
self->model = "models/props/sconce/lightg.md2";
|
||
|
}
|
||
|
else if (self->spawnflags & LIGHTR)
|
||
|
{
|
||
|
self->model = "models/props/sconce/lightr.md2";
|
||
|
}
|
||
|
else if (self->spawnflags & LIGHTY)
|
||
|
{
|
||
|
self->model = "models/props/sconce/lighty.md2";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self->model = "models/props/sconce/light.md2";
|
||
|
}
|
||
|
|
||
|
self->s.modelindex = gi.modelindex (self->model);
|
||
|
|
||
|
self->s.renderfx2 |= RF2_NOSHADOW;
|
||
|
|
||
|
if ((self->light_level) && (!(self->spawnflags & LIGHTB)))
|
||
|
{
|
||
|
self->s.renderfx |= RF_FULLBRIGHT;
|
||
|
self->flags |= RF_FULLBRIGHT;
|
||
|
}
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
// JOSEPH 1-MAR-99
|
||
|
/*QUAKED light_bulb (1 1 1) (-2 -2 -5) (2 2 5) START_OFF FLARE NORESIZE DYNAMIC
|
||
|
|
||
|
A bulb that outputs light
|
||
|
|
||
|
Non-displayed light.
|
||
|
Default light value is 300.
|
||
|
Default style is 0.
|
||
|
If targeted, will toggle between on and off.
|
||
|
Default _cone value is 10 (used to set size of light for spotlights)
|
||
|
movedir will be the color of the flare
|
||
|
health is size for lightflare
|
||
|
dmg will specify the flare type
|
||
|
FLARE_NORMAL 0
|
||
|
FLARE_SUN 1
|
||
|
FLARE_AMBER 2
|
||
|
FLARE_RED 3
|
||
|
FLARE_BLUE 4
|
||
|
FLARE_GREEN 5
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void SP_light_bulb (edict_t *self)
|
||
|
{
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
self->svflags |= SVF_PROP;
|
||
|
|
||
|
if (self->style >= 32)
|
||
|
{
|
||
|
self->use = light_use;
|
||
|
if (self->spawnflags & START_OFF)
|
||
|
gi.configstring (CS_LIGHTS+self->style, "a");
|
||
|
else
|
||
|
gi.configstring (CS_LIGHTS+self->style, "m");
|
||
|
}
|
||
|
|
||
|
if (self->spawnflags & FLARE)
|
||
|
{
|
||
|
SP_Flare (self);
|
||
|
}
|
||
|
// flares will never be a level.light_source
|
||
|
else
|
||
|
{
|
||
|
if (!(self->light_level))
|
||
|
self->light_level = 300;
|
||
|
|
||
|
if (self->light_level > 100)
|
||
|
AddLightSource(self);
|
||
|
}
|
||
|
|
||
|
self->model = "models/props/light/tris.md2";
|
||
|
self->s.modelindex = gi.modelindex (self->model);
|
||
|
|
||
|
self->s.renderfx2 |= RF2_NOSHADOW;
|
||
|
|
||
|
if (self->light_level)
|
||
|
{
|
||
|
self->s.renderfx |= RF_FULLBRIGHT;
|
||
|
self->flags |= RF_FULLBRIGHT;
|
||
|
}
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
// JOSEPH 16-APR-99
|
||
|
/*QUAKED light_deco_sconce (1 1 1) (-8 -8 -12) (8 8 12) START_OFF FLARE NORESIZE DYNAMIC
|
||
|
|
||
|
A deco sconce
|
||
|
|
||
|
Non-displayed light.
|
||
|
Default light value is 300.
|
||
|
Default style is 0.
|
||
|
If targeted, will toggle between on and off.
|
||
|
Default _cone value is 10 (used to set size of light for spotlights)
|
||
|
movedir will be the color of the flare
|
||
|
health is size for lightflare
|
||
|
dmg will specify the flare type
|
||
|
FLARE_NORMAL 0
|
||
|
FLARE_SUN 1
|
||
|
FLARE_AMBER 2
|
||
|
FLARE_RED 3
|
||
|
FLARE_BLUE 4
|
||
|
FLARE_GREEN 5
|
||
|
|
||
|
model="models\props\decosconce\tris.md2"
|
||
|
*/
|
||
|
|
||
|
void SP_light_deco_sconce (edict_t *self)
|
||
|
{
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
self->svflags |= SVF_PROP;
|
||
|
|
||
|
if (self->style >= 32)
|
||
|
{
|
||
|
self->use = light_use;
|
||
|
if (self->spawnflags & START_OFF)
|
||
|
gi.configstring (CS_LIGHTS+self->style, "a");
|
||
|
else
|
||
|
gi.configstring (CS_LIGHTS+self->style, "m");
|
||
|
}
|
||
|
|
||
|
if (self->spawnflags & FLARE)
|
||
|
{
|
||
|
SP_Flare (self);
|
||
|
}
|
||
|
// flares will never be a level.light_source
|
||
|
else
|
||
|
{
|
||
|
if (!(self->light_level))
|
||
|
self->light_level = 300;
|
||
|
|
||
|
if (self->light_level > 100)
|
||
|
AddLightSource(self);
|
||
|
}
|
||
|
|
||
|
self->model = "models/props/decosconce/tris.md2";
|
||
|
self->s.modelindex = gi.modelindex (self->model);
|
||
|
|
||
|
self->s.renderfx2 |= RF2_NOSHADOW;
|
||
|
|
||
|
if (self->light_level)
|
||
|
{
|
||
|
self->s.renderfx |= RF_FULLBRIGHT;
|
||
|
self->flags |= RF_FULLBRIGHT;
|
||
|
}
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 3-JUN-99
|
||
|
/*QUAKED light_chandelier (1 1 1) (-36 -34 -32) (36 34 32) START_OFF FLARE NORESIZE DYNAMIC
|
||
|
|
||
|
A deco sconce
|
||
|
|
||
|
Non-displayed light.
|
||
|
Default light value is 300.
|
||
|
Default style is 0.
|
||
|
If targeted, will toggle between on and off.
|
||
|
Default _cone value is 10 (used to set size of light for spotlights)
|
||
|
movedir will be the color of the flare
|
||
|
health is size for lightflare
|
||
|
dmg will specify the flare type
|
||
|
FLARE_NORMAL 0
|
||
|
FLARE_SUN 1
|
||
|
FLARE_AMBER 2
|
||
|
FLARE_RED 3
|
||
|
FLARE_BLUE 4
|
||
|
FLARE_GREEN 5
|
||
|
|
||
|
model="models\props\chandelier\tris.md2"
|
||
|
*/
|
||
|
|
||
|
void SP_light_chandelier (edict_t *self)
|
||
|
{
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
self->svflags |= SVF_PROP;
|
||
|
|
||
|
if (self->style >= 32)
|
||
|
{
|
||
|
self->use = light_use;
|
||
|
if (self->spawnflags & START_OFF)
|
||
|
gi.configstring (CS_LIGHTS+self->style, "a");
|
||
|
else
|
||
|
gi.configstring (CS_LIGHTS+self->style, "m");
|
||
|
}
|
||
|
|
||
|
if (self->spawnflags & FLARE)
|
||
|
{
|
||
|
SP_Flare (self);
|
||
|
}
|
||
|
// flares will never be a level.light_source
|
||
|
else
|
||
|
{
|
||
|
if (!(self->light_level))
|
||
|
self->light_level = 300;
|
||
|
|
||
|
if (self->light_level > 100)
|
||
|
AddLightSource(self);
|
||
|
}
|
||
|
|
||
|
self->model = "models/props/chandelier/tris.md2";
|
||
|
self->s.modelindex = gi.modelindex (self->model);
|
||
|
|
||
|
self->s.renderfx2 |= RF2_NOSHADOW;
|
||
|
|
||
|
if (self->light_level)
|
||
|
{
|
||
|
self->s.renderfx |= RF_FULLBRIGHT;
|
||
|
self->flags |= RF_FULLBRIGHT;
|
||
|
}
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
/*QUAKED light_pendant (1 1 1) (-16 -16 -4) (16 16 4) START_OFF FLARE NORESIZE DYNAMIC
|
||
|
|
||
|
A pendant light
|
||
|
|
||
|
Non-displayed light.
|
||
|
Default light value is 300.
|
||
|
Default style is 0.
|
||
|
If targeted, will toggle between on and off.
|
||
|
Default _cone value is 10 (used to set size of light for spotlights)
|
||
|
movedir will be the color of the flare
|
||
|
health is size for lightflare
|
||
|
dmg will specify the flare type
|
||
|
FLARE_NORMAL 0
|
||
|
FLARE_SUN 1
|
||
|
FLARE_AMBER 2
|
||
|
FLARE_RED 3
|
||
|
FLARE_BLUE 4
|
||
|
FLARE_GREEN 5
|
||
|
|
||
|
model="models\props\pendant\tris.md2"
|
||
|
*/
|
||
|
|
||
|
void SP_light_pendant (edict_t *self)
|
||
|
{
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
self->svflags |= SVF_PROP;
|
||
|
|
||
|
if (self->style >= 32)
|
||
|
{
|
||
|
self->use = light_use;
|
||
|
if (self->spawnflags & START_OFF)
|
||
|
gi.configstring (CS_LIGHTS+self->style, "a");
|
||
|
else
|
||
|
gi.configstring (CS_LIGHTS+self->style, "m");
|
||
|
}
|
||
|
|
||
|
if (self->spawnflags & FLARE)
|
||
|
{
|
||
|
SP_Flare (self);
|
||
|
}
|
||
|
// flares will never be a level.light_source
|
||
|
else
|
||
|
{
|
||
|
if (!(self->light_level))
|
||
|
self->light_level = 300;
|
||
|
|
||
|
if (self->light_level > 100)
|
||
|
AddLightSource(self);
|
||
|
}
|
||
|
|
||
|
self->model = "models/props/pendant/tris.md2";
|
||
|
self->s.modelindex = gi.modelindex (self->model);
|
||
|
|
||
|
self->s.renderfx2 |= RF2_NOSHADOW;
|
||
|
|
||
|
if (self->light_level)
|
||
|
{
|
||
|
self->s.renderfx |= RF_FULLBRIGHT;
|
||
|
self->flags |= RF_FULLBRIGHT;
|
||
|
}
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
/*QUAKED func_wall (0 .5 .8) ? TRIGGER_SPAWN TOGGLE START_ON ANIMATED ANIMATED_FAST SURF2_ALPHA
|
||
|
This is just a solid wall if not inhibited
|
||
|
|
||
|
TRIGGER_SPAWN the wall will not be present until triggered
|
||
|
it will then blink in to existance; it will
|
||
|
kill anything that was in it's way
|
||
|
|
||
|
TOGGLE only valid for TRIGGER_SPAWN walls
|
||
|
this allows the wall to be turned on and off
|
||
|
|
||
|
START_ON only valid for TRIGGER_SPAWN walls
|
||
|
the wall will initially be present
|
||
|
*/
|
||
|
|
||
|
void func_wall_use (edict_t *self, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
if (self->solid == SOLID_NOT)
|
||
|
{
|
||
|
self->solid = SOLID_BSP;
|
||
|
self->svflags &= ~SVF_NOCLIENT;
|
||
|
KillBox (self);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->svflags |= SVF_NOCLIENT;
|
||
|
}
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
if (!(self->spawnflags & 2))
|
||
|
self->use = NULL;
|
||
|
}
|
||
|
|
||
|
void SP_func_wall (edict_t *self)
|
||
|
{
|
||
|
self->movetype = MOVETYPE_PUSH;
|
||
|
gi.setmodel (self, self->model);
|
||
|
|
||
|
if (self->spawnflags & 8)
|
||
|
self->s.effects |= EF_ANIM_ALL;
|
||
|
if (self->spawnflags & 16)
|
||
|
self->s.effects |= EF_ANIM_ALLFAST;
|
||
|
|
||
|
// RAFAEL
|
||
|
if (self->spawnflags & 32)
|
||
|
self->s.renderfx2 |= RF2_SURF_ALPHA;
|
||
|
|
||
|
// just a wall
|
||
|
if ((self->spawnflags & 7) == 0)
|
||
|
{
|
||
|
self->solid = SOLID_BSP;
|
||
|
gi.linkentity (self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// it must be TRIGGER_SPAWN
|
||
|
if (!(self->spawnflags & 1))
|
||
|
{
|
||
|
// gi.dprintf("func_wall missing TRIGGER_SPAWN\n");
|
||
|
self->spawnflags |= 1;
|
||
|
}
|
||
|
|
||
|
// yell if the spawnflags are odd
|
||
|
if (self->spawnflags & 4)
|
||
|
{
|
||
|
if (!(self->spawnflags & 2))
|
||
|
{
|
||
|
gi.dprintf("func_wall START_ON without TOGGLE\n");
|
||
|
self->spawnflags |= 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
self->use = func_wall_use;
|
||
|
if (self->spawnflags & 4)
|
||
|
{
|
||
|
self->solid = SOLID_BSP;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->svflags |= SVF_NOCLIENT;
|
||
|
}
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED func_object (0 .5 .8) ? TRIGGER_SPAWN ANIMATED ANIMATED_FAST
|
||
|
This is solid bmodel that will fall if it's support it removed.
|
||
|
*/
|
||
|
|
||
|
void func_object_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
|
{
|
||
|
// only squash thing we fall on top of
|
||
|
if (!plane)
|
||
|
return;
|
||
|
if (plane->normal[2] < 1.0)
|
||
|
return;
|
||
|
if (other->takedamage == DAMAGE_NO)
|
||
|
return;
|
||
|
T_Damage (other, self, self, vec3_origin, self->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
|
||
|
}
|
||
|
|
||
|
void func_object_release (edict_t *self)
|
||
|
{
|
||
|
self->movetype = MOVETYPE_TOSS;
|
||
|
self->touch = func_object_touch;
|
||
|
}
|
||
|
|
||
|
void func_object_use (edict_t *self, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
self->solid = SOLID_BSP;
|
||
|
self->svflags &= ~SVF_NOCLIENT;
|
||
|
self->use = NULL;
|
||
|
KillBox (self);
|
||
|
func_object_release (self);
|
||
|
}
|
||
|
|
||
|
void SP_func_object (edict_t *self)
|
||
|
{
|
||
|
gi.setmodel (self, self->model);
|
||
|
|
||
|
self->mins[0] += 1;
|
||
|
self->mins[1] += 1;
|
||
|
self->mins[2] += 1;
|
||
|
self->maxs[0] -= 1;
|
||
|
self->maxs[1] -= 1;
|
||
|
self->maxs[2] -= 1;
|
||
|
|
||
|
if (!self->dmg)
|
||
|
self->dmg = 100;
|
||
|
|
||
|
if (self->spawnflags == 0)
|
||
|
{
|
||
|
self->solid = SOLID_BSP;
|
||
|
self->movetype = MOVETYPE_PUSH;
|
||
|
self->think = func_object_release;
|
||
|
self->nextthink = level.time + 2 * FRAMETIME;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->movetype = MOVETYPE_PUSH;
|
||
|
self->use = func_object_use;
|
||
|
self->svflags |= SVF_NOCLIENT;
|
||
|
}
|
||
|
|
||
|
if (self->spawnflags & 2)
|
||
|
self->s.effects |= EF_ANIM_ALL;
|
||
|
if (self->spawnflags & 4)
|
||
|
self->s.effects |= EF_ANIM_ALLFAST;
|
||
|
|
||
|
self->clipmask = MASK_MONSTERSOLID;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 18-FEB-99
|
||
|
/*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST SURF2_ALPHA
|
||
|
Any brush that you want to explode or break apart. If you want an
|
||
|
explosion, 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.
|
||
|
|
||
|
type - type of debris ("glass", "wood" or "metal")
|
||
|
type default is "glass"
|
||
|
|
||
|
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.
|
||
|
|
||
|
"dmg" how much radius damage should be done, defaults to 0
|
||
|
|
||
|
"fxdensity" size of explosion 1 - 100 (default is 10)
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void func_explosive_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mdx_part, int mdx_subobject)
|
||
|
{
|
||
|
vec3_t origin;
|
||
|
vec3_t chunkorigin;
|
||
|
vec3_t size;
|
||
|
int count;
|
||
|
int mass;
|
||
|
|
||
|
PlayerNoise( attacker, attacker->s.origin, PNOISE_WEAPON );
|
||
|
|
||
|
// 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, 250, 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;
|
||
|
if ((!self->type) || ((self->type) && (!strcmp(self->type, "glass"))))
|
||
|
{
|
||
|
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/props/glass/glass1.md2", 1, chunkorigin);
|
||
|
}
|
||
|
}
|
||
|
else if (((self->type) && (!strcmp(self->type, "wood"))))
|
||
|
{
|
||
|
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/props/wood/wood1.md2", 1, chunkorigin);
|
||
|
}
|
||
|
}
|
||
|
else if (((self->type) && (!strcmp(self->type, "metal"))))
|
||
|
{
|
||
|
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/props/metal/metal1.md2", 1, chunkorigin);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// small chunks
|
||
|
count = mass / 25;
|
||
|
if (count > 16)
|
||
|
count = 16;
|
||
|
if ((!self->type) || ((self->type) && (!strcmp(self->type, "glass"))))
|
||
|
{
|
||
|
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/props/glass/glass2.md2", 2, chunkorigin);
|
||
|
}
|
||
|
}
|
||
|
else if (((self->type) && (!strcmp(self->type, "wood"))))
|
||
|
{
|
||
|
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/props/wood/wood2.md2", 2, chunkorigin);
|
||
|
}
|
||
|
}
|
||
|
else if (((self->type) && (!strcmp(self->type, "metal"))))
|
||
|
{
|
||
|
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/props/metal/metal2.md2", 2, chunkorigin);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
G_UseTargets (self, attacker);
|
||
|
|
||
|
if (self->dmg)
|
||
|
BecomeExplosion1 (self);
|
||
|
else
|
||
|
G_FreeEdict (self);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
void func_explosive_use(edict_t *self, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
func_explosive_explode (self, self, other, self->health, vec3_origin, 0, 0);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 7-MAR-99
|
||
|
void func_explosive_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
|
{
|
||
|
if (!(other->svflags & SVF_MONSTER))
|
||
|
return;
|
||
|
|
||
|
if (!(other->onfiretime > 0))
|
||
|
return;
|
||
|
|
||
|
func_explosive_explode (self, self, other, self->health, vec3_origin, 0, 0);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
void func_explosive_spawn (edict_t *self, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
self->solid = SOLID_BSP;
|
||
|
self->svflags &= ~SVF_NOCLIENT;
|
||
|
self->use = NULL;
|
||
|
KillBox (self);
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
void SP_func_explosive (edict_t *self)
|
||
|
{
|
||
|
if (deathmatch->value)
|
||
|
{ // auto-remove for deathmatch
|
||
|
G_FreeEdict (self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
self->movetype = MOVETYPE_PUSH;
|
||
|
|
||
|
// JOSEPH 10-FEB-99
|
||
|
if (self->spawnflags & 8)
|
||
|
self->s.renderfx2 |= RF2_SURF_ALPHA;
|
||
|
// END JOSEPH
|
||
|
|
||
|
gi.modelindex ("models/props/glass/glass1.md2");
|
||
|
gi.modelindex ("models/props/glass/glass2.md2");
|
||
|
|
||
|
gi.setmodel (self, self->model);
|
||
|
|
||
|
if (self->spawnflags & 1)
|
||
|
{
|
||
|
self->svflags |= SVF_NOCLIENT;
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->use = func_explosive_spawn;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self->solid = SOLID_BSP;
|
||
|
if (self->targetname)
|
||
|
self->use = func_explosive_use;
|
||
|
}
|
||
|
|
||
|
if (self->spawnflags & 2)
|
||
|
self->s.effects |= EF_ANIM_ALL;
|
||
|
if (self->spawnflags & 4)
|
||
|
self->s.effects |= EF_ANIM_ALLFAST;
|
||
|
|
||
|
if (self->use != func_explosive_use)
|
||
|
{
|
||
|
if (!self->health)
|
||
|
self->health = 100;
|
||
|
self->die = func_explosive_explode;
|
||
|
self->takedamage = DAMAGE_YES;
|
||
|
}
|
||
|
|
||
|
// JOSEPH 7-MARCH-99
|
||
|
self->touch = func_explosive_touch;
|
||
|
// END JOSEPH
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 8-FEB-99
|
||
|
/*UAKED misc_explobox (0 .5 .8) (-16 -16 0) (16 16 40)
|
||
|
Large exploding box. You can override its mass (100),
|
||
|
health (80), and dmg (150).
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void barrel_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
|
|
||
|
{
|
||
|
float ratio;
|
||
|
vec3_t v;
|
||
|
|
||
|
if ((!other->groundentity) || (other->groundentity == self))
|
||
|
return;
|
||
|
|
||
|
ratio = (float)other->mass / (float)self->mass;
|
||
|
VectorSubtract (self->s.origin, other->s.origin, v);
|
||
|
M_walkmove (self, vectoyaw(v), 20 * ratio * FRAMETIME);
|
||
|
}
|
||
|
|
||
|
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/props/glass/glass1.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/props/glass/glass1.md2", spd, org);
|
||
|
|
||
|
// bottom corners
|
||
|
spd = 1.75 * (float)self->dmg / 200.0;
|
||
|
VectorCopy (self->absmin, org);
|
||
|
ThrowDebris (self, "models/props/glass/glass3.md2", spd, org);
|
||
|
VectorCopy (self->absmin, org);
|
||
|
org[0] += self->size[0];
|
||
|
ThrowDebris (self, "models/props/glass/glass3.md2", spd, org);
|
||
|
VectorCopy (self->absmin, org);
|
||
|
org[1] += self->size[1];
|
||
|
ThrowDebris (self, "models/props/glass/glass3.md2", spd, org);
|
||
|
VectorCopy (self->absmin, org);
|
||
|
org[0] += self->size[0];
|
||
|
org[1] += self->size[1];
|
||
|
ThrowDebris (self, "models/props/glass/glass3.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/props/glass/glass2.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/props/glass/glass2.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/props/glass/glass2.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/props/glass/glass2.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/props/glass/glass2.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/props/glass/glass2.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/props/glass/glass2.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/props/glass/glass2.md2", spd, org);
|
||
|
|
||
|
VectorCopy (save, self->s.origin);
|
||
|
if (self->groundentity)
|
||
|
BecomeExplosion2 (self);
|
||
|
else
|
||
|
BecomeExplosion1 (self);
|
||
|
}
|
||
|
|
||
|
void barrel_delay (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mdx_part, int mdx_subobject)
|
||
|
{
|
||
|
self->takedamage = DAMAGE_NO;
|
||
|
self->nextthink = level.time + 2 * FRAMETIME;
|
||
|
self->think = barrel_explode;
|
||
|
self->activator = attacker;
|
||
|
}
|
||
|
|
||
|
// JOSEPH 26-AUG-98
|
||
|
// JOSEPH TEMP
|
||
|
void SP_props_trashcanA (edict_t *self);
|
||
|
|
||
|
void SP_misc_explobox (edict_t *self)
|
||
|
{
|
||
|
// JOSEPH TEMP
|
||
|
SP_props_trashcanA (self);
|
||
|
return;
|
||
|
|
||
|
// END JOSEPH
|
||
|
|
||
|
if (deathmatch->value)
|
||
|
{ // auto-remove for deathmatch
|
||
|
G_FreeEdict (self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
gi.modelindex ("models/props/glass/glass1.md2");
|
||
|
gi.modelindex ("models/props/glass/glass2.md2");
|
||
|
gi.modelindex ("models/props/glass/glass3.md2");
|
||
|
|
||
|
|
||
|
self->solid = SOLID_BBOX;
|
||
|
self->movetype = MOVETYPE_STEP;
|
||
|
|
||
|
self->model = "models/objects/barrels/tris.md2";
|
||
|
self->s.modelindex = gi.modelindex (self->model);
|
||
|
VectorSet (self->mins, -16, -16, 0);
|
||
|
VectorSet (self->maxs, 16, 16, 40);
|
||
|
|
||
|
if (!self->mass)
|
||
|
self->mass = 400;
|
||
|
if (!self->health)
|
||
|
self->health = 10;
|
||
|
if (!self->dmg)
|
||
|
self->dmg = 150;
|
||
|
|
||
|
self->die = barrel_delay;
|
||
|
self->takedamage = DAMAGE_YES;
|
||
|
self->cast_info.aiflags = AI_NOSTEP;
|
||
|
|
||
|
self->touch = barrel_touch;
|
||
|
|
||
|
self->think = M_droptofloor;
|
||
|
self->nextthink = level.time + 2 * FRAMETIME;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 8-FEB-99
|
||
|
/*UAKED light_mine1 (0 1 0) (-2 -2 -12) (2 2 12)
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void SP_light_mine1 (edict_t *ent)
|
||
|
{
|
||
|
ent->movetype = MOVETYPE_NONE;
|
||
|
ent->solid = SOLID_BBOX;
|
||
|
ent->s.modelindex = gi.modelindex ("models/objects/minelite/light1/tris.md2");
|
||
|
gi.linkentity (ent);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 8-FEB-99
|
||
|
/*UAKED light_mine2 (0 1 0) (-2 -2 -12) (2 2 12)
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void SP_light_mine2 (edict_t *ent)
|
||
|
{
|
||
|
ent->movetype = MOVETYPE_NONE;
|
||
|
ent->solid = SOLID_BBOX;
|
||
|
ent->s.modelindex = gi.modelindex ("models/objects/minelite/light2/tris.md2");
|
||
|
gi.linkentity (ent);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 8-FEB-99
|
||
|
/*UAKED misc_gib_arm (1 0 0) (-8 -8 -8) (8 8 8)
|
||
|
Intended for use with the target_spawner
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void SP_misc_gib_arm (edict_t *ent)
|
||
|
{
|
||
|
gi.setmodel (ent, "models/objects/gibs/arm/tris.md2");
|
||
|
ent->solid = SOLID_NOT;
|
||
|
ent->s.effects |= EF_GIB;
|
||
|
ent->takedamage = DAMAGE_YES;
|
||
|
ent->die = gib_die;
|
||
|
ent->movetype = MOVETYPE_TOSS;
|
||
|
ent->svflags |= SVF_MONSTER;
|
||
|
ent->deadflag = DEAD_DEAD;
|
||
|
ent->avelocity[0] = random()*200;
|
||
|
ent->avelocity[1] = random()*200;
|
||
|
ent->avelocity[2] = random()*200;
|
||
|
ent->think = G_FreeEdict;
|
||
|
ent->nextthink = level.time + 30;
|
||
|
gi.linkentity (ent);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 8-FEB-99
|
||
|
/*UAKED misc_gib_leg (1 0 0) (-8 -8 -8) (8 8 8)
|
||
|
Intended for use with the target_spawner
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void SP_misc_gib_leg (edict_t *ent)
|
||
|
{
|
||
|
gi.setmodel (ent, "models/objects/gibs/leg/tris.md2");
|
||
|
ent->solid = SOLID_NOT;
|
||
|
ent->s.effects |= EF_GIB;
|
||
|
ent->takedamage = DAMAGE_YES;
|
||
|
ent->die = gib_die;
|
||
|
ent->movetype = MOVETYPE_TOSS;
|
||
|
ent->svflags |= SVF_MONSTER;
|
||
|
ent->deadflag = DEAD_DEAD;
|
||
|
ent->avelocity[0] = random()*200;
|
||
|
ent->avelocity[1] = random()*200;
|
||
|
ent->avelocity[2] = random()*200;
|
||
|
ent->think = G_FreeEdict;
|
||
|
ent->nextthink = level.time + 30;
|
||
|
gi.linkentity (ent);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 8-FEB-99
|
||
|
/*UAKED misc_gib_head (1 0 0) (-8 -8 -8) (8 8 8)
|
||
|
Intended for use with the target_spawner
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void SP_misc_gib_head (edict_t *ent)
|
||
|
{
|
||
|
gi.setmodel (ent, "models/objects/gibs/head/tris.md2");
|
||
|
ent->solid = SOLID_NOT;
|
||
|
ent->s.effects |= EF_GIB;
|
||
|
ent->takedamage = DAMAGE_YES;
|
||
|
ent->die = gib_die;
|
||
|
ent->movetype = MOVETYPE_TOSS;
|
||
|
ent->svflags |= SVF_MONSTER;
|
||
|
ent->deadflag = DEAD_DEAD;
|
||
|
ent->avelocity[0] = random()*200;
|
||
|
ent->avelocity[1] = random()*200;
|
||
|
ent->avelocity[2] = random()*200;
|
||
|
ent->think = G_FreeEdict;
|
||
|
ent->nextthink = level.time + 30;
|
||
|
gi.linkentity (ent);
|
||
|
}
|
||
|
|
||
|
//=====================================================
|
||
|
|
||
|
/*QUAKED target_character (0 0 1) ?
|
||
|
used with target_string (must be on same "team")
|
||
|
"count" is position in the string (starts at 1)
|
||
|
*/
|
||
|
|
||
|
void SP_target_character (edict_t *self)
|
||
|
{
|
||
|
self->movetype = MOVETYPE_PUSH;
|
||
|
gi.setmodel (self, self->model);
|
||
|
self->solid = SOLID_BSP;
|
||
|
self->s.frame = 12;
|
||
|
gi.linkentity (self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED target_string (0 0 1) (-8 -8 -8) (8 8 8)
|
||
|
*/
|
||
|
|
||
|
void target_string_use (edict_t *self, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
edict_t *e;
|
||
|
int n, l;
|
||
|
char c;
|
||
|
|
||
|
l = strlen(self->message);
|
||
|
for (e = self->teammaster; e; e = e->teamchain)
|
||
|
{
|
||
|
if (!e->count)
|
||
|
continue;
|
||
|
n = e->count - 1;
|
||
|
if (n > l)
|
||
|
{
|
||
|
e->s.frame = 12;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
c = self->message[n];
|
||
|
if (c >= '0' && c <= '9')
|
||
|
e->s.frame = c - '0';
|
||
|
else if (c == '-')
|
||
|
e->s.frame = 10;
|
||
|
else if (c == ':')
|
||
|
e->s.frame = 11;
|
||
|
else
|
||
|
e->s.frame = 12;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SP_target_string (edict_t *self)
|
||
|
{
|
||
|
if (!self->message)
|
||
|
self->message = "";
|
||
|
self->use = target_string_use;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED func_clock (0 0 1) (-8 -8 -8) (8 8 8) TIMER_UP TIMER_DOWN START_OFF MULTI_USE
|
||
|
target a target_string with this
|
||
|
|
||
|
The default is to be a time of day clock
|
||
|
|
||
|
TIMER_UP and TIMER_DOWN run for "count" seconds and the fire "pathtarget"
|
||
|
If START_OFF, this entity must be used before it starts
|
||
|
|
||
|
"style" 0 "xx"
|
||
|
1 "xx:xx"
|
||
|
2 "xx:xx:xx"
|
||
|
*/
|
||
|
|
||
|
#define CLOCK_MESSAGE_SIZE 16
|
||
|
|
||
|
// don't let field width of any clock messages change, or it
|
||
|
// could cause an overwrite after a game load
|
||
|
|
||
|
static void func_clock_reset (edict_t *self)
|
||
|
{
|
||
|
self->activator = NULL;
|
||
|
if (self->spawnflags & 1)
|
||
|
{
|
||
|
self->health = 0;
|
||
|
self->wait = self->count;
|
||
|
}
|
||
|
else if (self->spawnflags & 2)
|
||
|
{
|
||
|
self->health = self->count;
|
||
|
self->wait = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void func_clock_format_countdown (edict_t *self)
|
||
|
{
|
||
|
if (self->style == 0)
|
||
|
{
|
||
|
Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i", self->health);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (self->style == 1)
|
||
|
{
|
||
|
Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i", self->health / 60, self->health % 60);
|
||
|
if (self->message[3] == ' ')
|
||
|
self->message[3] = '0';
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (self->style == 2)
|
||
|
{
|
||
|
Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60);
|
||
|
if (self->message[3] == ' ')
|
||
|
self->message[3] = '0';
|
||
|
if (self->message[6] == ' ')
|
||
|
self->message[6] = '0';
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void func_clock_think (edict_t *self)
|
||
|
{
|
||
|
if (!self->enemy)
|
||
|
{
|
||
|
self->enemy = G_Find (NULL, FOFS(targetname), self->target);
|
||
|
if (!self->enemy)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (self->spawnflags & 1)
|
||
|
{
|
||
|
func_clock_format_countdown (self);
|
||
|
self->health++;
|
||
|
}
|
||
|
else if (self->spawnflags & 2)
|
||
|
{
|
||
|
func_clock_format_countdown (self);
|
||
|
self->health--;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
struct tm *ltime;
|
||
|
time_t gmtime;
|
||
|
|
||
|
time(&gmtime);
|
||
|
ltime = localtime(&gmtime);
|
||
|
Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
|
||
|
if (self->message[3] == ' ')
|
||
|
self->message[3] = '0';
|
||
|
if (self->message[6] == ' ')
|
||
|
self->message[6] = '0';
|
||
|
}
|
||
|
|
||
|
self->enemy->message = self->message;
|
||
|
self->enemy->use (self->enemy, self, self);
|
||
|
|
||
|
if (((self->spawnflags & 1) && (self->health > self->wait)) ||
|
||
|
((self->spawnflags & 2) && (self->health < self->wait)))
|
||
|
{
|
||
|
if (self->pathtarget)
|
||
|
{
|
||
|
char *savetarget;
|
||
|
char *savemessage;
|
||
|
|
||
|
savetarget = self->target;
|
||
|
savemessage = self->message;
|
||
|
self->target = self->pathtarget;
|
||
|
self->message = NULL;
|
||
|
G_UseTargets (self, self->activator);
|
||
|
self->target = savetarget;
|
||
|
self->message = savemessage;
|
||
|
}
|
||
|
|
||
|
if (!(self->spawnflags & 8))
|
||
|
return;
|
||
|
|
||
|
func_clock_reset (self);
|
||
|
|
||
|
if (self->spawnflags & 4)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
self->nextthink = level.time + 1;
|
||
|
}
|
||
|
|
||
|
void func_clock_use (edict_t *self, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
if (!(self->spawnflags & 8))
|
||
|
self->use = NULL;
|
||
|
if (self->activator)
|
||
|
return;
|
||
|
self->activator = activator;
|
||
|
self->think (self);
|
||
|
}
|
||
|
|
||
|
void SP_func_clock (edict_t *self)
|
||
|
{
|
||
|
if (!self->target)
|
||
|
{
|
||
|
gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
|
||
|
G_FreeEdict (self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((self->spawnflags & 2) && (!self->count))
|
||
|
{
|
||
|
gi.dprintf("%s with no count at %s\n", self->classname, vtos(self->s.origin));
|
||
|
G_FreeEdict (self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((self->spawnflags & 1) && (!self->count))
|
||
|
self->count = 60*60;;
|
||
|
|
||
|
func_clock_reset (self);
|
||
|
|
||
|
self->message = gi.TagMalloc (CLOCK_MESSAGE_SIZE, TAG_LEVEL);
|
||
|
|
||
|
self->think = func_clock_think;
|
||
|
|
||
|
if (self->spawnflags & 4)
|
||
|
self->use = func_clock_use;
|
||
|
else
|
||
|
self->nextthink = level.time + 1;
|
||
|
}
|
||
|
|
||
|
//=================================================================================
|
||
|
|
||
|
void teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
|
{
|
||
|
edict_t *dest;
|
||
|
int i;
|
||
|
|
||
|
if (!(other->client))
|
||
|
return;
|
||
|
dest = G_Find (NULL, FOFS(targetname), self->target);
|
||
|
if (!dest)
|
||
|
{
|
||
|
gi.dprintf ("Couldn't find destination\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// unlink to make sure it can't possibly interfere with KillBox
|
||
|
gi.unlinkentity (other);
|
||
|
|
||
|
VectorCopy (dest->s.origin, other->s.origin);
|
||
|
VectorCopy (dest->s.origin, other->s.old_origin);
|
||
|
other->s.origin[2] += 10;
|
||
|
|
||
|
// clear the velocity and hold them in place briefly
|
||
|
VectorClear (other->velocity);
|
||
|
other->client->ps.pmove.pm_time = 160>>3; // hold time
|
||
|
other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
|
||
|
|
||
|
// draw the teleport splash at source and on the player
|
||
|
self->owner->s.event = EV_PLAYER_TELEPORT;
|
||
|
other->s.event = EV_PLAYER_TELEPORT;
|
||
|
|
||
|
// set angles
|
||
|
for (i=0 ; i<3 ; i++)
|
||
|
other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
|
||
|
|
||
|
VectorClear (other->s.angles);
|
||
|
VectorClear (other->client->ps.viewangles);
|
||
|
VectorClear (other->client->v_angle);
|
||
|
|
||
|
// kill anything at the destination
|
||
|
KillBox (other);
|
||
|
|
||
|
gi.linkentity (other);
|
||
|
}
|
||
|
|
||
|
/*QUAKED misc_teleporter (1 0 0) (-32 -32 -24) (32 32 -16)
|
||
|
Stepping onto this disc will teleport players to the targeted misc_teleporter_dest object.
|
||
|
*/
|
||
|
void SP_misc_teleporter (edict_t *ent)
|
||
|
{
|
||
|
edict_t *trig;
|
||
|
|
||
|
if (!ent->target)
|
||
|
{
|
||
|
gi.dprintf ("teleporter without a target.\n");
|
||
|
G_FreeEdict (ent);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
gi.setmodel (ent, "models/objects/dmspot/tris.md2");
|
||
|
ent->s.skinnum = 1;
|
||
|
ent->s.effects = EF_TELEPORTER;
|
||
|
ent->s.sound = gi.soundindex ("world/amb10.wav");
|
||
|
ent->solid = SOLID_BBOX;
|
||
|
|
||
|
VectorSet (ent->mins, -32, -32, -24);
|
||
|
VectorSet (ent->maxs, 32, 32, -16);
|
||
|
gi.linkentity (ent);
|
||
|
|
||
|
trig = G_Spawn ();
|
||
|
trig->touch = teleporter_touch;
|
||
|
trig->solid = SOLID_TRIGGER;
|
||
|
trig->target = ent->target;
|
||
|
trig->owner = ent;
|
||
|
VectorCopy (ent->s.origin, trig->s.origin);
|
||
|
VectorSet (trig->mins, -8, -8, 8);
|
||
|
VectorSet (trig->maxs, 8, 8, 24);
|
||
|
gi.linkentity (trig);
|
||
|
|
||
|
}
|
||
|
|
||
|
/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
|
||
|
Point teleporters at these.
|
||
|
*/
|
||
|
void SP_misc_teleporter_dest (edict_t *ent)
|
||
|
{
|
||
|
gi.setmodel (ent, "models/objects/dmspot/tris.md2");
|
||
|
ent->s.skinnum = 0;
|
||
|
ent->solid = SOLID_BBOX;
|
||
|
// ent->s.effects |= EF_FLIES;
|
||
|
VectorSet (ent->mins, -32, -32, -24);
|
||
|
VectorSet (ent->maxs, 32, 32, -16);
|
||
|
gi.linkentity (ent);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 8-FEB-99
|
||
|
/*UAKED misc_amb4 (1 0 0) (-16 -16 -16) (16 16 16)
|
||
|
Mal's amb4 loop entity
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
static int amb4sound;
|
||
|
|
||
|
void amb4_think (edict_t *ent)
|
||
|
{
|
||
|
ent->nextthink = level.time + 2.7;
|
||
|
gi.sound(ent, CHAN_VOICE, amb4sound, 1, ATTN_NONE, 0);
|
||
|
}
|
||
|
|
||
|
void SP_misc_amb4 (edict_t *ent)
|
||
|
{
|
||
|
ent->think = amb4_think;
|
||
|
ent->nextthink = level.time + 1;
|
||
|
amb4sound = gi.soundindex ("world/amb4.wav");
|
||
|
gi.linkentity (ent);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 8-FEB-99
|
||
|
/*UAKED misc_smoke (1 0 0) (-16 -16 -64) (16 16 64) ALPHA1 ALPHA2 ALPHA4 ALPHA6 ALPHA8 SCALE50
|
||
|
ALPHA1 = 0.1
|
||
|
ALPHA8 = 0.8
|
||
|
SCALE 50 will scale it down 50 percent
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void SP_misc_smoke (edict_t *ent)
|
||
|
{
|
||
|
ent->s.modelindex = gi.modelindex ("sprites/s_smoke4.sp2");
|
||
|
|
||
|
ent->s.effects |= EF_ANIM_ALLFAST;
|
||
|
|
||
|
ent->s.renderfx |= RF_FACINGUP|RF_TRANSLUCENT;
|
||
|
ent->s.renderfx2 |= ent->spawnflags;
|
||
|
|
||
|
ent->movetype = MOVETYPE_NONE;
|
||
|
//ent->solid = SOLID_BBOX;
|
||
|
|
||
|
gi.linkentity (ent);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// Test vehicle models
|
||
|
|
||
|
void dodgeviper_think( edict_t *self)
|
||
|
{
|
||
|
if ((self->s.angles[1] += 8) > 360)
|
||
|
self->s.angles[1] -= 360;
|
||
|
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
}
|
||
|
|
||
|
void SP_misc_car (edict_t *self)
|
||
|
{
|
||
|
self->movetype = MOVETYPE_STEP;
|
||
|
self->solid = SOLID_BBOX;
|
||
|
VectorSet (self->mins, -16, -16, -24);
|
||
|
VectorSet (self->maxs, 16, 16, 32);
|
||
|
|
||
|
// temp for E3 demo, KP2 has characters in the ground
|
||
|
while (!ValidBoxAtLoc(self->s.origin, self->mins, self->maxs, self, MASK_PLAYERSOLID))
|
||
|
{
|
||
|
self->s.origin[2] += 16;
|
||
|
gi.linkentity (self);
|
||
|
}
|
||
|
|
||
|
self->s.modelindex = gi.modelindex("models/vehicles/cars/viper/tris.md2");
|
||
|
|
||
|
self->s.renderfx |= RF_REFL_MAP;
|
||
|
|
||
|
self->think = dodgeviper_think;
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
}
|
||
|
|
||
|
// JOSEPH 8-FEB-99
|
||
|
/*UAKED cast_punk_window (1 0 0) (-16 -16 -16) (16 16 16)
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
static int windowsound;
|
||
|
|
||
|
void usewindow (edict_t *ent, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
// ent->use = NULL;
|
||
|
gi.sound(ent, CHAN_VOICE, windowsound , 1, ATTN_NONE, 0);
|
||
|
}
|
||
|
|
||
|
void thinkdeadwindow (edict_t *ent)
|
||
|
{
|
||
|
ent->s.frame++;
|
||
|
if (ent->s.frame < 336)
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
}
|
||
|
|
||
|
void window_die (edict_t *ent, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mdx_part, int mdx_subobject)
|
||
|
{
|
||
|
ent->takedamage = DAMAGE_NO;
|
||
|
ent->nextthink = level.time + FRAMETIME;
|
||
|
ent->think = thinkdeadwindow;
|
||
|
ent->activator = attacker;
|
||
|
ent->s.frame = 322;
|
||
|
}
|
||
|
|
||
|
void thinkwindow (edict_t *ent)
|
||
|
{
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
ent->s.frame++;
|
||
|
if (ent->s.frame > 211)
|
||
|
ent->s.frame = 0;
|
||
|
}
|
||
|
|
||
|
void SP_cast_punk_window (edict_t *ent)
|
||
|
{
|
||
|
ent->s.modelindex = gi.modelindex ("models/actors/fidelC/tris.md2");
|
||
|
ent->movetype = MOVETYPE_STEP;
|
||
|
ent->solid = SOLID_BBOX;
|
||
|
gi.linkentity (ent);
|
||
|
|
||
|
ent->takedamage = DAMAGE_YES;
|
||
|
// ent->cast_info.aiflags = AI_NOSTEP;
|
||
|
|
||
|
ent->health = 1;
|
||
|
ent->use = usewindow;
|
||
|
ent->think = thinkwindow;
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
|
||
|
windowsound = gi.soundindex ("actors/specific/spec3.wav");
|
||
|
|
||
|
VectorSet (ent->mins, -16, -16, 0);
|
||
|
VectorSet (ent->maxs, 16, 16, 40);
|
||
|
|
||
|
ent->die = window_die;
|
||
|
|
||
|
}
|
||
|
|
||
|
/*QUAKED refl (1 0 0) (-16 -16 -16) (16 16 16)
|
||
|
*/
|
||
|
|
||
|
void SP_refl (edict_t *ent)
|
||
|
{
|
||
|
ent->s.modelindex = gi.modelindex ("models/vehicles/cars/viper/tris.md2");
|
||
|
|
||
|
ent->s.renderfx |= RF_REFL_MAP;
|
||
|
|
||
|
ent->movetype = MOVETYPE_NONE;
|
||
|
|
||
|
gi.linkentity (ent);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED elps (1 0 0) (-32 -32 -32) (32 32 32)
|
||
|
test entity for mdx bbox hit test
|
||
|
*/
|
||
|
|
||
|
void elpsthink (edict_t *self)
|
||
|
{
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
self->s.angles[YAW] += 3.0;
|
||
|
self->health = 1000;
|
||
|
}
|
||
|
|
||
|
void SP_elps (edict_t *self)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/elps_seg/up.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/elps_seg/up.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/elps_seg/rt.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_LEGS].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/elps_seg/rt.mdx", &self->s.model_parts[PART_LEGS] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/elps_seg/fwd.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_BODY].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/elps_seg/fwd.mdx", &self->s.model_parts[PART_BODY] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_GUN].modelindex = gi.modelindex("models/actors/elps_seg/diag.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_GUN].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/elps_seg/diag.mdx", &self->s.model_parts[PART_GUN] );
|
||
|
|
||
|
self->movetype = MOVETYPE_STEP;
|
||
|
self->solid = SOLID_BBOX;
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
self->takedamage = DAMAGE_YES;
|
||
|
|
||
|
self->health = 1000;
|
||
|
self->think = elpsthink;
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
|
||
|
VectorSet (self->mins, -64, -64, -64);
|
||
|
VectorSet (self->maxs, 64, 64, 64);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED misc_caustic (1 0 0) (-16 -16 -64) (16 16 64) ALPHA1 ALPHA2 ALPHA4 ALPHA6 ALPHA8
|
||
|
ALPHA1 = 0.1
|
||
|
ALPHA8 = 0.8
|
||
|
*/
|
||
|
// Ridah, not used, removed RF2_CAUSTIC flag
|
||
|
/*
|
||
|
void SP_misc_caustic (edict_t *ent)
|
||
|
{
|
||
|
ent->s.modelindex = gi.modelindex ("sprites/s_smoke4.sp2");
|
||
|
|
||
|
ent->s.renderfx |= RF_TRANSLUCENT;
|
||
|
ent->s.renderfx2 |= ent->spawnflags;
|
||
|
ent->s.renderfx2 |= RF2_CAUSTIC;
|
||
|
|
||
|
ent->movetype = MOVETYPE_NONE;
|
||
|
|
||
|
gi.linkentity (ent);
|
||
|
|
||
|
}
|
||
|
*/
|
||
|
/*QUAKED misc_rosie (1 .5 0) (-16 -16 -24) (16 16 32)
|
||
|
*/
|
||
|
|
||
|
void rosie_think (edict_t *self)
|
||
|
{
|
||
|
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
self->s.frame ++;
|
||
|
|
||
|
if (self->s.frame > 390)
|
||
|
self->s.frame = 0;
|
||
|
}
|
||
|
|
||
|
void SP_misc_rosie (edict_t *self)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
//self->s.origin[2] += 1;
|
||
|
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/rosie_seg/head.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/rosie_seg/head.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/rosie_seg/legs.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_LEGS].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/rosie_seg/legs.mdx", &self->s.model_parts[PART_LEGS] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/rosie_seg/body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_BODY].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/rosie_seg/body.mdx", &self->s.model_parts[PART_BODY] );
|
||
|
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
|
||
|
self->s.renderfx2 |= RF2_DIR_LIGHTS;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
self->think = rosie_think;
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED misc_fidelA (1 .5 0) (-16 -16 -24) (16 16 32)
|
||
|
*/
|
||
|
|
||
|
void fidelA_think (edict_t *self)
|
||
|
{
|
||
|
//return;
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
self->s.frame ++;
|
||
|
|
||
|
if (self->s.frame > 54)
|
||
|
self->s.frame = 0;
|
||
|
|
||
|
|
||
|
gi.dprintf ("frame: %d\n", self->s.frame);
|
||
|
}
|
||
|
|
||
|
void SP_misc_fidelA (edict_t *self)
|
||
|
{
|
||
|
int i;
|
||
|
//return;
|
||
|
//self->s.origin[2] += 1;
|
||
|
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/fidel_mdx/head.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fidel_mdx/head.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/fidel_mdx/lower_body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_LEGS].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fidel_mdx/lower_body.mdx", &self->s.model_parts[PART_LEGS] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/fidel_mdx/upper_body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_BODY].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fidel_mdx/upper_body.mdx", &self->s.model_parts[PART_BODY] );
|
||
|
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
|
||
|
self->s.renderfx2 |= RF2_DIR_LIGHTS;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
self->think = fidelA_think;
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
#define ALARM_ON 1
|
||
|
#define ALARM_OFF 2
|
||
|
|
||
|
void Think_Alarm (edict_t *ent)
|
||
|
{
|
||
|
if (ent->wait < 0)
|
||
|
{
|
||
|
// just ring once
|
||
|
/*
|
||
|
if (ent->delay)
|
||
|
{
|
||
|
ent->delay --;
|
||
|
ent->wait = ent->count;
|
||
|
}
|
||
|
else
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
gi.sound (ent, CHAN_VOICE, gi.soundindex ("world/alarm.wav"), 1, ATTN_NORM, 0);
|
||
|
ent->nextthink = level.time + 4.8;
|
||
|
ent->wait -= 4.8;
|
||
|
}
|
||
|
|
||
|
void Use_Alarm (edict_t *ent, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
ent->nextthink = level.time + 3;
|
||
|
ent->think = Think_Alarm;
|
||
|
|
||
|
if (ent->moveinfo.state == ALARM_OFF)
|
||
|
{
|
||
|
// gi.dprintf ("turning alarm on\n");
|
||
|
ent->moveinfo.state = ALARM_ON;
|
||
|
ent->wait = ent->count;
|
||
|
ent->delay = ent->speed;
|
||
|
|
||
|
// Ridah, do some special handling here
|
||
|
EP_EventScript( activator, "alarm" );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// gi.dprintf ("turning alarm off\n");
|
||
|
ent->moveinfo.state = ALARM_OFF;
|
||
|
ent->wait = -1;
|
||
|
ent->delay = ent->speed;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*QUAKED misc_alarm (1 .5 0) (-8 -8 -8) (8 8 8)
|
||
|
must be triggered to work
|
||
|
count is the duration of the alarm ringing default is 60 sec
|
||
|
*/
|
||
|
void SP_misc_alarm (edict_t *ent)
|
||
|
{
|
||
|
ent->use = Use_Alarm;
|
||
|
|
||
|
if (!(ent->count))
|
||
|
ent->count = 60;
|
||
|
|
||
|
if (!ent->speed || ent->speed < 0)
|
||
|
ent->delay = ent->speed = 3;
|
||
|
|
||
|
ent->moveinfo.state = ALARM_OFF;
|
||
|
|
||
|
// Ridah, NAV code only understands func_button's
|
||
|
ent->classname = "func_button";
|
||
|
ent->name = "misc_alarm";
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*QUAKED misc_corky_rosie_mdx (0 0 1) (-16 -16 -24) (16 16 34)
|
||
|
*/
|
||
|
|
||
|
void SP_misc_corky_rosie_mdx (edict_t *self)
|
||
|
{
|
||
|
|
||
|
int i;
|
||
|
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/bitch/head.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/bitch/head.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/bitch/legs.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_LEGS].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/bitch/legs.mdx", &self->s.model_parts[PART_LEGS] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/bitch/body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_BODY].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/bitch/body.mdx", &self->s.model_parts[PART_BODY] );
|
||
|
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
|
||
|
self->s.renderfx2 |= RF2_DIR_LIGHTS;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED misc_corky_fatguy_mdx (0 0 1) (-16 -16 -24) (16 16 34)
|
||
|
*/
|
||
|
|
||
|
void SP_misc_corky_fatguy_mdx (edict_t *self)
|
||
|
{
|
||
|
|
||
|
int i;
|
||
|
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/fatguy_mdx/head.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fatguy_mdx/head.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/fatguy_mdx/lower_body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_LEGS].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fatguy_mdx/lower_body.mdx", &self->s.model_parts[PART_LEGS] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/fatguy_mdx/upper_body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_BODY].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fatguy_mdx/upper_body.mdx", &self->s.model_parts[PART_BODY] );
|
||
|
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
|
||
|
self->s.renderfx2 |= RF2_DIR_LIGHTS;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED misc_corky_fidel_mdx_pcx (0 0 1) (-16 -16 -24) (16 16 34)
|
||
|
*/
|
||
|
/*QUAKED misc_corky_fidel_mdx_tga (0 0 1) (-16 -16 -24) (16 16 34)
|
||
|
*/
|
||
|
|
||
|
void SP_misc_corky_fidel_mdx_tga (edict_t *self)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/fidel_tga/head.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fidel_tga/head.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/fidel_tga/lower_body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_LEGS].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fidel_tga/lower_body.mdx", &self->s.model_parts[PART_LEGS] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/fidel_tga/upper_body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_BODY].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fidel_tga/upper_body.mdx", &self->s.model_parts[PART_BODY] );
|
||
|
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
|
||
|
self->s.renderfx2 |= RF2_DIR_LIGHTS;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
}
|
||
|
|
||
|
void SP_misc_corky_fidel_mdx_pcx (edict_t *self)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/thug/head.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/thug/head.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/thug/legs.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_LEGS].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/thug/legs.mdx", &self->s.model_parts[PART_LEGS] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/thug/body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_BODY].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/thug/body.mdx", &self->s.model_parts[PART_BODY] );
|
||
|
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
|
||
|
self->s.renderfx2 |= RF2_DIR_LIGHTS;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
/*QUAKED misc_barry_fidelc_maya (0 0 1) (-16 -16 -24) (16 16 34)
|
||
|
*/
|
||
|
/*QUAKED misc_barry_bitch (0 0 1) (-16 -16 -24) (16 16 34)
|
||
|
*/
|
||
|
|
||
|
void misc_barry_fidelc_maya_think (edict_t *self)
|
||
|
{
|
||
|
self->s.frame++;
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
|
||
|
if (self->s.frame >= 761)
|
||
|
self->s.frame = 0;
|
||
|
|
||
|
gi.dprintf ("frame: %d\n", self->s.frame);
|
||
|
}
|
||
|
|
||
|
void SP_misc_barry_fidelc_maya (edict_t *self)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/bitch/head.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].baseskin = self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/bitch/head.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/bitch/legs.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_LEGS].baseskin = self->s.model_parts[PART_LEGS].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/bitch/legs.mdx", &self->s.model_parts[PART_LEGS] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/bitch/body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_BODY].baseskin = self->s.model_parts[PART_BODY].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/bitch/body.mdx", &self->s.model_parts[PART_BODY] );
|
||
|
|
||
|
/*
|
||
|
int i;
|
||
|
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/bitch/head.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/bitch/head.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/bitch/legs.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_LEGS].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/bitch/legs.mdx", &self->s.model_parts[PART_LEGS] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/bitch/body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_BODY].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/bitch/body.mdx", &self->s.model_parts[PART_BODY] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_GUN].modelindex = gi.modelindex("models/actors/bitch/gun.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_GUN].baseskin = self->s.model_parts[PART_GUN].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/bitch/gun.mdx", &self->s.model_parts[PART_GUN] );
|
||
|
*/
|
||
|
/*
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/fidel_seg/head.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].baseskin = self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fidel_seg/head.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_LEGS].modelindex = gi.modelindex("models/actors/fidel_seg/legs.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_LEGS].baseskin = self->s.model_parts[PART_LEGS].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fidel_seg/legs.mdx", &self->s.model_parts[PART_LEGS] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_BODY].modelindex = gi.modelindex("models/actors/fidel_seg/body.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_BODY].baseskin = self->s.model_parts[PART_BODY].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fidel_seg/body.mdx", &self->s.model_parts[PART_BODY] );
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_GUN].modelindex = gi.modelindex("models/actors/fidel_seg/gun.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_GUN].baseskin = self->s.model_parts[PART_GUN].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/fidel_seg/gun.mdx", &self->s.model_parts[PART_GUN] );
|
||
|
*/
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
|
||
|
self->s.renderfx2 |= RF2_DIR_LIGHTS;
|
||
|
|
||
|
self->think = misc_barry_fidelc_maya_think;
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
}
|
||
|
|
||
|
/*QUAKED misc_barry_cube_mdx (0 0 1) (-16 -16 -24) (16 16 34)
|
||
|
*/
|
||
|
|
||
|
void misc_barry_cube_mdx_think (edict_t *self)
|
||
|
{
|
||
|
self->s.frame++;
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
if (self->s.frame >= 20)
|
||
|
self->s.frame = 0;
|
||
|
}
|
||
|
|
||
|
void SP_misc_barry_cube_mdx (edict_t *self)
|
||
|
{
|
||
|
|
||
|
int i;
|
||
|
|
||
|
memset(&(self->s.model_parts[0]), 0, sizeof(model_part_t) * MAX_MODEL_PARTS);
|
||
|
|
||
|
self->s.num_parts++;
|
||
|
self->s.model_parts[PART_HEAD].modelindex = gi.modelindex("models/actors/cube_mdx/cube.mdx");
|
||
|
for (i=0; i<MAX_MODELPART_OBJECTS; i++)
|
||
|
self->s.model_parts[PART_HEAD].skinnum[i] = self->s.skinnum;
|
||
|
gi.GetObjectBounds( "models/actors/cube_mdx/cube.mdx", &self->s.model_parts[PART_HEAD] );
|
||
|
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
|
||
|
self->s.renderfx2 |= RF2_DIR_LIGHTS;
|
||
|
|
||
|
self->think = misc_barry_cube_mdx_think;
|
||
|
self->nextthink = level.time + 0.1;
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED path_attractor (.4 .3 .8) (-16 -16 -24) (16 16 48)
|
||
|
When this is placed on the map it will attract actors by name
|
||
|
from the episodic ai routines
|
||
|
|
||
|
default delay is 10 sec.
|
||
|
*/
|
||
|
|
||
|
void SP_path_attractor (edict_t *self)
|
||
|
{
|
||
|
self->movetype = MOVETYPE_NONE;
|
||
|
self->solid = SOLID_NOT;
|
||
|
VectorSet (self->mins, -16, -16, -24);
|
||
|
VectorSet (self->maxs, 16, 16, 48);
|
||
|
|
||
|
if (!self->delay)
|
||
|
self->delay = 10;
|
||
|
|
||
|
AI_Ent_droptofloor( self );
|
||
|
}
|
||
|
|
||
|
|
||
|
// JOSEPH 16-DEC-98
|
||
|
|
||
|
/*QUAKED misc_cut_scene (0 0 1) (-16 -16 -16) (16 16 16)
|
||
|
*/
|
||
|
|
||
|
/*void CutSceneThink (edict_t *ent)
|
||
|
{
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
|
||
|
//if (level.time > (ent->nextthink + ent->wait))
|
||
|
// JOSEPH 7-DEC-98
|
||
|
if (!ent->wait--)
|
||
|
EndCutScene (ent);
|
||
|
}
|
||
|
|
||
|
void CutSceneThinkEnd (edict_t *ent)
|
||
|
{
|
||
|
EndCutScene (ent);
|
||
|
}
|
||
|
|
||
|
void CutSceneThinkStart (edict_t *ent)
|
||
|
{
|
||
|
if (!ent->count)
|
||
|
return;
|
||
|
|
||
|
ent->count--;
|
||
|
|
||
|
BeginCutScene (ent);
|
||
|
|
||
|
// JOSEPH 7-DEC-98
|
||
|
ent->think = CutSceneThink;
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
}
|
||
|
|
||
|
void Touch_CutScene (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
|
{
|
||
|
ent->think = CutSceneThinkStart;
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
}
|
||
|
|
||
|
void SP_misc_cut_scene (edict_t *self)
|
||
|
{
|
||
|
|
||
|
VectorSet (self->mins, -16, -16, -16);
|
||
|
VectorSet (self->maxs, 16, 16, 16);
|
||
|
|
||
|
self->solid = SOLID_TRIGGER;
|
||
|
self->touch = Touch_CutScene;
|
||
|
self->svflags |= SVF_NOCLIENT;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
if (!self->wait)
|
||
|
self->wait = 60;
|
||
|
|
||
|
self->wait=10; // just for now
|
||
|
|
||
|
self->count = 1;
|
||
|
|
||
|
}*/
|
||
|
|
||
|
// JOSEPH 25-FEB-99
|
||
|
/*QUAKED misc_cutscene_trigger (0 0 1) ?
|
||
|
|
||
|
Targets a misc_cutscene_camera
|
||
|
|
||
|
target - camera to target
|
||
|
debugprint - set to 1 to print out camera end position and angles
|
||
|
duration - fade in time.
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
|
||
|
// JOSEPH 19-MAR-99-B
|
||
|
/*QUAKED misc_cutscene_camera (0 0 1) (-16 -16 -16) (16 16 16)
|
||
|
|
||
|
Camera to be targeted from a misc_cutscene_trigger
|
||
|
|
||
|
targetname - camera target ID
|
||
|
|
||
|
cameraorigin - X Y Z camera start position
|
||
|
|
||
|
cameraangle - X Y Z start angles
|
||
|
|
||
|
rotate - X Y Z rotational velocity during cut scene
|
||
|
|
||
|
cameravel - [forward] [right] [up] speed to move from initial angle.
|
||
|
|
||
|
cameravelrel - [forward] [right] [up] speed to move relative to current frame angle.
|
||
|
|
||
|
wait - cut scene length in seconds (default 5)
|
||
|
|
||
|
target - next camera to target.
|
||
|
|
||
|
target2 - [NOT WORKING!!] camera angle points to this entity (overides other angle commands)
|
||
|
|
||
|
deadticks - fov for this camera;
|
||
|
|
||
|
duration - fade out time.
|
||
|
|
||
|
reactdelay - time into camera to start fading out
|
||
|
*/
|
||
|
// END JOSEPH
|
||
|
void CutSceneThink (edict_t *ent)
|
||
|
{
|
||
|
if (!ent->wait--)
|
||
|
{
|
||
|
{
|
||
|
edict_t *e;
|
||
|
int i;
|
||
|
int found = 0;
|
||
|
|
||
|
// Print end position if required
|
||
|
if (ent->debugprint)
|
||
|
{
|
||
|
// JOSEPH 24-FEB-99
|
||
|
vec3_t neworigin;
|
||
|
|
||
|
VectorCopy(ent->target_ent->s.origin, neworigin);
|
||
|
neworigin[2] += 40;
|
||
|
gi.dprintf("Camera \"%s\" end position %s\n", ent->target_ent->targetname, vtos(neworigin));
|
||
|
gi.dprintf("Camera \"%s\" end angles %s\n", ent->target_ent->targetname, vtos(ent->target_ent->s.angles));
|
||
|
// END JOSEPH
|
||
|
}
|
||
|
|
||
|
// Restore camera start position and angle
|
||
|
VectorCopy(ent->target_ent->save_avel, ent->target_ent->s.angles);
|
||
|
VectorCopy(ent->target_ent->savecameraorigin, ent->target_ent->s.origin);
|
||
|
|
||
|
// No more cameras
|
||
|
if (!ent->target_ent->target)
|
||
|
EndCutScene (ent->target_ent);
|
||
|
|
||
|
// Find next target entity camera
|
||
|
if (ent->target_ent->target)
|
||
|
{
|
||
|
for (i=1, e=g_edicts+i ; i < globals.num_edicts ; i++,e++)
|
||
|
{
|
||
|
if ((e->targetname) && (!strcmp(e->targetname, ent->target_ent->target)))
|
||
|
{
|
||
|
ent->target_ent = e;
|
||
|
found = 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Next camera
|
||
|
if (found)
|
||
|
{
|
||
|
// See if a target2 can be found
|
||
|
if (ent->target_ent->target2)
|
||
|
{
|
||
|
for (i=1, e=g_edicts+i ; i < globals.num_edicts ; i++,e++)
|
||
|
{
|
||
|
if ((e->targetname) && (!strcmp(e->targetname, ent->target_ent->target2)))
|
||
|
{
|
||
|
ent->target_ent->target2_ent = e;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ent->wait = ent->target_ent->wait*10.0;
|
||
|
if (!ent->wait)
|
||
|
ent->wait = 5.0*10.0;
|
||
|
NewCutSceneCamera (ent->target_ent);
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
|
||
|
// Ridah, Camera accel/decel
|
||
|
ent->target_ent->timestamp = level.time;
|
||
|
ent->target_ent->speed = 0;
|
||
|
|
||
|
// Ridah, play a sound if there is one
|
||
|
if (ent->target_ent->name)
|
||
|
{
|
||
|
edict_t *talkent;
|
||
|
|
||
|
if (!ent->target_ent->sight_target)
|
||
|
{
|
||
|
//gi.dprintf( "Warning: cutsecene camera has voice sound without a \"sight_target\" (speaking charecter's name)\n" );
|
||
|
gi.positioned_sound( ent->target_ent->s.origin, ent->target_ent, CHAN_AUTO, gi.soundindex( ent->target_ent->name ), 1.0, ATTN_NONE, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
talkent = EP_GetCharacterByName( ent->target_ent->sight_target );
|
||
|
gi.sound( talkent, CHAN_VOICE, gi.soundindex( ent->target_ent->name ), 1.0, 1, 0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Ridah, scripting
|
||
|
if (ent->target_ent->scriptname)
|
||
|
{
|
||
|
EP_EventScript( &g_edicts[1], ent->target_ent->scriptname );
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Ridah, scripting
|
||
|
if (ent->scriptname)
|
||
|
{
|
||
|
EP_EventScript( &g_edicts[1], ent->scriptname );
|
||
|
}
|
||
|
|
||
|
// No more cameras or target camera not found
|
||
|
ent->think = 0;
|
||
|
EndCutScene (ent->target_ent);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Process camera frame
|
||
|
AdjustCutSceneCamera(ent->target_ent);
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CutSceneThinkStart (edict_t *ent)
|
||
|
{
|
||
|
edict_t *e;
|
||
|
int i;
|
||
|
|
||
|
if (!ent->count)
|
||
|
return;
|
||
|
|
||
|
// JOSEPH 19-MAR-99-B
|
||
|
if (ent->duration)
|
||
|
{
|
||
|
level.inversefade = 0;
|
||
|
level.totalfade = ent->duration;
|
||
|
level.fadeendtime = level.time + level.totalfade;
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
ent->count--;
|
||
|
|
||
|
// Find target entity
|
||
|
ent->target_ent = 0;
|
||
|
|
||
|
if (ent->target)
|
||
|
{
|
||
|
for (i=1, e=g_edicts+i ; i < globals.num_edicts ; i++,e++)
|
||
|
{
|
||
|
if ((e->targetname) && (!strcmp(e->targetname, ent->target)))
|
||
|
{
|
||
|
ent->target_ent = e;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!ent->target_ent)
|
||
|
return;
|
||
|
|
||
|
// See if a target2 can be found
|
||
|
if (ent->target_ent->target2)
|
||
|
{
|
||
|
for (i=1, e=g_edicts+i ; i < globals.num_edicts ; i++,e++)
|
||
|
{
|
||
|
if ((e->targetname) && (!strcmp(e->targetname, ent->target_ent->target2)))
|
||
|
{
|
||
|
ent->target_ent->target2_ent = e;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Ridah, Camera accel/decel
|
||
|
ent->target_ent->timestamp = level.time;
|
||
|
ent->target_ent->speed = 0;
|
||
|
|
||
|
// Ridah, play a sound if there is one
|
||
|
if (ent->target_ent->name)
|
||
|
{
|
||
|
edict_t *talkent;
|
||
|
|
||
|
if (!ent->target_ent->sight_target)
|
||
|
{
|
||
|
//gi.dprintf( "Warning: cutsecene camera has voice sound without a \"sight_target\" (speaking charecter's name)\n" );
|
||
|
gi.positioned_sound( ent->target_ent->s.origin, ent->target_ent, CHAN_AUTO, gi.soundindex( ent->target_ent->name ), 1.0, ATTN_NONE, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
talkent = EP_GetCharacterByName( ent->target_ent->sight_target );
|
||
|
gi.sound( talkent, CHAN_VOICE, gi.soundindex( ent->target_ent->name ), 1.0, 1, 0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Ridah, scripting
|
||
|
if (ent->target_ent->scriptname)
|
||
|
{
|
||
|
EP_EventScript( &g_edicts[1], ent->target_ent->scriptname );
|
||
|
}
|
||
|
|
||
|
ent->wait = ent->target_ent->wait*10.0;
|
||
|
|
||
|
if (!ent->wait)
|
||
|
ent->wait = 5.0*5.0;
|
||
|
|
||
|
BeginCutScene (ent->target_ent);
|
||
|
|
||
|
ent->think = CutSceneThink;
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
}
|
||
|
|
||
|
void Touch_CutScene (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
||
|
{
|
||
|
CutSceneThinkStart(ent);
|
||
|
}
|
||
|
|
||
|
// JOSEPH 17-MAR-99-B
|
||
|
void Use_CutScene (edict_t *self, edict_t *other, edict_t *activator)
|
||
|
{
|
||
|
CutSceneThinkStart(self);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
// OLD
|
||
|
void SP_misc_cut_scene (edict_t *self)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
// JOSEPH 2-MAR-99
|
||
|
void PrecacheCutStuff (char* s)
|
||
|
{
|
||
|
char *start;
|
||
|
char data[MAX_QPATH];
|
||
|
int len;
|
||
|
|
||
|
if (!s || !s[0])
|
||
|
return;
|
||
|
|
||
|
// parse the space seperated precache string
|
||
|
while (*s)
|
||
|
{
|
||
|
start = s;
|
||
|
while (*s && *s != ' ')
|
||
|
s++;
|
||
|
|
||
|
len = s-start;
|
||
|
if (len >= MAX_QPATH || len < 5)
|
||
|
gi.error ("Bad precache string");
|
||
|
memcpy (data, start, len);
|
||
|
data[len] = 0;
|
||
|
if (*s)
|
||
|
s++;
|
||
|
|
||
|
// determine type based on extension
|
||
|
if (!strcmp(data+len-3, "md2"))
|
||
|
gi.modelindex (data);
|
||
|
else if (!strcmp (data+len-3, "mdx"))
|
||
|
gi.modelindex (data);
|
||
|
else if (!strcmp(data+len-3, "wav"))
|
||
|
gi.soundindex (data);
|
||
|
if (!strcmp(data+len-3, "pcx"))
|
||
|
gi.imageindex (data);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// JOSEPH 19-MAR-99-B
|
||
|
void SP_misc_cutscene_trigger (edict_t *self)
|
||
|
{
|
||
|
self->solid = SOLID_TRIGGER;
|
||
|
gi.setmodel (self, self->model);
|
||
|
self->svflags |= SVF_NOCLIENT;
|
||
|
|
||
|
if (self->targetname)
|
||
|
{
|
||
|
self->use = Use_CutScene;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self->touch = Touch_CutScene;
|
||
|
}
|
||
|
|
||
|
if (self->duration)
|
||
|
{
|
||
|
level.inversefade = 0;
|
||
|
level.totalfade = 60.0;
|
||
|
level.fadeendtime = level.time + level.totalfade;
|
||
|
}
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
self->count = 1;
|
||
|
|
||
|
PrecacheCutStuff (self->name);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
// JOSEPH 19-MAR-99-B
|
||
|
/*QUAKED misc_use_cutscene (.5 .5 .5) (-8 -8 -8) (8 8 8)
|
||
|
This fixed size trigger targets a misc_cutscene_camera
|
||
|
|
||
|
target - camera to target
|
||
|
debugprint - set to 1 to print out camera end position and angles
|
||
|
duration - fade in time.
|
||
|
*/
|
||
|
void SP_misc_use_cutscene (edict_t *self)
|
||
|
{
|
||
|
self->use = Use_CutScene;
|
||
|
|
||
|
if (self->duration)
|
||
|
{
|
||
|
level.inversefade = 0;
|
||
|
level.totalfade = 60.0;
|
||
|
level.fadeendtime = level.time + level.totalfade;
|
||
|
}
|
||
|
|
||
|
self->count = 1;
|
||
|
|
||
|
PrecacheCutStuff (self->name);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
void SP_misc_cutscene_camera (edict_t *self)
|
||
|
{
|
||
|
VectorSet (self->mins, -16, -16, -16);
|
||
|
VectorSet (self->maxs, 16, 16, 16);
|
||
|
|
||
|
VectorClear(self->s.angles);
|
||
|
|
||
|
if ((self->cameraorigin[0] != 0) || (self->cameraorigin[1] != 0) || (self->cameraorigin[2] != 0))
|
||
|
{
|
||
|
VectorCopy(self->cameraorigin, self->s.origin);
|
||
|
self->s.origin[2] -= 40;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self->s.origin[0] += 8;
|
||
|
self->s.origin[1] += 8;
|
||
|
self->s.origin[2] += 8;
|
||
|
}
|
||
|
|
||
|
self->solid = SOLID_NOT;
|
||
|
self->svflags |= SVF_NOCLIENT;
|
||
|
|
||
|
gi.linkentity (self);
|
||
|
|
||
|
if (!self->deadticks)
|
||
|
self->deadticks = 90;
|
||
|
|
||
|
PrecacheCutStuff (self->name);
|
||
|
}
|
||
|
// END JOSEPH
|
||
|
|
||
|
/*QUAKED sfx_beacon (0 0 1) (-16 -16 -16) (16 16 16)
|
||
|
*/
|
||
|
|
||
|
void beacon_think (edict_t *ent)
|
||
|
{
|
||
|
edict_t *ignore;
|
||
|
vec3_t start;
|
||
|
vec3_t end;
|
||
|
trace_t tr;
|
||
|
vec3_t forward;
|
||
|
|
||
|
ignore = ent;
|
||
|
|
||
|
ent->s.angles[YAW] += anglemod(level.time * 0.1);
|
||
|
|
||
|
AngleVectors (ent->s.angles, forward, NULL, NULL );
|
||
|
|
||
|
VectorCopy (ent->s.origin, start);
|
||
|
VectorMA (start, 2048, forward, end);
|
||
|
|
||
|
VectorCopy (forward, ent->movedir);
|
||
|
|
||
|
tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
|
||
|
|
||
|
VectorCopy (tr.endpos, ent->s.old_origin);
|
||
|
|
||
|
ent->nextthink = level.time + FRAMETIME;
|
||
|
|
||
|
}
|
||
|
|
||
|
void SP_sfx_beacon (edict_t *ent)
|
||
|
{
|
||
|
|
||
|
ent->movetype = MOVETYPE_NONE;
|
||
|
ent->solid = SOLID_NOT;
|
||
|
ent->s.modelindex = 1;
|
||
|
|
||
|
ent->s.renderfx |= RF_BEAM;
|
||
|
ent->s.renderfx2 |= RF2_BEAM2;
|
||
|
ent->s.frame = 64;
|
||
|
ent->s.effects |= EF_ROTATE;
|
||
|
ent->nextthink = level.time + 0.1;
|
||
|
ent->think = beacon_think;
|
||
|
ent->s.skinnum = 0xf2f2f0f0;
|
||
|
|
||
|
gi.linkentity (ent);
|
||
|
|
||
|
}
|