djcev.com

//

Git Repos / fte_dogmode / qc / func / new_plat.qc

Last update to this file was on 2024-03-24 at 17:34.

Show new_plat.qc

//==============================================================================
// func_new_plat - Rogue Dissolution Of Eternity platforms
//==============================================================================

// newplats.qc
// pmack
// september 1996

//======================================================================
// constants
//======================================================================

const float NEWPLAT_DN_N_WAIT = 1; // spawnflags
const float NEWPLAT_PLT_TOGGLE = 2;
const float NEWPLAT_ELEVATOR = 4;
const float NEWPLAT_START_AT_TOP = 8;
const float NEWPLAT_PLAT2 = 16;
const float NEWPLAT_PLAT2_BOTTOM = 32;

//======================================================================
// forward declarations
//======================================================================

// temp_new_plat_trigger
void() temp_new_plat_trigger_touch;
entity(entity own) spawn_temp_new_plat_trigger;
void(entity e) temp_new_plat_trigger_init;
strip void() temp_new_plat_trigger;

// func_new_plat
void() func_new_plat_downandwait_hit_top; // down and wait style
void() func_new_plat_downandwait_hit_bottom;
void() func_new_plat_downandwait_go_down;
void() func_new_plat_downandwait_go_up;
void() func_new_plat_downandwait_blocked;
void() func_new_plat_downandwait_use;
void() func_new_plat_toggle_hit_top; // toggle style
void() func_new_plat_toggle_hit_bottom;
void() func_new_plat_toggle_go_down;
void() func_new_plat_toggle_go_up;
void() func_new_plat_toggle_blocked;
void() func_new_plat_toggle_use;
void() func_new_plat_elvtr_stop; // DoE elevator style
void() func_new_plat_elvtr_go;
void() func_new_plat_elvtr_blocked;
void() func_new_plat_elvtr_use;
void() func_new_plat_plat2_hit_top; // plat2 style
void() func_new_plat_plat2_hit_bottom;
void() func_new_plat_plat2_go_down;
void() func_new_plat_plat2_go_up;
void() func_new_plat_plat2_use;
void() func_new_plat_plat2_blocked;
void(entity e) func_new_plat_init; // initialization & spawn function
void() func_new_plat;

//------------------------------------------------------------------------------

//----------------------------------------------------------------------
// class temp_new_plat_trigger: base_tempentity
// {
//--------------------------------------------------------------
// plat2_center_touch
//--------------------------------------------------------------
void() temp_new_plat_trigger_touch =
{
local float other_state;
local vector plat_position;

// from Copper -- dumptruck_ds
if (sub_checkvalidtouch(other) == FALSE)
return;

if (!self.owner)
{
remove (self);
return;
}

if (self.owner.classtype != CT_FUNC_NEW_PLAT)
return;

// at this point "self" is the trigger, "self.owner" is
// the plat, and "other" is the player.

if ((self.owner.invincible_time + 2) > time)
return;

if (self.owner.state > 4)
// disabled.
return;

if (self.owner.jump_flag > FUNC_STATE_BOTTOM)
{
if (self.owner.super_time < time)
{
if (self.owner.jump_flag == FUNC_STATE_UP)
sub_runvoidas (self.owner,
func_new_plat_plat2_go_up);
else
sub_runvoidas (self.owner,
func_new_plat_plat2_go_down);

self.owner.jump_flag = 0;
}
return;
}

if (self.owner.state > FUNC_STATE_BOTTOM)
// STATE_UP or STATE_DOWN
return;

plat_position = (self.owner.absmax + self.owner.absmin) * 0.5;

if (self.owner.state == FUNC_STATE_TOP)
{
other_state = FUNC_STATE_TOP;
if (plat_position_z > other.origin_z)
other_state = FUNC_STATE_BOTTOM;
}
else
{
other_state = FUNC_STATE_BOTTOM;
if ((other.origin_z - plat_position_z) >
self.owner.height)
{
other_state = FUNC_STATE_TOP;
}
}

if (self.owner.state == other_state)
{
self.owner.cnt = 0;
self.owner.super_time = time + 0.5;
}
else
{
self.owner.super_time = time + 0.1;
self.owner.cnt = 1;
}

if (self.owner.state == FUNC_STATE_BOTTOM)
self.owner.jump_flag = FUNC_STATE_UP;
else if (self.owner.state == FUNC_STATE_TOP)
self.owner.jump_flag = FUNC_STATE_DOWN;
};

//--------------------------------------------------------------
entity(entity own) spawn_temp_new_plat_trigger =
{
local entity e = spawn ();
e.owner = own;
temp_new_plat_trigger_init (e);
return e;
};

