mirror of
https://git.code.sf.net/p/quake/game-source
synced 2024-11-28 14:42:05 +00:00
263 lines
6 KiB
C++
263 lines
6 KiB
C++
#include "common.qh"
|
|
#include "effect.qh"
|
|
#include "weapon.qh"
|
|
#include "misc.qh"
|
|
|
|
#include "mapents_util.qh"
|
|
#include "damage.qh"
|
|
|
|
#include "mapents_triggers.qh"
|
|
#include "mapents.qh"
|
|
#include "teleport.qh"
|
|
|
|
float(float d) _takedamage_use = {
|
|
if (time < self.attack_finished)
|
|
return FALSE;
|
|
|
|
self.attack_finished = time + self.wait;
|
|
|
|
self.health -= d;
|
|
|
|
if (self.health <= 0) {
|
|
self.health = self.max_health;
|
|
|
|
if (util_use_targets())
|
|
self.use();
|
|
}
|
|
|
|
deathmsg_nodisplay();
|
|
|
|
if (self.wait <= 0) {
|
|
self.solid = SOLID_NOT;
|
|
util_map_entity_cull();
|
|
}
|
|
|
|
return FALSE; /* Lie */
|
|
};
|
|
|
|
void() _trigger_generic_touch = {
|
|
local void() selfuse;
|
|
|
|
if (!is_living(other))
|
|
return;
|
|
|
|
if (time < self.attack_finished)
|
|
return;
|
|
|
|
self.attack_finished = time + self.wait;
|
|
|
|
selfuse = self.use;
|
|
self.use = NOTHING_function; /* Avoid endless loop */
|
|
if (util_use_targets())
|
|
selfuse();
|
|
self.use = selfuse;
|
|
|
|
if (self.wait <= 0) {
|
|
self.solid = SOLID_NOT;
|
|
util_map_entity_cull();
|
|
}
|
|
};
|
|
|
|
/*QUAKED trigger_generic (.5 .5 .5) NOTOUCH
|
|
Variable sized repeatable trigger. Must be targeted at one or more entities.
|
|
If "model" is set, the trigger will set it as its model.
|
|
If "health" is set, trigger must be killed to activate each time.
|
|
If "delay" is set, the trigger waits some time after activating before firing.
|
|
If "wait" is set, the trigger waits some time before able to trigger again.
|
|
If "count" is > 0, the trigger will only trigger count times.
|
|
If notouch is set, the trigger is only fired by other entities, not by touching or killing.
|
|
"noise1" is played at the trigger when triggered, if set.
|
|
"noise2" is played to the activator when triggered, if set.
|
|
"message" is displayed when triggered, if set.
|
|
*/
|
|
void() trigger_generic = {
|
|
/* Get mins/maxs */
|
|
setmodel(self, self.model);
|
|
|
|
/* Avoid displaying triggers */
|
|
self.model = "";
|
|
self.modelindex = 0;
|
|
|
|
if (self.health) {
|
|
self.max_health = self.health;
|
|
self.solid = SOLID_BBOX;
|
|
|
|
self.takedamage = DAMAGE_YES;
|
|
self.th_takedamage = _takedamage_use;
|
|
}
|
|
|
|
if (!self.solid) {
|
|
if (!(self.spawnflags & SPAWNFLAGS_TRIGGER_NOTOUCH)) {
|
|
self.solid = SOLID_TRIGGER;
|
|
self.touch = _trigger_generic_touch;
|
|
}
|
|
}
|
|
|
|
/* FIXME: This is a hackaround for qwsv */
|
|
if (self.origin == '0 0 0') {
|
|
self.origin = (self.mins + self.maxs) * 0.5;
|
|
self.mins = self.mins - self.origin;
|
|
self.maxs = self.maxs - self.origin;
|
|
setsize(self, self.mins, self.maxs);
|
|
setorigin(self, self.origin);
|
|
}
|
|
|
|
if (!self.use)
|
|
self.use = NOTHING_function;
|
|
|
|
util_map_entity_init();
|
|
util_map_entity_cull();
|
|
};
|
|
|
|
/*QUAKED info_teleport_destination (.5 .5 .5) (-8 -8 -8) (8 8 32)
|
|
This is the destination marker for a teleporter. It should have a "targetname"
|
|
field with the same value as a teleporter's "target" field.
|
|
*/
|
|
void() info_teleport_destination = {
|
|
self.origin = self.origin + '0 0 27';
|
|
info_notnull();
|
|
};
|
|
|
|
void() _trigger_teleport_touch = {
|
|
local entity spot;
|
|
local float spd;
|
|
|
|
if (!is_teleportable(other))
|
|
return;
|
|
|
|
spot = find(world, targetname, self.target);
|
|
if (!spot) {
|
|
damage(other, other, other, DAMAGE_MUSTDIE, NOTHING_function);
|
|
return;
|
|
}
|
|
|
|
effect_teleport_fog(other.origin);
|
|
teleport(other, spot);
|
|
|
|
spd = vlen(other.velocity);
|
|
makevectors(other.angles);
|
|
other.velocity = v_forward * spd;
|
|
};
|
|
|
|
#define SPAWNFLAGS_SILENT 2
|
|
/*QUAKED trigger_teleport (.5 .5 .5) ? PLAYER_ONLY SILENT
|
|
Any object touching this will be transported to the corresponding
|
|
info_teleport_destination entity. You must set the "target" field,
|
|
and create an object with a "targetname" field that matches.
|
|
|
|
If the trigger_teleport has a targetname, it will only teleport
|
|
entities when it has been fired.
|
|
*/
|
|
void() trigger_teleport = {
|
|
if (!(self.spawnflags & SPAWNFLAGS_SILENT) && !self.noise)
|
|
self.noise = "ambience/hum1.wav";
|
|
setmodel(self, self.model);
|
|
|
|
self.model = NIL;
|
|
self.modelindex = 0;
|
|
|
|
util_map_entity_init();
|
|
|
|
self.solid = SOLID_TRIGGER;
|
|
|
|
self.touch = _trigger_teleport_touch;
|
|
self.use = _trigger_teleport_touch;
|
|
};
|
|
|
|
void() _trigger_hurt_deathmsg = {
|
|
bprint(PRINT_DEATH, name(self), " was in the wrong place.\n");
|
|
};
|
|
|
|
void() _trigger_hurt_use = {
|
|
damage(other, self, self, self.dmg, _trigger_hurt_deathmsg);
|
|
};
|
|
|
|
/*QUAKED trigger_hurt (.5 .5 .5) ?
|
|
Any object touching this will be hurt
|
|
set dmg to damage amount
|
|
*/
|
|
void() trigger_hurt = {
|
|
if (!self.wait) self.wait = 1;
|
|
|
|
trigger_generic();
|
|
self.use = _trigger_hurt_use;
|
|
};
|
|
|
|
#define SPAWNFLAGS_PUSH_ONCE 1
|
|
#define SPAWNFLAGS_PUSH_ADD 2
|
|
void() _trigger_push_use = {
|
|
if (!is_solid(other))
|
|
return;
|
|
|
|
if (!util_use_targets())
|
|
return;
|
|
|
|
if (self.spawnflags & SPAWNFLAGS_PUSH_ADD)
|
|
other.velocity = other.velocity + self.movedir;
|
|
else
|
|
other.velocity = self.movedir;
|
|
|
|
if (!is_living(other))
|
|
return;
|
|
|
|
if (self.noise3)
|
|
sound(other, CHAN_AUTO, self.noise3, 1, ATTN_NORM);
|
|
};
|
|
|
|
/*QUAKED trigger_push (.5 .5 .5) ? PUSH_ADD PUSH_ONCE
|
|
Pushes the player
|
|
*/
|
|
void() trigger_push = {
|
|
if (!self.wait) self.wait = 1;
|
|
|
|
if (!self.speed) self.speed = 1000;
|
|
|
|
if (!self.noise1 && !self.noise2 && !self.noise3)
|
|
self.noise3 = "ambience/windfly.wav";
|
|
|
|
if (self.noise3) precache_sound(self.noise3);
|
|
|
|
if (self.spawnflags & SPAWNFLAGS_PUSH_ONCE)
|
|
self.count = 1;
|
|
|
|
trigger_generic();
|
|
|
|
util_set_movedir();
|
|
self.movedir = self.movedir * self.speed * 10;
|
|
|
|
self.use = _trigger_push_use;
|
|
};
|
|
|
|
|
|
#define SPAWNFLAGS_NO_INTERMISSION 1
|
|
void() _trigger_changelevel_do = {
|
|
local string nextmap;
|
|
|
|
nextmap = self.map;
|
|
if (!self.map) nextmap = "start.bsp";
|
|
|
|
changelevel(nextmap);
|
|
};
|
|
|
|
void() _trigger_changelevel_use = {
|
|
if (!is_living(other) || !is_cl(other))
|
|
return;
|
|
|
|
// Bleah.
|
|
self.touch = NOTHING_function;
|
|
self.think = _trigger_changelevel_do;
|
|
self.nextthink = time;
|
|
};
|
|
|
|
/*QUAKED trigger_changelevel (.5 .5 .5) ? NO_INTERMISSION
|
|
When a player touches this, the level changes. The level
|
|
will change to the map set in the map variable. If it is
|
|
not set, the map will change to a random level in the list.
|
|
|
|
If NO_INTERMISSION is set, the view will not go to an
|
|
info_intermission spot and display stats in co-op games.
|
|
*/
|
|
void() trigger_changelevel = {
|
|
trigger_generic();
|
|
self.use = _trigger_changelevel_use;
|
|
};
|