#include <u.h>#include <libc.h>#include <stdio.h>#include "../dat.h"#include "../fns.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;} // the wait time has passed, so set back up for another activationvoid multi_wait (edict_t *ent){ ent->nextthink = 0;} // the trigger was just activated// ent->activator should be set to the activator so it can be held through a delay// so wait for the delay time before firingvoid multi_trigger (edict_t *ent){ if (ent->nextthink) return; // already been triggered G_UseTargets (ent, ent->activator); if (ent->wait > 0) { ent->think = multi_wait; ent->nextthink = level.time + ent->wait; } else { // we can't just remove (self) here, because this is a touch function // called while looping through area links... ent->touch = NULL; ent->nextthink = level.time + FRAMETIME; ent->think = G_FreeEdict; }} void Use_Multi (edict_t *ent, edict_t *, edict_t *activator){ ent->activator = activator; multi_trigger (ent);} void Touch_Multi (edict_t *self, edict_t *other, cplane_t *, csurface_t *){ 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);} /*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGEREDVariable sized repeatable trigger. Must be targeted at one or more entities.If "delay" is set, the trigger waits some time after activating before firing."wait" : Seconds between triggerings. (.2 default)sounds1) secret2) beep beep3) large switch4)set "message" to text string*/void trigger_enable (edict_t *self, edict_t *, edict_t *){ 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);} /*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGEREDTriggers once, then removes itself.You must set the key "target" to the name of another object in the level that has a matching "targetname". If TRIGGERED, this trigger must be triggered before it is live. sounds 1) secret 2) beep beep 3) large switch 4) "message" string to be displayed when triggered*/ void SP_trigger_once(edict_t *ent){ // make old maps work because I messed up on flag assignments here // triggered was on bit 1 when it should have been on bit 4 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);} /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)This fixed size trigger cannot be touched, it can only be fired by other events.*/void trigger_relay_use (edict_t *self, edict_t *, edict_t *activator){ G_UseTargets (self, activator);} void SP_trigger_relay (edict_t *self){ self->use = trigger_relay_use;} /*============================================================================== trigger_key ==============================================================================*/ /*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8)A relay trigger that only fires it's targets if player has the proper key.Use "item" to specify the required key, for example "key_data_cd"*/void trigger_key_use (edict_t *self, edict_t *, 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;} /*============================================================================== trigger_counter ==============================================================================*/ /*QUAKED trigger_counter (.5 .5 .5) ? nomessageActs as an intermediary for an action that takes multiple inputs. If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished. After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.*/ void trigger_counter_use(edict_t *self, edict_t *, 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;} /*============================================================================== trigger_always ==============================================================================*/ /*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)This trigger will always fire. It is activated by the world.*/void SP_trigger_always (edict_t *ent){ // we must have some delay to make sure our use targets are present if (ent->delay < 0.2) ent->delay = 0.2; G_UseTargets(ent, ent);} /*============================================================================== trigger_push ==============================================================================*//*#define PUSH_ONCE 1 static int windsound; void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *, csurface_t *){ if (strcmp(other->classname, "grenade") == 0) { VectorScale (self->movedir, self->speed * 10, other->velocity); } else if (other->health > 0) { VectorScale (self->movedir, self->speed * 10, other->velocity); if (other->client) { // don't take falling damage immediately from this 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);}*/ // RAFAEL#define PUSH_ONCE 1 static int windsound; void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *, csurface_t *){ if (strcmp(other->classname, "grenade") == 0) { VectorScale (self->movedir, self->speed * 10, other->velocity); } else if (other->health > 0) { VectorScale (self->movedir, self->speed * 10, other->velocity); if (other->client) { // don't take falling damage immediately from this 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);} /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE PUSH_PLUS PUSH_RAMPPushes the player"speed" defaults to 1000"wait" defaults to 10 must use PUSH_PLUS used for on*/ void trigger_push_active (edict_t *self); void trigger_effect (edict_t *self){ vec3_t origin; vec3_t size; int i; VectorScale (self->size, 0.5, size); VectorAdd (self->absmin, size, origin); for (i=0; i<10; i++) { origin[2] += (self->speed * 0.01) * (i + qrandom()); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_TUNNEL_SPARKS); gi.WriteByte (1); gi.WritePosition (origin); gi.WriteDir (vec3_origin); gi.WriteByte (0x74 + (rand()&7)); gi.multicast (self->s.origin, MULTICAST_PVS); } } void trigger_push_inactive (edict_t *self){ if (self->delay > level.time) { self->nextthink = level.time + 0.1; } else { self->touch = trigger_push_touch; self->think = trigger_push_active; self->nextthink = level.time + 0.1; self->delay = self->nextthink + self->wait; }} void trigger_push_active (edict_t *self){ if (self->delay > level.time) { self->nextthink = level.time + 0.1; trigger_effect (self); } else {Lines 1–500 of 694. Load more
#include <u.h> #include <libc.h> #include <stdio.h> #include "../dat.h" #include "../fns.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; } // the wait time has passed, so set back up for another activation void multi_wait (edict_t *ent) { ent->nextthink = 0; } // the trigger was just activated // ent->activator should be set to the activator so it can be held through a delay // so wait for the delay time before firing void multi_trigger (edict_t *ent) { if (ent->nextthink) return; // already been triggered G_UseTargets (ent, ent->activator); if (ent->wait > 0) { ent->think = multi_wait; ent->nextthink = level.time + ent->wait; } else { // we can't just remove (self) here, because this is a touch function // called while looping through area links... ent->touch = NULL; ent->nextthink = level.time + FRAMETIME; ent->think = G_FreeEdict; } } void Use_Multi (edict_t *ent, edict_t *, edict_t *activator) { ent->activator = activator; multi_trigger (ent); } void Touch_Multi (edict_t *self, edict_t *other, cplane_t *, csurface_t *) { 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); } /*QUAKED trigger_multiple (.5 .5 .5) ? MONSTER NOT_PLAYER TRIGGERED Variable sized repeatable trigger. Must be targeted at one or more entities. If "delay" is set, the trigger waits some time after activating before firing. "wait" : Seconds between triggerings. (.2 default) sounds 1) secret 2) beep beep 3) large switch 4) set "message" to text string */ void trigger_enable (edict_t *self, edict_t *, edict_t *) { 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); } /*QUAKED trigger_once (.5 .5 .5) ? x x TRIGGERED Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching "targetname". If TRIGGERED, this trigger must be triggered before it is live. sounds 1) secret 2) beep beep 3) large switch 4) "message" string to be displayed when triggered */ void SP_trigger_once(edict_t *ent) { // make old maps work because I messed up on flag assignments here // triggered was on bit 1 when it should have been on bit 4 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); } /*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) This fixed size trigger cannot be touched, it can only be fired by other events. */ void trigger_relay_use (edict_t *self, edict_t *, edict_t *activator) { G_UseTargets (self, activator); } void SP_trigger_relay (edict_t *self) { self->use = trigger_relay_use; } /* ============================================================================== trigger_key ============================================================================== */ /*QUAKED trigger_key (.5 .5 .5) (-8 -8 -8) (8 8 8) A relay trigger that only fires it's targets if player has the proper key. Use "item" to specify the required key, for example "key_data_cd" */ void trigger_key_use (edict_t *self, edict_t *, 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; } /* ============================================================================== trigger_counter ============================================================================== */ /*QUAKED trigger_counter (.5 .5 .5) ? nomessage Acts as an intermediary for an action that takes multiple inputs. If nomessage is not set, t will print "1 more.. " etc when triggered and "sequence complete" when finished. After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself. */ void trigger_counter_use(edict_t *self, edict_t *, 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; } /* ============================================================================== trigger_always ============================================================================== */ /*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8) This trigger will always fire. It is activated by the world. */ void SP_trigger_always (edict_t *ent) { // we must have some delay to make sure our use targets are present if (ent->delay < 0.2) ent->delay = 0.2; G_UseTargets(ent, ent); } /* ============================================================================== trigger_push ============================================================================== */ /* #define PUSH_ONCE 1 static int windsound; void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *, csurface_t *) { if (strcmp(other->classname, "grenade") == 0) { VectorScale (self->movedir, self->speed * 10, other->velocity); } else if (other->health > 0) { VectorScale (self->movedir, self->speed * 10, other->velocity); if (other->client) { // don't take falling damage immediately from this 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); } */ // RAFAEL #define PUSH_ONCE 1 static int windsound; void trigger_push_touch (edict_t *self, edict_t *other, cplane_t *, csurface_t *) { if (strcmp(other->classname, "grenade") == 0) { VectorScale (self->movedir, self->speed * 10, other->velocity); } else if (other->health > 0) { VectorScale (self->movedir, self->speed * 10, other->velocity); if (other->client) { // don't take falling damage immediately from this 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); } /*QUAKED trigger_push (.5 .5 .5) ? PUSH_ONCE PUSH_PLUS PUSH_RAMP Pushes the player "speed" defaults to 1000 "wait" defaults to 10 must use PUSH_PLUS used for on */ void trigger_push_active (edict_t *self); void trigger_effect (edict_t *self) { vec3_t origin; vec3_t size; int i; VectorScale (self->size, 0.5, size); VectorAdd (self->absmin, size, origin); for (i=0; i<10; i++) { origin[2] += (self->speed * 0.01) * (i + qrandom()); gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_TUNNEL_SPARKS); gi.WriteByte (1); gi.WritePosition (origin); gi.WriteDir (vec3_origin); gi.WriteByte (0x74 + (rand()&7)); gi.multicast (self->s.origin, MULTICAST_PVS); } } void trigger_push_inactive (edict_t *self) { if (self->delay > level.time) { self->nextthink = level.time + 0.1; } else { self->touch = trigger_push_touch; self->think = trigger_push_active; self->nextthink = level.time + 0.1; self->delay = self->nextthink + self->wait; } } void trigger_push_active (edict_t *self) { if (self->delay > level.time) { self->nextthink = level.time + 0.1; trigger_effect (self); } else {