#include "g_local.h"
void InitTrigger(edict_t *self) {
if(!VectorCompare(self->s.angles, vec3_origin))
G_SetMovedir(self->s.angles, self->movedir);
self->solid = SOLID_TRIGGER;
self->movetype = MOVETYPE_NONE;
gi.setmodel(self, self->model);
self->svflags = SVF_NOCLIENT;
}
void multi_wait(edict_t *ent) { ent->nextthink = 0; }
void multi_trigger(edict_t *ent) {
if(ent->nextthink)
return;
G_UseTargets(ent, ent->activator);
if(ent->wait > 0) {
ent->think = multi_wait;
ent->nextthink = level.time + ent->wait;
} else { ent->touch = NULL;
ent->nextthink = level.time + FRAMETIME;
ent->think = G_FreeEdict;
}
}
void Use_Multi(edict_t *ent, edict_t *other, edict_t *activator) {
ent->activator = activator;
multi_trigger(ent);
}
void Touch_Multi(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) {
if(other->client) {
if(self->spawnflags & 2)
return;
} else if(other->svflags & SVF_MONSTER) {
if(!(self->spawnflags & 1))
return;
} else
return;
if(!VectorCompare(self->movedir, vec3_origin)) {
vec3_t forward;
AngleVectors(other->s.angles, forward, NULL, NULL);
if(_DotProduct(forward, self->movedir) < 0)
return;
}
self->activator = other;
multi_trigger(self);
}
void trigger_enable(edict_t *self, edict_t *other, edict_t *activator) {
self->solid = SOLID_TRIGGER;
self->use = Use_Multi;
gi.linkentity(self);
}
void SP_trigger_multiple(edict_t *ent) {
if(ent->sounds == 1)
ent->noise_index = gi.soundindex("misc/secret.wav");
else if(ent->sounds == 2)
ent->noise_index = gi.soundindex("misc/talk.wav");
else if(ent->sounds == 3)
ent->noise_index = gi.soundindex("misc/trigger1.wav");
if(!ent->wait)
ent->wait = 0.2;
ent->touch = Touch_Multi;
ent->movetype = MOVETYPE_NONE;
ent->svflags |= SVF_NOCLIENT;
if(ent->spawnflags & 4) {
ent->solid = SOLID_NOT;
ent->use = trigger_enable;
} else {
ent->solid = SOLID_TRIGGER;
ent->use = Use_Multi;
}
if(!VectorCompare(ent->s.angles, vec3_origin))
G_SetMovedir(ent->s.angles, ent->movedir);
gi.setmodel(ent, ent->model);
gi.linkentity(ent);
}
void SP_trigger_once(edict_t *ent) {
if(ent->spawnflags & 1) {
vec3_t v;
VectorMA(ent->mins, 0.5, ent->size, v);
ent->spawnflags &= ~1;
ent->spawnflags |= 4;
gi.dprintf("fixed TRIGGERED flag on %s at %s\n", ent->classname, vtos(v));
}
ent->wait = -1;
SP_trigger_multiple(ent);
}
void trigger_relay_use(edict_t *self, edict_t *other, edict_t *activator) { G_UseTargets(self, activator); }
void SP_trigger_relay(edict_t *self) { self->use = trigger_relay_use; }
void trigger_key_use(edict_t *self, edict_t *other, edict_t *activator) {
int index;
if(!self->item)
return;
if(!activator->client)
return;
index = ITEM_INDEX(self->item);
if(!activator->client->pers.inventory[index]) {
if(level.time < self->touch_debounce_time)
return;
self->touch_debounce_time = level.time + 5.0;
gi.centerprintf(activator, "You need the %s", self->item->pickup_name);
gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/keytry.wav"), 1, ATTN_NORM, 0);
return;
}
gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/keyuse.wav"), 1, ATTN_NORM, 0);
if(coop->value) {
int player;
edict_t *ent;
if(strcmp(self->item->classname, "key_power_cube") == 0) {
int cube;
for(cube = 0; cube < 8; cube++)
if(activator->client->pers.power_cubes & (1 << cube))
break;
for(player = 1; player <= game.maxclients; player++) {
ent = &g_edicts[player];
if(!ent->inuse)
continue;
if(!ent->client)
continue;
if(ent->client->pers.power_cubes & (1 << cube)) {
ent->client->pers.inventory[index]--;
ent->client->pers.power_cubes &= ~(1 << cube);
}
}
} else {
for(player = 1; player <= game.maxclients; player++) {
ent = &g_edicts[player];
if(!ent->inuse)
continue;
if(!ent->client)
continue;
ent->client->pers.inventory[index] = 0;
}
}
} else {
activator->client->pers.inventory[index]--;
}
G_UseTargets(self, activator);
self->use = NULL;
}
void SP_trigger_key(edict_t *self) {
if(!st.item) {
gi.dprintf("no key item for trigger_key at %s\n", vtos(self->s.origin));
return;
}
self->item = FindItemByClassname(st.item);
if(!self->item) {
gi.dprintf("item %s not found for trigger_key at %s\n", st.item, vtos(self->s.origin));
return;
}
if(!self->target) {
gi.dprintf("%s at %s has no target\n", self->classname, vtos(self->s.origin));
return;
}
gi.soundindex("misc/keytry.wav");
gi.soundindex("misc/keyuse.wav");
self->use = trigger_key_use;
}
void trigger_counter_use(edict_t *self, edict_t *other, edict_t *activator) {
if(self->count == 0)
return;
self->count--;
if(self->count) {
if(!(self->spawnflags & 1)) {
gi.centerprintf(activator, "%i more to go...", self->count);
gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/talk1.wav"), 1, ATTN_NORM, 0);
}
return;
}
if(!(self->spawnflags & 1)) {
gi.centerprintf(activator, "Sequence completed!");
gi.sound(activator, CHAN_AUTO, gi.soundindex("misc/talk1.wav"), 1, ATTN_NORM, 0);
}
self->activator = activator;
multi_trigger(self);
}
void SP_trigger_counter(edict_t *self) {
self->wait = -1;
if(!self->count)
self->count = 2;
self->use = trigger_counter_use;
}
void SP_trigger_always(edict_t *ent) {
if(ent->delay < 0.2)
ent->delay = 0.2;
G_UseTargets(ent, ent);
}
#define PUSH_ONCE 1
static int windsound;
void trigger_push_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) {
if(strcmp(other->classname, "grenade") == 0) {
VectorScale(self->movedir, self->speed * 10, other->velocity);
} else if(ent_read_health(other)->value > 0) {
VectorScale(self->movedir, self->speed * 10, other->velocity);
if(other->client) {
VectorCopy(other->velocity, other->client->oldvelocity);
if(other->fly_sound_debounce_time < level.time) {
other->fly_sound_debounce_time = level.time + 1.5;
gi.sound(other, CHAN_AUTO, windsound, 1, ATTN_NORM, 0);
}
}
}
if(self->spawnflags & PUSH_ONCE)
G_FreeEdict(self);
}
void SP_trigger_push(edict_t *self) {
InitTrigger(self);
windsound = gi.soundindex("misc/windfly.wav");
self->touch = trigger_push_touch;
if(!self->speed)
self->speed = 1000;
gi.linkentity(self);
}
void hurt_use(edict_t *self, edict_t *other, edict_t *activator) {
if(self->solid == SOLID_NOT)
self->solid = SOLID_TRIGGER;
else
self->solid = SOLID_NOT;
gi.linkentity(self);
if(!(self->spawnflags & 2))
self->use = NULL;
}
void hurt_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) {
int dflags;
if(!other->takedamage)
return;
if(self->timestamp > level.time)
return;
if(self->spawnflags & 16)
self->timestamp = level.time + 1;
else
self->timestamp = level.time + FRAMETIME;
if(!(self->spawnflags & 4)) {
if((level.framenum % 10) == 0)
gi.sound(other, CHAN_AUTO, self->noise_index, 1, ATTN_NORM, 0);
}
if(self->spawnflags & 8)
dflags = DAMAGE_NO_PROTECTION;
else
dflags = 0;
T_Damage(other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, self->dmg, dflags,
MOD_TRIGGER_HURT);
}
void SP_trigger_hurt(edict_t *self) {
InitTrigger(self);
self->noise_index = gi.soundindex("world/electro.wav");
self->touch = hurt_touch;
if(!self->dmg)
self->dmg = 5;
if(self->spawnflags & 1)
self->solid = SOLID_NOT;
else
self->solid = SOLID_TRIGGER;
if(self->spawnflags & 2)
self->use = hurt_use;
gi.linkentity(self);
}
void trigger_gravity_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) {
other->gravity = self->gravity;
}
void SP_trigger_gravity(edict_t *self) {
if(st.gravity == 0) {
gi.dprintf("trigger_gravity without gravity set at %s\n", vtos(self->s.origin));
G_FreeEdict(self);
return;
}
InitTrigger(self);
self->gravity = atoi(st.gravity);
self->touch = trigger_gravity_touch;
}
void trigger_monsterjump_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf) {
if(other->flags & (FL_FLY | FL_SWIM))
return;
if(other->svflags & SVF_DEADMONSTER)
return;
if(!(other->svflags & SVF_MONSTER))
return;
other->velocity[0] = self->movedir[0] * self->speed;
other->velocity[1] = self->movedir[1] * self->speed;
if(!other->groundentity)
return;
other->groundentity = NULL;
other->velocity[2] = self->movedir[2];
}
void SP_trigger_monsterjump(edict_t *self) {
if(!self->speed)
self->speed = 200;
if(!st.height)
st.height = 200;
if(self->s.angles[YAW] == 0)
self->s.angles[YAW] = 360;
InitTrigger(self);
self->touch = trigger_monsterjump_touch;
self->movedir[2] = st.height;
}