gzdoom/code/P_floor.c

1156 lines
29 KiB
C
Raw Normal View History

1998-04-07 00:00:00 +00:00
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Floor animation: raising stairs.
//
//-----------------------------------------------------------------------------
#include "z_zone.h"
#include "doomdef.h"
#include "p_local.h"
1998-12-22 00:00:00 +00:00
#include "p_lnspec.h"
1998-04-07 00:00:00 +00:00
#include "s_sound.h"
1999-02-17 00:00:00 +00:00
#include "s_sndseq.h"
1998-04-07 00:00:00 +00:00
#include "doomstat.h"
#include "r_state.h"
1998-12-22 00:00:00 +00:00
#include "tables.h"
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
extern fixed_t FloatBobOffsets[64];
1998-04-07 00:00:00 +00:00
//
// FLOORS
//
//
// Move a plane (floor or ceiling) and check for crushing
1998-12-22 00:00:00 +00:00
// [RH] Made crush specify the actual amount of crushing damage inflictable.
// (Use -1 to prevent it from trying to crush)
1998-04-07 00:00:00 +00:00
//
result_e
T_MovePlane
( sector_t* sector,
fixed_t speed,
fixed_t dest,
1998-12-22 00:00:00 +00:00
int crush,
1998-04-07 00:00:00 +00:00
int floorOrCeiling,
int direction )
{
1998-07-14 00:00:00 +00:00
BOOL flag;
1998-04-07 00:00:00 +00:00
fixed_t lastpos;
1998-12-22 00:00:00 +00:00
fixed_t destheight; //jff 02/04/98 used to keep floors/ceilings
// from moving thru each other
1999-02-17 00:00:00 +00:00
switch (floorOrCeiling)
1998-04-07 00:00:00 +00:00
{
case 0:
// FLOOR
1999-02-17 00:00:00 +00:00
switch (direction)
1998-04-07 00:00:00 +00:00
{
case -1:
// DOWN
if (sector->floorheight - speed < dest)
{
lastpos = sector->floorheight;
sector->floorheight = dest;
1999-02-17 00:00:00 +00:00
flag = P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
if (flag == true)
{
1998-12-22 00:00:00 +00:00
sector->floorheight = lastpos;
1999-02-17 00:00:00 +00:00
P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
//return crushed;
}
return pastdest;
}
else
{
lastpos = sector->floorheight;
sector->floorheight -= speed;
1999-02-17 00:00:00 +00:00
flag = P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
if (flag == true)
{
sector->floorheight = lastpos;
1999-02-17 00:00:00 +00:00
P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
return crushed;
}
}
break;
case 1:
// UP
1998-12-22 00:00:00 +00:00
// jff 02/04/98 keep floor from moving thru ceilings
1999-02-17 00:00:00 +00:00
destheight = (dest < sector->ceilingheight) ? dest : sector->ceilingheight;
1998-12-22 00:00:00 +00:00
if (sector->floorheight + speed > destheight)
1998-04-07 00:00:00 +00:00
{
lastpos = sector->floorheight;
1998-12-22 00:00:00 +00:00
sector->floorheight = destheight;
1999-02-17 00:00:00 +00:00
flag = P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
if (flag == true)
{
sector->floorheight = lastpos;
1999-02-17 00:00:00 +00:00
P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
//return crushed;
}
return pastdest;
}
else
{
// COULD GET CRUSHED
lastpos = sector->floorheight;
sector->floorheight += speed;
1999-02-17 00:00:00 +00:00
flag = P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
if (flag == true)
{
if (crush == true)
return crushed;
sector->floorheight = lastpos;
1999-02-17 00:00:00 +00:00
P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
return crushed;
}
}
break;
}
break;
case 1:
// CEILING
switch(direction)
{
case -1:
// DOWN
1998-12-22 00:00:00 +00:00
// jff 02/04/98 keep ceiling from moving thru floors
1999-02-17 00:00:00 +00:00
destheight = (dest > sector->floorheight) ? dest : sector->floorheight;
1998-12-22 00:00:00 +00:00
if (sector->ceilingheight - speed < destheight)
1998-04-07 00:00:00 +00:00
{
lastpos = sector->ceilingheight;
1998-12-22 00:00:00 +00:00
sector->ceilingheight = destheight;
1999-02-17 00:00:00 +00:00
flag = P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
if (flag == true)
{
sector->ceilingheight = lastpos;
1999-02-17 00:00:00 +00:00
P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
//return crushed;
}
return pastdest;
}
else
{
// COULD GET CRUSHED
lastpos = sector->ceilingheight;
sector->ceilingheight -= speed;
1999-02-17 00:00:00 +00:00
flag = P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
if (flag == true)
{
if (crush == true)
return crushed;
sector->ceilingheight = lastpos;
1999-02-17 00:00:00 +00:00
P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
return crushed;
}
}
break;
case 1:
// UP
if (sector->ceilingheight + speed > dest)
{
lastpos = sector->ceilingheight;
sector->ceilingheight = dest;
1999-02-17 00:00:00 +00:00
flag = P_ChangeSector (sector,crush);
1998-04-07 00:00:00 +00:00
if (flag == true)
{
sector->ceilingheight = lastpos;
1999-02-17 00:00:00 +00:00
P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
//return crushed;
}
return pastdest;
}
else
{
lastpos = sector->ceilingheight;
sector->ceilingheight += speed;
1999-02-17 00:00:00 +00:00
flag = P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
// UNUSED
#if 0
if (flag == true)
{
sector->ceilingheight = lastpos;
1999-02-17 00:00:00 +00:00
P_ChangeSector (sector, crush);
1998-04-07 00:00:00 +00:00
return crushed;
}
#endif
}
break;
}
break;
}
return ok;
}
//
// MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
//
1998-07-26 00:00:00 +00:00
void T_MoveFloor (floormove_t *floor)
1998-04-07 00:00:00 +00:00
{
1998-07-26 00:00:00 +00:00
result_e res;
1998-12-22 00:00:00 +00:00
// [RH] Handle reseting stairs
if (floor->type == buildStair || floor->type == waitStair) {
if (floor->resetcount) {
if (--floor->resetcount == 0) {
floor->type = resetStair;
floor->direction = (floor->direction > 0) ? -1 : 1;
floor->floordestheight = floor->orgheight;
}
}
if (floor->pausetime) {
floor->pausetime--;
return;
} else if (floor->steptime) {
if (--floor->steptime == 0) {
floor->pausetime = floor->delay;
floor->steptime = floor->persteptime;
}
}
}
if (floor->type == waitStair)
return;
1998-04-07 00:00:00 +00:00
res = T_MovePlane(floor->sector,
floor->speed,
floor->floordestheight,
floor->crush,0,floor->direction);
if (res == pastdest)
{
1999-02-17 00:00:00 +00:00
SN_StopSequence ((mobj_t *)&floor->sector->soundorg);
1998-04-07 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
if (floor->type == buildStair)
floor->type = waitStair;
if (floor->type != waitStair || floor->resetcount == 0)
1998-04-07 00:00:00 +00:00
{
1998-12-22 00:00:00 +00:00
if (floor->direction == 1)
1998-04-07 00:00:00 +00:00
{
1998-12-22 00:00:00 +00:00
switch(floor->type)
{
case donutRaise:
case genFloorChgT:
case genFloorChg0:
floor->sector->special = floor->newspecial;
//fall thru
case genFloorChg:
floor->sector->floorpic = floor->texture;
break;
default:
break;
}
1998-04-07 00:00:00 +00:00
}
1998-12-22 00:00:00 +00:00
else if (floor->direction == -1)
1998-04-07 00:00:00 +00:00
{
1998-12-22 00:00:00 +00:00
switch(floor->type)
{
case floorLowerAndChange:
case genFloorChgT:
case genFloorChg0:
floor->sector->special = floor->newspecial;
//fall thru
case genFloorChg:
floor->sector->floorpic = floor->texture;
break;
default:
break;
}
1998-04-07 00:00:00 +00:00
}
1998-12-22 00:00:00 +00:00
floor->sector->floordata = NULL; //jff 2/22/98
P_RemoveThinker (&floor->thinker);
//jff 2/26/98 implement stair retrigger lockout while still building
// note this only applies to the retriggerable generalized stairs
1998-04-07 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
if (floor->sector->stairlock == -2) // if this sector is stairlocked
{
sector_t *sec = floor->sector;
sec->stairlock = -1; // thinker done, promote lock to -1
while (sec->prevsec != -1 && sectors[sec->prevsec].stairlock != -2)
sec = &sectors[sec->prevsec]; // search for a non-done thinker
if (sec->prevsec == -1) // if all thinkers previous are done
{
sec = floor->sector; // search forward
while (sec->nextsec != -1 && sectors[sec->nextsec].stairlock != -2)
sec = &sectors[sec->nextsec];
if (sec->nextsec == -1) // if all thinkers ahead are done too
{
while (sec->prevsec != -1) // clear all locks
{
sec->stairlock = 0;
sec = &sectors[sec->prevsec];
}
sec->stairlock = 0;
}
}
}
}
}
1998-04-07 00:00:00 +00:00
}
1998-07-26 00:00:00 +00:00
//
// T_MoveElevator()
//
// Move an elevator to it's destination (up or down)
// Called once per tick for each moving floor.
//
// Passed an elevator_t structure that contains all pertinent info about the
// move. See P_SPEC.H for fields.
// No return.
//
// jff 02/22/98 added to support parallel floor/ceiling motion
//
void T_MoveElevator (elevator_t* elevator)
{
result_e res;
if (elevator->direction<0) // moving down
{
res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor
(
elevator->sector,
elevator->speed,
elevator->ceilingdestheight,
1998-12-22 00:00:00 +00:00
-1,
1998-07-26 00:00:00 +00:00
1, // move floor
elevator->direction
);
if (res==ok || res==pastdest) // jff 4/7/98 don't move ceil if blocked
T_MovePlane
(
elevator->sector,
elevator->speed,
elevator->floordestheight,
1998-12-22 00:00:00 +00:00
-1,
1998-07-26 00:00:00 +00:00
0, // move ceiling
elevator->direction
);
}
else // up
{
res = T_MovePlane //jff 4/7/98 reverse order of ceiling/floor
(
elevator->sector,
elevator->speed,
elevator->floordestheight,
1998-12-22 00:00:00 +00:00
-1,
1998-07-26 00:00:00 +00:00
0, // move ceiling
elevator->direction
);
if (res==ok || res==pastdest) // jff 4/7/98 don't move floor if blocked
T_MovePlane
(
elevator->sector,
elevator->speed,
elevator->ceilingdestheight,
1998-12-22 00:00:00 +00:00
-1,
1998-07-26 00:00:00 +00:00
1, // move floor
elevator->direction
);
}
if (res == pastdest) // if destination height acheived
{
1999-02-17 00:00:00 +00:00
// make floor stop sound
SN_StopSequence ((mobj_t *)&elevator->sector->soundorg);
1998-07-26 00:00:00 +00:00
elevator->sector->floordata = NULL; //jff 2/22/98
elevator->sector->ceilingdata = NULL; //jff 2/22/98
P_RemoveThinker(&elevator->thinker); // remove elevator from actives
1999-02-17 00:00:00 +00:00
}
}
1998-07-26 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
static void StartFloorSound (sector_t *sec)
{
if (sec->seqType >= 0)
{
SN_StartSequence ((mobj_t *)&sec->soundorg, sec->seqType, SEQ_PLATFORM);
}
else
{
SN_StartSequenceName ((mobj_t *)&sec->soundorg, "Floor");
1998-07-26 00:00:00 +00:00
}
}
1998-04-07 00:00:00 +00:00
//
// HANDLE FLOOR TYPES
1998-12-22 00:00:00 +00:00
// [RH] Added tag, speed, height, crush, change params.
1998-04-07 00:00:00 +00:00
//
1998-12-22 00:00:00 +00:00
BOOL EV_DoFloor (floor_e floortype, line_t *line, int tag,
fixed_t speed, fixed_t height, int crush, int change)
1998-04-07 00:00:00 +00:00
{
int secnum;
1998-12-22 00:00:00 +00:00
BOOL rtn;
1998-04-07 00:00:00 +00:00
sector_t* sec;
floormove_t* floor;
1998-12-22 00:00:00 +00:00
BOOL manual = false;
rtn = false;
// check if a manual trigger, if so do just the sector on the backside
if (tag == 0)
{
if (!line || !(sec = line->backsector))
return rtn;
secnum = sec-sectors;
manual = true;
goto manual_floor;
}
1998-04-07 00:00:00 +00:00
secnum = -1;
1998-12-22 00:00:00 +00:00
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
1998-04-07 00:00:00 +00:00
{
sec = &sectors[secnum];
1998-12-22 00:00:00 +00:00
manual_floor:
1998-04-07 00:00:00 +00:00
// ALREADY MOVING? IF SO, KEEP GOING...
1998-07-26 00:00:00 +00:00
if (P_SectorActive (floor_special, sec)) //jff 2/33/98
1998-04-07 00:00:00 +00:00
continue;
// new floor thinker
1998-12-22 00:00:00 +00:00
rtn = true;
1998-04-07 00:00:00 +00:00
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
1998-07-26 00:00:00 +00:00
sec->floordata = floor; //jff 2/22/98
1998-04-07 00:00:00 +00:00
floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
floor->type = floortype;
1998-12-22 00:00:00 +00:00
floor->crush = -1;
floor->speed = speed;
floor->sector = sec;
floor->resetcount = 0; // [RH]
floor->orgheight = sec->floorheight; // [RH]
1998-04-07 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
StartFloorSound (sec);
1998-04-07 00:00:00 +00:00
switch(floortype)
{
1998-12-22 00:00:00 +00:00
case floorLowerToHighest:
1998-04-07 00:00:00 +00:00
floor->direction = -1;
1998-12-22 00:00:00 +00:00
floor->floordestheight = P_FindHighestFloorSurrounding(sec);
// [RH] DOOM's turboLower type did this. I've just extended it
// to be applicable to all LowerToHighest types.
if (floor->floordestheight != sec->floorheight)
floor->floordestheight += height;
1998-04-07 00:00:00 +00:00
break;
1998-12-22 00:00:00 +00:00
case floorLowerToLowest:
1998-04-07 00:00:00 +00:00
floor->direction = -1;
1998-12-22 00:00:00 +00:00
floor->floordestheight = P_FindLowestFloorSurrounding(sec);
1998-04-07 00:00:00 +00:00
break;
1998-12-22 00:00:00 +00:00
case floorLowerToNearest:
//jff 02/03/30 support lowering floor to next lowest floor
floor->direction = -1;
floor->floordestheight =
P_FindNextLowestFloor (sec, sec->floorheight);
break;
case floorLowerInstant:
floor->speed = height;
case floorLowerByValue:
1998-04-07 00:00:00 +00:00
floor->direction = -1;
floor->sector = sec;
1998-12-22 00:00:00 +00:00
floor->floordestheight = sec->floorheight - height;
1998-04-07 00:00:00 +00:00
break;
1998-12-22 00:00:00 +00:00
case floorRaiseInstant:
floor->speed = height;
case floorRaiseByValue:
floor->direction = 1;
floor->floordestheight = sec->floorheight + height;
break;
case floorMoveToValue:
floor->direction = (height - sec->floorheight) > 0 ? 1 : -1;
floor->floordestheight = height;
break;
case floorRaiseAndCrush:
floor->crush = crush;
case floorRaiseToLowestCeiling:
1998-04-07 00:00:00 +00:00
floor->direction = 1;
floor->floordestheight =
P_FindLowestCeilingSurrounding(sec);
if (floor->floordestheight > sec->ceilingheight)
floor->floordestheight = sec->ceilingheight;
1998-12-22 00:00:00 +00:00
if (floortype == floorRaiseAndCrush)
floor->floordestheight -= 8 * FRACUNIT;
1998-04-07 00:00:00 +00:00
break;
1998-12-22 00:00:00 +00:00
case floorRaiseToHighest:
1998-04-07 00:00:00 +00:00
floor->direction = 1;
1998-12-22 00:00:00 +00:00
floor->floordestheight = P_FindHighestFloorSurrounding(sec);
1998-04-07 00:00:00 +00:00
break;
1998-12-22 00:00:00 +00:00
case floorRaiseToNearest:
1998-04-07 00:00:00 +00:00
floor->direction = 1;
1998-12-22 00:00:00 +00:00
floor->floordestheight = P_FindNextHighestFloor(sec,sec->floorheight);
1998-04-07 00:00:00 +00:00
break;
1998-12-22 00:00:00 +00:00
case floorRaiseToLowest:
1998-04-07 00:00:00 +00:00
floor->direction = 1;
1998-12-22 00:00:00 +00:00
floor->floordestheight = P_FindLowestFloorSurrounding(sec);
1998-04-07 00:00:00 +00:00
break;
1998-12-22 00:00:00 +00:00
case floorRaiseToCeiling:
1998-04-07 00:00:00 +00:00
floor->direction = 1;
1998-12-22 00:00:00 +00:00
floor->floordestheight = sec->ceilingheight;
break;
case floorLowerToLowestCeiling:
floor->direction = -1;
floor->floordestheight = P_FindLowestCeilingSurrounding(sec);
break;
case floorLowerByTexture:
floor->direction = -1;
floor->floordestheight = sec->floorheight -
P_FindShortestTextureAround (secnum);
1998-04-07 00:00:00 +00:00
break;
1998-12-22 00:00:00 +00:00
case floorLowerToCeiling:
// [RH] Essentially instantly raises the floor to the ceiling
floor->direction = -1;
floor->floordestheight = sec->ceilingheight;
break;
case floorRaiseByTexture:
1998-04-07 00:00:00 +00:00
floor->direction = 1;
1998-12-22 00:00:00 +00:00
// [RH] Use P_FindShortestTextureAround from BOOM to do this
// since the code is identical to what was here. (Oddly
// enough, BOOM preserved the code here even though it
// also had this function.)
floor->floordestheight = sec->floorheight +
P_FindShortestTextureAround (secnum);
break;
case floorRaiseAndChange:
floor->direction = 1;
floor->floordestheight = sec->floorheight + height;
1998-04-07 00:00:00 +00:00
sec->floorpic = line->frontsector->floorpic;
sec->special = line->frontsector->special;
break;
1998-12-22 00:00:00 +00:00
case floorLowerAndChange:
1998-04-07 00:00:00 +00:00
floor->direction = -1;
floor->floordestheight =
1998-12-22 00:00:00 +00:00
P_FindLowestFloorSurrounding (sec);
1998-04-07 00:00:00 +00:00
floor->texture = sec->floorpic;
1998-12-22 00:00:00 +00:00
// jff 1/24/98 make sure floor->newspecial gets initialized
// in case no surrounding sector is at floordestheight
// --> should not affect compatibility <--
floor->newspecial = sec->special;
1998-04-07 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
//jff 5/23/98 use model subroutine to unify fixes and handling
sec = P_FindModelFloorSector (floor->floordestheight,sec-sectors);
if (sec)
1998-04-07 00:00:00 +00:00
{
1998-12-22 00:00:00 +00:00
floor->texture = sec->floorpic;
floor->newspecial = sec->special;
}
break;
1998-04-07 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
default:
break;
}
1998-04-07 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
if (change & 3) {
// [RH] Need to do some transferring
if (change & 4) {
// Numeric model change
sector_t *sec;
sec = (floortype == floorRaiseToLowestCeiling ||
floortype == floorLowerToLowestCeiling ||
floortype == floorRaiseToCeiling ||
floortype == floorLowerToCeiling) ?
P_FindModelCeilingSector (floor->floordestheight, secnum) :
P_FindModelFloorSector (floor->floordestheight, secnum);
if (sec) {
floor->texture = sec->floorpic;
switch (change & 3) {
case 1:
floor->newspecial = 0;
floor->type = genFloorChg0;
break;
case 2:
1998-04-07 00:00:00 +00:00
floor->newspecial = sec->special;
1998-12-22 00:00:00 +00:00
floor->type = genFloorChgT;
break;
case 3:
floor->type = genFloorChg;
1998-04-07 00:00:00 +00:00
break;
}
}
1998-12-22 00:00:00 +00:00
} else if (line) {
// Trigger model change
floor->texture = line->frontsector->floorpic;
switch (change & 3) {
case 1:
floor->newspecial = 0;
floor->type = genFloorChg0;
break;
case 2:
floor->newspecial = sec->special;
floor->type = genFloorChgT;
break;
case 3:
floor->type = genFloorChg;
break;
}
1998-04-07 00:00:00 +00:00
}
}
1998-12-22 00:00:00 +00:00
if (manual)
return rtn;
1998-04-07 00:00:00 +00:00
}
return rtn;
}
1998-12-22 00:00:00 +00:00
// [RH]
// EV_FloorCrushStop
// Stop a floor from crushing!
//
BOOL EV_FloorCrushStop (int tag)
{
int secnum = -1;
1998-04-07 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
{
sector_t *sec = sectors + secnum;
if (sec->floordata &&
1999-02-17 00:00:00 +00:00
((thinker_t *)(sec->floordata))->function.acp1 == (actionf_p1) T_MoveFloor &&
1998-12-22 00:00:00 +00:00
((floormove_t *)(sec->floordata))->type == floorRaiseAndCrush) {
1999-02-17 00:00:00 +00:00
SN_StopSequence ((mobj_t *)&sec->soundorg);
1998-12-22 00:00:00 +00:00
P_RemoveThinker ((thinker_t *)(sec->floordata));
sec->floordata = NULL;
}
}
return true;
}
//
// EV_DoChange()
//
// Handle pure change types. These change floor texture and sector type
// by trigger or numeric model without moving the floor.
//
// The linedef causing the change and the type of change is passed
// Returns true if any sector changes
//
// jff 3/15/98 added to better support generalized sector types
// [RH] Added tag parameter.
//
BOOL EV_DoChange (line_t *line, change_e changetype, int tag)
{
int secnum;
BOOL rtn;
sector_t *sec;
sector_t *secm;
secnum = -1;
rtn = false;
// change all sectors with the same tag as the linedef
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
{
sec = &sectors[secnum];
rtn = true;
// handle trigger or numeric change type
switch(changetype)
{
case trigChangeOnly:
if (line) { // [RH] if no line, no change
sec->floorpic = line->frontsector->floorpic;
sec->special = line->frontsector->special;
}
break;
case numChangeOnly:
secm = P_FindModelFloorSector (sec->floorheight,secnum);
if (secm) // if no model, no change
{
sec->floorpic = secm->floorpic;
sec->special = secm->special;
}
break;
default:
break;
}
}
return rtn;
}
1998-04-07 00:00:00 +00:00
//
// BUILD A STAIRCASE!
1998-12-22 00:00:00 +00:00
// [RH] Added stairsize, srcspeed, delay, reset, igntxt, usespecials parameters
// If usespecials is non-zero, then each sector in a stair is determined
// by its special. If usespecials is 2, each sector stays in "sync" with
// the others.
1998-04-07 00:00:00 +00:00
//
1998-12-22 00:00:00 +00:00
BOOL EV_BuildStairs (int tag, stair_e type, line_t *line,
fixed_t stairsize, fixed_t speed, int delay, int reset, int igntxt,
int usespecials)
1998-04-07 00:00:00 +00:00
{
int secnum;
1998-12-22 00:00:00 +00:00
int osecnum; //jff 3/4/98 save old loop index
1998-04-07 00:00:00 +00:00
int height;
int i;
int newsecnum;
int texture;
int ok;
1998-12-22 00:00:00 +00:00
int persteptime;
BOOL rtn = false;
1998-04-07 00:00:00 +00:00
sector_t* sec;
sector_t* tsec;
1998-12-22 00:00:00 +00:00
sector_t* prev = NULL;
1998-04-07 00:00:00 +00:00
floormove_t* floor;
1998-12-22 00:00:00 +00:00
BOOL manual = false;
if (speed == 0)
return false;
persteptime = FixedDiv (stairsize, speed) >> FRACBITS;
// check if a manual trigger, if so do just the sector on the backside
if (tag == 0)
{
if (!line || !(sec = line->backsector))
return rtn;
secnum = sec-sectors;
manual = true;
goto manual_stair;
}
1998-04-07 00:00:00 +00:00
secnum = -1;
1998-12-22 00:00:00 +00:00
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
1998-04-07 00:00:00 +00:00
{
sec = &sectors[secnum];
1998-12-22 00:00:00 +00:00
manual_stair:
1998-04-07 00:00:00 +00:00
// ALREADY MOVING? IF SO, KEEP GOING...
1998-12-22 00:00:00 +00:00
//jff 2/26/98 add special lockout condition to wait for entire
//staircase to build before retriggering
if (P_SectorActive (floor_special, sec) || sec->stairlock) {
if (!manual)
continue;
else
return rtn;
}
1998-04-07 00:00:00 +00:00
// new floor thinker
1998-12-22 00:00:00 +00:00
rtn = true;
1998-04-07 00:00:00 +00:00
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
1998-12-22 00:00:00 +00:00
sec->floordata = floor; //jff 2/22/98
1998-04-07 00:00:00 +00:00
floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
1998-12-22 00:00:00 +00:00
floor->direction = (type == buildUp) ? 1 : -1;
1998-04-07 00:00:00 +00:00
floor->sector = sec;
1998-12-22 00:00:00 +00:00
floor->type = buildStair; //jff 3/31/98 do not leave uninited
floor->resetcount = reset; // [RH] Tics until reset (0 if never)
floor->orgheight = sec->floorheight; // [RH] Height to reset to
// [RH] Set up delay values
floor->delay = delay;
floor->pausetime = 0;
floor->steptime = floor->persteptime = persteptime;
1999-02-17 00:00:00 +00:00
floor->crush = (!usespecials && speed == 4*FRACUNIT) ? 10 : -1; //jff 2/27/98 fix uninitialized crush field
1998-12-22 00:00:00 +00:00
1998-04-07 00:00:00 +00:00
floor->speed = speed;
1998-12-22 00:00:00 +00:00
height = sec->floorheight + stairsize * floor->direction;
1998-04-07 00:00:00 +00:00
floor->floordestheight = height;
1998-07-26 00:00:00 +00:00
1998-04-07 00:00:00 +00:00
texture = sec->floorpic;
1998-12-22 00:00:00 +00:00
osecnum = secnum; //jff 3/4/98 preserve loop index
1998-04-07 00:00:00 +00:00
// Find next sector to raise
1998-12-22 00:00:00 +00:00
// 1. Find 2-sided line with same sector side[0] (lowest numbered)
1998-04-07 00:00:00 +00:00
// 2. Other side is the next sector to raise
1998-12-22 00:00:00 +00:00
// 3. Unless already moving, or different texture, then stop building
1998-04-07 00:00:00 +00:00
do
{
ok = 0;
1998-07-26 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
if (usespecials) {
// [RH] Find the next sector by scanning for Stairs_Special?
tsec = P_NextSpecialSector (sec,
(sec->special & 0xff) == Stairs_Special1 ?
Stairs_Special2 : Stairs_Special1, prev);
1998-07-26 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
if ( (ok = (tsec != NULL)) ) {
height += floor->direction * stairsize;
1998-04-07 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
// if sector's floor already moving, look for another
//jff 2/26/98 special lockout condition for retriggering
if (P_SectorActive (floor_special,tsec) || tsec->stairlock) {
prev = sec;
sec = tsec;
continue;
}
}
1998-04-07 00:00:00 +00:00
newsecnum = tsec - sectors;
1998-12-22 00:00:00 +00:00
} else {
for (i = 0; i < sec->linecount; i++)
{
if ( !((sec->lines[i])->flags & ML_TWOSIDED) )
continue;
tsec = (sec->lines[i])->frontsector;
if (!tsec) continue; //jff 5/7/98 if no backside, continue
newsecnum = tsec-sectors;
1998-04-07 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
if (secnum != newsecnum)
continue;
1998-07-26 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
tsec = (sec->lines[i])->backsector;
newsecnum = tsec - sectors;
1998-04-07 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
if (!igntxt && tsec->floorpic != texture)
continue;
1998-07-26 00:00:00 +00:00
1998-12-22 00:00:00 +00:00
height += floor->direction * stairsize;
// if sector's floor already moving, look for another
//jff 2/26/98 special lockout condition for retriggering
if (P_SectorActive (floor_special,tsec) || tsec->stairlock)
continue;
ok = true;
break;
}
}
if (ok) {
// jff 2/26/98
// link the stair chain in both directions
// lock the stair sector until building complete
sec->nextsec = newsecnum; // link step to next
tsec->prevsec = secnum; // link next back
tsec->nextsec = -1; // set next forward link as end
tsec->stairlock = -2; // lock the step
prev = sec;
1998-04-07 00:00:00 +00:00
sec = tsec;
secnum = newsecnum;
1998-12-22 00:00:00 +00:00
// create and initialize a thinker for the next step
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
1998-04-07 00:00:00 +00:00
P_AddThinker (&floor->thinker);
1999-02-17 00:00:00 +00:00
StartFloorSound (sec);
1998-12-22 00:00:00 +00:00
sec->floordata = floor; //jff 2/22/98
1998-04-07 00:00:00 +00:00
floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
1998-12-22 00:00:00 +00:00
floor->direction = (type == buildUp) ? 1 : -1;
1998-04-07 00:00:00 +00:00
floor->sector = sec;
floor->floordestheight = height;
1998-12-22 00:00:00 +00:00
// [RH] Set up delay values
floor->delay = delay;
floor->pausetime = 0;
floor->steptime = floor->persteptime = persteptime;
if (usespecials == 2) {
// [RH]
fixed_t rise = (floor->floordestheight - sec->floorheight)
* floor->direction;
floor->speed = FixedDiv (FixedMul (speed, rise), stairsize);
} else {
floor->speed = speed;
}
floor->type = buildStair; //jff 3/31/98 do not leave uninited
//jff 2/27/98 fix uninitialized crush field
1999-02-17 00:00:00 +00:00
floor->crush = (!usespecials && speed == 4*FRACUNIT) ? 10 : -1;
1998-12-22 00:00:00 +00:00
floor->resetcount = reset; // [RH] Tics until reset (0 if never)
floor->orgheight = sec->floorheight; // [RH] Height to reset to
1998-04-07 00:00:00 +00:00
}
} while(ok);
1998-12-22 00:00:00 +00:00
if (manual)
return rtn;
secnum = osecnum; //jff 3/4/98 restore loop index
}
return rtn;
}
// [RH] Added pillarspeed and slimespeed parameters
int EV_DoDonut (int tag, fixed_t pillarspeed, fixed_t slimespeed)
{
sector_t* s1;
sector_t* s2;
sector_t* s3;
int secnum;
int rtn;
int i;
floormove_t* floor;
secnum = -1;
rtn = 0;
while ((secnum = P_FindSectorFromTag(tag,secnum)) >= 0)
{
s1 = &sectors[secnum]; // s1 is pillar's sector
// ALREADY MOVING? IF SO, KEEP GOING...
if (P_SectorActive (floor_special, s1)) //jff 2/22/98
continue;
rtn = 1;
s2 = getNextSector (s1->lines[0],s1); // s2 is pool's sector
if (!s2) // note lowest numbered line around
continue; // pillar must be two-sided
for (i = 0; i < s2->linecount; i++)
{
if ((!s2->lines[i]->flags & ML_TWOSIDED) ||
(s2->lines[i]->backsector == s1))
continue;
s3 = s2->lines[i]->backsector;
// Spawn rising slime
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
s2->floordata = floor; //jff 2/22/98
floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
floor->type = donutRaise;
floor->crush = -1;
floor->direction = 1;
floor->sector = s2;
floor->speed = slimespeed;
floor->texture = s3->floorpic;
floor->newspecial = 0;
floor->floordestheight = s3->floorheight;
1999-02-17 00:00:00 +00:00
StartFloorSound (s2);
1998-12-22 00:00:00 +00:00
// Spawn lowering donut-hole
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
s1->floordata = floor; //jff 2/22/98
floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
floor->type = floorLowerToNearest;
floor->crush = -1;
floor->direction = -1;
floor->sector = s1;
floor->speed = pillarspeed;
floor->floordestheight = s3->floorheight;
1999-02-17 00:00:00 +00:00
StartFloorSound (s1);
1998-12-22 00:00:00 +00:00
break;
}
1998-04-07 00:00:00 +00:00
}
return rtn;
}
1998-07-26 00:00:00 +00:00
//
// EV_DoElevator
//
// Handle elevator linedef types
//
// Passed the linedef that triggered the elevator and the elevator action
//
// jff 2/22/98 new type to move floor and ceiling in parallel
1998-12-22 00:00:00 +00:00
// [RH] Added speed, tag, and height parameters and new types.
1998-07-26 00:00:00 +00:00
//
1998-12-22 00:00:00 +00:00
BOOL EV_DoElevator (line_t *line, elevator_e elevtype,
fixed_t speed, fixed_t height, int tag)
1998-07-26 00:00:00 +00:00
{
int secnum;
1998-12-22 00:00:00 +00:00
BOOL rtn;
1998-07-26 00:00:00 +00:00
sector_t* sec;
elevator_t* elevator;
1998-12-22 00:00:00 +00:00
if (!line && (elevtype == elevateCurrent))
return false;
1998-07-26 00:00:00 +00:00
secnum = -1;
1998-12-22 00:00:00 +00:00
rtn = false;
1998-07-26 00:00:00 +00:00
// act on all sectors with the same tag as the triggering linedef
1998-12-22 00:00:00 +00:00
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
1998-07-26 00:00:00 +00:00
{
sec = &sectors[secnum];
// If either floor or ceiling is already activated, skip it
if (sec->floordata || sec->ceilingdata) //jff 2/22/98
continue;
// create and initialize new elevator thinker
1998-12-22 00:00:00 +00:00
rtn = true;
1998-07-26 00:00:00 +00:00
elevator = Z_Malloc (sizeof(*elevator), PU_LEVSPEC, 0);
P_AddThinker (&elevator->thinker);
sec->floordata = elevator; //jff 2/22/98
sec->ceilingdata = elevator; //jff 2/22/98
elevator->thinker.function.acp1 = (actionf_p1) T_MoveElevator;
elevator->type = elevtype;
1998-12-22 00:00:00 +00:00
elevator->sector = sec;
elevator->speed = speed;
1999-02-17 00:00:00 +00:00
StartFloorSound (sec);
1998-07-26 00:00:00 +00:00
// set up the fields according to the type of elevator action
1998-12-22 00:00:00 +00:00
switch (elevtype)
1998-07-26 00:00:00 +00:00
{
// elevator down to next floor
case elevateDown:
elevator->direction = -1;
elevator->floordestheight =
P_FindNextLowestFloor(sec,sec->floorheight);
elevator->ceilingdestheight =
elevator->floordestheight + sec->ceilingheight - sec->floorheight;
break;
// elevator up to next floor
case elevateUp:
elevator->direction = 1;
elevator->floordestheight =
P_FindNextHighestFloor(sec,sec->floorheight);
elevator->ceilingdestheight =
elevator->floordestheight + sec->ceilingheight - sec->floorheight;
break;
// elevator to floor height of activating switch's front sector
case elevateCurrent:
elevator->floordestheight = line->frontsector->floorheight;
elevator->ceilingdestheight =
elevator->floordestheight + sec->ceilingheight - sec->floorheight;
elevator->direction =
elevator->floordestheight>sec->floorheight? 1 : -1;
break;
1998-12-22 00:00:00 +00:00
// [RH] elevate up by a specific amount
case elevateRaise:
elevator->direction = 1;
elevator->floordestheight = sec->floorheight + height;
elevator->ceilingdestheight = sec->ceilingheight + height;
break;
// [RH] elevate down by a specific amount
case elevateLower:
elevator->direction = -1;
elevator->floordestheight = sec->floorheight - height;
elevator->ceilingdestheight = sec->ceilingheight - height;
1998-07-26 00:00:00 +00:00
break;
}
}
return rtn;
}
1998-12-22 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
//==========================================================================
1998-12-22 00:00:00 +00:00
//
1999-02-17 00:00:00 +00:00
// T_FloorWaggle
1998-12-22 00:00:00 +00:00
//
1999-02-17 00:00:00 +00:00
//==========================================================================
#define WGLSTATE_EXPAND 1
#define WGLSTATE_STABLE 2
#define WGLSTATE_REDUCE 3
void T_FloorWaggle (floorWaggle_t *waggle)
1998-12-22 00:00:00 +00:00
{
1999-02-17 00:00:00 +00:00
switch(waggle->state)
{
case WGLSTATE_EXPAND:
if((waggle->scale += waggle->scaleDelta)
>= waggle->targetScale)
{
waggle->scale = waggle->targetScale;
waggle->state = WGLSTATE_STABLE;
1998-12-22 00:00:00 +00:00
}
break;
1999-02-17 00:00:00 +00:00
case WGLSTATE_REDUCE:
if((waggle->scale -= waggle->scaleDelta) <= 0)
{ // Remove
waggle->sector->floorheight = waggle->originalHeight;
P_ChangeSector(waggle->sector, true);
waggle->sector->floordata = NULL;
P_RemoveThinker(&waggle->thinker);
return;
}
1998-12-22 00:00:00 +00:00
break;
1999-02-17 00:00:00 +00:00
case WGLSTATE_STABLE:
if(waggle->ticker != -1)
{
if(!--waggle->ticker)
{
waggle->state = WGLSTATE_REDUCE;
}
1998-12-22 00:00:00 +00:00
}
break;
}
1999-02-17 00:00:00 +00:00
waggle->accumulator += waggle->accDelta;
waggle->sector->floorheight = waggle->originalHeight
+FixedMul(FloatBobOffsets[(waggle->accumulator>>FRACBITS)&63],
waggle->scale);
P_ChangeSector(waggle->sector, true);
1998-12-22 00:00:00 +00:00
}
1999-02-17 00:00:00 +00:00
//==========================================================================
//
// EV_StartFloorWaggle
//
//==========================================================================
1998-12-22 00:00:00 +00:00
1999-02-17 00:00:00 +00:00
BOOL EV_StartFloorWaggle (int tag, int height, int speed, int offset,
int timer)
{
int sectorIndex;
sector_t *sector;
floorWaggle_t *waggle;
BOOL retCode;
retCode = false;
sectorIndex = -1;
while ((sectorIndex = P_FindSectorFromTag(tag, sectorIndex)) >= 0)
1998-12-22 00:00:00 +00:00
{
1999-02-17 00:00:00 +00:00
sector = &sectors[sectorIndex];
if (sector->floordata)
{ // Already busy with another thinker
1998-12-22 00:00:00 +00:00
continue;
1999-02-17 00:00:00 +00:00
}
retCode = true;
waggle = Z_Malloc(sizeof(*waggle), PU_LEVSPEC, 0);
sector->floordata = waggle;
waggle->thinker.function.acp1 = (actionf_p1) 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*TICRATE : -1;
waggle->state = WGLSTATE_EXPAND;
P_AddThinker(&waggle->thinker);
1998-12-22 00:00:00 +00:00
}
1999-02-17 00:00:00 +00:00
return retCode;
}