Files
quakemapping/mod_xj19/my_progs/func_plats.qc
2020-01-01 23:35:17 +01:00

319 lines
11 KiB
Plaintext

/*======================================================================
PLATFORM FUNCTIONS
======================================================================*/
float PLAT_LOW_TRIGGER = 1;
float PLAT_MIN_TRIGGER = 4;
float PLAT_START_LOWER = 8;
float PLAT_START_OPEN = 16;
float PLAT_STARTDIS = 32; // Platform starts in disabled state
/*======================================================================
/*QUAKED func_plat (0 .5 .8) ? LOW_TRIGGER x MIN_TRIGGER START_LOWER START_OPEN x STARTOFF x
A Platform (bmodel) with 2 states
-------- KEYS --------
targetname : = "" plat start low, != "" plat starts high and reqs trigger to work
if using entity state system set START_LOWER spawnflags to fix this problem
speed : moving speed (def=150)
height : determines the distance to move, instead of bmodel bounds
sounds : 1=Base, 0 or 2=Medieval (def), 4=Silent, 5=Custom sounds
noise : custom sound - moving (looping)
noise1 : custom sound - Stopped
_dirt : -1 = will be excluded from dirtmapping
_minlight : Minimum light level for any surface of the brush model
_mincolor : Minimum light color for any surface (def='1 1 1' RGB)
_shadow : Will cast shadows on other models and itself
_shadowself : Will cast shadows on itself
-------- SPAWNFLAGS --------
LOW_TRIGGER : touch trigger will not keep the platform at the top, will reset
MIN_TRIGGER : uses the min bounding box (instead of max) to calculate trigger
START_LOWER : will start the platform lower regardless of targetname
START_OPEN : Used for lighting issues, place at bottom position
STARTOFF : Starts off and waits for trigger
-------- NOTES --------
Platforms are always created in the upper position, so they can be lit better.
If targetname is defined the func_plat starts high and is locked until triggered
Once the func_plat has been triggered, it will become a normal platform.
======================================================================*/
void() func_plat_hit_bottom =
{
if (self.estate == ESTATE_OFF) return;
self.state = STATE_BOTTOM;
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
};
//----------------------------------------------------------------------
void() func_plat_go_down =
{
if (self.estate == ESTATE_OFF) return;
self.state = STATE_DOWN;
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
SUB_CalcMove (self.pos2, self.speed, func_plat_hit_bottom);
};
//----------------------------------------------------------------------
void() func_plat_hit_top =
{
if (self.estate == ESTATE_OFF) return;
self.state = STATE_TOP;
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.think = func_plat_go_down;
self.nextthink = self.ltime + 3;
};
//----------------------------------------------------------------------
void() func_plat_go_up =
{
if (self.estate == ESTATE_OFF) return;
self.state = STATE_UP;
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
SUB_CalcMove (self.pos1, self.speed, func_plat_hit_top);
};
//----------------------------------------------------------------------
void() func_plat_trigger_touch =
{
if (self.owner.estate & ESTATE_BLOCK) return;
if (self.owner.state == STATE_DISABLED) return;
if (!(other.flags & FL_CLIENT)) return;
if (other.health <= 0) return;
// Switch the platform entity
self = self.owner;
if (self.state == STATE_BOTTOM) func_plat_go_up ();
else if (self.state == STATE_TOP)
self.nextthink = self.ltime + 1; // delay going down
};
//----------------------------------------------------------------------
void() func_plat_trigger_spawn =
{
local entity trigger;
local vector tmin, tmax;
trigger = spawn();
trigger.owner = self;
trigger.touch = func_plat_trigger_touch;
trigger.movetype = MOVETYPE_NONE;
trigger.solid = SOLID_TRIGGER;
tmin = self.mins + '25 25 0';
tmax = self.maxs - '25 25 -8';
// The ID method is to take the maximum size of the platform
// and subtract the height. This fails if the platform
// is moving around a central height point. The Alternative
// method uses the min bounding box value instead of max
// This is not 100% capatible with id maps, so hence extra option!
if (self.spawnflags & PLAT_MIN_TRIGGER) tmin_z = tmin_z - (self.height + 8);
else tmin_z = tmax_z - (self.pos1_z - self.pos2_z + 8);
if (self.spawnflags & PLAT_LOW_TRIGGER) tmax_z = tmin_z + 8;
if (self.size_x <= 50) {
tmin_x = (self.mins_x + self.maxs_x) / 2;
tmax_x = tmin_x + 1;
}
if (self.size_y <= 50) {
tmin_y = (self.mins_y + self.maxs_y) / 2;
tmax_y = tmin_y + 1;
}
setsize (trigger, tmin, tmax);
};
//----------------------------------------------------------------------
void() func_plat_use =
{
// Deal with START OFF functionality first
if (self.spawnflags & ENT_STARTOFF) self.estate_on();
else {
// Block USE functionality if state wrong
if (self.estate & ESTATE_BLOCK) return;
if (self.state == STATE_DISABLED) func_plat_go_down();
}
};
//----------------------------------------------------------------------
void() func_plat_on =
{
// Stop re-triggering ON state
if (self.estate == ESTATE_ON) return;
// No longer need this spawnflag, remove it
self.spawnflags = self.spawnflags - (self.spawnflags & ENT_STARTOFF);
self.estate = ESTATE_ON;
self.movetype = MOVETYPE_PUSH;
self.solid = SOLID_BSP;
setmodel (self, self.mdl);
if (self.state != STATE_DISABLED) {
// Reset health, state and frame back to default
setorigin(self, self.pos2);
self.state = STATE_BOTTOM;
self.think = SUB_Null;
}
// If platform started disable, release to lower position
if (self.spawnflags & PLAT_STARTDIS) {
// No longer need this spawnflag, remove it
self.spawnflags = self.spawnflags - (self.spawnflags & PLAT_STARTDIS);
if (self.state == STATE_DISABLED) func_plat_go_down();
}
};
//----------------------------------------------------------------------
void() func_plat_off =
{
// Stop re-triggering OFF state
if (self.estate == ESTATE_OFF) return;
self.estate = ESTATE_OFF;
self.movetype = MOVETYPE_NONE;
self.solid = SOLID_NOT;
setmodel (self, "");
// Stop all movement sounds
sound (self, CHAN_VOICE, SOUND_EMPTY, 1, ATTN_NORM);
if (self.state != STATE_DISABLED) {
// Reset health, position and frame back to default
setorigin(self, self.pos2);
self.state = STATE_BOTTOM;
self.think = SUB_Null;
}
};
//----------------------------------------------------------------------
void() func_plat_disable =
{
// Lock platform in current location
self.estate = ESTATE_DISABLE;
};
//----------------------------------------------------------------------
void() func_plat_blocked =
{
T_Damage (other, self, self, 1, DAMARMOR);
if (self.state == STATE_UP) func_plat_go_down ();
else if (self.state == STATE_DOWN) func_plat_go_up ();
};
//----------------------------------------------------------------------
void() func_plat =
{
if (check_bmodel_keys()) return; // Check for bmodel errors
// default sound = medieval
if (self.sounds == 0) self.sounds = 2;
if (self.sounds == 1) {
self.noise = "plats/plat1.wav";
self.noise1 = "plats/plat2.wav";
}
else if (self.sounds == 2) {
self.noise = "plats/medplat1.wav";
self.noise1 = "plats/medplat2.wav";
}
else {
// sounds 4 = silent, sounds 5 = custom
if (self.noise == "" || self.sounds == 4) self.noise = SOUND_EMPTY;
if (self.noise1 == "" || self.sounds == 4) self.noise1 = SOUND_EMPTY;
}
precache_sound (self.noise);
precache_sound (self.noise1);
self.classtype = CT_FUNCPLAT;
self.classgroup = CG_FUNCMOVER;
self.bsporigin = TRUE;
self.mdl = self.model;
// angles has to be 0 0 0 otherwise brush model is twisted
// save angles to mangle for use later by movement code
self.mangle = self.angles;
self.angles = '0 0 0';
// This is not used anywhere, old code ideas from ID
if (!self.t_length) self.t_length = 80;
if (!self.t_width) self.t_width = 10;
if (!self.speed) self.speed = 150;
self.state = STATE_BOTTOM; // Default state (lower)
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
setorigin (self, self.origin);
setmodel (self, self.mdl);
setsize (self, self.mins , self.maxs);
// Cannot have a platform start off or disabled
// with no targetname, how can it be actived!?!
if (self.spawnflags & PLAT_STARTDIS && self.targetname == "") {
dprint("\b[PLAT]\b Starting DISABLED with no targetname!\n");
self.oldorigin = bmodel_origin(self);
spawn_marker(self.oldorigin, SPNMARK_YELLOW);
entity_hide(self);
return;
}
if (self.spawnflags & ENT_STARTOFF && self.targetname == "") {
dprint("\b[PLAT]\b Starting OFF with no targetname!\n");
self.oldorigin = bmodel_origin(self);
spawn_marker(self.oldorigin, SPNMARK_YELLOW);
entity_hide(self);
return;
}
// Check for spawning conditions (nightmare, coop)
// Needs to exist after entity has been added to work for BSPorigin
if (check_nightmare() == TRUE) return;
if (check_coop() == TRUE) return;
// Move the platform up to open position (lighting issues)
// Need to update mins/maxs so that spawn trigger is correct
// otherwise it will be in original position and spawn low
if (self.spawnflags & PLAT_START_OPEN) {
self.origin_z = self.origin_z + self.height;
self.mins_z = self.mins_z + self.height;
self.maxs_z = self.maxs_z + self.height;
}
// pos1 is the top position, pos2 is the bottom
self.pos1 = self.pos2 = self.origin;
// self.height cannot be a negative, min/maxs will be back-to-front
if (self.height) self.pos2_z = self.origin_z - fabs(self.height);
else self.pos2_z = self.origin_z - self.size_z + 8;
// Setup touch trigger and block function
func_plat_trigger_spawn ();
self.blocked = func_plat_blocked;
// Damn annoying that the targetname is being used like this because
// there could have been a better way to do this type of functionality
// == "" Platform starts in lower position (default)
// != "" Platform starts in upper position and requires trigger to work
//
if (self.targetname != "" && !(self.spawnflags & PLAT_START_LOWER) )
self.state = STATE_DISABLED;
else setorigin (self, self.pos2); // Start in lower position
// Setup Entity State functionality
if (self.targetname != "") self.use = entity_state_use;
self.estate_on = func_plat_on;
self.estate_off = func_plat_off;
self.estate_use = func_plat_use;
self.estate_disable = func_plat_disable;
// Check for the easy way to start a platform disabled
if (self.spawnflags & PLAT_STARTDIS) self.estate_disable();
// Check for starting override for entity state
else if (self.spawnflags & ENT_STARTOFF) self.estate_off();
else self.estate_on();
};
//----------------------------------------------------------------------
// Re-direction for map hacks (not used normally)
//----------------------------------------------------------------------
void() plat_hit_bottom = { func_plat_hit_bottom(); };