summaryrefslogtreecommitdiff
path: root/src/hexen/p_floor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hexen/p_floor.c')
-rw-r--r--src/hexen/p_floor.c952
1 files changed, 952 insertions, 0 deletions
diff --git a/src/hexen/p_floor.c b/src/hexen/p_floor.c
new file mode 100644
index 00000000..40f9b934
--- /dev/null
+++ b/src/hexen/p_floor.c
@@ -0,0 +1,952 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+
+
+#include "h2def.h"
+#include "i_system.h"
+#include "p_local.h"
+
+extern fixed_t FloatBobOffsets[64];
+
+//==================================================================
+//==================================================================
+//
+// FLOORS
+//
+//==================================================================
+//==================================================================
+
+//==================================================================
+//
+// Move a plane (floor or ceiling) and check for crushing
+//
+//==================================================================
+result_e T_MovePlane(sector_t * sector, fixed_t speed,
+ fixed_t dest, int crush, int floorOrCeiling,
+ int direction)
+{
+ boolean flag;
+ fixed_t lastpos;
+
+ switch (floorOrCeiling)
+ {
+ case 0: // FLOOR
+ switch (direction)
+ {
+ case -1: // DOWN
+ if (sector->floorheight - speed < dest)
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight = dest;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector, crush);
+ //return RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight -= speed;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_CRUSHED;
+ }
+ }
+ break;
+
+ case 1: // UP
+ if (sector->floorheight + speed > dest)
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight = dest;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector, crush);
+ //return RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else // COULD GET CRUSHED
+ {
+ lastpos = sector->floorheight;
+ sector->floorheight += speed;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ //if (crush == true)
+ //{
+ // return RES_CRUSHED;
+ //}
+ sector->floorheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_CRUSHED;
+ }
+ }
+ break;
+ }
+ break;
+
+ case 1: // CEILING
+ switch (direction)
+ {
+ case -1: // DOWN
+ if (sector->ceilingheight - speed < dest)
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight = dest;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector, crush);
+ //return RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else // COULD GET CRUSHED
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight -= speed;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ //if (crush == true)
+ //{
+ // return RES_CRUSHED;
+ //}
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_CRUSHED;
+ }
+ }
+ break;
+
+ case 1: // UP
+ if (sector->ceilingheight + speed > dest)
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight = dest;
+ flag = P_ChangeSector(sector, crush);
+ if (flag == true)
+ {
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector, crush);
+ //return RES_CRUSHED;
+ }
+ return RES_PASTDEST;
+ }
+ else
+ {
+ lastpos = sector->ceilingheight;
+ sector->ceilingheight += speed;
+ flag = P_ChangeSector(sector, crush);
+#if 0
+ if (flag == true)
+ {
+ sector->ceilingheight = lastpos;
+ P_ChangeSector(sector, crush);
+ return RES_CRUSHED;
+ }
+#endif
+ }
+ break;
+ }
+ break;
+
+ }
+ return RES_OK;
+}
+
+//==================================================================
+//
+// MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
+//
+//==================================================================
+void T_MoveFloor(floormove_t * floor)
+{
+ result_e res;
+
+ if (floor->resetDelayCount)
+ {
+ floor->resetDelayCount--;
+ if (!floor->resetDelayCount)
+ {
+ floor->floordestheight = floor->resetHeight;
+ floor->direction = -floor->direction;
+ floor->resetDelay = 0;
+ floor->delayCount = 0;
+ floor->delayTotal = 0;
+ }
+ }
+ if (floor->delayCount)
+ {
+ floor->delayCount--;
+ if (!floor->delayCount && floor->textureChange)
+ {
+ floor->sector->floorpic += floor->textureChange;
+ }
+ return;
+ }
+
+ res = T_MovePlane(floor->sector, floor->speed,
+ floor->floordestheight, floor->crush, 0,
+ floor->direction);
+
+ if (floor->type == FLEV_RAISEBUILDSTEP)
+ {
+ if ((floor->direction == 1 && floor->sector->floorheight >=
+ floor->stairsDelayHeight) || (floor->direction == -1 &&
+ floor->sector->floorheight <=
+ floor->stairsDelayHeight))
+ {
+ floor->delayCount = floor->delayTotal;
+ floor->stairsDelayHeight += floor->stairsDelayHeightDelta;
+ }
+ }
+ if (res == RES_PASTDEST)
+ {
+ SN_StopSequence((mobj_t *) & floor->sector->soundorg);
+ if (floor->delayTotal)
+ {
+ floor->delayTotal = 0;
+ }
+ if (floor->resetDelay)
+ {
+// floor->resetDelayCount = floor->resetDelay;
+// floor->resetDelay = 0;
+ return;
+ }
+ floor->sector->specialdata = NULL;
+ /*
+ if (floor->direction == 1)
+ switch(floor->type)
+ {
+ case donutRaise:
+ floor->sector->special = floor->newspecial;
+ floor->sector->floorpic = floor->texture;
+ default:
+ break;
+ }
+ else if (floor->direction == -1)
+ switch(floor->type)
+ {
+ case lowerAndChange:
+ floor->sector->special = floor->newspecial;
+ floor->sector->floorpic = floor->texture;
+ default:
+ break;
+ }
+ */
+ if (floor->textureChange)
+ {
+ floor->sector->floorpic -= floor->textureChange;
+ }
+ P_TagFinished(floor->sector->tag);
+ P_RemoveThinker(&floor->thinker);
+ }
+}
+
+//==================================================================
+//
+// HANDLE FLOOR TYPES
+//
+//==================================================================
+int EV_DoFloor(line_t * line, byte * args, floor_e floortype)
+{
+ int secnum;
+ int rtn;
+ sector_t *sec;
+ floormove_t *floor = NULL;
+
+ secnum = -1;
+ rtn = 0;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+
+ // ALREADY MOVING? IF SO, KEEP GOING...
+ if (sec->specialdata)
+ continue;
+
+ //
+ // new floor thinker
+ //
+ rtn = 1;
+ floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
+ memset(floor, 0, sizeof(*floor));
+ P_AddThinker(&floor->thinker);
+ sec->specialdata = floor;
+ floor->thinker.function = T_MoveFloor;
+ floor->type = floortype;
+ floor->crush = 0;
+ floor->speed = args[1] * (FRACUNIT / 8);
+ if (floortype == FLEV_LOWERTIMES8INSTANT ||
+ floortype == FLEV_RAISETIMES8INSTANT)
+ {
+ floor->speed = 2000 << FRACBITS;
+ }
+ switch (floortype)
+ {
+ case FLEV_LOWERFLOOR:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = P_FindHighestFloorSurrounding(sec);
+ break;
+ case FLEV_LOWERFLOORTOLOWEST:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = P_FindLowestFloorSurrounding(sec);
+ break;
+ case FLEV_LOWERFLOORBYVALUE:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight -
+ args[2] * FRACUNIT;
+ break;
+ case FLEV_LOWERTIMES8INSTANT:
+ case FLEV_LOWERBYVALUETIMES8:
+ floor->direction = -1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight -
+ args[2] * FRACUNIT * 8;
+ break;
+ case FLEV_RAISEFLOORCRUSH:
+ floor->crush = args[2]; // arg[2] = crushing value
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = sec->ceilingheight - 8 * FRACUNIT;
+ break;
+ case FLEV_RAISEFLOOR:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
+ if (floor->floordestheight > sec->ceilingheight)
+ floor->floordestheight = sec->ceilingheight;
+ break;
+ case FLEV_RAISEFLOORTONEAREST:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight =
+ P_FindNextHighestFloor(sec, sec->floorheight);
+ break;
+ case FLEV_RAISEFLOORBYVALUE:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight +
+ args[2] * FRACUNIT;
+ break;
+ case FLEV_RAISETIMES8INSTANT:
+ case FLEV_RAISEBYVALUETIMES8:
+ floor->direction = 1;
+ floor->sector = sec;
+ floor->floordestheight = floor->sector->floorheight +
+ args[2] * FRACUNIT * 8;
+ break;
+ case FLEV_MOVETOVALUETIMES8:
+ floor->sector = sec;
+ floor->floordestheight = args[2] * FRACUNIT * 8;
+ if (args[3])
+ {
+ floor->floordestheight = -floor->floordestheight;
+ }
+ if (floor->floordestheight > floor->sector->floorheight)
+ {
+ floor->direction = 1;
+ }
+ else if (floor->floordestheight < floor->sector->floorheight)
+ {
+ floor->direction = -1;
+ }
+ else
+ { // already at lowest position
+ rtn = 0;
+ }
+ break;
+ default:
+ rtn = 0;
+ break;
+ }
+ }
+ if (rtn)
+ {
+ SN_StartSequence((mobj_t *) & floor->sector->soundorg,
+ SEQ_PLATFORM + floor->sector->seqType);
+ }
+ return rtn;
+}
+
+//============================================================================
+//
+// EV_DoFloorAndCeiling
+//
+//============================================================================
+
+int EV_DoFloorAndCeiling(line_t * line, byte * args, boolean raise)
+{
+ boolean floor, ceiling;
+ int secnum;
+ sector_t *sec;
+
+ if (raise)
+ {
+ floor = EV_DoFloor(line, args, FLEV_RAISEFLOORBYVALUE);
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ sec->specialdata = NULL;
+ }
+ ceiling = EV_DoCeiling(line, args, CLEV_RAISEBYVALUE);
+ }
+ else
+ {
+ floor = EV_DoFloor(line, args, FLEV_LOWERFLOORBYVALUE);
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ sec->specialdata = NULL;
+ }
+ ceiling = EV_DoCeiling(line, args, CLEV_LOWERBYVALUE);
+ }
+ return (floor | ceiling);
+}
+
+// ===== Build Stairs Private Data =====
+
+#define STAIR_SECTOR_TYPE 26
+#define STAIR_QUEUE_SIZE 32
+
+struct
+{
+ sector_t *sector;
+ int type;
+ int height;
+} StairQueue[STAIR_QUEUE_SIZE];
+
+static int QueueHead;
+static int QueueTail;
+
+static int StepDelta;
+static int Direction;
+static int Speed;
+static int Texture;
+static int StartDelay;
+static int StartDelayDelta;
+static int TextureChange;
+static int StartHeight;
+
+//==========================================================================
+//
+// QueueStairSector
+//
+//==========================================================================
+
+static void QueueStairSector(sector_t * sec, int type, int height)
+{
+ if ((QueueTail + 1) % STAIR_QUEUE_SIZE == QueueHead)
+ {
+ I_Error("BuildStairs: Too many branches located.\n");
+ }
+ StairQueue[QueueTail].sector = sec;
+ StairQueue[QueueTail].type = type;
+ StairQueue[QueueTail].height = height;
+
+ QueueTail = (QueueTail + 1) % STAIR_QUEUE_SIZE;
+}
+
+//==========================================================================
+//
+// DequeueStairSector
+//
+//==========================================================================
+
+static sector_t *DequeueStairSector(int *type, int *height)
+{
+ sector_t *sec;
+
+ if (QueueHead == QueueTail)
+ { // queue is empty
+ return NULL;
+ }
+ *type = StairQueue[QueueHead].type;
+ *height = StairQueue[QueueHead].height;
+ sec = StairQueue[QueueHead].sector;
+ QueueHead = (QueueHead + 1) % STAIR_QUEUE_SIZE;
+
+ return sec;
+}
+
+//==========================================================================
+//
+// ProcessStairSector
+//
+//==========================================================================
+
+static void ProcessStairSector(sector_t * sec, int type, int height,
+ stairs_e stairsType, int delay, int resetDelay)
+{
+ int i;
+ sector_t *tsec;
+ floormove_t *floor;
+
+ //
+ // new floor thinker
+ //
+ height += StepDelta;
+ floor = Z_Malloc(sizeof(*floor), PU_LEVSPEC, 0);
+ memset(floor, 0, sizeof(*floor));
+ P_AddThinker(&floor->thinker);
+ sec->specialdata = floor;
+ floor->thinker.function = T_MoveFloor;
+ floor->type = FLEV_RAISEBUILDSTEP;
+ floor->direction = Direction;
+ floor->sector = sec;
+ floor->floordestheight = height;
+ switch (stairsType)
+ {
+ case STAIRS_NORMAL:
+ floor->speed = Speed;
+ if (delay)
+ {
+ floor->delayTotal = delay;
+ floor->stairsDelayHeight = sec->floorheight + StepDelta;
+ floor->stairsDelayHeightDelta = StepDelta;
+ }
+ floor->resetDelay = resetDelay;
+ floor->resetDelayCount = resetDelay;
+ floor->resetHeight = sec->floorheight;
+ break;
+ case STAIRS_SYNC:
+ floor->speed = FixedMul(Speed, FixedDiv(height - StartHeight,
+ StepDelta));
+ floor->resetDelay = delay; //arg4
+ floor->resetDelayCount = delay;
+ floor->resetHeight = sec->floorheight;
+ break;
+/*
+ case STAIRS_PHASED:
+ floor->floordestheight = sec->floorheight+StepDelta;
+ floor->speed = Speed;
+ floor->delayCount = StartDelay;
+ StartDelay += StartDelayDelta;
+ floor->textureChange = TextureChange;
+ floor->resetDelayCount = StartDelay;
+ break;
+*/
+ default:
+ break;
+ }
+ SN_StartSequence((mobj_t *) & sec->soundorg, SEQ_PLATFORM + sec->seqType);
+ //
+ // Find next sector to raise
+ // Find nearby sector with sector special equal to type
+ //
+ for (i = 0; i < sec->linecount; i++)
+ {
+ if (!((sec->lines[i])->flags & ML_TWOSIDED))
+ {
+ continue;
+ }
+ tsec = (sec->lines[i])->frontsector;
+ if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata
+ && tsec->floorpic == Texture && tsec->validcount != validcount)
+ {
+ QueueStairSector(tsec, type ^ 1, height);
+ tsec->validcount = validcount;
+ //tsec->special = 0;
+ }
+ tsec = (sec->lines[i])->backsector;
+ if (tsec->special == type + STAIR_SECTOR_TYPE && !tsec->specialdata
+ && tsec->floorpic == Texture && tsec->validcount != validcount)
+ {
+ QueueStairSector(tsec, type ^ 1, height);
+ tsec->validcount = validcount;
+ //tsec->special = 0;
+ }
+ }
+}
+
+//==================================================================
+//
+// BUILD A STAIRCASE!
+//
+// Direction is either positive or negative, denoting build stairs
+// up or down.
+//==================================================================
+
+int EV_BuildStairs(line_t * line, byte * args, int direction,
+ stairs_e stairsType)
+{
+ int secnum;
+ int height;
+ int delay;
+ int resetDelay;
+ sector_t *sec;
+ sector_t *qSec;
+ int type;
+
+ // Set global stairs variables
+ TextureChange = 0;
+ Direction = direction;
+ StepDelta = Direction * (args[2] * FRACUNIT);
+ Speed = args[1] * (FRACUNIT / 8);
+ resetDelay = args[4];
+ delay = args[3];
+ if (stairsType == STAIRS_PHASED)
+ {
+ StartDelayDelta = args[3];
+ StartDelay = StartDelayDelta;
+ resetDelay = StartDelayDelta;
+ delay = 0;
+ TextureChange = args[4];
+ }
+
+ secnum = -1;
+
+ validcount++;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+
+ Texture = sec->floorpic;
+ StartHeight = sec->floorheight;
+
+ // ALREADY MOVING? IF SO, KEEP GOING...
+ if (sec->specialdata)
+ continue;
+
+ QueueStairSector(sec, 0, sec->floorheight);
+ sec->special = 0;
+ }
+ while ((qSec = DequeueStairSector(&type, &height)) != NULL)
+ {
+ ProcessStairSector(qSec, type, height, stairsType, delay, resetDelay);
+ }
+ return (1);
+}
+
+//=========================================================================
+//
+// T_BuildPillar
+//
+//=========================================================================
+
+void T_BuildPillar(pillar_t * pillar)
+{
+ result_e res1;
+ result_e res2;
+
+ // First, raise the floor
+ res1 = T_MovePlane(pillar->sector, pillar->floorSpeed, pillar->floordest, pillar->crush, 0, pillar->direction); // floorOrCeiling, direction
+ // Then, lower the ceiling
+ res2 = T_MovePlane(pillar->sector, pillar->ceilingSpeed,
+ pillar->ceilingdest, pillar->crush, 1,
+ -pillar->direction);
+ if (res1 == RES_PASTDEST && res2 == RES_PASTDEST)
+ {
+ pillar->sector->specialdata = NULL;
+ SN_StopSequence((mobj_t *) & pillar->sector->soundorg);
+ P_TagFinished(pillar->sector->tag);
+ P_RemoveThinker(&pillar->thinker);
+ }
+}
+
+//=========================================================================
+//
+// EV_BuildPillar
+//
+//=========================================================================
+
+int EV_BuildPillar(line_t * line, byte * args, boolean crush)
+{
+ int secnum;
+ sector_t *sec;
+ pillar_t *pillar;
+ int newHeight;
+ int rtn;
+
+ rtn = 0;
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if (sec->specialdata)
+ continue; // already moving
+ if (sec->floorheight == sec->ceilingheight)
+ { // pillar is already closed
+ continue;
+ }
+ rtn = 1;
+ if (!args[2])
+ {
+ newHeight = sec->floorheight +
+ ((sec->ceilingheight - sec->floorheight) / 2);
+ }
+ else
+ {
+ newHeight = sec->floorheight + (args[2] << FRACBITS);
+ }
+
+ pillar = Z_Malloc(sizeof(*pillar), PU_LEVSPEC, 0);
+ sec->specialdata = pillar;
+ P_AddThinker(&pillar->thinker);
+ pillar->thinker.function = T_BuildPillar;
+ pillar->sector = sec;
+ if (!args[2])
+ {
+ pillar->ceilingSpeed = pillar->floorSpeed =
+ args[1] * (FRACUNIT / 8);
+ }
+ else if (newHeight - sec->floorheight >
+ sec->ceilingheight - newHeight)
+ {
+ pillar->floorSpeed = args[1] * (FRACUNIT / 8);
+ pillar->ceilingSpeed = FixedMul(sec->ceilingheight - newHeight,
+ FixedDiv(pillar->floorSpeed,
+ newHeight -
+ sec->floorheight));
+ }
+ else
+ {
+ pillar->ceilingSpeed = args[1] * (FRACUNIT / 8);
+ pillar->floorSpeed = FixedMul(newHeight - sec->floorheight,
+ FixedDiv(pillar->ceilingSpeed,
+ sec->ceilingheight -
+ newHeight));
+ }
+ pillar->floordest = newHeight;
+ pillar->ceilingdest = newHeight;
+ pillar->direction = 1;
+ pillar->crush = crush * args[3];
+ SN_StartSequence((mobj_t *) & pillar->sector->soundorg,
+ SEQ_PLATFORM + pillar->sector->seqType);
+ }
+ return rtn;
+}
+
+//=========================================================================
+//
+// EV_OpenPillar
+//
+//=========================================================================
+
+int EV_OpenPillar(line_t * line, byte * args)
+{
+ int secnum;
+ sector_t *sec;
+ pillar_t *pillar;
+ int rtn;
+
+ rtn = 0;
+ secnum = -1;
+ while ((secnum = P_FindSectorFromTag(args[0], secnum)) >= 0)
+ {
+ sec = &sectors[secnum];
+ if (sec->specialdata)
+ continue; // already moving
+ if (sec->floorheight != sec->ceilingheight)
+ { // pillar isn't closed
+ continue;
+ }
+ rtn = 1;
+ pillar = Z_Malloc(sizeof(*pillar), PU_LEVSPEC, 0);
+ sec->specialdata = pillar;
+ P_AddThinker(&pillar->thinker);
+ pillar->thinker.function = T_BuildPillar;
+ pillar->sector = sec;
+ if (!args[2])
+ {
+ pillar->floordest = P_FindLowestFloorSurrounding(sec);
+ }
+ else
+ {
+ pillar->floordest = sec->floorheight - (args[2] << FRACBITS);
+ }
+ if (!args[3])
+ {
+ pillar->ceilingdest = P_FindHighestCeilingSurrounding(sec);
+ }
+ else
+ {
+ pillar->ceilingdest = sec->ceilingheight + (args[3] << FRACBITS);
+ }
+ if (sec->floorheight - pillar->floordest >= pillar->ceilingdest -
+ sec->ceilingheight)
+ {
+ pillar->floorSpeed = args[1] * (FRACUNIT / 8);
+ pillar->ceilingSpeed = FixedMul(sec->ceilingheight -
+ pillar->ceilingdest,
+ FixedDiv(pillar->floorSpeed,
+ pillar->floordest -
+ sec->floorheight));
+ }
+ else
+ {
+ pillar->ceilingSpeed = args[1] * (FRACUNIT / 8);
+ pillar->floorSpeed =
+ FixedMul(pillar->floordest - sec->floorheight,
+ FixedDiv(pillar->ceilingSpeed,
+ sec->ceilingheight - pillar->ceilingdest));
+ }
+ pillar->direction = -1; // open the pillar
+ SN_StartSequence((mobj_t *) & pillar->sector->soundorg,
+ SEQ_PLATFORM + pillar->sector->seqType);
+ }
+ return rtn;
+}
+
+//=========================================================================
+//
+// EV_FloorCrushStop
+//
+//=========================================================================
+
+int EV_FloorCrushStop(line_t * line, byte * args)
+{
+ thinker_t *think;
+ floormove_t *floor;
+ boolean rtn;
+
+ rtn = 0;
+ for (think = thinkercap.next; think != &thinkercap; think = think->next)
+ {
+ if (think->function != T_MoveFloor)
+ {
+ continue;
+ }
+ floor = (floormove_t *) think;
+ if (floor->type != FLEV_RAISEFLOORCRUSH)
+ {
+ continue;
+ }
+ // Completely remove the crushing floor
+ SN_StopSequence((mobj_t *) & floor->sector->soundorg);
+ floor->sector->specialdata = NULL;
+ P_TagFinished(floor->sector->tag);
+ P_RemoveThinker(&floor->thinker);
+ rtn = 1;
+ }
+ return rtn;
+}
+
+//==========================================================================
+//
+// T_FloorWaggle
+//
+//==========================================================================
+
+#define WGLSTATE_EXPAND 1
+#define WGLSTATE_STABLE 2
+#define WGLSTATE_REDUCE 3
+
+void T_FloorWaggle(floorWaggle_t * waggle)
+{
+ switch (waggle->state)
+ {
+ case WGLSTATE_EXPAND:
+ if ((waggle->scale += waggle->scaleDelta) >= waggle->targetScale)
+ {
+ waggle->scale = waggle->targetScale;
+ waggle->state = WGLSTATE_STABLE;
+ }
+ break;
+ case WGLSTATE_REDUCE:
+ if ((waggle->scale -= waggle->scaleDelta) <= 0)
+ { // Remove
+ waggle->sector->floorheight = waggle->originalHeight;
+ P_ChangeSector(waggle->sector, true);
+ waggle->sector->specialdata = NULL;
+ P_TagFinished(waggle->sector->tag);
+ P_RemoveThinker(&waggle->thinker);
+ return;
+ }
+ break;
+ case WGLSTATE_STABLE:
+ if (waggle->ticker != -1)
+ {
+ if (!--waggle->ticker)
+ {
+ waggle->state = WGLSTATE_REDUCE;
+ }
+ }
+ break;
+ }
+ waggle->accumulator += waggle->accDelta;
+ waggle->sector->floorheight = waggle->originalHeight
+ + FixedMul(FloatBobOffsets[(waggle->accumulator >> FRACBITS) & 63],
+ waggle->scale);
+ P_ChangeSector(waggle->sector, true);
+}
+
+//==========================================================================
+//
+// EV_StartFloorWaggle
+//
+//==========================================================================
+
+boolean EV_StartFloorWaggle(int tag, int height, int speed, int offset,
+ int timer)
+{
+ int sectorIndex;
+ sector_t *sector;
+ floorWaggle_t *waggle;
+ boolean retCode;
+
+ retCode = false;
+ sectorIndex = -1;
+ while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
+ {
+ sector = &sectors[sectorIndex];
+ if (sector->specialdata)
+ { // Already busy with another thinker
+ continue;
+ }
+ retCode = true;
+ waggle = Z_Malloc(sizeof(*waggle), PU_LEVSPEC, 0);
+ sector->specialdata = waggle;
+ waggle->thinker.function = T_FloorWaggle;
+ waggle->sector = sector;
+ waggle->originalHeight = sector->floorheight;
+ waggle->accumulator = offset * FRACUNIT;
+ waggle->accDelta = speed << 10;
+ waggle->scale = 0;
+ waggle->targetScale = height << 10;
+ waggle->scaleDelta = waggle->targetScale
+ / (35 + ((3 * 35) * height) / 255);
+ waggle->ticker = timer ? timer * 35 : -1;
+ waggle->state = WGLSTATE_EXPAND;
+ P_AddThinker(&waggle->thinker);
+ }
+ return retCode;
+}