raze/source/games/duke/src/sectors.cpp

1325 lines
32 KiB
C++
Raw Normal View History

//-------------------------------------------------------------------------
/*
Copyright (C) 1996, 2003 - 3D Realms Entertainment
Copyright (C) 2000, 2003 - Matt Saettler (EDuke Enhancements)
2020-05-13 14:19:39 +00:00
Copyright (C) 2020 - Christoph Oelckers
This file is part of Enhanced Duke Nukem 3D version 1.5 - Atomic Edition
Duke Nukem 3D 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.
Original Source: 1996 - Todd Replogle
Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
EDuke enhancements integrated: 04/13/2003 - Matt Saettler
Note: EDuke source was in transition. Changes are in-progress in the
source as it is released.
*/
//-------------------------------------------------------------------------
#include <utility>
#include "ns.h"
#include "global.h"
2020-06-24 19:21:02 +00:00
#include "sounds.h"
#include "dukeactor.h"
#include "interpolate.h"
// PRIMITIVE
BEGIN_DUKE_NS
static int interptype[] = { Interp_Sect_Floorz, Interp_Sect_Ceilingz, Interp_Wall_X, Interp_Wall_Y };
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static bool haltsoundhack;
int callsound(sectortype* sn, DDukeActor* whatsprite, bool endstate)
{
if (!isRRRA() && haltsoundhack)
{
haltsoundhack = 0;
return -1;
}
2020-10-23 15:38:49 +00:00
DukeSectIterator it(sn);
while (auto act = it.Next())
{
2021-12-21 20:39:57 +00:00
if (act->spr.picnum == MUSICANDSFX && act->spr.lotag < 1000)
{
2020-10-23 15:38:49 +00:00
if (whatsprite == nullptr) whatsprite = act;
2021-12-21 20:39:57 +00:00
int snum = act->spr.lotag;
auto flags = S_GetUserFlags(snum);
// Reset if the desired actor isn't playing anything.
2021-12-21 20:39:57 +00:00
bool hival = S_IsSoundValid(act->spr.hitag);
if (act->temp_data[0] == 1 && !hival && !endstate)
{
2020-10-23 15:38:49 +00:00
if (!S_CheckActorSoundPlaying(act->temp_actor, snum))
act->temp_data[0] = 0;
}
2020-10-23 15:38:49 +00:00
if (act->temp_data[0] == 0)
{
if ((flags & (SF_GLOBAL | SF_DTAG)) != SF_GLOBAL)
{
if (snum)
{
2021-12-21 20:39:57 +00:00
if (act->spr.hitag && snum != act->spr.hitag)
S_StopSound(act->spr.hitag, act->temp_actor);
S_PlayActorSound(snum, whatsprite);
2020-10-23 15:38:49 +00:00
act->temp_actor = whatsprite;
}
if ((act->sector()->lotag & 0xff) != ST_22_SPLITTING_DOOR)
2020-10-23 15:38:49 +00:00
act->temp_data[0] = 1;
}
}
2021-12-21 20:39:57 +00:00
else if (act->spr.hitag < 1000)
{
// The original code performed these two actions in reverse order which in case of a looped sound being stopped
// being the same as the sound about to be started, the newly started sound would fall through some cracks in the sound system and be rejected.
// Here this case needs to be simulated.
bool stopped = false;
2021-12-21 20:39:57 +00:00
if ((flags & SF_LOOP) || (act->spr.hitag && act->spr.hitag != act->spr.lotag))
{
2021-12-21 20:39:57 +00:00
S_StopSound(act->spr.lotag, act->temp_actor);
if (act->spr.hitag == act->spr.lotag) stopped = true;
}
if (act->spr.hitag && !stopped) S_PlayActorSound(act->spr.hitag, whatsprite);
2020-10-23 15:38:49 +00:00
act->temp_data[0] = 0;
act->temp_actor = whatsprite;
}
2021-12-21 20:39:57 +00:00
return act->spr.lotag;
}
}
return -1;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
int check_activator_motion(int lotag)
{
DukeStatIterator it(STAT_ACTIVATOR);
while (auto act = it.Next())
{
if (act->spr.lotag == lotag)
{
for (int j = animatecnt - 1; j >= 0; j--)
if (act->sector() == animatesect[j])
return(1);
DukeStatIterator it1(STAT_EFFECTOR);
while (auto act2 = it1.Next())
{
if (act->sector() == act2->sector())
switch (act2->spr.lotag)
{
case SE_11_SWINGING_DOOR:
case SE_30_TWO_WAY_TRAIN:
if (act2->temp_data[4])
return(1);
break;
case SE_18_INCREMENTAL_SECTOR_RISE_FALL:
if (isRRRA()) break;
[[fallthrough]];
case SE_20_STRETCH_BRIDGE:
case SE_31_FLOOR_RISE_FALL:
case SE_32_CEILING_RISE_FALL:
if (act2->temp_data[0])
return(1);
break;
}
}
}
}
return(0);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
bool isanunderoperator(int lotag)
{
switch (lotag & 0xff)
{
case ST_15_WARP_ELEVATOR:
case ST_16_PLATFORM_DOWN:
case ST_17_PLATFORM_UP:
case ST_18_ELEVATOR_DOWN:
case ST_19_ELEVATOR_UP:
case ST_26_SPLITTING_ST_DOOR:
return true;
case ST_22_SPLITTING_DOOR:
return !isRR();
}
return false;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
bool isanearoperator(int lotag)
{
switch (lotag & 0xff)
{
case ST_9_SLIDING_ST_DOOR:
case ST_15_WARP_ELEVATOR:
case ST_16_PLATFORM_DOWN:
case ST_17_PLATFORM_UP:
case ST_18_ELEVATOR_DOWN:
case ST_19_ELEVATOR_UP:
case ST_20_CEILING_DOOR:
case ST_21_FLOOR_DOOR:
case ST_22_SPLITTING_DOOR:
case ST_23_SWINGING_DOOR:
case ST_25_SLIDING_DOOR:
case ST_26_SPLITTING_ST_DOOR:
case ST_29_TEETH_DOOR:
return true;
case 41:
return isRR();
}
return false;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-10-23 15:44:45 +00:00
int findplayer(const DDukeActor* actor, int* d)
{
int j, closest_player;
int x, closest;
const auto s = actor->int_pos();
if (ud.multimode < 2)
{
if (d) *d = abs(ps[myconnectindex].player_int_opos().X - s.X) + abs(ps[myconnectindex].player_int_opos().Y - s.Y) + ((abs(ps[myconnectindex].player_int_opos().Z - s.Z + (28 << 8))) >> 4);
return myconnectindex;
}
closest = 0x7fffffff;
closest_player = 0;
for (j = connecthead; j >= 0; j = connectpoint2[j])
{
x = abs(ps[j].player_int_opos().X - s.X) + abs(ps[j].player_int_opos().Y - s.Y) + ((abs(ps[j].player_int_opos().Z - s.Z + (28 << 8))) >> 4);
if (x < closest && ps[j].GetActor()->spr.extra > 0)
{
closest_player = j;
closest = x;
}
}
if (d) *d = closest;
return closest_player;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
int findotherplayer(int p, int* d)
{
int j, closest_player;
int x, closest;
closest = 0x7fffffff;
closest_player = p;
for (j = connecthead; j >= 0; j = connectpoint2[j])
if (p != j && ps[j].GetActor()->spr.extra > 0)
{
x = abs(ps[j].player_int_opos().X - ps[p].player_int_pos().X) + abs(ps[j].player_int_opos().Y - ps[p].player_int_pos().Y) + (abs(ps[j].player_int_opos().Z - ps[p].player_int_pos().Z) >> 4);
if (x < closest)
{
closest_player = j;
closest = x;
}
}
*d = closest;
return closest_player;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
double getanimatevalue(int type, int index)
{
switch (type)
{
case anim_floorz:
return sector[index].int_floorz();
case anim_ceilingz:
return sector[index].int_ceilingz();
case anim_vertexx:
return wall[index].wall_int_pos().X;
case anim_vertexy:
return wall[index].wall_int_pos().Y;
default:
assert(false);
return 0;
}
}
double getanimatevalue(int i)
{
return getanimatevalue(animatetype[i], animatetarget[i]);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void setanimatevalue(int type, int index, double value)
{
static int scratch;
switch (type)
{
case anim_floorz:
sector[index].set_int_floorz((int)value);
break;
case anim_ceilingz:
sector[index].set_int_ceilingz((int)value);
break;
case anim_vertexx:
wall[index].pos.X = value * inttoworld;
wall[index].moved();
break;
case anim_vertexy:
wall[index].pos.Y = value * inttoworld;
wall[index].moved();
break;
default:
assert(false);
}
}
void setanimatevalue(int i, double value)
{
return setanimatevalue(animatetype[i], animatetarget[i], value);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void doanimations(void)
{
int i, a, p, v;
for (i = animatecnt - 1; i >= 0; i--)
{
a = (int)getanimatevalue(i);
v = animatevel[i] * TICSPERFRAME;
auto dasectp = animatesect[i];
if (a == animategoal[i])
{
StopInterpolation(animatetarget[i], interptype[animatetype[i]]);
animatecnt--;
animatetype[i] = animatetype[animatecnt];
animatetarget[i] = animatetarget[animatecnt];
animategoal[i] = animategoal[animatecnt];
animatevel[i] = animatevel[animatecnt];
animatesect[i] = animatesect[animatecnt];
dasectp = animatesect[i];
if (dasectp->lotag == ST_18_ELEVATOR_DOWN || dasectp->lotag == ST_19_ELEVATOR_UP)
if (animatetype[i] == anim_ceilingz)
continue;
if ((dasectp->lotag & 0xff) != ST_22_SPLITTING_DOOR)
callsound(dasectp, nullptr, true);
continue;
}
if (v > 0) { a = min(a + v, animategoal[i]); }
else { a = max(a + v, animategoal[i]); }
if (animatetype[i] == anim_floorz)
{
for (p = connecthead; p >= 0; p = connectpoint2[p])
if (ps[p].cursector == dasectp)
if ((dasectp->int_floorz() - ps[p].player_int_pos().Z) < (64 << 8))
if (ps[p].GetActor()->GetOwner() != nullptr)
{
2022-02-05 11:56:49 +00:00
ps[p].player_add_int_z(v);
ps[p].vel.Z = 0;
}
DukeSectIterator it(dasectp);
while (auto act = it.Next())
{
if (act->spr.statnum != STAT_EFFECTOR)
{
act->backupz();
2022-01-30 23:02:46 +00:00
act->add_int_z(v);
act->floorz = dasectp->floorz + v * zinttoworld;
}
}
}
setanimatevalue(i, a);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 19:01:33 +00:00
int getanimationgoal(int animtype, sectortype* animtargetp)
{
int i, j;
j = -1;
2021-11-18 19:01:33 +00:00
int animtarget = sectnum(animtargetp);
for (i = animatecnt - 1; i >= 0; i--)
if (animtype == animatetype[i] && animtarget == animatetarget[i])
{
j = i;
break;
}
return(j);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static int dosetanimation(sectortype* animsect, int animtype, int animtarget, int thegoal, int thevel)
{
int i, j;
if (animatecnt >= MAXANIMATES - 1)
return(-1);
j = animatecnt;
for (i = 0; i < animatecnt; i++)
if (animtype == animatetype[i] && animtarget == animatetarget[i])
{
j = i;
break;
}
auto animval = (int)getanimatevalue(animtype, animtarget);
animatesect[j] = animsect;
animatetype[j] = animtype;
animatetarget[j] = animtarget;
animategoal[j] = thegoal;
if (thegoal >= animval)
animatevel[j] = thevel;
else
animatevel[j] = -thevel;
if (j == animatecnt) animatecnt++;
StartInterpolation(animatetarget[i], interptype[animatetype[i]]);
return(j);
}
2021-11-18 17:35:59 +00:00
int setanimation(sectortype* animsect, int animtype, walltype* animtarget, int thegoal, int thevel)
{
assert(animtype == anim_vertexx || animtype == anim_vertexy);
return dosetanimation(animsect, animtype, wallnum(animtarget), thegoal, thevel);
2021-11-18 17:35:59 +00:00
}
int setanimation(sectortype* animsect, int animtype, sectortype* animtarget, int thegoal, int thevel)
{
assert(animtype == anim_ceilingz || animtype == anim_floorz);
return dosetanimation(animsect, animtype, sectnum(animtarget), thegoal, thevel);
2021-11-18 17:35:59 +00:00
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-10-23 15:46:46 +00:00
bool activatewarpelevators(DDukeActor* actor, int d) //Parm = sectoreffectornum
{
auto sect = actor->sector();
// See if the sector exists
2020-10-23 15:46:46 +00:00
DukeStatIterator it(STAT_EFFECTOR);
DDukeActor *act2;
while ((act2 = it.Next()))
{
if (act2->spr.lotag == SE_17_WARP_ELEVATOR || (isRRRA() && act2->spr.lotag == SE_18_INCREMENTAL_SECTOR_RISE_FALL))
if (act2->spr.hitag == actor->spr.hitag)
if ((abs(sect->int_floorz() - actor->temp_data[2]) > act2->spr.yvel) ||
2021-11-20 23:33:17 +00:00
(act2->sector()->hitag == (sect->hitag - d)))
break;
}
2020-10-23 15:46:46 +00:00
if (act2 == nullptr)
{
d = 0;
return 1; // No find
}
else
{
if (d == 0)
2020-10-23 15:46:46 +00:00
S_PlayActorSound(ELEVATOR_OFF, actor);
else S_PlayActorSound(ELEVATOR_ON, actor);
}
it.Reset(STAT_EFFECTOR);
2020-10-23 15:46:46 +00:00
while ((act2 = it.Next()))
{
if (act2->spr.lotag == SE_17_WARP_ELEVATOR || (isRRRA() && act2->spr.lotag == SE_18_INCREMENTAL_SECTOR_RISE_FALL))
if (act2->spr.hitag == actor->spr.hitag)
{
2020-10-23 15:46:46 +00:00
act2->temp_data[0] = d;
act2->temp_data[1] = d; //Make all check warp
}
}
return 0;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:35:59 +00:00
static void handle_st09(sectortype* sptr, DDukeActor* actor)
{
int dax, day, dax2, day2, sp;
2021-11-17 21:49:27 +00:00
walltype* wallfind[2];
sp = sptr->extra >> 4;
//first find center point by averaging all points
dax = 0L, day = 0L;
2021-11-17 21:49:27 +00:00
for (auto& wal : wallsofsector(sptr))
{
dax += wal.wall_int_pos().X;
day += wal.wall_int_pos().Y;
}
2021-11-17 21:49:27 +00:00
dax /= sptr->wallnum;
day /= sptr->wallnum;
//find any points with either same x or same y coordinate
// as center (dax, day) - should be 2 points found.
2021-11-17 21:49:27 +00:00
wallfind[0] = nullptr;
wallfind[1] = nullptr;
for (auto& wal : wallsofsector(sptr))
if ((wal.wall_int_pos().X == dax) || (wal.wall_int_pos().Y == day))
{
2021-11-17 21:49:27 +00:00
if (wallfind[0] == nullptr)
wallfind[0] = &wal;
else wallfind[1] = &wal;
}
for (int j = 0; j < 2; j++)
{
2021-11-17 21:49:27 +00:00
auto wal = wallfind[j];
2021-11-17 21:49:27 +00:00
//find what direction door should open by averaging the
// 2 neighboring points of wallfind[0] & wallfind[1].
auto prevwall = wal - 1;
if (prevwall < sptr->firstWall()) prevwall += sptr->wallnum;
if ((wal->wall_int_pos().X == dax) && (wal->wall_int_pos().Y == day))
{
dax2 = ((prevwall->wall_int_pos().X + wal->point2Wall()->wall_int_pos().X) >> 1) - wal->wall_int_pos().X;
day2 = ((prevwall->wall_int_pos().Y + wal->point2Wall()->wall_int_pos().Y) >> 1) - wal->wall_int_pos().Y;
if (dax2 != 0)
{
dax2 = wal->point2Wall()->point2Wall()->wall_int_pos().X;
dax2 -= wal->point2Wall()->wall_int_pos().X;
setanimation(sptr, anim_vertexx, wal, wal->wall_int_pos().X + dax2, sp);
setanimation(sptr, anim_vertexx, prevwall, prevwall->wall_int_pos().X + dax2, sp);
setanimation(sptr, anim_vertexx, wal->point2Wall(), wal->point2Wall()->wall_int_pos().X + dax2, sp);
2021-11-18 17:35:59 +00:00
callsound(sptr, actor);
}
else if (day2 != 0)
{
day2 = wal->point2Wall()->point2Wall()->wall_int_pos().Y;
day2 -= wal->point2Wall()->wall_int_pos().Y;
setanimation(sptr, anim_vertexy, wal, wal->wall_int_pos().Y + day2, sp);
setanimation(sptr, anim_vertexy, prevwall, prevwall->wall_int_pos().Y + day2, sp);
setanimation(sptr, anim_vertexy, wal->point2Wall(), wal->point2Wall()->wall_int_pos().Y + day2, sp);
2021-11-18 17:35:59 +00:00
callsound(sptr, actor);
}
}
else
{
dax2 = ((prevwall->wall_int_pos().X + wal->point2Wall()->wall_int_pos().X) >> 1) - wal->wall_int_pos().X;
day2 = ((prevwall->wall_int_pos().Y + wal->point2Wall()->wall_int_pos().Y) >> 1) - wal->wall_int_pos().Y;
if (dax2 != 0)
{
2021-11-18 17:35:59 +00:00
setanimation(sptr, anim_vertexx, wal, dax, sp);
setanimation(sptr, anim_vertexx, prevwall, dax + dax2, sp);
setanimation(sptr, anim_vertexx, wal->point2Wall(), dax + dax2, sp);
callsound(sptr, actor);
}
else if (day2 != 0)
{
2021-11-18 17:35:59 +00:00
setanimation(sptr, anim_vertexy, wal, day, sp);
setanimation(sptr, anim_vertexy, prevwall, day + day2, sp);
setanimation(sptr, anim_vertexy, wal->point2Wall(), day + day2, sp);
callsound(sptr, actor);
}
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:38:09 +00:00
static void handle_st15(sectortype* sptr, DDukeActor* actor)
{
if (!actor->isPlayer()) return;
2021-11-18 17:38:09 +00:00
DukeSectIterator it(sptr);
2020-10-23 17:08:11 +00:00
DDukeActor* a2;
while ((a2 = it.Next()))
{
if (a2->spr.picnum == SECTOREFFECTOR && a2->spr.lotag == ST_17_PLATFORM_UP) break;
}
2020-10-23 17:08:11 +00:00
if (!a2) return;
if (actor->sector() == sptr)
{
2020-10-23 17:08:11 +00:00
if (activatewarpelevators(a2, -1))
activatewarpelevators(a2, 1);
else if (activatewarpelevators(a2, 1))
activatewarpelevators(a2, -1);
return;
}
else
{
if (sptr->int_floorz() > a2->int_pos().Z)
2020-10-23 17:08:11 +00:00
activatewarpelevators(a2, -1);
else
2020-10-23 17:08:11 +00:00
activatewarpelevators(a2, 1);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:38:09 +00:00
static void handle_st16(sectortype* sptr, DDukeActor* actor)
{
2021-11-18 19:01:33 +00:00
int i = getanimationgoal(anim_floorz, sptr);
sectortype* sectp;
if (i == -1)
{
sectp = nextsectorneighborzptr(sptr, sptr->int_floorz(), Find_FloorDown);
if (sectp == nullptr)
{
sectp = nextsectorneighborzptr(sptr, sptr->int_floorz(), Find_FloorUp);
if (sectp == nullptr) return;
setanimation(sptr, anim_floorz, sptr, sectp->int_floorz(), sptr->extra);
}
else
{
setanimation(sptr, anim_floorz, sptr, sectp->int_floorz(), sptr->extra);
}
2021-11-18 17:38:09 +00:00
callsound(sptr, actor);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:43:25 +00:00
static void handle_st18(sectortype* sptr, DDukeActor* actor)
{
2021-11-18 19:01:33 +00:00
int i = getanimationgoal(anim_floorz, sptr);
if (i == -1)
{
auto sectp = nextsectorneighborzptr(sptr, sptr->int_floorz(), Find_FloorUp);
if (sectp == nullptr) sectp = nextsectorneighborzptr(sptr, sptr->int_floorz(), Find_FloorDown);
if (sectp == nullptr) return;
int j = sectp->int_floorz();
int q = sptr->extra;
int l = sptr->int_ceilingz() - sptr->int_floorz();
2021-11-18 17:43:25 +00:00
setanimation(sptr, anim_floorz, sptr, j, q);
setanimation(sptr, anim_ceilingz, sptr, j + l, q);
callsound(sptr, actor);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:43:25 +00:00
static void handle_st29(sectortype* sptr, DDukeActor* actor)
{
2020-10-23 17:09:27 +00:00
int j;
if (sptr->lotag & 0x8000)
j = nextsectorneighborzptr(sptr, sptr->int_ceilingz(), Find_FloorDown | Find_Safe)->int_floorz();
else
j = nextsectorneighborzptr(sptr, sptr->int_ceilingz(), Find_CeilingUp | Find_Safe)->int_ceilingz();
2020-10-23 17:09:27 +00:00
DukeStatIterator it(STAT_EFFECTOR);
while (auto act2 = it.Next())
{
if ((act2->spr.lotag == 22) &&
(act2->spr.hitag == sptr->hitag))
{
2021-11-20 23:33:17 +00:00
act2->sector()->extra = -act2->sector()->extra;
act2->temp_data[0] = sectnum(sptr);
2020-10-23 17:09:27 +00:00
act2->temp_data[1] = 1;
}
}
sptr->lotag ^= 0x8000;
2021-11-18 17:43:25 +00:00
setanimation(sptr, anim_ceilingz, sptr, j, sptr->extra);
2021-11-18 17:43:25 +00:00
callsound(sptr, actor);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:43:25 +00:00
static void handle_st20(sectortype* sptr, DDukeActor* actor)
{
int j = 0;
REDODOOR:
if (sptr->lotag & 0x8000)
{
2020-10-23 17:10:40 +00:00
DDukeActor* a2;
2021-11-18 17:43:25 +00:00
DukeSectIterator it(sptr);
2020-10-23 17:10:40 +00:00
while ((a2 = it.Next()))
{
if (a2->spr.statnum == 3 && a2->spr.lotag == 9)
{
j = a2->int_pos().Z;
break;
}
}
2020-10-23 17:10:40 +00:00
if (a2 == nullptr)
j = sptr->int_floorz();
}
else
{
auto sectp = nextsectorneighborzptr(sptr, sptr->int_ceilingz(), Find_CeilingUp);
if (sectp) j = sectp->int_ceilingz();
else
{
sptr->lotag |= 32768;
goto REDODOOR;
}
}
sptr->lotag ^= 0x8000;
2021-11-18 17:43:25 +00:00
setanimation(sptr, anim_ceilingz, sptr, j, sptr->extra);
callsound(sptr, actor);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:43:25 +00:00
static void handle_st21(sectortype* sptr, DDukeActor* actor)
{
2021-11-18 19:01:33 +00:00
int i = getanimationgoal(anim_floorz, sptr);
int j;
if (i >= 0)
{
if (animategoal[i] == sptr->int_ceilingz())
animategoal[i] = nextsectorneighborzptr(sptr, sptr->int_ceilingz(), Find_FloorDown | Find_Safe)->int_floorz();
else animategoal[i] = sptr->int_ceilingz();
j = animategoal[i];
}
else
{
if (sptr->int_ceilingz() == sptr->int_floorz())
j = nextsectorneighborzptr(sptr, sptr->int_ceilingz(), Find_FloorDown | Find_Safe)->int_floorz();
else j = sptr->int_ceilingz();
sptr->lotag ^= 0x8000;
2021-11-18 17:43:25 +00:00
if (setanimation(sptr, anim_floorz, sptr, j, sptr->extra) >= 0)
callsound(sptr, actor);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:43:25 +00:00
static void handle_st22(sectortype* sptr, DDukeActor* actor)
{
int j, q;
if ((sptr->lotag & 0x8000))
{
q = (sptr->int_ceilingz() + sptr->int_floorz()) >> 1;
2021-11-18 17:43:25 +00:00
j = setanimation(sptr, anim_floorz, sptr, q, sptr->extra);
j = setanimation(sptr, anim_ceilingz, sptr, q, sptr->extra);
}
else
{
q = nextsectorneighborzptr(sptr, sptr->int_floorz(), Find_FloorDown | Find_Safe)->int_floorz();
2021-11-18 17:43:25 +00:00
j = setanimation(sptr, anim_floorz, sptr, q, sptr->extra);
q = nextsectorneighborzptr(sptr, sptr->int_ceilingz(), Find_CeilingUp | Find_Safe)->int_ceilingz();
2021-11-18 17:43:25 +00:00
j = setanimation(sptr, anim_ceilingz, sptr, q, sptr->extra);
}
sptr->lotag ^= 0x8000;
2021-11-18 17:43:25 +00:00
callsound(sptr, actor);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:46:04 +00:00
static void handle_st23(sectortype* sptr, DDukeActor* actor)
{
int q = 0;
2020-10-23 17:15:18 +00:00
DukeStatIterator it(STAT_EFFECTOR);
DDukeActor* act2;
while ((act2 = it.Next()))
{
if (act2->spr.lotag == SE_11_SWINGING_DOOR && act2->sector() == sptr && !act2->temp_data[4])
{
break;
}
}
2020-10-23 17:15:18 +00:00
if (!act2) return;
2021-11-20 23:33:17 +00:00
int l = act2->sector()->lotag & 0x8000;
2020-10-23 17:15:18 +00:00
if (act2)
{
DukeStatIterator itr(STAT_EFFECTOR);
while (auto act3 = itr.Next())
{
if (l == (act3->sector()->lotag & 0x8000) && act3->spr.lotag == SE_11_SWINGING_DOOR && act2->spr.hitag == act3->spr.hitag && act3->temp_data[4])
{
return;
}
}
itr.Reset(STAT_EFFECTOR);
while (auto act3 = itr.Next())
{
if (l == (act3->sector()->lotag & 0x8000) && act3->spr.lotag == SE_11_SWINGING_DOOR && act2->spr.hitag == act3->spr.hitag)
{
2021-11-20 23:33:17 +00:00
if (act3->sector()->lotag & 0x8000) act3->sector()->lotag &= 0x7fff;
else act3->sector()->lotag |= 0x8000;
2020-10-23 17:15:18 +00:00
act3->temp_data[4] = 1;
act3->temp_data[3] = -act3->temp_data[3];
if (q == 0)
{
2021-11-18 17:46:04 +00:00
callsound(sptr, act3);
q = 1;
}
}
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:46:04 +00:00
static void handle_st25(sectortype* sptr, DDukeActor* actor)
{
2020-10-23 17:16:39 +00:00
DukeStatIterator it(STAT_EFFECTOR);
DDukeActor* act2;
while ((act2 = it.Next()))
{
if (act2->spr.lotag == 15 && act2->sector() == sptr)
2020-10-23 17:16:39 +00:00
{
break;
}
}
2020-10-23 17:16:39 +00:00
if (act2 == nullptr)
return;
it.Reset(STAT_EFFECTOR);
2020-10-23 17:16:39 +00:00
while (auto act3 = it.Next())
{
if (act3->spr.hitag == act2->spr.hitag)
{
if (act3->spr.lotag == 15)
{
2021-11-20 23:33:17 +00:00
act3->sector()->lotag ^= 0x8000; // Toggle the open or close
2022-08-16 21:26:39 +00:00
act3->add_int_ang(1024;
2021-11-20 23:33:17 +00:00
if (act3->temp_data[4]) callsound(act3->sector(), act3);
callsound(act3->sector(), act3);
if (act3->sector()->lotag & 0x8000) act3->temp_data[4] = 1;
2020-10-23 17:16:39 +00:00
else act3->temp_data[4] = 2;
}
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:46:04 +00:00
static void handle_st27(sectortype* sptr, DDukeActor* actor)
{
2020-10-23 17:17:30 +00:00
DukeStatIterator it(STAT_EFFECTOR);
while (auto act2 = it.Next())
{
if ((act2->spr.lotag & 0xff) == 20 && act2->sector() == sptr) //Bridge
{
2021-11-18 17:46:04 +00:00
sptr->lotag ^= 0x8000;
if (sptr->lotag & 0x8000) //OPENING
2020-10-23 17:17:30 +00:00
act2->temp_data[0] = 1;
else act2->temp_data[0] = 2;
2021-11-18 17:46:04 +00:00
callsound(sptr, actor);
break;
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:46:04 +00:00
static void handle_st28(sectortype* sptr, DDukeActor* actor)
{
//activate the rest of them
2020-10-23 17:19:30 +00:00
int j = -1;
2021-11-18 17:46:04 +00:00
DukeSectIterator it(sptr);
2020-10-23 17:19:30 +00:00
while (auto a2 = it.Next())
{
if (a2->spr.statnum == 3 && (a2->spr.lotag & 0xff) == 21)
2020-10-23 17:19:30 +00:00
{
j = a2->spr.hitag;
break; //Found it
2020-10-23 17:19:30 +00:00
}
}
2020-10-23 17:19:30 +00:00
if (j == -1) return;
DukeStatIterator it1(STAT_EFFECTOR);
while (auto act3 = it.Next())
{
if ((act3->spr.lotag & 0xff) == 21 && !act3->temp_data[0] &&
(act3->spr.hitag) == j)
2020-10-23 17:19:30 +00:00
act3->temp_data[0] = 1;
}
2021-11-18 17:46:04 +00:00
callsound(sptr, actor);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-18 17:51:19 +00:00
void operatesectors(sectortype* sptr, DDukeActor *actor)
{
2021-11-17 22:31:08 +00:00
int j=0;
int i;
switch (sptr->lotag & (0x3fff))
{
case 41:
if (isRR()) operatejaildoors(sptr->hitag);
break;
case 7:
if (!isRR()) break;
2021-11-17 21:50:56 +00:00
for (auto& wal : wallsofsector(sptr))
{
setanimation(sptr, anim_vertexx, &wal, wal.wall_int_pos().X + 1024, 4);
if (wal.twoSided()) setanimation(sptr, anim_vertexx, wal.nextWall(), wal.nextWall()->wall_int_pos().X + 1024, 4);
}
break;
case ST_30_ROTATE_RISE_BRIDGE:
2020-10-23 17:20:46 +00:00
{
auto act = barrier_cast<DDukeActor*>(sptr->hitagactor);
2020-11-04 18:15:44 +00:00
if (!act) break;
2021-11-18 17:51:19 +00:00
if (act->tempang == 0 || act->tempang == 256) callsound(sptr, actor);
if (act->spr.extra == 1) act->spr.extra = 3;
else act->spr.extra = 1;
break;
2020-10-23 17:20:46 +00:00
}
case ST_31_TWO_WAY_TRAIN:
2020-10-23 17:20:46 +00:00
{
auto act = barrier_cast<DDukeActor*>(sptr->hitagactor);
2020-11-04 18:15:44 +00:00
if (!act) break;
2020-10-23 17:20:46 +00:00
if (act->temp_data[4] == 0)
act->temp_data[4] = 1;
2021-11-18 17:51:19 +00:00
callsound(sptr, actor);
break;
2020-10-23 17:20:46 +00:00
}
case ST_26_SPLITTING_ST_DOOR: //The split doors
2021-11-18 19:01:33 +00:00
i = getanimationgoal(anim_ceilingz, sptr);
if (i == -1) //if the door has stopped
{
haltsoundhack = 1;
sptr->lotag &= 0xff00;
sptr->lotag |= ST_22_SPLITTING_DOOR;
2021-11-18 17:51:19 +00:00
operatesectors(sptr, actor);
sptr->lotag &= 0xff00;
sptr->lotag |= ST_9_SLIDING_ST_DOOR;
2021-11-18 17:51:19 +00:00
operatesectors(sptr, actor);
sptr->lotag &= 0xff00;
sptr->lotag |= ST_26_SPLITTING_ST_DOOR;
}
return;
case ST_9_SLIDING_ST_DOOR:
2021-11-18 17:35:59 +00:00
handle_st09(sptr, actor);
return;
case ST_15_WARP_ELEVATOR://Warping elevators
2021-11-18 17:38:09 +00:00
handle_st15(sptr, actor);
return;
case ST_16_PLATFORM_DOWN:
case ST_17_PLATFORM_UP:
2021-11-18 17:38:09 +00:00
handle_st16(sptr, actor);
return;
case ST_18_ELEVATOR_DOWN:
case ST_19_ELEVATOR_UP:
2021-11-18 17:43:25 +00:00
handle_st18(sptr, actor);
return;
case ST_29_TEETH_DOOR:
2021-11-18 17:43:25 +00:00
handle_st29(sptr, actor);
return;
case ST_20_CEILING_DOOR:
2021-11-18 17:43:25 +00:00
handle_st20(sptr, actor);
return;
case ST_21_FLOOR_DOOR:
2021-11-18 17:43:25 +00:00
handle_st21(sptr, actor);
return;
case ST_22_SPLITTING_DOOR:
2021-11-18 17:43:25 +00:00
handle_st22(sptr, actor);
return;
case ST_23_SWINGING_DOOR: //Swingdoor
2021-11-18 17:46:04 +00:00
handle_st23(sptr, actor);
return;
case ST_25_SLIDING_DOOR: //Subway type sliding doors
{
2021-11-18 17:46:04 +00:00
handle_st25(sptr, actor);
return;
}
case ST_27_STRETCH_BRIDGE: //Extended bridge
2021-11-18 17:46:04 +00:00
handle_st27(sptr, actor);
return;
case ST_28_DROP_FLOOR:
2021-11-18 17:46:04 +00:00
handle_st28(sptr, actor);
return;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void operateactivators(int low, int plnum)
{
int i, j, k;
Cycler * p;
walltype* wal;
for (i = numcyclers - 1; i >= 0; i--)
{
p = &cyclers[i];
if (p->hitag == low)
{
auto sect = p->sector;
p->state = !p->state;
sect->floorshade = sect->ceilingshade = (int8_t)p->shade2;
2021-11-07 07:46:15 +00:00
wal = sect->firstWall();
for (j = sect->wallnum; j > 0; j--, wal++)
wal->shade = (int8_t)p->shade2;
}
}
k = -1;
DukeStatIterator it(STAT_ACTIVATOR);
while (auto act = it.Next())
{
if (act->spr.lotag == low)
{
if (act->spr.picnum == ACTIVATORLOCKED)
{
2021-11-20 23:33:17 +00:00
act->sector()->lotag ^= 16384;
if (plnum >= 0)
{
2021-11-20 23:33:17 +00:00
if (act->sector()->lotag & 16384)
FTA(4, &ps[plnum]);
else FTA(8, &ps[plnum]);
}
}
else
{
switch (act->spr.hitag)
{
case 0:
break;
case 1:
if (act->sector()->int_floorz() != act->sector()->int_ceilingz())
{
continue;
}
break;
case 2:
if (act->sector()->int_floorz() == act->sector()->int_ceilingz())
{
continue;
}
break;
}
2021-11-20 23:33:17 +00:00
if (act->sector()->lotag < 3)
{
DukeSectIterator itr(act->sector());
while (auto a2 = itr.Next())
{
if (a2->spr.statnum == 3) switch (a2->spr.lotag)
{
case SE_18_INCREMENTAL_SECTOR_RISE_FALL:
if (isRRRA()) break;
[[fallthrough]];
case SE_36_PROJ_SHOOTER:
case SE_31_FLOOR_RISE_FALL:
case SE_32_CEILING_RISE_FALL:
a2->temp_data[0] = 1 - a2->temp_data[0];
2021-11-20 23:33:17 +00:00
callsound(act->sector(), a2);
break;
}
}
}
if (k == -1 && (act->sector()->lotag & 0xff) == SE_22_TEETH_DOOR)
2021-11-20 23:33:17 +00:00
k = callsound(act->sector(), act);
2021-11-20 23:33:17 +00:00
operatesectors(act->sector(), act);
}
}
}
fi.operaterespawns(low);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void operatemasterswitches(int low)
{
DukeStatIterator it(STAT_STANDABLE);
while (auto act2 = it.Next())
{
if (act2->spr.picnum == MASTERSWITCH && act2->spr.lotag == low && act2->spr.yvel == 0)
act2->spr.yvel = 1;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-10-23 18:02:57 +00:00
void operateforcefields_common(DDukeActor *effector, int low, const std::initializer_list<int> &tiles)
{
2021-11-17 23:30:37 +00:00
for (int p = numanimwalls-1; p >= 0; p--)
{
2021-11-17 23:30:37 +00:00
auto wal = animwall[p].wall;
2021-11-17 21:50:56 +00:00
if (low == wal->lotag || low == -1)
if (isIn(wal->overpicnum, tiles))
{
animwall[p].tag = 0;
2021-11-17 21:50:56 +00:00
if (wal->cstat)
{
2021-11-17 21:50:56 +00:00
wal->cstat = 0;
if (effector && effector->spr.picnum == SECTOREFFECTOR && effector->spr.lotag == 30)
2021-11-17 21:50:56 +00:00
wal->lotag = 0;
}
else
2021-12-18 14:16:31 +00:00
wal->cstat = (CSTAT_WALL_BLOCK | CSTAT_WALL_ALIGN_BOTTOM | CSTAT_WALL_MASKED | CSTAT_WALL_BLOCK_HITSCAN);
}
}
}
2020-05-10 18:59:38 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-11-17 23:32:46 +00:00
void breakwall(int newpn, DDukeActor* spr, walltype* wal)
2020-05-10 18:59:38 +00:00
{
2021-11-17 23:32:46 +00:00
wal->picnum = newpn;
S_PlayActorSound(VENT_BUST, spr);
S_PlayActorSound(GLASS_HEAVYBREAK, spr);
2021-11-17 23:38:20 +00:00
lotsofglass(spr, wal, 10);
2020-05-10 18:59:38 +00:00
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void allignwarpelevators(void)
{
2020-10-23 18:02:57 +00:00
DukeStatIterator it(STAT_EFFECTOR);
while (auto act = it.Next())
{
if (act->spr.lotag == SE_17_WARP_ELEVATOR && act->spr.shade > 16)
{
2020-10-23 18:02:57 +00:00
DukeStatIterator it1(STAT_EFFECTOR);
while (auto act2 = it1.Next())
{
if ((act2->spr.lotag) == SE_17_WARP_ELEVATOR && act != act2 && act->spr.hitag == act2->spr.hitag)
{
act2->sector()->set_int_floorz(act->sector()->int_floorz());
act2->sector()->set_int_ceilingz(act->sector()->int_ceilingz());
}
}
}
}
2020-05-10 18:59:38 +00:00
}
2020-07-06 00:05:31 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void moveclouds(double smoothratio)
2020-07-06 00:05:31 +00:00
{
// The math here is very messy.. :(
int myclock = smoothratio < 32768? PlayClock-2 : PlayClock;
if (myclock > cloudclock || myclock < (cloudclock - 7))
2020-07-06 00:05:31 +00:00
{
cloudclock = myclock + 6;
2020-07-06 00:05:31 +00:00
// cloudx/y were an array, but all entries were always having the same value so a single pair is enough.
2021-05-12 15:57:36 +00:00
cloudx += (float)ps[screenpeek].angle.ang.fcos() * 0.5f;
cloudy += (float)ps[screenpeek].angle.ang.fsin() * 0.5f;
2020-07-06 00:05:31 +00:00
for (int i = 0; i < numclouds; i++)
{
2022-08-03 13:50:27 +00:00
// no clamping here!
clouds[i]->ceilingxpan_ = cloudx;
clouds[i]->ceilingypan_ = cloudy;
2021-11-17 23:04:52 +00:00
clouds[i]->exflags |= SECTOREX_CLOUDSCROLL;
2020-07-06 00:05:31 +00:00
}
}
}
END_DUKE_NS