//--------------------------------------------------------------
void(entity e) temp_new_plat_trigger_init =
{
e.classname = "temp_new_plat_trigger";
e.classtype = CT_TEMP_NEWPLAT_TRIGGER;
base_tempentity_init (e);
e.touch = temp_new_plat_trigger_touch;
e.movetype = MOVETYPE_NONE;
e.solid = SOLID_TRIGGER;

local vector tmin = e.owner.mins + '25 25 0';
local vector tmax = e.owner.maxs - '25 25 -8';
tmin_z = tmax_z - (e.owner.pos1_z - e.owner.pos2_z + 8);

if (e.owner.spawnflags & PLAT_LOW_TRIGGER)
tmax_z = tmin_z + 8;

if (e.owner.size_x <= 50)
{
tmin_x = (e.owner.mins_x + e.owner.maxs_x) / 2;
tmax_x = tmin_x + 1;
}
if (e.owner.size_y <= 50)
{
tmin_y = (e.owner.mins_y + e.owner.maxs_y) / 2;
tmax_y = tmin_y + 1;
}

setsize (e, tmin, tmax);
};

//--------------------------------------------------------------
strip void() temp_new_plat_trigger =
{
temp_new_plat_trigger_init (self);
};
// };

/*QUAKED func_new_plat (0 .5 .8) ? DN_N_WAIT PLT_TOGGLE ELEVATOR START_AT_TOP PLAT2 P2_BOTTOM X X NOT_ON_EASY NOT_ON_NORMAL NOT_ON_HARD_OR_NIGHTMARE NOT_IN_DEATHMATCH NOT_IN_COOP NOT_IN_SINGLEPLAYER X NOT_ON_HARD_ONLY NOT_ON_NIGHTMARE_ONLY

--------------
DN_N_WAIT is a plat that starts at the top and when triggered, goes down, waits, then comes back up.
health - number of seconds to wait (default 5)
--------------
PLT_TOGGLE is a plat that will change between the top and bottom each time it is triggered.
--------------
ELEVATOR is an elevator plat. You can have as many levels as you want but they must be all the same distance away. Use elevator button entity as the trigger.
cnt is the number of floors
height is the distance between floors
wait is the number of seconds before the elevator can be activated again after starting or stopping (default 0)

START_AT_TOP is an optional flag for elevators. It just tells the elevator that it's position is the top floor. (Default is the bottom floor) USE THIS ONLY WITH ELEVATORS!
-------------
PLAT2 is a fixed version of the original plat. If you want the plat to start at the bottom and move to the top on demand, use a negative height. That will tell Quake to lower the plat at spawn time. Always place this plat type in the top position when making the map. This will ensure correct lighting, hopefully. If a plat2 is the target of a trigger, it will be disabled until it has been triggered. Delay is the wait before the plat returns to original position.

If you don't want to bother figuring out the height, don't put a
value in the height

delay default 3
speed default 150
cnt default 2

P2_BOTTOM is an optional switch to have an auto-sized plat2 start at the bottom.
--------------
Plats are always drawn in the extended position, so they will light correctly.

If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is trigger, when it will lower and become a normal plat.

If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determined by the model's height.
Set "sounds" to one of the following:
1) base fast
2) chain slow
*/
//----------------------------------------------------------------------
// class func_new_plat: base_func
// {
//==============================================================
// down N and wait code
//==============================================================

//--------------------------------------------------------------
void() func_new_plat_downandwait_hit_top =
{
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = FUNC_STATE_TOP;
};

//--------------------------------------------------------------
void() func_new_plat_downandwait_hit_bottom =
{
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = FUNC_STATE_BOTTOM;
self.think = func_new_plat_downandwait_go_up;
self.nextthink = self.ltime + self.health;
};

//--------------------------------------------------------------
void() func_new_plat_downandwait_go_down =
{
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.state = FUNC_STATE_DOWN;
sub_calcmove (self, self.pos2, self.speed,
func_new_plat_downandwait_hit_bottom);
};

//--------------------------------------------------------------
void() func_new_plat_downandwait_go_up =
{
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.state = FUNC_STATE_UP;
sub_calcmove (self, self.pos1, self.speed,
func_new_plat_downandwait_hit_top);
};

//--------------------------------------------------------------
void() func_new_plat_downandwait_blocked =
{
// handle projectiles -- CEV
if (other.classgroup & CG_PROJECTILE)
{
if (other.mins != '0 0 0' || other.maxs != '0 0 0')
setsize (other, '0 0 0', '0 0 0');
}

t_damage2 (other, self, self, 1);

if (self.state == FUNC_STATE_UP)
func_new_plat_downandwait_go_down ();
else if (self.state == FUNC_STATE_DOWN)
func_new_plat_downandwait_go_up ();
else
objerror ("func_new_plat_downandwait_blocked: "
"bad self.state\n");
};

