RingRacers/src/p_ceilng.c
Sally Cochenour 58df481cd3 Replace "Block Enemies" with "Block Players"
We don't need the ability to make invisible walls for enemies as often as we've needed invisible walls for players that don't block their thrown items.
2020-03-21 19:08:59 -04:00

681 lines
19 KiB
C

// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2018 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file p_ceilng.c
/// \brief Ceiling aninmation (lowering, crushing, raising)
#include "doomdef.h"
#include "p_local.h"
#include "r_main.h"
#include "s_sound.h"
#include "z_zone.h"
#include "d_netcmd.h"
// ==========================================================================
// CEILINGS
// ==========================================================================
// the list of ceilings moving currently, including crushers
INT32 ceilmovesound = sfx_None;
/** Moves a moving ceiling.
*
* \param ceiling Thinker for the ceiling to be moved.
* \sa EV_DoCeiling
* \todo Split up into multiple functions.
*/
void T_MoveCeiling(ceiling_t *ceiling)
{
result_e res;
boolean dontupdate = false;
if (ceiling->delaytimer)
{
ceiling->delaytimer--;
return;
}
switch (ceiling->direction)
{
case 0: // IN STASIS
break;
case 1: // UP
res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight, false,
1, ceiling->direction);
if (ceiling->type == bounceCeiling)
{
const fixed_t origspeed = FixedDiv(ceiling->origspeed,(ELEVATORSPEED/2));
const fixed_t fs = abs(ceiling->sector->ceilingheight - lines[ceiling->texture].frontsector->ceilingheight);
const fixed_t bs = abs(ceiling->sector->ceilingheight - lines[ceiling->texture].backsector->ceilingheight);
if (fs < bs)
ceiling->speed = FixedDiv(fs,25*FRACUNIT) + FRACUNIT/4;
else
ceiling->speed = FixedDiv(bs,25*FRACUNIT) + FRACUNIT/4;
ceiling->speed = FixedMul(ceiling->speed,origspeed);
}
if (res == pastdest)
{
switch (ceiling->type)
{
case instantMoveCeilingByFrontSector:
ceiling->sector->ceilingpic = ceiling->texture;
ceiling->sector->ceilingdata = NULL;
ceiling->sector->ceilspeed = 0;
P_RemoveThinker(&ceiling->thinker);
dontupdate = true;
break;
case moveCeilingByFrontSector:
if (ceiling->texture < -1) // chained linedef executing
P_LinedefExecute((INT16)(ceiling->texture + INT16_MAX + 2), NULL, NULL);
if (ceiling->texture > -1) // flat changing
ceiling->sector->ceilingpic = ceiling->texture;
/* FALLTHRU */
case raiseToHighest:
// case raiseCeilingByLine:
case moveCeilingByFrontTexture:
ceiling->sector->ceilingdata = NULL;
ceiling->sector->ceilspeed = 0;
P_RemoveThinker(&ceiling->thinker);
dontupdate = true;
break;
case fastCrushAndRaise:
case crushAndRaise:
ceiling->direction = -1;
break;
case bounceCeiling:
{
fixed_t dest = ceiling->topheight;
if (dest == lines[ceiling->texture].frontsector->ceilingheight)
dest = lines[ceiling->texture].backsector->ceilingheight;
else
dest = lines[ceiling->texture].frontsector->ceilingheight;
if (dest < ceiling->sector->ceilingheight) // must move down
{
ceiling->direction = -1;
ceiling->bottomheight = dest;
}
else // must move up
{
ceiling->direction = 1;
ceiling->topheight = dest;
}
ceiling->delaytimer = ceiling->delay;
// That's it. Do not set dontupdate, do not remove the thinker.
break;
}
case bounceCeilingCrush:
{
fixed_t dest = ceiling->topheight;
if (dest == lines[ceiling->texture].frontsector->ceilingheight)
{
dest = lines[ceiling->texture].backsector->ceilingheight;
ceiling->speed = ceiling->origspeed = FixedDiv(abs(lines[ceiling->texture].dy),4*FRACUNIT); // return trip, use dy
}
else
{
dest = lines[ceiling->texture].frontsector->ceilingheight;
ceiling->speed = ceiling->origspeed = FixedDiv(abs(lines[ceiling->texture].dx),4*FRACUNIT); // going frontways, use dx
}
if (dest < ceiling->sector->ceilingheight) // must move down
{
ceiling->direction = -1;
ceiling->bottomheight = dest;
}
else // must move up
{
ceiling->direction = 1;
ceiling->topheight = dest;
}
ceiling->delaytimer = ceiling->delay;
// That's it. Do not set dontupdate, do not remove the thinker.
break;
}
default:
break;
}
}
break;
case -1: // DOWN
res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight,
ceiling->crush, 1, ceiling->direction);
if (ceiling->type == bounceCeiling)
{
const fixed_t origspeed = FixedDiv(ceiling->origspeed,(ELEVATORSPEED/2));
const fixed_t fs = abs(ceiling->sector->ceilingheight - lines[ceiling->texture].frontsector->ceilingheight);
const fixed_t bs = abs(ceiling->sector->ceilingheight - lines[ceiling->texture].backsector->ceilingheight);
if (fs < bs)
ceiling->speed = FixedDiv(fs,25*FRACUNIT) + FRACUNIT/4;
else
ceiling->speed = FixedDiv(bs,25*FRACUNIT) + FRACUNIT/4;
ceiling->speed = FixedMul(ceiling->speed,origspeed);
}
if (res == pastdest)
{
switch (ceiling->type)
{
// make platform stop at bottom of all crusher strokes
// except generalized ones, reset speed, start back up
case crushAndRaise:
ceiling->speed = CEILSPEED;
/* FALLTHRU */
case fastCrushAndRaise:
ceiling->direction = 1;
break;
case instantMoveCeilingByFrontSector:
ceiling->sector->ceilingpic = ceiling->texture;
ceiling->sector->ceilingdata = NULL;
ceiling->sector->ceilspeed = 0;
P_RemoveThinker(&ceiling->thinker);
dontupdate = true;
break;
case moveCeilingByFrontSector:
if (ceiling->texture < -1) // chained linedef executing
P_LinedefExecute((INT16)(ceiling->texture + INT16_MAX + 2), NULL, NULL);
if (ceiling->texture > -1) // flat changing
ceiling->sector->ceilingpic = ceiling->texture;
// don't break
/* FALLTHRU */
// in all other cases, just remove the active ceiling
case lowerAndCrush:
case lowerToLowest:
case raiseToLowest:
// case lowerCeilingByLine:
case moveCeilingByFrontTexture:
ceiling->sector->ceilingdata = NULL;
ceiling->sector->ceilspeed = 0;
P_RemoveThinker(&ceiling->thinker);
dontupdate = true;
break;
case bounceCeiling:
{
fixed_t dest = ceiling->bottomheight;
if (dest == lines[ceiling->texture].frontsector->ceilingheight)
dest = lines[ceiling->texture].backsector->ceilingheight;
else
dest = lines[ceiling->texture].frontsector->ceilingheight;
if (dest < ceiling->sector->ceilingheight) // must move down
{
ceiling->direction = -1;
ceiling->bottomheight = dest;
}
else // must move up
{
ceiling->direction = 1;
ceiling->topheight = dest;
}
ceiling->delaytimer = ceiling->delay;
// That's it. Do not set dontupdate, do not remove the thinker.
break;
}
case bounceCeilingCrush:
{
fixed_t dest = ceiling->bottomheight;
if (dest == lines[ceiling->texture].frontsector->ceilingheight)
{
dest = lines[ceiling->texture].backsector->ceilingheight;
ceiling->speed = ceiling->origspeed = FixedDiv(abs(lines[ceiling->texture].dy),4*FRACUNIT); // return trip, use dy
}
else
{
dest = lines[ceiling->texture].frontsector->ceilingheight;
ceiling->speed = ceiling->origspeed = FixedDiv(abs(lines[ceiling->texture].dx),4*FRACUNIT); // going frontways, use dx
}
if (dest < ceiling->sector->ceilingheight) // must move down
{
ceiling->direction = -1;
ceiling->bottomheight = dest;
}
else // must move up
{
ceiling->direction = 1;
ceiling->topheight = dest;
}
ceiling->delaytimer = ceiling->delay;
// That's it. Do not set dontupdate, do not remove the thinker.
break;
}
default:
break;
}
}
else if (res == crushed)
{
switch (ceiling->type)
{
case crushAndRaise:
case lowerAndCrush:
ceiling->speed = FixedDiv(CEILSPEED,8*FRACUNIT);
break;
default:
break;
}
}
break;
}
if (!dontupdate)
ceiling->sector->ceilspeed = ceiling->speed*ceiling->direction;
else
ceiling->sector->ceilspeed = 0;
}
/** Moves a ceiling crusher.
*
* \param ceiling Thinker for the crusher to be moved.
* \sa EV_DoCrush
*/
void T_CrushCeiling(ceiling_t *ceiling)
{
result_e res;
switch (ceiling->direction)
{
case 0: // IN STASIS
break;
case 1: // UP
if (ceiling->type == crushBothOnce)
{
// Move the floor
T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight-(ceiling->topheight-ceiling->bottomheight), false, 0, -ceiling->direction);
}
res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight,
false, 1, ceiling->direction);
if (res == pastdest)
{
ceiling->direction = -1;
if (lines[ceiling->sourceline].flags & ML_EFFECT4)
ceiling->speed = ceiling->oldspeed;
else
ceiling->speed = ceiling->oldspeed*2;
if (ceiling->type == crushCeilOnce
|| ceiling->type == crushBothOnce)
{
// Remove
switch(ceiling->type)
{
case crushCeilOnce:
ceiling->sector->ceilspeed = 0;
ceiling->sector->ceilingdata = NULL;
break;
case crushBothOnce:
ceiling->sector->floorspeed = 0;
ceiling->sector->ceilspeed = 0;
ceiling->sector->ceilingdata = NULL;
break;
default:
break;
}
P_RemoveThinker(&ceiling->thinker);
return;
}
}
break;
case -1: // DOWN
if (ceiling->type == crushBothOnce)
{
// Move the floor
T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, ceiling->crush, 0, -ceiling->direction);
}
res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight,
ceiling->crush, 1, ceiling->direction);
if (res == pastdest)
{
mobj_t *mp = (void *)&ceiling->sector->soundorg;
ceiling->sector->soundorg.z = ceiling->sector->floorheight;
S_StartSound(mp,sfx_pstop);
if (lines[ceiling->sourceline].flags & ML_EFFECT4)
ceiling->speed = ceiling->oldspeed;
else
ceiling->speed = ceiling->oldspeed/2;
ceiling->direction = 1;
}
break;
}
if (ceiling->type == crushBothOnce)
ceiling->sector->floorspeed = ceiling->speed*(-ceiling->direction);
ceiling->sector->ceilspeed = ceiling->speed*ceiling->direction;
}
/** Starts a ceiling mover.
*
* \param line The source line.
* \param type The type of ceiling movement.
* \return 1 if at least one ceiling mover was started, 0 otherwise.
* \sa EV_DoCrush, EV_DoFloor, EV_DoElevator, T_MoveCeiling
*/
INT32 EV_DoCeiling(line_t *line, ceiling_e type)
{
INT32 rtn = 0, firstone = 1;
INT32 secnum = -1;
sector_t *sec;
ceiling_t *ceiling;
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->ceilingdata)
continue;
// new door thinker
rtn = 1;
ceiling = Z_Calloc(sizeof (*ceiling), PU_LEVSPEC, NULL);
P_AddThinker(&ceiling->thinker);
sec->ceilingdata = ceiling;
ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
ceiling->sector = sec;
ceiling->crush = false;
ceiling->sourceline = (INT32)(line-lines);
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 crushAndRaise:
ceiling->crush = true;
ceiling->topheight = sec->ceilingheight;
/* FALLTHRU */
case lowerAndCrush:
ceiling->bottomheight = sec->floorheight;
ceiling->bottomheight += 4*FRACUNIT;
ceiling->direction = -1;
ceiling->speed = line->dx;
break;
case raiseToHighest:
ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
ceiling->direction = 1;
ceiling->speed = CEILSPEED;
break;
//SoM: 3/6/2000: Added Boom types
case lowerToLowest:
ceiling->bottomheight = P_FindLowestCeilingSurrounding(sec);
ceiling->direction = -1;
ceiling->speed = CEILSPEED;
break;
case raiseToLowest: // Graue 09-07-2004
ceiling->topheight = P_FindLowestCeilingSurrounding(sec) - 4*FRACUNIT;
ceiling->direction = 1;
ceiling->speed = line->dx; // hack
break;
case lowerToLowestFast:
ceiling->bottomheight = P_FindLowestCeilingSurrounding(sec);
ceiling->direction = -1;
ceiling->speed = 4*FRACUNIT;
break;
case instantRaise:
ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
ceiling->direction = 1;
ceiling->speed = INT32_MAX/2;
break;
// Linedef executor excellence
case moveCeilingByFrontSector:
ceiling->speed = P_AproxDistance(line->dx, line->dy);
ceiling->speed = FixedDiv(ceiling->speed,8*FRACUNIT);
if (line->frontsector->ceilingheight >= sec->ceilingheight) // Move up
{
ceiling->direction = 1;
ceiling->topheight = line->frontsector->ceilingheight;
}
else // Move down
{
ceiling->direction = -1;
ceiling->bottomheight = line->frontsector->ceilingheight;
}
// chained linedef executing ability
if (line->flags & ML_BLOCKPLAYERS)
{
// only set it on ONE of the moving sectors (the smallest numbered)
// and front side x offset must be positive
if (firstone && sides[line->sidenum[0]].textureoffset > 0)
ceiling->texture = (sides[line->sidenum[0]].textureoffset>>FRACBITS) - 32769;
else
ceiling->texture = -1;
}
// flat changing ability
else if (line->flags & ML_NOCLIMB)
ceiling->texture = line->frontsector->ceilingpic;
else
ceiling->texture = -1;
break;
// More linedef executor junk
case instantMoveCeilingByFrontSector:
ceiling->speed = INT32_MAX/2;
if (line->frontsector->ceilingheight >= sec->ceilingheight) // Move up
{
ceiling->direction = 1;
ceiling->topheight = line->frontsector->ceilingheight;
}
else // Move down
{
ceiling->direction = -1;
ceiling->bottomheight = line->frontsector->ceilingheight;
}
ceiling->texture = line->frontsector->ceilingpic;
break;
case moveCeilingByFrontTexture:
if (line->flags & ML_NOCLIMB)
ceiling->speed = INT32_MAX/2; // as above, "instant" is one tic
else
ceiling->speed = FixedDiv(sides[line->sidenum[0]].textureoffset,8*FRACUNIT); // texture x offset
if (sides[line->sidenum[0]].rowoffset > 0)
{
ceiling->direction = 1; // up
ceiling->topheight = sec->ceilingheight + sides[line->sidenum[0]].rowoffset; // texture y offset
}
else {
ceiling->direction = -1; // down
ceiling->bottomheight = sec->ceilingheight + sides[line->sidenum[0]].rowoffset; // texture y offset
}
break;
/*
case lowerCeilingByLine:
ceiling->speed = FixedDiv(abs(line->dx),8*FRACUNIT);
ceiling->direction = -1; // Move down
ceiling->bottomheight = sec->ceilingheight - abs(line->dy);
break;
case raiseCeilingByLine:
ceiling->speed = FixedDiv(abs(line->dx),8*FRACUNIT);
ceiling->direction = 1; // Move up
ceiling->topheight = sec->ceilingheight + abs(line->dy);
break;
*/
case bounceCeiling:
ceiling->speed = P_AproxDistance(line->dx, line->dy); // same speed as elevateContinuous
ceiling->speed = FixedDiv(ceiling->speed,4*FRACUNIT);
ceiling->origspeed = ceiling->speed;
if (line->frontsector->ceilingheight >= sec->ceilingheight) // Move up
{
ceiling->direction = 1;
ceiling->topheight = line->frontsector->ceilingheight;
}
else // Move down
{
ceiling->direction = -1;
ceiling->bottomheight = line->frontsector->ceilingheight;
}
// Any delay?
ceiling->delay = sides[line->sidenum[0]].textureoffset >> FRACBITS;
ceiling->delaytimer = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Initial delay
ceiling->texture = (fixed_t)(line - lines); // hack: use texture to store sourceline number
break;
case bounceCeilingCrush:
ceiling->speed = abs(line->dx); // same speed as elevateContinuous
ceiling->speed = FixedDiv(ceiling->speed,4*FRACUNIT);
ceiling->origspeed = ceiling->speed;
if (line->frontsector->ceilingheight >= sec->ceilingheight) // Move up
{
ceiling->direction = 1;
ceiling->topheight = line->frontsector->ceilingheight;
}
else // Move down
{
ceiling->direction = -1;
ceiling->bottomheight = line->frontsector->ceilingheight;
}
// Any delay?
ceiling->delay = sides[line->sidenum[0]].textureoffset >> FRACBITS;
ceiling->delaytimer = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Initial delay
ceiling->texture = (fixed_t)(line - lines); // hack: use texture to store sourceline number
break;
default:
break;
}
ceiling->tag = sec->tag;
ceiling->type = type;
firstone = 0;
}
return rtn;
}
/** Starts a ceiling crusher.
*
* \param line The source line.
* \param type The type of ceiling, either ::crushAndRaise or
* ::fastCrushAndRaise.
* \return 1 if at least one crusher was started, 0 otherwise.
* \sa EV_DoCeiling, EV_DoFloor, EV_DoElevator, T_CrushCeiling
*/
INT32 EV_DoCrush(line_t *line, ceiling_e type)
{
INT32 rtn = 0;
INT32 secnum = -1;
sector_t *sec;
ceiling_t *ceiling;
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->ceilingdata)
continue;
// new door thinker
rtn = 1;
ceiling = Z_Calloc(sizeof (*ceiling), PU_LEVSPEC, NULL);
P_AddThinker(&ceiling->thinker);
sec->ceilingdata = ceiling;
ceiling->thinker.function.acp1 = (actionf_p1)T_CrushCeiling;
ceiling->sector = sec;
ceiling->crush = true;
ceiling->sourceline = (INT32)(line-lines);
if (line->flags & ML_EFFECT4)
ceiling->oldspeed = FixedDiv(abs(line->dx),4*FRACUNIT);
else
ceiling->oldspeed = (R_PointToDist2(line->v2->x, line->v2->y, line->v1->x, line->v1->y)/16);
switch(type)
{
case fastCrushAndRaise: // Up and then down
ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
ceiling->direction = 1;
ceiling->speed = ceiling->oldspeed;
ceiling->bottomheight = sec->floorheight + FRACUNIT;
break;
case crushBothOnce:
ceiling->topheight = sec->ceilingheight;
ceiling->bottomheight = sec->floorheight + (sec->ceilingheight-sec->floorheight)/2;
ceiling->direction = -1;
if (line->flags & ML_EFFECT4)
ceiling->speed = ceiling->oldspeed;
else
ceiling->speed = ceiling->oldspeed*2;
break;
case crushCeilOnce:
default: // Down and then up.
ceiling->topheight = sec->ceilingheight;
ceiling->direction = -1;
if (line->flags & ML_EFFECT4)
ceiling->speed = ceiling->oldspeed;
else
ceiling->speed = ceiling->oldspeed*2;
ceiling->bottomheight = sec->floorheight + FRACUNIT;
break;
}
ceiling->tag = sec->tag;
ceiling->type = type;
}
return rtn;
}