424 lines
17 KiB
Plaintext
424 lines
17 KiB
Plaintext
/*======================================================================
|
|
TRAP PENDULUM
|
|
======================================================================*/
|
|
float PEND_MAXFRAME = 12; // Frames 0-12
|
|
float PEND_ANIMGROUP = 13; // Size of animation group
|
|
float PEND_MIDFRAME = 7; // Fastest think frame
|
|
|
|
float PEND_REVERSE = 1; // Start at frame 12 instead of 0
|
|
float PEND_ONESWING = 2; // Do one swing cycle and stop (back+forth)
|
|
float PEND_SHORT = 16; // Short pole version (128 instead of 192)
|
|
float PEND_XSWING = 32; // Swing X axis (def=Y)
|
|
|
|
//----------------------------------------------------------------------
|
|
// The array is setup from world.qc before anything loads
|
|
//----------------------------------------------------------------------
|
|
vector pend_X[26], pend_Y[26], pend_short[26];
|
|
|
|
//----------------------------------------------------------------------
|
|
// As the pendulum swings the bounding box is adjusted around the blade
|
|
// Some swings have the bbox ahead of the blade to catch impacts better
|
|
// bbox values taken from the original pendulum from Rogue mission pack
|
|
// Using view_ofs because the model has been rebuilt/reskinned
|
|
//----------------------------------------------------------------------
|
|
void() pendulum_setuparray =
|
|
{
|
|
local float loopc, loopd, tempx;
|
|
local vector tbuffer;
|
|
|
|
pend_Y[0] = '-8 -176 48'; pend_Y[1] = '8 -120 128';
|
|
pend_Y[2] = '-8 -172 12'; pend_Y[3] = '8 -112 88';
|
|
pend_Y[4] = '-8 -160 -22'; pend_Y[5] = '8 -96 50';
|
|
pend_Y[6] = '-8 -138 -51'; pend_Y[7] = '8 -70 17';
|
|
pend_Y[8] = '-8 -110 -72'; pend_Y[9] = '8 -38 -8';
|
|
pend_Y[10] = '-8 -76 -83'; pend_Y[11] = '8 0 -23';
|
|
pend_Y[12] = '-8 -40 -88'; pend_Y[13] = '8 40 -32';
|
|
pend_Y[14] = '-8 0 -83'; pend_Y[15] = '8 76 -23';
|
|
pend_Y[16] = '-8 38 -72'; pend_Y[17] = '8 100 -8';
|
|
pend_Y[18] = '-8 70 -51'; pend_Y[19] = '8 138 17';
|
|
pend_Y[20] = '-8 96 -22'; pend_Y[21] = '8 160 50';
|
|
pend_Y[22] = '-8 112 12'; pend_Y[23] = '8 172 88';
|
|
pend_Y[24] = '-8 120 48'; pend_Y[25] = '8 176 128';
|
|
|
|
// 128 unit pendulum - Y Swing (default)
|
|
pend_short[0] = '0 64 -108'; pend_short[1] = '0 56 -92';
|
|
pend_short[2] = '0 56 -76'; pend_short[3] = '0 48 -60';
|
|
pend_short[4] = '0 36 -52'; pend_short[5] = '0 16 -44';
|
|
pend_short[6] = '0 0 -44'; pend_short[7] = '0 -16 -44';
|
|
pend_short[8] = '0 -32 -52'; pend_short[9] = '0 -48 -60';
|
|
pend_short[10] = '0 -56 -76'; pend_short[11] = '0 -56 -92';
|
|
pend_short[12] = '0 -64 -108';
|
|
|
|
loopc = loopd = 0;
|
|
|
|
while (loopc < PEND_ANIMGROUP) {
|
|
// Generate X axis vector offset from Y axis data (short pendulum)
|
|
tbuffer = pend_short[loopc]; // Read vector offset
|
|
tempx = tbuffer_x; // Tempoary store
|
|
tbuffer_x = tbuffer_y; // Swap around
|
|
tbuffer_y = tempx; // Restore temp
|
|
pend_short[PEND_ANIMGROUP + loopc] = tbuffer;
|
|
|
|
// Generate X axis swing min/max vector from Y axis data
|
|
tbuffer = pend_Y[loopd]; // min bbox
|
|
tempx = tbuffer_x;
|
|
tbuffer_x = tbuffer_y;
|
|
tbuffer_y = tempx;
|
|
pend_X[loopd] = tbuffer;
|
|
tbuffer = pend_Y[loopd+1]; // max bbox
|
|
tempx = tbuffer_x;
|
|
tbuffer_x = tbuffer_y;
|
|
tbuffer_y = tempx;
|
|
pend_X[loopd+1] = tbuffer;
|
|
|
|
loopc = loopc + 1;
|
|
loopd = loopd + 2;
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// The original rogue pendulum adjusted the bbox every animation frame
|
|
// FTEQCC supports arrays and the previous method can now be done easier
|
|
// Also sets the nextthink time to adjust for swing momentum
|
|
//----------------------------------------------------------------------
|
|
void(float frame_seq) trap_pendsize = {
|
|
self.cnt = frame_seq * 2;
|
|
|
|
// Short pendulum needs a different offset each frame
|
|
if (self.spawnflags & PEND_SHORT) {
|
|
if (self.spawnflags & PEND_XSWING) self.view_ofs = pend_short[PEND_ANIMGROUP+frame_seq];
|
|
else self.view_ofs = pend_short[frame_seq];
|
|
}
|
|
|
|
// X/Y swing axis have different bbox vectors
|
|
if (self.spawnflags & PEND_XSWING) {
|
|
self.pos1 = pend_X[self.cnt] + self.view_ofs;
|
|
self.pos2 = pend_X[self.cnt + 1] + self.view_ofs;
|
|
}
|
|
else {
|
|
self.pos1 = pend_Y[self.cnt] + self.view_ofs;
|
|
self.pos2 = pend_Y[self.cnt + 1] + self.view_ofs;
|
|
}
|
|
setsize( self, self.pos1, self.pos2 );
|
|
|
|
if (self.think) {
|
|
// Change nextthink time to simulate the pendulum going fast/slow from momentum
|
|
self.cnt = 0.05 + (fabs(PEND_MIDFRAME - (frame_seq + 1)) * 0.02);
|
|
self.nextthink = time + self.cnt;
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// Pendulum animation frames
|
|
//----------------------------------------------------------------------
|
|
$frame pend_frame1 pend_frame2 pend_frame3 pend_frame4 pend_frame5 pend_frame6 pend_frame7
|
|
$frame pend_frame8 pend_frame9 pend_frame10 pend_frame11 pend_frame12 pend_frame13
|
|
|
|
// Stationary idle for beginning and ending
|
|
void() pend_idle1 =[ $pend_frame1, pend_idle1 ] {};
|
|
void() pend_idle21 =[ $pend_frame13, pend_idle21 ] {};
|
|
|
|
//----------------------------------------------------------------------
|
|
// Pendulum Swing (one cycle is 26 frames)
|
|
//----------------------------------------------------------------------
|
|
void() pend_swing1 =[ $pend_frame1, pend_swing2 ] {
|
|
// Stop the pendulum if state is OFF / DISABLED
|
|
if (self.estate & ESTATE_BLOCK) self.think = pend_idle1;
|
|
else if (self.state == STATE_OFF) self.think = pend_idle1;
|
|
else {
|
|
self.count = self.count + 1;
|
|
if (self.spawnflags & PEND_ONESWING && self.count > 2) {
|
|
self.state = STATE_OFF;
|
|
self.think = pend_idle1;
|
|
}
|
|
else {
|
|
trap_pendsize(0); // Move bbox to frame 0
|
|
self.aflag = 1; // Direction of pendulum blade (touch function)
|
|
}
|
|
}
|
|
};
|
|
void() pend_swing2 =[ $pend_frame2, pend_swing3 ] { trap_pendsize(1);};
|
|
void() pend_swing3 =[ $pend_frame3, pend_swing4 ] { trap_pendsize(2);};
|
|
void() pend_swing4 =[ $pend_frame4, pend_swing5 ] { trap_pendsize(3);
|
|
sound ( self, CHAN_VOICE, self.noise1, 0.5, ATTN_NORM);};
|
|
void() pend_swing5 =[ $pend_frame5, pend_swing6 ] {trap_pendsize(4);};
|
|
void() pend_swing6 =[ $pend_frame6, pend_swing7 ] {trap_pendsize(5);};
|
|
void() pend_swing7 =[ $pend_frame7, pend_swing8 ] {trap_pendsize(6);};
|
|
void() pend_swing8 =[ $pend_frame8, pend_swing9 ] {trap_pendsize(7);};
|
|
void() pend_swing9 =[ $pend_frame9, pend_swing10 ] {trap_pendsize(8);};
|
|
void() pend_swing10 =[ $pend_frame10, pend_swing11 ] {trap_pendsize(9);};
|
|
void() pend_swing11 =[ $pend_frame11, pend_swing12 ] {trap_pendsize(10);};
|
|
void() pend_swing12 =[ $pend_frame12, pend_swing13 ] {trap_pendsize(11);};
|
|
// One extra frame pause at end of sequence
|
|
void() pend_swing13 =[ $pend_frame13, pend_swing21 ] {trap_pendsize(12);};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() pend_swing21 =[ $pend_frame13, pend_swing22 ] {
|
|
// Stop the pendulum if state is OFF / DISABLED
|
|
if (self.estate & ESTATE_BLOCK) self.think = pend_idle21;
|
|
else if (self.state == STATE_OFF) self.think = pend_idle21;
|
|
else {
|
|
self.count = self.count + 1;
|
|
if (self.spawnflags & PEND_ONESWING && self.count > 2) {
|
|
self.state = STATE_OFF;
|
|
self.think = pend_idle21;
|
|
}
|
|
else {
|
|
trap_pendsize(12); // Move bbox to frame 12
|
|
self.aflag = -1; // Direction of pendulum blade (touch function)
|
|
}
|
|
}
|
|
};
|
|
void() pend_swing22 =[ $pend_frame12, pend_swing23 ] {trap_pendsize(11);};
|
|
void() pend_swing23 =[ $pend_frame11, pend_swing24 ] {trap_pendsize(10);};
|
|
void() pend_swing24 =[ $pend_frame10, pend_swing25 ] {trap_pendsize(9);
|
|
sound ( self, CHAN_VOICE, self.noise1, 0.5, ATTN_NORM);};
|
|
void() pend_swing25 =[ $pend_frame9, pend_swing26 ] {trap_pendsize(8);};
|
|
void() pend_swing26 =[ $pend_frame8, pend_swing27 ] {trap_pendsize(7);};
|
|
void() pend_swing27 =[ $pend_frame7, pend_swing28 ] {trap_pendsize(6);};
|
|
void() pend_swing28 =[ $pend_frame6, pend_swing29 ] {trap_pendsize(5);};
|
|
void() pend_swing29 =[ $pend_frame5, pend_swing30 ] {trap_pendsize(4);};
|
|
void() pend_swing30 =[ $pend_frame4, pend_swing31 ] {trap_pendsize(3);};
|
|
void() pend_swing31 =[ $pend_frame3, pend_swing32 ] {trap_pendsize(2);};
|
|
void() pend_swing32 =[ $pend_frame2, pend_swing33 ] {trap_pendsize(1);};
|
|
// One extra frame pause at end of sequence
|
|
void() pend_swing33 =[ $pend_frame1, pend_swing1 ] {trap_pendsize(0);};
|
|
|
|
//----------------------------------------------------------------------
|
|
// if something has touched the pendulum, damage and bounce away
|
|
//----------------------------------------------------------------------
|
|
void() trap_pendulum_touch =
|
|
{
|
|
// Blade can still hurt if touched, except when OFF = not visible
|
|
if (self.estate & ESTATE_OFF) return;
|
|
// Double check if dead monster body!
|
|
if (trigger_check_body(other,DEAD_EXPLODE)) return;
|
|
if (other.health < 1 || other.takedamage == DAMAGE_NO) return;
|
|
if (self.attack_finished > time) return;
|
|
if (self.waitmin > 0) self.attack_finished = time + self.waitmin;
|
|
|
|
// only play hit sound once per second
|
|
if (self.pain_finished < time) {
|
|
sound ( self, CHAN_VOICE, self.noise2, 1, ATTN_NORM);
|
|
self.pain_finished = time + 1;
|
|
}
|
|
|
|
// Instant death for monsters, they can get knocked into wierd locations
|
|
if (other.flags & FL_MONSTER)
|
|
T_Damage (other, self, self, other.max_health + 100, DAMARMOR);
|
|
else
|
|
// Small damage but can be lethal because of how often touch runs
|
|
T_Damage (other, self, self, self.dmg, DAMARMOR);
|
|
|
|
// Fling the player/object away from blade
|
|
// Setting aflag in animation frame to specify direction
|
|
if (self.spawnflags & PEND_XSWING) other.velocity_x = self.aflag * 250;
|
|
else other.velocity_y = self.aflag * 250;
|
|
other.velocity_z = 200; // Little upward lift
|
|
|
|
// Blood and gore at object location not pendulum
|
|
SpawnMeatSpray (other, other, crandom() * 200);
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() trap_pendulum_fire =
|
|
{
|
|
// Swing counter
|
|
self.count = 0;
|
|
// Make sure starting frame is start or finish
|
|
if (self.frame != 0 && self.frame != PEND_MAXFRAME)
|
|
self.frame = self.frame_override;
|
|
|
|
// Setup next frame to update swing
|
|
if (self.frame == 0) self.think = pend_swing1;
|
|
else self.think = pend_swing13;
|
|
self.nextthink = time + 0.01 + self.wait;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() trap_pendulum_use =
|
|
{
|
|
// Deal with STARTOFF functionality first
|
|
if (self.spawnflags & ENT_STARTOFF) {
|
|
// Remove spawnflag and switch ON entity
|
|
self.spawnflags = self.spawnflags - ENT_STARTOFF;
|
|
self.state = STATE_OFF; // use toggle function
|
|
self.estate_on(); // switch on
|
|
}
|
|
|
|
// Block USE functionality if state wrong
|
|
if (self.estate & ESTATE_BLOCK) return;
|
|
|
|
// Toggle state of pendulum to start/stop
|
|
if (self.state == STATE_OFF) {
|
|
self.state = STATE_ON;
|
|
trap_pendulum_fire();
|
|
}
|
|
else self.state = STATE_OFF;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() trap_pendulum_on =
|
|
{
|
|
// Turn on model/world interaction
|
|
self.estate = ESTATE_ON;
|
|
self.solid = SOLID_TRIGGER;
|
|
self.movetype = MOVETYPE_NONE;
|
|
setmodel (self, self.mdl);
|
|
setsize (self, self.mins , self.maxs);
|
|
trap_pendsize(self.frame);
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() trap_pendulum_off =
|
|
{
|
|
self.estate = ESTATE_OFF;
|
|
self.movetype = MOVETYPE_NONE;
|
|
self.solid = SOLID_NOT;
|
|
setmodel (self, "");
|
|
self.frame = self.frame_override;
|
|
self.state = STATE_OFF;
|
|
self.think = SUB_Null;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() trap_pendulum_disable =
|
|
{
|
|
self.state = STATE_OFF;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() trap_pendlong =
|
|
{
|
|
// Short/long version of the model
|
|
if (self.spawnflags & PEND_SHORT) self.mdl = "progs/trap_pendshort.mdl";
|
|
else self.mdl = "progs/trap_pendlong.mdl";
|
|
precache_model (self.mdl);
|
|
|
|
self.view_ofs = '0 0 -108'; // Offset bbox vectors (new model different location)
|
|
self.oldorigin = '0 0 0'; // Entity is correct location
|
|
|
|
self.noise1 = "traps/pend_swing.wav";
|
|
self.noise2 = "traps/pend_hit.wav";
|
|
precache_sound (self.noise1);
|
|
precache_sound (self.noise2);
|
|
|
|
self.classtype = CT_PENDULUM;
|
|
if (self.dmg == 0) self.dmg = 5; // Default touch damage
|
|
if (self.dmg < 0) self.dmg = 0; // Use -1 for no damage option
|
|
if (self.wait <= 0) self.wait = 0; // Default starting delay
|
|
if (!self.waitmin) self.waitmin = 0.5; // Damage throttle
|
|
self.state = STATE_OFF;
|
|
|
|
// Error - Check for targetname for trigger event
|
|
if (self.targetname == "") {
|
|
dprint("\b[PENDULUM]\b missing targetname, cannot be triggered!\n");
|
|
}
|
|
|
|
// Rotate model and swing on X axis instead
|
|
if (self.spawnflags & PEND_XSWING) self.angles = '0 270 0';
|
|
else self.angles = '0 0 0';
|
|
|
|
// Start the opposite way around (frame 13 instead of 1)
|
|
// This also affects one swing parameter
|
|
if (self.spawnflags & PEND_REVERSE) self.frame_override = PEND_MAXFRAME;
|
|
else self.frame_override = 0;
|
|
self.frame = self.frame_override;
|
|
|
|
// Setup Entity State functionality
|
|
if (self.targetname != "") self.use = entity_state_use;
|
|
self.estate_on = trap_pendulum_on;
|
|
self.estate_off = trap_pendulum_off;
|
|
self.estate_use = trap_pendulum_use;
|
|
self.estate_disable = trap_pendulum_disable;
|
|
self.touch = trap_pendulum_touch;
|
|
if (self.spawnflags & ENT_STARTOFF) self.estate_off();
|
|
else self.estate_on();
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void() trap_pendlongx =
|
|
{
|
|
self.spawnflags = self.spawnflags | PEND_XSWING;
|
|
trap_pendlong();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void() trap_pendshort =
|
|
{
|
|
self.spawnflags = self.spawnflags | PEND_SHORT;
|
|
trap_pendlong();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void() trap_pendshortx =
|
|
{
|
|
self.spawnflags = self.spawnflags | PEND_SHORT;
|
|
self.spawnflags = self.spawnflags | PEND_XSWING;
|
|
trap_pendlong();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/*QUAKED trap_pendlong (0.5 0.75 0) (-8 -192 -24) (8 0 24) REVERSE ONESWING x x x x STARTOFF x
|
|
Long (192 units) Pendulum (From Rogue mission pack)
|
|
-------- KEYS --------
|
|
targetname : toggle state (use trigger ent for exact state)
|
|
dmg : Damage to do for each contact, def=5
|
|
waitmin : Damage throttle to touch function, def=0.5s
|
|
wait : amount of time (seconds) before starting swinging. def=0
|
|
-------- SPAWNFLAGS --------
|
|
REVERSE : Starts at frame 12 instead 0
|
|
ONESWING : Will do a single swing (back + forth) when triggered
|
|
STARTOFF : Starts off and waits for trigger
|
|
-------- NOTES --------
|
|
Long (192 units) Pendulum (From Rogue mission pack)
|
|
*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/*QUAKED trap_pendlongx (0.5 0.75 0) (-192 -8 -24) (0 8 24) REVERSE ONESWING x x x x STARTOFF x
|
|
Long (192 units) Pendulum working on X axis only
|
|
-------- KEYS --------
|
|
targetname : toggle state (use trigger ent for exact state)
|
|
dmg : Damage to do for each contact, def=5
|
|
waitmin : Damage throttle to touch function, def=0.5s
|
|
wait : amount of time (seconds) before starting swinging. def=0
|
|
-------- SPAWNFLAGS --------
|
|
REVERSE : Starts at frame 12 instead 0
|
|
ONESWING : Will do a single swing (back + forth) when triggered
|
|
STARTOFF : Starts off and waits for trigger
|
|
-------- NOTES --------
|
|
Long (192 units) Pendulum working on X axis only
|
|
*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/*QUAKED trap_pendshort (0.5 0.75 0) (-8 -192 -24) (8 0 24) REVERSE ONESWING x x x x STARTOFF x
|
|
Short (128 units) Pendulum
|
|
-------- KEYS --------
|
|
targetname : toggle state (use trigger ent for exact state)
|
|
dmg : Damage to do for each contact, def=5
|
|
waitmin : Damage throttle to touch function, def=0.5s
|
|
wait : amount of time (seconds) before starting swinging. def=0
|
|
-------- SPAWNFLAGS --------
|
|
REVERSE : Starts at frame 12 instead 0
|
|
ONESWING : Will do a single swing (back + forth) when triggered
|
|
STARTOFF : Starts off and waits for trigger
|
|
-------- NOTES --------
|
|
Short (128 units) Pendulum
|
|
*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/*QUAKED trap_pendshortx (0.5 0.75 0) (-192 -8 -24) (0 8 24) REVERSE ONESWING x x x x STARTOFF x
|
|
Short (128 units) Pendulum working on X axis only
|
|
-------- KEYS --------
|
|
targetname : toggle state (use trigger ent for exact state)
|
|
dmg : Damage to do for each contact, def=5
|
|
waitmin : Damage throttle to touch function, def=0.5s
|
|
wait : amount of time (seconds) before starting swinging. def=0
|
|
-------- SPAWNFLAGS --------
|
|
REVERSE : Starts at frame 12 instead 0
|
|
ONESWING : Will do a single swing (back + forth) when triggered
|
|
STARTOFF : Starts off and waits for trigger
|
|
-------- NOTES --------
|
|
Short (128 units) Pendulum working on X axis only
|
|
*/
|