//--------------------------------------------------------------
void() func_new_plat_downandwait_use =
{
if (self.state != FUNC_STATE_TOP)
return;

func_new_plat_downandwait_go_down ();
};

//==============================================================
// toggle type code
//==============================================================

//--------------------------------------------------------------
void() func_new_plat_toggle_hit_top =
{
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = FUNC_STATE_TOP;
};

//--------------------------------------------------------------
void() func_new_plat_toggle_hit_bottom =
{
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = FUNC_STATE_BOTTOM;
};

//--------------------------------------------------------------
void() func_new_plat_toggle_go_down =
{
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.state = FUNC_STATE_DOWN;
sub_calcmove (self, self.pos2, self.speed,
func_new_plat_toggle_hit_bottom);
};

//--------------------------------------------------------------
void() func_new_plat_toggle_go_up =
{
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.state = FUNC_STATE_UP;
sub_calcmove (self, self.pos1, self.speed,
func_new_plat_toggle_hit_top);
};

//--------------------------------------------------------------
void() func_new_plat_toggle_blocked =
{
// handle projectiles -- CEV
if (other.classgroup & CG_PROJECTILE)
{
if (other.mins != '0 0 0' || other.maxs != '0 0 0')
setsize (other, '0 0 0', '0 0 0');
}

t_damage2 (other, self, self, 1);

if (self.state == FUNC_STATE_UP)
func_new_plat_toggle_go_down ();
else if (self.state == FUNC_STATE_DOWN)
func_new_plat_toggle_go_up ();
else
objerror ("func_new_plat_toggle_blocked: "
"bad self.state\n");
};

//--------------------------------------------------------------
void() func_new_plat_toggle_use =
{
if (self.state == FUNC_STATE_TOP)
func_new_plat_toggle_go_down ();
else if (self.state == FUNC_STATE_BOTTOM)
func_new_plat_toggle_go_up ();
};

//==============================================================
// elvtr type code
// reusing fields; old -> current -- CEV
// elevatorDestination -> finaldest (will be rewritten by calcmove)
// elevatorLastUsed -> rad_time
// elevatorOnFloor -> style
// elevatorToFloor -> style2
//==============================================================

//--------------------------------------------------------------
void() func_new_plat_elvtr_stop =
{
self.style = self.style2;
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = FUNC_STATE_BOTTOM;
self.rad_time = time;
};

//--------------------------------------------------------------
void() func_new_plat_elvtr_go =
{
self.finaldest = self.pos2;
self.finaldest_z = self.pos2_z +
(self.height * self.style2);
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.state = FUNC_STATE_UP;
sub_calcmove (self, self.finaldest, self.speed,
func_new_plat_elvtr_stop);
self.rad_time = time;
};

//--------------------------------------------------------------
void() func_new_plat_elvtr_blocked =
{
// handle projectiles -- CEV
if (other.classgroup & CG_PROJECTILE)
{
if (other.mins != '0 0 0' || other.maxs != '0 0 0')
setsize (other, '0 0 0', '0 0 0');
}

local float tmp;

// T_Damage (other, self, self, 1);

// the elevator is changing direction, so swap the floor
// it's coming from and the floor it's going to -- iw
tmp = self.style;
self.style = self.style2;
self.style2 = tmp;

func_new_plat_elvtr_go ();
};

//--------------------------------------------------------------
// elvtr_use -- elevator use function
// self = plat, other = elevator button, other.enemy = player
//--------------------------------------------------------------
void() func_new_plat_elvtr_use =
{
// the original DoE code allowed an elevator to be activated
// again when it was in the process of moving between floors
// (assuming the wait period was over); this resulted in
// sometimes unintuitive behavior, so, the following test
// prevents this -- iw
if (self.style2 != self.style)
return;

// the original DoE code had a hard-coded two second wait
// period; this has been changed for progs_dump so that
// this.wait is used instead -- iw
if ((self.rad_time + self.wait) > time)
return;

local float temp_dist, elvPos, btnPos;

self.rad_time = time;

if (elv_butn_dir == 0)
return;

elvPos = (self.absmin_z + self.absmax_z) * 0.5;
btnPos = (other.absmin_z + other.absmax_z) * 0.5;

if (elvPos > btnPos)
{
temp_dist = (elvPos - btnPos) / self.height;
temp_dist = ceil (temp_dist);
self.style2 = self.style - temp_dist;
func_new_plat_elvtr_go ();
return;
}
else
{
temp_dist = btnPos - elvPos;
if (temp_dist > self.height)
{
temp_dist = temp_dist / self.height;
temp_dist = floor (temp_dist);
self.style2 = self.style +
temp_dist;
func_new_plat_elvtr_go ();
return;
}
}

if (elv_butn_dir == -1)
{
if (self.style > 0)
{
self.style2 = self.style - 1;
func_new_plat_elvtr_go ();
}
}
else if (elv_butn_dir == 1)
{
if (self.style < (self.cnt - 1))
{
self.style2 = self.style + 1;
func_new_plat_elvtr_go ();
}
}
};

