2006-03-28 15:44:01 +00:00
|
|
|
/* Emacs style mode select -*- C++ -*-
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* PrBoom a Doom port merged with LxDoom and LSDLDoom
|
|
|
|
* based on BOOM, a modified and improved DOOM engine
|
|
|
|
* Copyright (C) 1999 by
|
|
|
|
* id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
|
|
|
|
* Copyright (C) 1999-2000 by
|
|
|
|
* Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* DESCRIPTION:
|
|
|
|
* Ceiling aninmation (lowering, crushing, raising)
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
#include "doomstat.h"
|
|
|
|
#include "r_main.h"
|
|
|
|
#include "p_spec.h"
|
|
|
|
#include "p_tick.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "sounds.h"
|
|
|
|
#include "z_zone.h"
|
|
|
|
#include "doomdef.h"
|
|
|
|
#define PU_LEVSPEC 51 // a special thinker in a level
|
|
|
|
#include "rockmacros.h"
|
|
|
|
|
|
|
|
// the list of ceilings moving currently, including crushers
|
|
|
|
ceilinglist_t *activeceilings;
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Ceiling action routine and linedef type handler
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//
|
|
|
|
// T_MoveCeiling
|
|
|
|
//
|
|
|
|
// Action routine that moves ceilings. Called once per tick.
|
|
|
|
//
|
|
|
|
// Passed a ceiling_t structure that contains all the info about the move.
|
|
|
|
// see P_SPEC.H for fields. No return.
|
|
|
|
//
|
|
|
|
// jff 02/08/98 all cases with labels beginning with gen added to support
|
|
|
|
// generalized line type behaviors.
|
|
|
|
//
|
|
|
|
void T_MoveCeiling (ceiling_t* ceiling)
|
|
|
|
{
|
|
|
|
result_e res;
|
|
|
|
|
|
|
|
switch(ceiling->direction)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
// If ceiling in stasis, do nothing
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
// Ceiling is moving up
|
|
|
|
res = T_MovePlane
|
|
|
|
(
|
|
|
|
ceiling->sector,
|
|
|
|
ceiling->speed,
|
|
|
|
ceiling->topheight,
|
|
|
|
false,
|
|
|
|
1,
|
|
|
|
ceiling->direction
|
|
|
|
);
|
|
|
|
|
|
|
|
// if not a silent crusher, make moving sound
|
|
|
|
if (!(leveltime&7))
|
|
|
|
{
|
|
|
|
switch(ceiling->type)
|
|
|
|
{
|
|
|
|
case silentCrushAndRaise:
|
|
|
|
case genSilentCrusher:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle reaching destination height
|
|
|
|
if (res == pastdest)
|
|
|
|
{
|
|
|
|
switch(ceiling->type)
|
|
|
|
{
|
|
|
|
// plain movers are just removed
|
|
|
|
case raiseToHighest:
|
|
|
|
case genCeiling:
|
|
|
|
P_RemoveActiveCeiling(ceiling);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// movers with texture change, change the texture then get removed
|
|
|
|
case genCeilingChgT:
|
|
|
|
case genCeilingChg0:
|
|
|
|
ceiling->sector->special = ceiling->newspecial;
|
|
|
|
//jff 3/14/98 transfer old special field as well
|
|
|
|
ceiling->sector->oldspecial = ceiling->oldspecial;
|
|
|
|
case genCeilingChg:
|
|
|
|
ceiling->sector->ceilingpic = ceiling->texture;
|
|
|
|
P_RemoveActiveCeiling(ceiling);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// crushers reverse direction at the top
|
|
|
|
case silentCrushAndRaise:
|
|
|
|
S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop);
|
2021-07-24 14:39:01 +00:00
|
|
|
/* fallthrough */
|
2006-03-28 15:44:01 +00:00
|
|
|
case genSilentCrusher:
|
|
|
|
case genCrusher:
|
|
|
|
case fastCrushAndRaise:
|
|
|
|
case crushAndRaise:
|
|
|
|
ceiling->direction = -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case -1:
|
|
|
|
// Ceiling moving down
|
|
|
|
res = T_MovePlane
|
|
|
|
(
|
|
|
|
ceiling->sector,
|
|
|
|
ceiling->speed,
|
|
|
|
ceiling->bottomheight,
|
|
|
|
ceiling->crush,
|
|
|
|
1,
|
|
|
|
ceiling->direction
|
|
|
|
);
|
|
|
|
|
|
|
|
// if not silent crusher type make moving sound
|
|
|
|
if (!(leveltime&7))
|
|
|
|
{
|
|
|
|
switch(ceiling->type)
|
|
|
|
{
|
|
|
|
case silentCrushAndRaise:
|
|
|
|
case genSilentCrusher:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_stnmov);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle reaching destination height
|
|
|
|
if (res == pastdest)
|
|
|
|
{
|
|
|
|
switch(ceiling->type)
|
|
|
|
{
|
|
|
|
// 02/09/98 jff change slow crushers' speed back to normal
|
|
|
|
// start back up
|
|
|
|
case genSilentCrusher:
|
|
|
|
case genCrusher:
|
|
|
|
if (ceiling->oldspeed<CEILSPEED*3)
|
|
|
|
ceiling->speed = ceiling->oldspeed;
|
|
|
|
ceiling->direction = 1; //jff 2/22/98 make it go back up!
|
|
|
|
break;
|
|
|
|
|
|
|
|
// make platform stop at bottom of all crusher strokes
|
|
|
|
// except generalized ones, reset speed, start back up
|
|
|
|
case silentCrushAndRaise:
|
|
|
|
S_StartSound((mobj_t *)&ceiling->sector->soundorg,sfx_pstop);
|
2021-07-24 14:39:01 +00:00
|
|
|
/* fallthrough */
|
2006-03-28 15:44:01 +00:00
|
|
|
case crushAndRaise:
|
|
|
|
ceiling->speed = CEILSPEED;
|
2021-07-24 14:39:01 +00:00
|
|
|
/* fallthrough */
|
2006-03-28 15:44:01 +00:00
|
|
|
case fastCrushAndRaise:
|
|
|
|
ceiling->direction = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// in the case of ceiling mover/changer, change the texture
|
|
|
|
// then remove the active ceiling
|
|
|
|
case genCeilingChgT:
|
|
|
|
case genCeilingChg0:
|
|
|
|
ceiling->sector->special = ceiling->newspecial;
|
|
|
|
//jff add to fix bug in special transfers from changes
|
|
|
|
ceiling->sector->oldspecial = ceiling->oldspecial;
|
|
|
|
case genCeilingChg:
|
|
|
|
ceiling->sector->ceilingpic = ceiling->texture;
|
|
|
|
P_RemoveActiveCeiling(ceiling);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// all other case, just remove the active ceiling
|
|
|
|
case lowerAndCrush:
|
|
|
|
case lowerToFloor:
|
|
|
|
case lowerToLowest:
|
|
|
|
case lowerToMaxFloor:
|
|
|
|
case genCeiling:
|
|
|
|
P_RemoveActiveCeiling(ceiling);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // ( res != pastdest )
|
|
|
|
{
|
|
|
|
// handle the crusher encountering an obstacle
|
|
|
|
if (res == crushed)
|
|
|
|
{
|
|
|
|
switch(ceiling->type)
|
|
|
|
{
|
|
|
|
//jff 02/08/98 slow down slow crushers on obstacle
|
|
|
|
case genCrusher:
|
|
|
|
case genSilentCrusher:
|
|
|
|
if (ceiling->oldspeed < CEILSPEED*3)
|
|
|
|
ceiling->speed = CEILSPEED / 8;
|
|
|
|
break;
|
|
|
|
case silentCrushAndRaise:
|
|
|
|
case crushAndRaise:
|
|
|
|
case lowerAndCrush:
|
|
|
|
ceiling->speed = CEILSPEED / 8;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// EV_DoCeiling
|
|
|
|
//
|
|
|
|
// Move a ceiling up/down or start a crusher
|
|
|
|
//
|
|
|
|
// Passed the linedef activating the function and the type of function desired
|
|
|
|
// returns true if a thinker started
|
|
|
|
//
|
|
|
|
int EV_DoCeiling
|
|
|
|
( line_t* line,
|
|
|
|
ceiling_e type )
|
|
|
|
{
|
|
|
|
int secnum;
|
|
|
|
int rtn;
|
|
|
|
sector_t* sec;
|
|
|
|
ceiling_t* ceiling;
|
|
|
|
|
|
|
|
secnum = -1;
|
|
|
|
rtn = 0;
|
|
|
|
|
|
|
|
// Reactivate in-stasis ceilings...for certain types.
|
|
|
|
// This restarts a crusher after it has been stopped
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case fastCrushAndRaise:
|
|
|
|
case silentCrushAndRaise:
|
|
|
|
case crushAndRaise:
|
|
|
|
//jff 4/5/98 return if activated
|
|
|
|
rtn = P_ActivateInStasisCeiling(line);
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// affects all sectors with the same tag as the linedef
|
|
|
|
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
|
|
|
|
{
|
|
|
|
sec = §ors[secnum];
|
|
|
|
|
|
|
|
// if ceiling already moving, don't start a second function on it
|
|
|
|
if (P_SectorActive(ceiling_special,sec)) //jff 2/22/98
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// create a new ceiling thinker
|
|
|
|
rtn = 1;
|
|
|
|
ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0);
|
|
|
|
P_AddThinker (&ceiling->thinker);
|
|
|
|
sec->ceilingdata = ceiling; //jff 2/22/98
|
|
|
|
ceiling->thinker.function = T_MoveCeiling;
|
|
|
|
ceiling->sector = sec;
|
|
|
|
ceiling->crush = false;
|
|
|
|
|
|
|
|
// setup ceiling structure according to type of function
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case fastCrushAndRaise:
|
|
|
|
ceiling->crush = true;
|
|
|
|
ceiling->topheight = sec->ceilingheight;
|
|
|
|
ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
|
|
|
|
ceiling->direction = -1;
|
|
|
|
ceiling->speed = CEILSPEED * 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case silentCrushAndRaise:
|
|
|
|
case crushAndRaise:
|
|
|
|
ceiling->crush = true;
|
|
|
|
ceiling->topheight = sec->ceilingheight;
|
|
|
|
case lowerAndCrush:
|
|
|
|
case lowerToFloor:
|
|
|
|
ceiling->bottomheight = sec->floorheight;
|
|
|
|
if (type != lowerToFloor)
|
|
|
|
ceiling->bottomheight += 8*FRACUNIT;
|
|
|
|
ceiling->direction = -1;
|
|
|
|
ceiling->speed = CEILSPEED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case raiseToHighest:
|
|
|
|
ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
|
|
|
|
ceiling->direction = 1;
|
|
|
|
ceiling->speed = CEILSPEED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lowerToLowest:
|
|
|
|
ceiling->bottomheight = P_FindLowestCeilingSurrounding(sec);
|
|
|
|
ceiling->direction = -1;
|
|
|
|
ceiling->speed = CEILSPEED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lowerToMaxFloor:
|
|
|
|
ceiling->bottomheight = P_FindHighestFloorSurrounding(sec);
|
|
|
|
ceiling->direction = -1;
|
|
|
|
ceiling->speed = CEILSPEED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the ceiling to the active list
|
|
|
|
ceiling->tag = sec->tag;
|
|
|
|
ceiling->type = type;
|
|
|
|
P_AddActiveCeiling(ceiling);
|
|
|
|
}
|
|
|
|
return rtn;
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Active ceiling list primitives
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// jff 2/22/98 - modified Lee's plat code to work for ceilings
|
|
|
|
//
|
|
|
|
// The following were all rewritten by Lee Killough
|
|
|
|
// to use the new structure which places no limits
|
|
|
|
// on active ceilings. It also avoids spending as much
|
|
|
|
// time searching for active ceilings. Previously a
|
|
|
|
// fixed-size array was used, with NULL indicating
|
|
|
|
// empty entries, while now a doubly-linked list
|
|
|
|
// is used.
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_ActivateInStasisCeiling()
|
|
|
|
//
|
|
|
|
// Reactivates all stopped crushers with the right tag
|
|
|
|
//
|
|
|
|
// Passed the line reactivating the crusher
|
|
|
|
// Returns true if a ceiling reactivated
|
|
|
|
//
|
|
|
|
//jff 4/5/98 return if activated
|
|
|
|
int P_ActivateInStasisCeiling(line_t *line)
|
|
|
|
{
|
|
|
|
ceilinglist_t *cl;
|
|
|
|
int rtn=0;
|
|
|
|
|
|
|
|
for (cl=activeceilings; cl; cl=cl->next)
|
|
|
|
{
|
|
|
|
ceiling_t *ceiling = cl->ceiling;
|
|
|
|
if (ceiling->tag == line->tag && ceiling->direction == 0)
|
|
|
|
{
|
|
|
|
ceiling->direction = ceiling->olddirection;
|
|
|
|
ceiling->thinker.function = T_MoveCeiling;
|
|
|
|
//jff 4/5/98 return if activated
|
|
|
|
rtn=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rtn;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// EV_CeilingCrushStop()
|
|
|
|
//
|
|
|
|
// Stops all active ceilings with the right tag
|
|
|
|
//
|
|
|
|
// Passed the linedef stopping the ceilings
|
|
|
|
// Returns true if a ceiling put in stasis
|
|
|
|
//
|
|
|
|
int EV_CeilingCrushStop(line_t* line)
|
|
|
|
{
|
|
|
|
int rtn=0;
|
|
|
|
|
|
|
|
ceilinglist_t *cl;
|
|
|
|
for (cl=activeceilings; cl; cl=cl->next)
|
|
|
|
{
|
|
|
|
ceiling_t *ceiling = cl->ceiling;
|
|
|
|
if (ceiling->direction != 0 && ceiling->tag == line->tag)
|
|
|
|
{
|
|
|
|
ceiling->olddirection = ceiling->direction;
|
|
|
|
ceiling->direction = 0;
|
|
|
|
ceiling->thinker.function = NULL;
|
|
|
|
rtn=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return rtn;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_AddActiveCeiling()
|
|
|
|
//
|
|
|
|
// Adds a ceiling to the head of the list of active ceilings
|
|
|
|
//
|
|
|
|
// Passed the ceiling motion structure
|
|
|
|
// Returns nothing
|
|
|
|
//
|
|
|
|
void P_AddActiveCeiling(ceiling_t* ceiling)
|
|
|
|
{
|
|
|
|
ceilinglist_t *list = malloc(sizeof *list);
|
|
|
|
list->ceiling = ceiling;
|
|
|
|
ceiling->list = list;
|
|
|
|
if ((list->next = activeceilings))
|
|
|
|
list->next->prev = &list->next;
|
|
|
|
list->prev = &activeceilings;
|
|
|
|
activeceilings = list;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_RemoveActiveCeiling()
|
|
|
|
//
|
|
|
|
// Removes a ceiling from the list of active ceilings
|
|
|
|
//
|
|
|
|
// Passed the ceiling motion structure
|
|
|
|
// Returns nothing
|
|
|
|
//
|
|
|
|
void P_RemoveActiveCeiling(ceiling_t* ceiling)
|
|
|
|
{
|
|
|
|
ceilinglist_t *list = ceiling->list;
|
|
|
|
ceiling->sector->ceilingdata = NULL; //jff 2/22/98
|
|
|
|
P_RemoveThinker(&ceiling->thinker);
|
|
|
|
if ((*list->prev = list->next))
|
|
|
|
list->next->prev = list->prev;
|
|
|
|
free(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_RemoveAllActiveCeilings()
|
|
|
|
//
|
|
|
|
// Removes all ceilings from the active ceiling list
|
|
|
|
//
|
|
|
|
// Passed nothing, returns nothing
|
|
|
|
//
|
|
|
|
void P_RemoveAllActiveCeilings(void)
|
|
|
|
{
|
|
|
|
while (activeceilings)
|
|
|
|
{
|
|
|
|
ceilinglist_t *next = activeceilings->next;
|
|
|
|
free(activeceilings);
|
|
|
|
activeceilings = next;
|
|
|
|
}
|
|
|
|
}
|