mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-03 23:10:48 +00:00
1a2b93f402
This needs to take the composite texture into account because panning in Build is based on tile size, not map dimension. It was also redone to use floating point to get rid of the horrible precision of the scrolling effect.
1273 lines
29 KiB
C++
1273 lines
29 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 1996, 2003 - 3D Realms Entertainment
|
|
Copyright (C) 2000, 2003 - Matt Saettler (EDuke Enhancements)
|
|
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"
|
|
#include "sounds.h"
|
|
#include "dukeactor.h"
|
|
#include "interpolate.h"
|
|
|
|
using std::min;
|
|
using std::max;
|
|
// PRIMITIVE
|
|
BEGIN_DUKE_NS
|
|
|
|
static int interptype[] = { Interp_Sect_Floorz, Interp_Sect_Ceilingz, Interp_Wall_X, Interp_Wall_Y };
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
static bool haltsoundhack;
|
|
|
|
int callsound(int sn, DDukeActor* whatsprite)
|
|
{
|
|
if (!isRRRA() && haltsoundhack)
|
|
{
|
|
haltsoundhack = 0;
|
|
return -1;
|
|
}
|
|
|
|
DukeSectIterator it(sn);
|
|
while (auto act = it.Next())
|
|
{
|
|
auto si = &act->s;
|
|
if (si->picnum == MUSICANDSFX && si->lotag < 1000)
|
|
{
|
|
if (whatsprite == nullptr) whatsprite = act;
|
|
|
|
int snum = si->lotag;
|
|
auto flags = S_GetUserFlags(snum);
|
|
|
|
// Reset if the desired actor isn't playing anything.
|
|
bool hival = S_IsSoundValid(si->hitag);
|
|
if (act->temp_data[0] == 1 && !hival)
|
|
{
|
|
if (!S_CheckActorSoundPlaying(act->temp_actor, snum))
|
|
act->temp_data[0] = 0;
|
|
}
|
|
|
|
if (act->temp_data[0] == 0)
|
|
{
|
|
if ((flags & (SF_GLOBAL | SF_DTAG)) != SF_GLOBAL)
|
|
{
|
|
if (snum)
|
|
{
|
|
if (si->hitag && snum != si->hitag)
|
|
S_StopSound(si->hitag, act->temp_actor);
|
|
S_PlayActorSound(snum, whatsprite);
|
|
act->temp_actor = whatsprite;
|
|
}
|
|
|
|
if ((sector[si->sectnum].lotag & 0xff) != ST_22_SPLITTING_DOOR)
|
|
act->temp_data[0] = 1;
|
|
}
|
|
}
|
|
else if (si->hitag < 1000)
|
|
{
|
|
if ((flags & SF_LOOP) || (si->hitag && si->hitag != si->lotag))
|
|
S_StopSound(si->lotag, act->temp_actor);
|
|
if (si->hitag) S_PlayActorSound(si->hitag, whatsprite);
|
|
act->temp_data[0] = 0;
|
|
act->temp_actor = whatsprite;
|
|
}
|
|
return si->lotag;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int check_activator_motion(int lotag)
|
|
{
|
|
DukeStatIterator it(STAT_ACTIVATOR);
|
|
while (auto act = it.Next())
|
|
{
|
|
if (act->s.lotag == lotag)
|
|
{
|
|
for (int j = animatecnt - 1; j >= 0; j--)
|
|
if (act->s.sectnum == animatesect[j])
|
|
return(1);
|
|
|
|
DukeStatIterator it1(STAT_EFFECTOR);
|
|
while (auto act2 = it1.Next())
|
|
{
|
|
if (act->s.sectnum == act2->s.sectnum)
|
|
switch (act2->s.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;
|
|
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;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int findplayer(const DDukeActor* actor, int* d)
|
|
{
|
|
short j, closest_player;
|
|
int x, closest;
|
|
auto s = &actor->s.pos;
|
|
|
|
if (ud.multimode < 2)
|
|
{
|
|
if (d) *d = abs(ps[myconnectindex].oposx - s->x) + abs(ps[myconnectindex].oposy - s->y) + ((abs(ps[myconnectindex].oposz - s->z + (28 << 8))) >> 4);
|
|
return myconnectindex;
|
|
}
|
|
|
|
closest = 0x7fffffff;
|
|
closest_player = 0;
|
|
|
|
for (j = connecthead; j >= 0; j = connectpoint2[j])
|
|
{
|
|
x = abs(ps[j].oposx - s->x) + abs(ps[j].oposy - s->y) + ((abs(ps[j].oposz - s->z + (28 << 8))) >> 4);
|
|
if (x < closest && ps[j].GetActor()->s.extra > 0)
|
|
{
|
|
closest_player = j;
|
|
closest = x;
|
|
}
|
|
}
|
|
|
|
if (d) *d = closest;
|
|
return closest_player;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int findotherplayer(int p, int* d)
|
|
{
|
|
short 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()->s.extra > 0)
|
|
{
|
|
x = abs(ps[j].oposx - ps[p].posx) + abs(ps[j].oposy - ps[p].posy) + (abs(ps[j].oposz - ps[p].posz) >> 4);
|
|
|
|
if (x < closest)
|
|
{
|
|
closest_player = j;
|
|
closest = x;
|
|
}
|
|
}
|
|
|
|
*d = closest;
|
|
return closest_player;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int* animateptr(int type, int index)
|
|
{
|
|
static int scratch;
|
|
switch (type)
|
|
{
|
|
case anim_floorz:
|
|
return §or[index].floorz;
|
|
case anim_ceilingz:
|
|
return §or[index].ceilingz;
|
|
case anim_vertexx:
|
|
return &wall[index].x;
|
|
case anim_vertexy:
|
|
return &wall[index].y;
|
|
default:
|
|
assert(false);
|
|
return &scratch;
|
|
}
|
|
}
|
|
|
|
int* animateptr(int i)
|
|
{
|
|
return animateptr(animatetype[i], animatetarget[i]);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void doanimations(void)
|
|
{
|
|
int i, a, p, v, dasect;
|
|
|
|
for (i = animatecnt - 1; i >= 0; i--)
|
|
{
|
|
a = *animateptr(i);
|
|
v = animatevel[i] * TICSPERFRAME;
|
|
dasect = 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];
|
|
if (sector[animatesect[i]].lotag == ST_18_ELEVATOR_DOWN || sector[animatesect[i]].lotag == ST_19_ELEVATOR_UP)
|
|
if (animatetype[i] == anim_ceilingz)
|
|
continue;
|
|
|
|
if ((sector[dasect].lotag & 0xff) != ST_22_SPLITTING_DOOR)
|
|
callsound(dasect, nullptr);
|
|
|
|
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].cursectnum == dasect)
|
|
if ((sector[dasect].floorz - ps[p].posz) < (64 << 8))
|
|
if (ps[p].GetActor()->GetOwner() != nullptr)
|
|
{
|
|
ps[p].posz += v;
|
|
ps[p].poszv = 0;
|
|
}
|
|
|
|
DukeSectIterator it(dasect);
|
|
while (auto act = it.Next())
|
|
{
|
|
if (act->s.statnum != STAT_EFFECTOR)
|
|
{
|
|
act->bposz = act->s.z;
|
|
act->s.z += v;
|
|
act->floorz = sector[dasect].floorz + v;
|
|
}
|
|
}
|
|
}
|
|
|
|
*animateptr(i) = a;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int getanimationgoal(int animtype, int animtarget)
|
|
{
|
|
int i, j;
|
|
|
|
j = -1;
|
|
for (i = animatecnt - 1; i >= 0; i--)
|
|
if (animtype == animatetype[i] && animtarget == animatetarget[i])
|
|
{
|
|
j = i;
|
|
break;
|
|
}
|
|
return(j);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
int setanimation(short 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 animptr = animateptr(animtype, animtarget);
|
|
animatesect[j] = animsect;
|
|
animatetype[j] = animtype;
|
|
animatetarget[j] = animtarget;
|
|
animategoal[j] = thegoal;
|
|
if (thegoal >= *animptr)
|
|
animatevel[j] = thevel;
|
|
else
|
|
animatevel[j] = -thevel;
|
|
|
|
if (j == animatecnt) animatecnt++;
|
|
|
|
StartInterpolation(animatetarget[i], interptype[animatetype[i]]);
|
|
return(j);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool activatewarpelevators(DDukeActor* actor, int d) //Parm = sectoreffectornum
|
|
{
|
|
int sn = actor->s.sectnum;
|
|
|
|
// See if the sector exists
|
|
|
|
DukeStatIterator it(STAT_EFFECTOR);
|
|
DDukeActor *act2;
|
|
while ((act2 = it.Next()))
|
|
{
|
|
if (act2->s.lotag == SE_17_WARP_ELEVATOR || (isRRRA() && act2->s.lotag == SE_18_INCREMENTAL_SECTOR_RISE_FALL))
|
|
if (act2->s.hitag == actor->s.hitag)
|
|
if ((abs(sector[sn].floorz - actor->temp_data[2]) > act2->s.yvel) ||
|
|
(sector[act2->s.sectnum].hitag == (sector[sn].hitag - d)))
|
|
break;
|
|
}
|
|
|
|
if (act2 == nullptr)
|
|
{
|
|
d = 0;
|
|
return 1; // No find
|
|
}
|
|
else
|
|
{
|
|
if (d == 0)
|
|
S_PlayActorSound(ELEVATOR_OFF, actor);
|
|
else S_PlayActorSound(ELEVATOR_ON, actor);
|
|
}
|
|
|
|
|
|
it.Reset(STAT_EFFECTOR);
|
|
while ((act2 = it.Next()))
|
|
{
|
|
if (act2->s.lotag == SE_17_WARP_ELEVATOR || (isRRRA() && act2->s.lotag == SE_18_INCREMENTAL_SECTOR_RISE_FALL))
|
|
if (act2->s.hitag == actor->s.hitag)
|
|
{
|
|
act2->temp_data[0] = d;
|
|
act2->temp_data[1] = d; //Make all check warp
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st09(int sn, DDukeActor* actor)
|
|
{
|
|
int dax, day, dax2, day2, sp;
|
|
int wallfind[2];
|
|
sectortype* sptr = §or[sn];
|
|
|
|
int startwall = sptr->wallptr;
|
|
int endwall = startwall + sptr->wallnum - 1;
|
|
|
|
sp = sptr->extra >> 4;
|
|
|
|
//first find center point by averaging all points
|
|
dax = 0L, day = 0L;
|
|
for (int i = startwall; i <= endwall; i++)
|
|
{
|
|
dax += wall[i].x;
|
|
day += wall[i].y;
|
|
}
|
|
dax /= (endwall - startwall + 1);
|
|
day /= (endwall - startwall + 1);
|
|
|
|
//find any points with either same x or same y coordinate
|
|
// as center (dax, day) - should be 2 points found.
|
|
wallfind[0] = -1;
|
|
wallfind[1] = -1;
|
|
for (int i = startwall; i <= endwall; i++)
|
|
if ((wall[i].x == dax) || (wall[i].y == day))
|
|
{
|
|
if (wallfind[0] == -1)
|
|
wallfind[0] = i;
|
|
else wallfind[1] = i;
|
|
}
|
|
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
if ((wall[wallfind[j]].x == dax) && (wall[wallfind[j]].y == day))
|
|
{
|
|
//find what direction door should open by averaging the
|
|
// 2 neighboring points of wallfind[0] & wallfind[1].
|
|
int i = wallfind[j] - 1; if (i < startwall) i = endwall;
|
|
dax2 = ((wall[i].x + wall[wall[wallfind[j]].point2].x) >> 1) - wall[wallfind[j]].x;
|
|
day2 = ((wall[i].y + wall[wall[wallfind[j]].point2].y) >> 1) - wall[wallfind[j]].y;
|
|
if (dax2 != 0)
|
|
{
|
|
dax2 = wall[wall[wall[wallfind[j]].point2].point2].x;
|
|
dax2 -= wall[wall[wallfind[j]].point2].x;
|
|
setanimation(sn, anim_vertexx, wallfind[j], wall[wallfind[j]].x + dax2, sp);
|
|
setanimation(sn, anim_vertexx, i, wall[i].x + dax2, sp);
|
|
setanimation(sn, anim_vertexx, wall[wallfind[j]].point2, wall[wall[wallfind[j]].point2].x + dax2, sp);
|
|
callsound(sn, actor);
|
|
}
|
|
else if (day2 != 0)
|
|
{
|
|
day2 = wall[wall[wall[wallfind[j]].point2].point2].y;
|
|
day2 -= wall[wall[wallfind[j]].point2].y;
|
|
setanimation(sn, anim_vertexy, wallfind[j], wall[wallfind[j]].y + day2, sp);
|
|
setanimation(sn, anim_vertexy, i, wall[i].y + day2, sp);
|
|
setanimation(sn, anim_vertexy, wall[wallfind[j]].point2, wall[wall[wallfind[j]].point2].y + day2, sp);
|
|
callsound(sn, actor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int i = wallfind[j] - 1; if (i < startwall) i = endwall;
|
|
dax2 = ((wall[i].x + wall[wall[wallfind[j]].point2].x) >> 1) - wall[wallfind[j]].x;
|
|
day2 = ((wall[i].y + wall[wall[wallfind[j]].point2].y) >> 1) - wall[wallfind[j]].y;
|
|
if (dax2 != 0)
|
|
{
|
|
setanimation(sn, anim_vertexx, wallfind[j], dax, sp);
|
|
setanimation(sn, anim_vertexx, i, dax + dax2, sp);
|
|
setanimation(sn, anim_vertexx, wall[wallfind[j]].point2, dax + dax2, sp);
|
|
callsound(sn, actor);
|
|
}
|
|
else if (day2 != 0)
|
|
{
|
|
setanimation(sn, anim_vertexy, wallfind[j], day, sp);
|
|
setanimation(sn, anim_vertexy, i, day + day2, sp);
|
|
setanimation(sn, anim_vertexy, wall[wallfind[j]].point2, day + day2, sp);
|
|
callsound(sn, actor);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st15(int sn, DDukeActor* actor)
|
|
{
|
|
if (actor->s.picnum != TILE_APLAYER) return;
|
|
|
|
sectortype* sptr = §or[sn];
|
|
DukeSectIterator it(sn);
|
|
DDukeActor* a2;
|
|
while ((a2 = it.Next()))
|
|
{
|
|
if (a2->s.picnum == SECTOREFFECTOR && a2->s.lotag == ST_17_PLATFORM_UP) break;
|
|
}
|
|
if (!a2) return;
|
|
|
|
if (actor->s.sectnum == sn)
|
|
{
|
|
if (activatewarpelevators(a2, -1))
|
|
activatewarpelevators(a2, 1);
|
|
else if (activatewarpelevators(a2, 1))
|
|
activatewarpelevators(a2, -1);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (sptr->floorz > a2->s.z)
|
|
activatewarpelevators(a2, -1);
|
|
else
|
|
activatewarpelevators(a2, 1);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st16(int sn, DDukeActor* actor)
|
|
{
|
|
sectortype* sptr = §or[sn];
|
|
int i = getanimationgoal(anim_floorz, sn);
|
|
int j;
|
|
|
|
if (i == -1)
|
|
{
|
|
i = nextsectorneighborz(sn, sptr->floorz, 1, 1);
|
|
if (i == -1)
|
|
{
|
|
i = nextsectorneighborz(sn, sptr->floorz, 1, -1);
|
|
if (i == -1) return;
|
|
j = sector[i].floorz;
|
|
setanimation(sn, anim_floorz, sn, j, sptr->extra);
|
|
}
|
|
else
|
|
{
|
|
j = sector[i].floorz;
|
|
setanimation(sn, anim_floorz, sn, j, sptr->extra);
|
|
}
|
|
callsound(sn, actor);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st18(int sn, DDukeActor* actor)
|
|
{
|
|
sectortype* sptr = §or[sn];
|
|
int i = getanimationgoal(anim_floorz, sn);
|
|
|
|
if (i == -1)
|
|
{
|
|
i = nextsectorneighborz(sn, sptr->floorz, 1, -1);
|
|
if (i == -1) i = nextsectorneighborz(sn, sptr->floorz, 1, 1);
|
|
if (i == -1) return;
|
|
int j = sector[i].floorz;
|
|
int q = sptr->extra;
|
|
int l = sptr->ceilingz - sptr->floorz;
|
|
setanimation(sn, anim_floorz, sn, j, q);
|
|
setanimation(sn, anim_ceilingz, sn, j + l, q);
|
|
callsound(sn, actor);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st29(int sn, DDukeActor* actor)
|
|
{
|
|
sectortype* sptr = §or[sn];
|
|
int j;
|
|
|
|
if (sptr->lotag & 0x8000)
|
|
j = sector[nextsectorneighborz(sn, sptr->ceilingz, 1, 1)].floorz;
|
|
else
|
|
j = sector[nextsectorneighborz(sn, sptr->ceilingz, -1, -1)].ceilingz;
|
|
|
|
DukeStatIterator it(STAT_EFFECTOR);
|
|
while (auto act2 = it.Next())
|
|
{
|
|
if ((act2->s.lotag == 22) &&
|
|
(act2->s.hitag == sptr->hitag))
|
|
{
|
|
sector[act2->s.sectnum].extra = -sector[act2->s.sectnum].extra;
|
|
|
|
act2->temp_data[0] = sn;
|
|
act2->temp_data[1] = 1;
|
|
}
|
|
}
|
|
|
|
sptr->lotag ^= 0x8000;
|
|
|
|
setanimation(sn, anim_ceilingz, sn, j, sptr->extra);
|
|
|
|
callsound(sn, actor);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st20(int sn, DDukeActor* actor)
|
|
{
|
|
sectortype* sptr = §or[sn];
|
|
int j;
|
|
REDODOOR:
|
|
|
|
if (sptr->lotag & 0x8000)
|
|
{
|
|
DDukeActor* a2;
|
|
DukeSectIterator it(sn);
|
|
while ((a2 = it.Next()))
|
|
{
|
|
if (a2->s.statnum == 3 && a2->s.lotag == 9)
|
|
{
|
|
j = a2->s.z;
|
|
break;
|
|
}
|
|
}
|
|
if (a2 == nullptr)
|
|
j = sptr->floorz;
|
|
}
|
|
else
|
|
{
|
|
j = nextsectorneighborz(sn, sptr->ceilingz, -1, -1);
|
|
|
|
if (j >= 0) j = sector[j].ceilingz;
|
|
else
|
|
{
|
|
sptr->lotag |= 32768;
|
|
goto REDODOOR;
|
|
}
|
|
}
|
|
|
|
sptr->lotag ^= 0x8000;
|
|
|
|
setanimation(sn, anim_ceilingz, sn, j, sptr->extra);
|
|
callsound(sn, actor);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st21(int sn, DDukeActor* actor)
|
|
{
|
|
sectortype* sptr = §or[sn];
|
|
int i = getanimationgoal(anim_floorz, sn);
|
|
int j;
|
|
if (i >= 0)
|
|
{
|
|
if (animategoal[sn] == sptr->ceilingz)
|
|
animategoal[i] = sector[nextsectorneighborz(sn, sptr->ceilingz, 1, 1)].floorz;
|
|
else animategoal[i] = sptr->ceilingz;
|
|
j = animategoal[i];
|
|
}
|
|
else
|
|
{
|
|
if (sptr->ceilingz == sptr->floorz)
|
|
j = sector[nextsectorneighborz(sn, sptr->ceilingz, 1, 1)].floorz;
|
|
else j = sptr->ceilingz;
|
|
|
|
sptr->lotag ^= 0x8000;
|
|
|
|
if (setanimation(sn, anim_floorz, sn, j, sptr->extra) >= 0)
|
|
callsound(sn, actor);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st22(int sn, DDukeActor* actor)
|
|
{
|
|
sectortype* sptr = §or[sn];
|
|
int j, q;
|
|
if ((sptr->lotag & 0x8000))
|
|
{
|
|
q = (sptr->ceilingz + sptr->floorz) >> 1;
|
|
j = setanimation(sn, anim_floorz, sn, q, sptr->extra);
|
|
j = setanimation(sn, anim_ceilingz, sn, q, sptr->extra);
|
|
}
|
|
else
|
|
{
|
|
q = sector[nextsectorneighborz(sn, sptr->floorz, 1, 1)].floorz;
|
|
j = setanimation(sn, anim_floorz, sn, q, sptr->extra);
|
|
q = sector[nextsectorneighborz(sn, sptr->ceilingz, -1, -1)].ceilingz;
|
|
j = setanimation(sn, anim_ceilingz, sn, q, sptr->extra);
|
|
}
|
|
|
|
sptr->lotag ^= 0x8000;
|
|
|
|
callsound(sn, actor);
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st23(int sn, DDukeActor* actor)
|
|
{
|
|
int q = 0;
|
|
|
|
DukeStatIterator it(STAT_EFFECTOR);
|
|
DDukeActor* act2;
|
|
while ((act2 = it.Next()))
|
|
{
|
|
if (act2->s.lotag == 11 && act2->s.sectnum == sn && !act2->temp_data[4])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (!act2) return;
|
|
|
|
int l = sector[act2->s.sectnum].lotag & 0x8000;
|
|
|
|
if (act2)
|
|
{
|
|
DukeStatIterator it(STAT_EFFECTOR);
|
|
while (auto act3 = it.Next())
|
|
{
|
|
if (l == (sector[act3->s.sectnum].lotag & 0x8000) && act3->s.lotag == 11 && act2->s.hitag == act3->s.hitag && !act3->temp_data[4])
|
|
{
|
|
if (sector[act3->s.sectnum].lotag & 0x8000) sector[act3->s.sectnum].lotag &= 0x7fff;
|
|
else sector[act3->s.sectnum].lotag |= 0x8000;
|
|
act3->temp_data[4] = 1;
|
|
act3->temp_data[3] = -act3->temp_data[3];
|
|
if (q == 0)
|
|
{
|
|
callsound(sn, act3);
|
|
q = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st25(int sn, DDukeActor* actor)
|
|
{
|
|
DukeStatIterator it(STAT_EFFECTOR);
|
|
DDukeActor* act2;
|
|
while ((act2 = it.Next()))
|
|
{
|
|
if (act2->s.lotag == 15 && act2->s.sectnum == sn)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (act2 == nullptr)
|
|
return;
|
|
|
|
it.Reset(STAT_EFFECTOR);
|
|
while (auto act3 = it.Next())
|
|
{
|
|
if (act3->s.hitag == act2->s.hitag)
|
|
{
|
|
if (act3->s.lotag == 15)
|
|
{
|
|
sector[act3->s.sectnum].lotag ^= 0x8000; // Toggle the open or close
|
|
act3->s.ang += 1024;
|
|
if (act3->temp_data[4]) callsound(act3->s.sectnum, act3);
|
|
callsound(act3->s.sectnum, act3);
|
|
if (sector[act3->s.sectnum].lotag & 0x8000) act3->temp_data[4] = 1;
|
|
else act3->temp_data[4] = 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st27(int sn, DDukeActor* actor)
|
|
{
|
|
DukeStatIterator it(STAT_EFFECTOR);
|
|
while (auto act2 = it.Next())
|
|
{
|
|
if ((act2->s.lotag & 0xff) == 20 && act2->s.sectnum == sn) //Bridge
|
|
{
|
|
|
|
sector[sn].lotag ^= 0x8000;
|
|
if (sector[sn].lotag & 0x8000) //OPENING
|
|
act2->temp_data[0] = 1;
|
|
else act2->temp_data[0] = 2;
|
|
callsound(sn, actor);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
static void handle_st28(int sn, DDukeActor* actor)
|
|
{
|
|
//activate the rest of them
|
|
int j = -1;
|
|
DukeSectIterator it(sn);
|
|
while (auto a2 = it.Next())
|
|
{
|
|
if (a2->s.statnum == 3 && (a2->s.lotag & 0xff) == 21)
|
|
{
|
|
j = a2->s.hitag;
|
|
break; //Found it
|
|
}
|
|
}
|
|
|
|
if (j == -1) return;
|
|
DukeStatIterator it1(STAT_EFFECTOR);
|
|
while (auto act3 = it.Next())
|
|
{
|
|
if ((act3->s.lotag & 0xff) == 21 && !act3->temp_data[0] &&
|
|
(act3->s.hitag) == j)
|
|
act3->temp_data[0] = 1;
|
|
}
|
|
callsound(sn, actor);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void operatesectors(int sn, DDukeActor *actor)
|
|
{
|
|
int j=0, startwall, endwall;
|
|
int i;
|
|
sectortype* sptr;
|
|
|
|
sptr = §or[sn];
|
|
|
|
switch (sptr->lotag & (0x3fff))
|
|
{
|
|
|
|
case 41:
|
|
if (isRR()) operatejaildoors(sptr->hitag);
|
|
break;
|
|
|
|
case 7:
|
|
if (!isRR()) break;
|
|
startwall = sptr->wallptr;
|
|
endwall = startwall + sptr->wallnum;
|
|
for (j = startwall; j < endwall; j++)
|
|
{
|
|
setanimation(sn, anim_vertexx, j, wall[j].x + 1024, 4);
|
|
setanimation(sn, anim_vertexx, wall[j].nextwall, wall[wall[j].nextwall].x + 1024, 4);
|
|
}
|
|
break;
|
|
|
|
case ST_30_ROTATE_RISE_BRIDGE:
|
|
{
|
|
auto act = ScriptIndexToActor(sector[sn].hitag);
|
|
if (!act) break;
|
|
if (act->tempang == 0 || act->tempang == 256) callsound(sn, actor);
|
|
if (act->s.extra == 1) act->s.extra = 3;
|
|
else act->s.extra = 1;
|
|
break;
|
|
}
|
|
|
|
case ST_31_TWO_WAY_TRAIN:
|
|
{
|
|
auto act = ScriptIndexToActor(sector[sn].hitag);
|
|
if (!act) break;
|
|
if (act->temp_data[4] == 0)
|
|
act->temp_data[4] = 1;
|
|
|
|
callsound(sn, actor);
|
|
break;
|
|
}
|
|
case ST_26_SPLITTING_ST_DOOR: //The split doors
|
|
i = getanimationgoal(anim_ceilingz, sn);
|
|
if (i == -1) //if the door has stopped
|
|
{
|
|
haltsoundhack = 1;
|
|
sptr->lotag &= 0xff00;
|
|
sptr->lotag |= ST_22_SPLITTING_DOOR;
|
|
operatesectors(sn, actor);
|
|
sptr->lotag &= 0xff00;
|
|
sptr->lotag |= ST_9_SLIDING_ST_DOOR;
|
|
operatesectors(sn, actor);
|
|
sptr->lotag &= 0xff00;
|
|
sptr->lotag |= ST_26_SPLITTING_ST_DOOR;
|
|
}
|
|
return;
|
|
|
|
case ST_9_SLIDING_ST_DOOR:
|
|
handle_st09(sn, actor);
|
|
return;
|
|
|
|
case ST_15_WARP_ELEVATOR://Warping elevators
|
|
handle_st15(sn, actor);
|
|
return;
|
|
|
|
case ST_16_PLATFORM_DOWN:
|
|
case ST_17_PLATFORM_UP:
|
|
handle_st16(sn, actor);
|
|
return;
|
|
|
|
case ST_18_ELEVATOR_DOWN:
|
|
case ST_19_ELEVATOR_UP:
|
|
handle_st18(sn, actor);
|
|
return;
|
|
|
|
case ST_29_TEETH_DOOR:
|
|
handle_st29(sn, actor);
|
|
return;
|
|
case ST_20_CEILING_DOOR:
|
|
handle_st20(sn, actor);
|
|
return;
|
|
|
|
case ST_21_FLOOR_DOOR:
|
|
handle_st21(sn, actor);
|
|
return;
|
|
|
|
case ST_22_SPLITTING_DOOR:
|
|
handle_st22(sn, actor);
|
|
return;
|
|
|
|
case ST_23_SWINGING_DOOR: //Swingdoor
|
|
handle_st23(sn, actor);
|
|
return;
|
|
|
|
case ST_25_SLIDING_DOOR: //Subway type sliding doors
|
|
{
|
|
handle_st25(sn, actor);
|
|
return;
|
|
}
|
|
case ST_27_STRETCH_BRIDGE: //Extended bridge
|
|
handle_st27(sn, actor);
|
|
return;
|
|
|
|
case ST_28_DROP_FLOOR:
|
|
handle_st28(sn, actor);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void operateactivators(int low, int plnum)
|
|
{
|
|
int i, j, k;
|
|
short * p;
|
|
walltype* wal;
|
|
|
|
for (i = numcyclers - 1; i >= 0; i--)
|
|
{
|
|
p = &cyclers[i][0];
|
|
|
|
if (p[4] == low)
|
|
{
|
|
p[5] = !p[5];
|
|
|
|
sector[p[0]].floorshade = sector[p[0]].ceilingshade = p[3];
|
|
wal = &wall[sector[p[0]].wallptr];
|
|
for (j = sector[p[0]].wallnum; j > 0; j--, wal++)
|
|
wal->shade = p[3];
|
|
}
|
|
}
|
|
|
|
k = -1;
|
|
DukeStatIterator it(STAT_ACTIVATOR);
|
|
while (auto act = it.Next())
|
|
{
|
|
if (act->s.lotag == low)
|
|
{
|
|
if (act->s.picnum == ACTIVATORLOCKED)
|
|
{
|
|
sector[act->s.sectnum].lotag ^= 16384;
|
|
|
|
if (plnum >= 0)
|
|
{
|
|
if (sector[act->s.sectnum].lotag & 16384)
|
|
FTA(4, &ps[plnum]);
|
|
else FTA(8, &ps[plnum]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (act->s.hitag)
|
|
{
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
if (sector[act->s.sectnum].floorz != sector[act->s.sectnum].ceilingz)
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (sector[act->s.sectnum].floorz == sector[act->s.sectnum].ceilingz)
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (sector[act->s.sectnum].lotag < 3)
|
|
{
|
|
DukeSectIterator it(act->s.sectnum);
|
|
while (auto a2 = it.Next())
|
|
{
|
|
if (a2->s.statnum == 3) switch (a2->s.lotag)
|
|
{
|
|
case SE_18_INCREMENTAL_SECTOR_RISE_FALL:
|
|
if (isRRRA()) break;
|
|
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];
|
|
callsound(act->s.sectnum, a2);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (k == -1 && (sector[act->s.sectnum].lotag & 0xff) == 22)
|
|
k = callsound(act->s.sectnum, act);
|
|
|
|
operatesectors(act->s.sectnum, act);
|
|
}
|
|
}
|
|
}
|
|
|
|
fi.operaterespawns(low);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void operatemasterswitches(int low)
|
|
{
|
|
DukeStatIterator it(STAT_STANDABLE);
|
|
while (auto act2 = it.Next())
|
|
{
|
|
if (act2->s.picnum == MASTERSWITCH && act2->s.lotag == low && act2->s.yvel == 0)
|
|
act2->s.yvel = 1;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void operateforcefields_common(DDukeActor *effector, int low, const std::initializer_list<int> &tiles)
|
|
{
|
|
int i, p;
|
|
|
|
for (p = numanimwalls; p >= 0; p--)
|
|
{
|
|
i = animwall[p].wallnum;
|
|
|
|
if (low == wall[i].lotag || low == -1)
|
|
if (isIn(wall[i].overpicnum, tiles))
|
|
{
|
|
animwall[p].tag = 0;
|
|
|
|
if (wall[i].cstat)
|
|
{
|
|
wall[i].cstat = 0;
|
|
|
|
if (effector && effector->s.picnum == SECTOREFFECTOR && effector->s.lotag == 30)
|
|
wall[i].lotag = 0;
|
|
}
|
|
else
|
|
wall[i].cstat = 85;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void breakwall(short newpn, DDukeActor* spr, short dawallnum)
|
|
{
|
|
wall[dawallnum].picnum = newpn;
|
|
S_PlayActorSound(VENT_BUST, spr);
|
|
S_PlayActorSound(GLASS_HEAVYBREAK, spr);
|
|
lotsofglass(spr, dawallnum, 10);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void allignwarpelevators(void)
|
|
{
|
|
DukeStatIterator it(STAT_EFFECTOR);
|
|
while (auto act = it.Next())
|
|
{
|
|
if (act->s.lotag == SE_17_WARP_ELEVATOR && act->s.shade > 16)
|
|
{
|
|
DukeStatIterator it1(STAT_EFFECTOR);
|
|
while (auto act2 = it1.Next())
|
|
{
|
|
if ((act2->s.lotag) == SE_17_WARP_ELEVATOR && act != act2 && act->s.hitag == act2->s.hitag)
|
|
{
|
|
sector[act2->s.sectnum].floorz = sector[act->s.sectnum].floorz;
|
|
sector[act2->s.sectnum].ceilingz = sector[act->s.sectnum].ceilingz;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
//
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void moveclouds(double smoothratio)
|
|
{
|
|
// The math here is very messy.. :(
|
|
int myclock = smoothratio < 32768? ud.levelclock-2 : ud.levelclock;
|
|
if (myclock > cloudclock || myclock < (cloudclock - 7))
|
|
{
|
|
cloudclock = myclock + 6;
|
|
|
|
// cloudx/y were an array, but all entries were always having the same value so a single pair is enough.
|
|
cloudx += ps[screenpeek].angle.ang.fcos() * 0.5f;
|
|
cloudy += ps[screenpeek].angle.ang.fsin() * 0.5f;
|
|
for (int i = 0; i < numclouds; i++)
|
|
{
|
|
sector[clouds[i]].setceilingxpan(cloudx);
|
|
sector[clouds[i]].setceilingypan(cloudy);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
END_DUKE_NS
|