//==============================================================
// PLAT2 type code
// reusing fields; old -> current -- CEV
// plat2Called -> cnt
// plat2LastMove -> invincible_time
// plat2GoTime -> super_time
// plat2GoTo -> jump_flag
//==============================================================

//--------------------------------------------------------------
void() func_new_plat_plat2_hit_top =
{
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = FUNC_STATE_TOP;

self.invincible_time = time;
if (self.cnt == 1)
{
// allow immediate move
self.invincible_time = 0;
self.cnt = 0;
self.think = func_new_plat_plat2_go_down;
self.nextthink = self.ltime + 1.5;
}
else if (!(self.spawnflags & NEWPLAT_START_AT_TOP))
{
self.cnt = 0;
self.think = func_new_plat_plat2_go_down;
self.nextthink = self.ltime + self.delay;
}
};

//--------------------------------------------------------------
void() func_new_plat_plat2_hit_bottom =
{
sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM);
self.state = FUNC_STATE_BOTTOM;

self.invincible_time = time;
if (self.cnt == 1)
{
// allow immediate move
self.invincible_time = 0;
self.cnt = 0;
self.think = func_new_plat_plat2_go_up;
self.nextthink = self.ltime + 1.5;
}
else if (self.spawnflags & NEWPLAT_START_AT_TOP)
{
self.cnt = 0;
self.think = func_new_plat_plat2_go_up;
self.nextthink = self.ltime + self.delay;
}
};

//--------------------------------------------------------------
void() func_new_plat_plat2_go_down =
{
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.state = FUNC_STATE_DOWN;
sub_calcmove (self, self.pos2, self.speed,
func_new_plat_plat2_hit_bottom);
};

//--------------------------------------------------------------
void() func_new_plat_plat2_go_up =
{
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
self.state = FUNC_STATE_UP;
sub_calcmove (self, self.pos1, self.speed,
func_new_plat_plat2_hit_top);
};

//--------------------------------------------------------------
void() func_new_plat_plat2_use =
{
if (self.state > 4)
self.state = self.state - 10;

self.use = sub_null;
};

//--------------------------------------------------------------
void() func_new_plat_plat2_blocked =
{
// handle projectiles -- CEV
if (other.classgroup & CG_PROJECTILE)
{
if (other.mins != '0 0 0' || other.maxs != '0 0 0')
setsize (other, '0 0 0', '0 0 0');
}

t_damage2 (other, self, self, 1);

if (self.state == FUNC_STATE_UP)
func_new_plat_plat2_go_down ();
else if (self.state == FUNC_STATE_DOWN)
func_new_plat_plat2_go_up ();
else
objerror ("func_new_plat_plat2_blocked: "
"bad self.state\n");
};

//==============================================================
// Common Plat Code
//==============================================================

