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.c931
1 files changed, 931 insertions, 0 deletions
diff --git a/src/hexen/p_floor.c b/src/hexen/p_floor.c
new file mode 100644
index 00000000..41b1575a
--- /dev/null
+++ b/src/hexen/p_floor.c
@@ -0,0 +1,931 @@
+
+//**************************************************************************
+//**
+//** p_floor.c : Heretic 2 : Raven Software, Corp.
+//**
+//** $RCSfile: p_floor.c,v $
+//** $Revision: 1.23 $
+//** $Date: 95/10/06 16:53:19 $
+//** $Author: paul $
+//**
+//**************************************************************************
+
+#include "h2def.h"
+#include "p_local.h"
+#include "soundst.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;
+}