#include <u.h>#include <libc.h>#include <stdio.h>#include "../dat.h"#include "../fns.h" /*========================================================= PLATS movement options: linear smooth start, hard stop smooth start, smooth stop start end acceleration speed deceleration begin sound end sound target fired when reaching end wait at end object characteristics that use move segments --------------------------------------------- movetype_push, or movetype_stop action when touched action when blocked action when used disabled? auto trigger spawning =========================================================*/ #define PLAT_LOW_TRIGGER 1 #define STATE_TOP 0#define STATE_BOTTOM 1#define STATE_UP 2#define STATE_DOWN 3 #define DOOR_START_OPEN 1#define DOOR_REVERSE 2#define DOOR_CRUSHER 4#define DOOR_NOMONSTER 8#define DOOR_TOGGLE 32#define DOOR_X_AXIS 64#define DOOR_Y_AXIS 128 //// Support routines for movement (changes in origin using velocity)// void Move_Done (edict_t *ent){ VectorClear (ent->velocity); ent->moveinfo.endfunc (ent);} void Move_Final (edict_t *ent){ if (ent->moveinfo.remaining_distance == 0) { Move_Done (ent); return; } VectorScale (ent->moveinfo.dir, ent->moveinfo.remaining_distance / FRAMETIME, ent->velocity); ent->think = Move_Done; ent->nextthink = level.time + FRAMETIME;} void Move_Begin (edict_t *ent){ float frames; if ((ent->moveinfo.speed * FRAMETIME) >= ent->moveinfo.remaining_distance) { Move_Final (ent); return; } VectorScale (ent->moveinfo.dir, ent->moveinfo.speed, ent->velocity); frames = floor((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME); ent->moveinfo.remaining_distance -= frames * ent->moveinfo.speed * FRAMETIME; ent->nextthink = level.time + (frames * FRAMETIME); ent->think = Move_Final;} void Think_AccelMove (edict_t *ent); void Move_Calc (edict_t *ent, vec3_t dest, void(*func)(edict_t*)){ VectorClear (ent->velocity); VectorSubtract (dest, ent->s.origin, ent->moveinfo.dir); ent->moveinfo.remaining_distance = VectorNormalize (ent->moveinfo.dir); ent->moveinfo.endfunc = func; if (ent->moveinfo.speed == ent->moveinfo.accel && ent->moveinfo.speed == ent->moveinfo.decel) { if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent)) { Move_Begin (ent); } else { ent->nextthink = level.time + FRAMETIME; ent->think = Move_Begin; } } else { // accelerative ent->moveinfo.current_speed = 0; ent->think = Think_AccelMove; ent->nextthink = level.time + FRAMETIME; }} //// Support routines for angular movement (changes in angle using avelocity)// void AngleMove_Done (edict_t *ent){ VectorClear (ent->avelocity); ent->moveinfo.endfunc (ent);} void AngleMove_Final (edict_t *ent){ vec3_t move; if (ent->moveinfo.state == STATE_UP) VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, move); else VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, move); if (VectorCompare (move, vec3_origin)) { AngleMove_Done (ent); return; } VectorScale (move, 1.0/FRAMETIME, ent->avelocity); ent->think = AngleMove_Done; ent->nextthink = level.time + FRAMETIME;} void AngleMove_Begin (edict_t *ent){ vec3_t destdelta; float len; float traveltime; float frames; // set destdelta to the vector needed to move if (ent->moveinfo.state == STATE_UP) VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, destdelta); else VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, destdelta); // calculate length of vector len = VectorLength (destdelta); // divide by speed to get time to reach dest traveltime = len / ent->moveinfo.speed; if (traveltime < FRAMETIME) { AngleMove_Final (ent); return; } frames = floor(traveltime / FRAMETIME); // scale the destdelta vector by the time spent traveling to get velocity VectorScale (destdelta, 1.0 / traveltime, ent->avelocity); // set nextthink to trigger a think when dest is reached ent->nextthink = level.time + frames * FRAMETIME; ent->think = AngleMove_Final;} void AngleMove_Calc (edict_t *ent, void(*func)(edict_t*)){ VectorClear (ent->avelocity); ent->moveinfo.endfunc = func; if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent)) { AngleMove_Begin (ent); } else { ent->nextthink = level.time + FRAMETIME; ent->think = AngleMove_Begin; }} /*==============Think_AccelMove The team has completed a frame of movement, sochange the speed for the next frame==============*/#define AccelerationDistance(target, rate) (target * ((target / rate) + 1) / 2) void plat_CalcAcceleratedMove(moveinfo_t *moveinfo){ float accel_dist; float decel_dist; moveinfo->move_speed = moveinfo->speed; if (moveinfo->remaining_distance < moveinfo->accel) { moveinfo->current_speed = moveinfo->remaining_distance; return; } accel_dist = AccelerationDistance (moveinfo->speed, moveinfo->accel); decel_dist = AccelerationDistance (moveinfo->speed, moveinfo->decel); if ((moveinfo->remaining_distance - accel_dist - decel_dist) < 0) { float f; f = (moveinfo->accel + moveinfo->decel) / (moveinfo->accel * moveinfo->decel); moveinfo->move_speed = (-2 + sqrt(4 - 4 * f * (-2 * moveinfo->remaining_distance))) / (2 * f); decel_dist = AccelerationDistance (moveinfo->move_speed, moveinfo->decel); } moveinfo->decel_distance = decel_dist;}; void plat_Accelerate (moveinfo_t *moveinfo){ // are we decelerating? if (moveinfo->remaining_distance <= moveinfo->decel_distance) { if (moveinfo->remaining_distance < moveinfo->decel_distance) { if (moveinfo->next_speed) { moveinfo->current_speed = moveinfo->next_speed; moveinfo->next_speed = 0; return; } if (moveinfo->current_speed > moveinfo->decel) moveinfo->current_speed -= moveinfo->decel; } return; } // are we at full speed and need to start decelerating during this move? if (moveinfo->current_speed == moveinfo->move_speed) if ((moveinfo->remaining_distance - moveinfo->current_speed) < moveinfo->decel_distance) { float p1_distance; float p2_distance; float distance; p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance; p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / moveinfo->move_speed)); distance = p1_distance + p2_distance; moveinfo->current_speed = moveinfo->move_speed; moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance); return; } // are we accelerating? if (moveinfo->current_speed < moveinfo->speed) { float old_speed; float p1_distance; float p1_speed; float p2_distance; float distance; old_speed = moveinfo->current_speed; // figure simple acceleration up to move_speed moveinfo->current_speed += moveinfo->accel; if (moveinfo->current_speed > moveinfo->speed) moveinfo->current_speed = moveinfo->speed; // are we accelerating throughout this entire move? if ((moveinfo->remaining_distance - moveinfo->current_speed) >= moveinfo->decel_distance) return; // during this move we will accelrate from current_speed to move_speed // and cross over the decel_distance; figure the average speed for the // entire move p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance; p1_speed = (old_speed + moveinfo->move_speed) / 2.0; p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / p1_speed)); distance = p1_distance + p2_distance; moveinfo->current_speed = (p1_speed * (p1_distance / distance)) + (moveinfo->move_speed * (p2_distance / distance)); moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance); return; } // we are at constant velocity (move_speed) return;}; void Think_AccelMove (edict_t *ent){ ent->moveinfo.remaining_distance -= ent->moveinfo.current_speed; if (ent->moveinfo.current_speed == 0) // starting or blocked plat_CalcAcceleratedMove(&ent->moveinfo); plat_Accelerate (&ent->moveinfo); // will the entire move complete on next frame? if (ent->moveinfo.remaining_distance <= ent->moveinfo.current_speed) { Move_Final (ent); return; } VectorScale (ent->moveinfo.dir, ent->moveinfo.current_speed*10, ent->velocity); ent->nextthink = level.time + FRAMETIME; ent->think = Think_AccelMove;} void plat_go_down (edict_t *ent); void plat_hit_top (edict_t *ent){ if (!(ent->flags & FL_TEAMSLAVE)) { if (ent->moveinfo.sound_end) gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0); ent->s.sound = 0; } ent->moveinfo.state = STATE_TOP; ent->think = plat_go_down; ent->nextthink = level.time + 3;} void plat_hit_bottom (edict_t *ent){ if (!(ent->flags & FL_TEAMSLAVE)) { if (ent->moveinfo.sound_end) gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0); ent->s.sound = 0; } ent->moveinfo.state = STATE_BOTTOM;} void plat_go_down (edict_t *ent){ if (!(ent->flags & FL_TEAMSLAVE)) { if (ent->moveinfo.sound_start) gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0); ent->s.sound = ent->moveinfo.sound_middle; } ent->moveinfo.state = STATE_DOWN; Move_Calc (ent, ent->moveinfo.end_origin, plat_hit_bottom);} void plat_go_up (edict_t *ent){ if (!(ent->flags & FL_TEAMSLAVE)) { if (ent->moveinfo.sound_start) gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0); ent->s.sound = ent->moveinfo.sound_middle; } ent->moveinfo.state = STATE_UP; Move_Calc (ent, ent->moveinfo.start_origin, plat_hit_top);} void plat_blocked (edict_t *self, edict_t *other){ if (!(other->svflags & SVF_MONSTER) && (!other->client) ) { // give it a chance to go away on it's own terms (like gibs) T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it if (other) BecomeExplosion1 (other); return; } T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH); if (self->moveinfo.state == STATE_UP) plat_go_down (self); else if (self->moveinfo.state == STATE_DOWN) plat_go_up (self);} void Use_Plat (edict_t *ent, edict_t */*other*/, edict_t */*activator*/){ if (ent->think) return; // already down plat_go_down (ent);} void Touch_Plat_Center (edict_t *ent, edict_t *other, cplane_t */*plane*/, csurface_t */*surf*/){ if (!other->client) return; if (other->health <= 0) return; ent = ent->enemy; // now point at the plat, not the trigger if (ent->moveinfo.state == STATE_BOTTOM) plat_go_up (ent); else if (ent->moveinfo.state == STATE_TOP) ent->nextthink = level.time + 1; // the player is still on the plat, so delay going down} void plat_spawn_inside_trigger (edict_t *ent){ edict_t *trigger; vec3_t tmin, tmax; //// middle trigger// trigger = G_Spawn(); trigger->touch = Touch_Plat_Center; trigger->movetype = MOVETYPE_NONE; trigger->solid = SOLID_TRIGGER; trigger->enemy = ent; tmin[0] = ent->mins[0] + 25; tmin[1] = ent->mins[1] + 25; tmin[2] = ent->mins[2]; tmax[0] = ent->maxs[0] - 25; tmax[1] = ent->maxs[1] - 25; tmax[2] = ent->maxs[2] + 8; tmin[2] = tmax[2] - (ent->pos1[2] - ent->pos2[2] + st.lip); if (ent->spawnflags & PLAT_LOW_TRIGGER) tmax[2] = tmin[2] + 8; if (tmax[0] - tmin[0] <= 0) { tmin[0] = (ent->mins[0] + ent->maxs[0]) *0.5; tmax[0] = tmin[0] + 1; } if (tmax[1] - tmin[1] <= 0) { tmin[1] = (ent->mins[1] + ent->maxs[1]) *0.5; tmax[1] = tmin[1] + 1; } VectorCopy (tmin, trigger->mins); VectorCopy (tmax, trigger->maxs); gi.linkentity (trigger);} /*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGERspeed default 150 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. "speed" overrides default 200."accel" overrides default 500"lip" overrides default 8 pixel lip If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determoveinfoned by the model's height. Set "sounds" to one of the following:1) base fast2) chain slow*/void SP_func_plat (edict_t *ent){ VectorClear (ent->s.angles);Lines 1–500 of 2033. Load more
#include <u.h> #include <libc.h> #include <stdio.h> #include "../dat.h" #include "../fns.h" /* ========================================================= PLATS movement options: linear smooth start, hard stop smooth start, smooth stop start end acceleration speed deceleration begin sound end sound target fired when reaching end wait at end object characteristics that use move segments --------------------------------------------- movetype_push, or movetype_stop action when touched action when blocked action when used disabled? auto trigger spawning ========================================================= */ #define PLAT_LOW_TRIGGER 1 #define STATE_TOP 0 #define STATE_BOTTOM 1 #define STATE_UP 2 #define STATE_DOWN 3 #define DOOR_START_OPEN 1 #define DOOR_REVERSE 2 #define DOOR_CRUSHER 4 #define DOOR_NOMONSTER 8 #define DOOR_TOGGLE 32 #define DOOR_X_AXIS 64 #define DOOR_Y_AXIS 128 // // Support routines for movement (changes in origin using velocity) // void Move_Done (edict_t *ent) { VectorClear (ent->velocity); ent->moveinfo.endfunc (ent); } void Move_Final (edict_t *ent) { if (ent->moveinfo.remaining_distance == 0) { Move_Done (ent); return; } VectorScale (ent->moveinfo.dir, ent->moveinfo.remaining_distance / FRAMETIME, ent->velocity); ent->think = Move_Done; ent->nextthink = level.time + FRAMETIME; } void Move_Begin (edict_t *ent) { float frames; if ((ent->moveinfo.speed * FRAMETIME) >= ent->moveinfo.remaining_distance) { Move_Final (ent); return; } VectorScale (ent->moveinfo.dir, ent->moveinfo.speed, ent->velocity); frames = floor((ent->moveinfo.remaining_distance / ent->moveinfo.speed) / FRAMETIME); ent->moveinfo.remaining_distance -= frames * ent->moveinfo.speed * FRAMETIME; ent->nextthink = level.time + (frames * FRAMETIME); ent->think = Move_Final; } void Think_AccelMove (edict_t *ent); void Move_Calc (edict_t *ent, vec3_t dest, void(*func)(edict_t*)) { VectorClear (ent->velocity); VectorSubtract (dest, ent->s.origin, ent->moveinfo.dir); ent->moveinfo.remaining_distance = VectorNormalize (ent->moveinfo.dir); ent->moveinfo.endfunc = func; if (ent->moveinfo.speed == ent->moveinfo.accel && ent->moveinfo.speed == ent->moveinfo.decel) { if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent)) { Move_Begin (ent); } else { ent->nextthink = level.time + FRAMETIME; ent->think = Move_Begin; } } else { // accelerative ent->moveinfo.current_speed = 0; ent->think = Think_AccelMove; ent->nextthink = level.time + FRAMETIME; } } // // Support routines for angular movement (changes in angle using avelocity) // void AngleMove_Done (edict_t *ent) { VectorClear (ent->avelocity); ent->moveinfo.endfunc (ent); } void AngleMove_Final (edict_t *ent) { vec3_t move; if (ent->moveinfo.state == STATE_UP) VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, move); else VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, move); if (VectorCompare (move, vec3_origin)) { AngleMove_Done (ent); return; } VectorScale (move, 1.0/FRAMETIME, ent->avelocity); ent->think = AngleMove_Done; ent->nextthink = level.time + FRAMETIME; } void AngleMove_Begin (edict_t *ent) { vec3_t destdelta; float len; float traveltime; float frames; // set destdelta to the vector needed to move if (ent->moveinfo.state == STATE_UP) VectorSubtract (ent->moveinfo.end_angles, ent->s.angles, destdelta); else VectorSubtract (ent->moveinfo.start_angles, ent->s.angles, destdelta); // calculate length of vector len = VectorLength (destdelta); // divide by speed to get time to reach dest traveltime = len / ent->moveinfo.speed; if (traveltime < FRAMETIME) { AngleMove_Final (ent); return; } frames = floor(traveltime / FRAMETIME); // scale the destdelta vector by the time spent traveling to get velocity VectorScale (destdelta, 1.0 / traveltime, ent->avelocity); // set nextthink to trigger a think when dest is reached ent->nextthink = level.time + frames * FRAMETIME; ent->think = AngleMove_Final; } void AngleMove_Calc (edict_t *ent, void(*func)(edict_t*)) { VectorClear (ent->avelocity); ent->moveinfo.endfunc = func; if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent)) { AngleMove_Begin (ent); } else { ent->nextthink = level.time + FRAMETIME; ent->think = AngleMove_Begin; } } /* ============== Think_AccelMove The team has completed a frame of movement, so change the speed for the next frame ============== */ #define AccelerationDistance(target, rate) (target * ((target / rate) + 1) / 2) void plat_CalcAcceleratedMove(moveinfo_t *moveinfo) { float accel_dist; float decel_dist; moveinfo->move_speed = moveinfo->speed; if (moveinfo->remaining_distance < moveinfo->accel) { moveinfo->current_speed = moveinfo->remaining_distance; return; } accel_dist = AccelerationDistance (moveinfo->speed, moveinfo->accel); decel_dist = AccelerationDistance (moveinfo->speed, moveinfo->decel); if ((moveinfo->remaining_distance - accel_dist - decel_dist) < 0) { float f; f = (moveinfo->accel + moveinfo->decel) / (moveinfo->accel * moveinfo->decel); moveinfo->move_speed = (-2 + sqrt(4 - 4 * f * (-2 * moveinfo->remaining_distance))) / (2 * f); decel_dist = AccelerationDistance (moveinfo->move_speed, moveinfo->decel); } moveinfo->decel_distance = decel_dist; }; void plat_Accelerate (moveinfo_t *moveinfo) { // are we decelerating? if (moveinfo->remaining_distance <= moveinfo->decel_distance) { if (moveinfo->remaining_distance < moveinfo->decel_distance) { if (moveinfo->next_speed) { moveinfo->current_speed = moveinfo->next_speed; moveinfo->next_speed = 0; return; } if (moveinfo->current_speed > moveinfo->decel) moveinfo->current_speed -= moveinfo->decel; } return; } // are we at full speed and need to start decelerating during this move? if (moveinfo->current_speed == moveinfo->move_speed) if ((moveinfo->remaining_distance - moveinfo->current_speed) < moveinfo->decel_distance) { float p1_distance; float p2_distance; float distance; p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance; p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / moveinfo->move_speed)); distance = p1_distance + p2_distance; moveinfo->current_speed = moveinfo->move_speed; moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance); return; } // are we accelerating? if (moveinfo->current_speed < moveinfo->speed) { float old_speed; float p1_distance; float p1_speed; float p2_distance; float distance; old_speed = moveinfo->current_speed; // figure simple acceleration up to move_speed moveinfo->current_speed += moveinfo->accel; if (moveinfo->current_speed > moveinfo->speed) moveinfo->current_speed = moveinfo->speed; // are we accelerating throughout this entire move? if ((moveinfo->remaining_distance - moveinfo->current_speed) >= moveinfo->decel_distance) return; // during this move we will accelrate from current_speed to move_speed // and cross over the decel_distance; figure the average speed for the // entire move p1_distance = moveinfo->remaining_distance - moveinfo->decel_distance; p1_speed = (old_speed + moveinfo->move_speed) / 2.0; p2_distance = moveinfo->move_speed * (1.0 - (p1_distance / p1_speed)); distance = p1_distance + p2_distance; moveinfo->current_speed = (p1_speed * (p1_distance / distance)) + (moveinfo->move_speed * (p2_distance / distance)); moveinfo->next_speed = moveinfo->move_speed - moveinfo->decel * (p2_distance / distance); return; } // we are at constant velocity (move_speed) return; }; void Think_AccelMove (edict_t *ent) { ent->moveinfo.remaining_distance -= ent->moveinfo.current_speed; if (ent->moveinfo.current_speed == 0) // starting or blocked plat_CalcAcceleratedMove(&ent->moveinfo); plat_Accelerate (&ent->moveinfo); // will the entire move complete on next frame? if (ent->moveinfo.remaining_distance <= ent->moveinfo.current_speed) { Move_Final (ent); return; } VectorScale (ent->moveinfo.dir, ent->moveinfo.current_speed*10, ent->velocity); ent->nextthink = level.time + FRAMETIME; ent->think = Think_AccelMove; } void plat_go_down (edict_t *ent); void plat_hit_top (edict_t *ent) { if (!(ent->flags & FL_TEAMSLAVE)) { if (ent->moveinfo.sound_end) gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0); ent->s.sound = 0; } ent->moveinfo.state = STATE_TOP; ent->think = plat_go_down; ent->nextthink = level.time + 3; } void plat_hit_bottom (edict_t *ent) { if (!(ent->flags & FL_TEAMSLAVE)) { if (ent->moveinfo.sound_end) gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_end, 1, ATTN_STATIC, 0); ent->s.sound = 0; } ent->moveinfo.state = STATE_BOTTOM; } void plat_go_down (edict_t *ent) { if (!(ent->flags & FL_TEAMSLAVE)) { if (ent->moveinfo.sound_start) gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0); ent->s.sound = ent->moveinfo.sound_middle; } ent->moveinfo.state = STATE_DOWN; Move_Calc (ent, ent->moveinfo.end_origin, plat_hit_bottom); } void plat_go_up (edict_t *ent) { if (!(ent->flags & FL_TEAMSLAVE)) { if (ent->moveinfo.sound_start) gi.sound (ent, CHAN_NO_PHS_ADD+CHAN_VOICE, ent->moveinfo.sound_start, 1, ATTN_STATIC, 0); ent->s.sound = ent->moveinfo.sound_middle; } ent->moveinfo.state = STATE_UP; Move_Calc (ent, ent->moveinfo.start_origin, plat_hit_top); } void plat_blocked (edict_t *self, edict_t *other) { if (!(other->svflags & SVF_MONSTER) && (!other->client) ) { // give it a chance to go away on it's own terms (like gibs) T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, 100000, 1, 0, MOD_CRUSH); // if it's still there, nuke it if (other) BecomeExplosion1 (other); return; } T_Damage (other, self, self, vec3_origin, other->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH); if (self->moveinfo.state == STATE_UP) plat_go_down (self); else if (self->moveinfo.state == STATE_DOWN) plat_go_up (self); } void Use_Plat (edict_t *ent, edict_t */*other*/, edict_t */*activator*/) { if (ent->think) return; // already down plat_go_down (ent); } void Touch_Plat_Center (edict_t *ent, edict_t *other, cplane_t */*plane*/, csurface_t */*surf*/) { if (!other->client) return; if (other->health <= 0) return; ent = ent->enemy; // now point at the plat, not the trigger if (ent->moveinfo.state == STATE_BOTTOM) plat_go_up (ent); else if (ent->moveinfo.state == STATE_TOP) ent->nextthink = level.time + 1; // the player is still on the plat, so delay going down } void plat_spawn_inside_trigger (edict_t *ent) { edict_t *trigger; vec3_t tmin, tmax; // // middle trigger // trigger = G_Spawn(); trigger->touch = Touch_Plat_Center; trigger->movetype = MOVETYPE_NONE; trigger->solid = SOLID_TRIGGER; trigger->enemy = ent; tmin[0] = ent->mins[0] + 25; tmin[1] = ent->mins[1] + 25; tmin[2] = ent->mins[2]; tmax[0] = ent->maxs[0] - 25; tmax[1] = ent->maxs[1] - 25; tmax[2] = ent->maxs[2] + 8; tmin[2] = tmax[2] - (ent->pos1[2] - ent->pos2[2] + st.lip); if (ent->spawnflags & PLAT_LOW_TRIGGER) tmax[2] = tmin[2] + 8; if (tmax[0] - tmin[0] <= 0) { tmin[0] = (ent->mins[0] + ent->maxs[0]) *0.5; tmax[0] = tmin[0] + 1; } if (tmax[1] - tmin[1] <= 0) { tmin[1] = (ent->mins[1] + ent->maxs[1]) *0.5; tmax[1] = tmin[1] + 1; } VectorCopy (tmin, trigger->mins); VectorCopy (tmax, trigger->maxs); gi.linkentity (trigger); } /*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER speed default 150 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. "speed" overrides default 200. "accel" overrides default 500 "lip" overrides default 8 pixel lip If the "height" key is set, that will determine the amount the plat moves, instead of being implicitly determoveinfoned by the model's height. Set "sounds" to one of the following: 1) base fast 2) chain slow */ void SP_func_plat (edict_t *ent) { VectorClear (ent->s.angles);