//--------------------------------------------------------------
void(entity e) func_new_plat_init =
{
e.classname = "plat";
e.classtype = CT_FUNC_NEW_PLAT;
base_func_init (e);

// local entity t;
local float negative_height = 0;

if (!e.t_length)
e.t_length = 80;
if (!e.t_width)
e.t_width = 10;

if (e.sounds == 0)
e.sounds = 2;

// FIX THIS TO LOAD A GENERIC PLAT SOUND

if (e.sounds == 1)
{
if (!e.noise || e.noise == "")
e.noise = "plats/plat1.wav";
if (!e.noise1 || e.noise1 == "")
e.noise1 = "plats/plat2.wav";
}
else if (e.sounds == 2)
{
if (!e.noise || e.noise == "")
e.noise = "plats/medplat1.wav";
if (!e.noise1 || e.noise1 == "")
e.noise1 = "plats/medplat2.wav";
}
else if (e.sounds == 3)
{
// base door sound
if (!e.noise || e.noise == "")
e.noise = "doors/hydro1.wav";
if (!e.noise1 || e.noise1 == "")
e.noise1 = "doors/hydro2.wav";
}
else if (e.sounds == 4)
{
// func_train sounds
if (!e.noise || e.noise == "")
e.noise = "plats/train1.wav";
if (!e.noise1 || e.noise1 == "")
e.noise1 = "plats/train2.wav";
}
else
{
if (!e.noise || e.noise == "")
e.noise = "misc/null.wav";
if (!e.noise1 || e.noise1 == "")
e.noise1 = "misc/null.wav";
}

precache_sound (e.noise);
precache_sound (e.noise1);

e.mangle = e.angles;
e.angles = '0 0 0';

e.solid = SOLID_BSP;
e.movetype = MOVETYPE_PUSH;
setorigin (e, e.origin);
setmodel (e, e.model);
setsize (e, e.mins , e.maxs);

if (!e.speed)
e.speed = 150;

// pos1 is the top position, pos2 is the bottom
e.pos1 = e.origin;
e.pos2 = e.origin;

if (e.height < 0)
{
negative_height = 1;
e.height = 0 - e.height;
}

if (e.height)
{
e.pos2_z = e.origin_z - e.height;
}
else
{
negative_height = 1;
e.height = e.size_z - 8;
e.pos2_z = e.origin_z - e.height;
}

if (e.spawnflags & NEWPLAT_DN_N_WAIT)
{
e.blocked = func_new_plat_downandwait_blocked;
e.use = func_new_plat_downandwait_use;

if (negative_height == 1)
{
e.state = FUNC_STATE_BOTTOM;
setorigin (e, e.pos2);
}
else
{
e.state = FUNC_STATE_TOP;
}

if (!e.health)
e.health = 5;
}
else if (e.spawnflags & NEWPLAT_PLT_TOGGLE)
{
e.blocked = func_new_plat_toggle_blocked;
e.use = func_new_plat_toggle_use;

if (negative_height == 1)
{
setorigin (e, e.pos2);
e.state = FUNC_STATE_BOTTOM;
}
else
{
e.state = FUNC_STATE_TOP;
}
}
else if (e.spawnflags & NEWPLAT_ELEVATOR)
{
e.rad_time = 0;

// allow the mapper to set e.wait, but don't
// allow a negative wait period -- iw
if (e.wait < 0)
e.wait = 0;

if (e.spawnflags & NEWPLAT_START_AT_TOP)
{
e.pos1 = e.origin;
e.pos2 = e.origin;
e.pos2_z = e.origin_z -
(e.height * (e.cnt - 1));
e.style = e.cnt - 1;
e.style2 = e.style;
}
else
{
e.pos1 = e.origin;
e.pos2 = e.origin;
e.pos1_z = e.origin_z +
(e.height * (e.cnt - 1));
e.style = 0;
e.style2 = e.style;
}

e.blocked = func_new_plat_elvtr_blocked;
e.use = func_new_plat_elvtr_use;
}
else if (e.spawnflags & NEWPLAT_PLAT2)
{
e.cnt = 0;
e.invincible_time = 0;
e.jump_flag = 0;
e.super_time = 0;

e.blocked = func_new_plat_plat2_blocked;

if (!e.delay)
e.delay = 3;

if (negative_height == 1)
{
e.state = FUNC_STATE_BOTTOM;
// make sure START_AT_TOP isn't set.
// We need that...
e.spawnflags = NEWPLAT_PLAT2;
setorigin (e, e.pos2);
}
else
{
// default position is top.
e.spawnflags |= NEWPLAT_START_AT_TOP;
e.state = FUNC_STATE_TOP;
}

if (e.targetname != "")
{
e.use = func_new_plat_plat2_use;
e.state = e.state + 10;
}

// the "start moving" trigger
e.trigger_field = spawn_temp_new_plat_trigger (e);
}
};

//--------------------------------------------------------------
void() func_new_plat =
{
// new spawnflags for all entities -- iw
if (SUB_Inhibit())
return;

func_new_plat_init (self);
};
// };

Return to the top of this page or return to the overview of this repo.

Log new_plat.qc

Date Commit Message Author + -
2024-03-24 Fix projectile and func_ blocked interaction cev +28  
2024-03-24 2nd pass refactor, rework QC class structure cev +421 -425
2024-02-18 Client/player, projectiles, entrypoints refactor cev +6 -6
2024-01-31 Class based monster refactor & start projectiles cev +16 -9
2024-01-09 Continue OO / Class-based refactor cev +650 -564
2023-11-27 Code reorg, minor movement changes, misc cev +685  

Return to the top of this page or return to the overview of this repo.