- moved all scroller related code into its own file, including the DScroller class definition.

This commit is contained in:
Christoph Oelckers 2016-03-28 17:27:55 +02:00
parent b70fee8ed8
commit b5f333798e
10 changed files with 766 additions and 665 deletions

View file

@ -1071,6 +1071,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
p_plats.cpp
p_pspr.cpp
p_saveg.cpp
p_scroll.cpp
p_sectors.cpp
p_setup.cpp
p_sight.cpp

View file

@ -42,6 +42,7 @@ class PClass;
class FArchive;
class DObject;
/*
class DArgs;
class DCanvas;
class DConsoleCommand;
@ -77,6 +78,7 @@ class DFloor;
class DFloorWaggle;
class DPlat;
class DPillar;
*/
class PClassActor;

View file

@ -42,6 +42,7 @@ class AActor;
class player_t;
struct pspdef_s;
struct FState;
class DThinker;
class FThinkerIterator;

View file

@ -2023,7 +2023,7 @@ void FLevelLocals::Tick ()
//
//==========================================================================
void FLevelLocals::AddScroller (DScroller *scroller, int secnum)
void FLevelLocals::AddScroller (int secnum)
{
if (secnum < 0)
{

View file

@ -383,7 +383,7 @@ struct FSectorScrollValues
struct FLevelLocals
{
void Tick ();
void AddScroller (DScroller *, int secnum);
void AddScroller (int secnum);
int time; // time in the hub
int maptime; // time in the map

View file

@ -2145,17 +2145,11 @@ FUNC(LS_Sector_ChangeFlags)
return rtn;
}
struct FThinkerCollection
{
int RefNum;
DThinker *Obj;
};
static TArray<FThinkerCollection> Collection;
void AdjustPusher (int tag, int magnitude, int angle, DPusher::EPusher type)
{
// Find pushers already attached to the sector, and change their parameters.
TArray<FThinkerCollection> Collection;
{
TThinkerIterator<DPusher> iterator;
FThinkerCollection collect;
@ -2188,7 +2182,6 @@ void AdjustPusher (int tag, int magnitude, int angle, DPusher::EPusher type)
new DPusher (type, NULL, magnitude, angle, NULL, secnum);
}
}
Collection.Clear ();
}
FUNC(LS_Sector_SetWind)
@ -2249,76 +2242,9 @@ FUNC(LS_Sector_SetLink)
return false;
}
void SetWallScroller(int id, int sidechoice, fixed_t dx, fixed_t dy, EScrollPos Where);
void SetScroller(int tag, EScroll type, fixed_t dx, fixed_t dy);
static void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, int Where)
{
Where &=7;
if (Where == 0) return;
if ((dx | dy) == 0)
{
// Special case: Remove the scroller, because the deltas are both 0.
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
DScroller *scroller;
while ( (scroller = iterator.Next ()) )
{
int wallnum = scroller->GetWallNum ();
if (wallnum >= 0 && tagManager.LineHasID(sides[wallnum].linedef, id) &&
int(sides[wallnum].linedef->sidedef[sidechoice] - sides) == wallnum &&
Where == scroller->GetScrollParts())
{
scroller->Destroy ();
}
}
}
else
{
// Find scrollers already attached to the matching walls, and change
// their rates.
{
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
FThinkerCollection collect;
while ( (collect.Obj = iterator.Next ()) )
{
if ((collect.RefNum = ((DScroller *)collect.Obj)->GetWallNum ()) != -1 &&
tagManager.LineHasID(sides[collect.RefNum].linedef, id) &&
int(sides[collect.RefNum].linedef->sidedef[sidechoice] - sides) == collect.RefNum &&
Where == ((DScroller *)collect.Obj)->GetScrollParts())
{
((DScroller *)collect.Obj)->SetRate (dx, dy);
Collection.Push (collect);
}
}
}
size_t numcollected = Collection.Size ();
int linenum;
// Now create scrollers for any walls that don't already have them.
FLineIdIterator itr(id);
while ((linenum = itr.Next()) >= 0)
{
if (lines[linenum].sidedef[sidechoice] != NULL)
{
int sidenum = int(lines[linenum].sidedef[sidechoice] - sides);
unsigned int i;
for (i = 0; i < numcollected; i++)
{
if (Collection[i].RefNum == sidenum)
break;
}
if (i == numcollected)
{
new DScroller (DScroller::sc_side, dx, dy, -1, sidenum, 0, Where);
}
}
}
Collection.Clear ();
}
}
FUNC(LS_Scroll_Texture_Both)
// Scroll_Texture_Both (id, left, right, up, down)
@ -2340,7 +2266,7 @@ FUNC(LS_Scroll_Texture_Both)
sidechoice = 0;
}
SetWallScroller (arg0, sidechoice, dx, dy, 7);
SetWallScroller (arg0, sidechoice, dx, dy, scw_all);
return true;
}
@ -2351,47 +2277,10 @@ FUNC(LS_Scroll_Wall)
if (arg0 == 0)
return false;
SetWallScroller (arg0, !!arg3, arg1, arg2, arg4);
SetWallScroller (arg0, !!arg3, arg1, arg2, EScrollPos(arg4));
return true;
}
static void SetScroller (int tag, DScroller::EScrollType type, fixed_t dx, fixed_t dy)
{
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
DScroller *scroller;
int i;
// Check if there is already a scroller for this tag
// If at least one sector with this tag is scrolling, then they all are.
// If the deltas are both 0, we don't remove the scroller, because a
// displacement/accelerative scroller might have been set up, and there's
// no way to create one after the level is fully loaded.
i = 0;
while ( (scroller = iterator.Next ()) )
{
if (scroller->IsType (type))
{
if (tagManager.SectorHasTag(scroller->GetAffectee (), tag))
{
i++;
scroller->SetRate (dx, dy);
}
}
}
if (i > 0 || (dx|dy) == 0)
{
return;
}
// Need to create scrollers for the sector(s)
FSectorTagIterator itr(tag);
while ((i = itr.Next()) >= 0)
{
new DScroller (type, dx, dy, -1, i, 0);
}
}
// NOTE: For the next two functions, x-move and y-move are
// 0-based, not 128-based as they are if they appear on lines.
// Note also that parameter ordering is different.
@ -2404,19 +2293,19 @@ FUNC(LS_Scroll_Floor)
if (arg3 == 0 || arg3 == 2)
{
SetScroller (arg0, DScroller::sc_floor, -dx, dy);
SetScroller (arg0, EScroll::sc_floor, -dx, dy);
}
else
{
SetScroller (arg0, DScroller::sc_floor, 0, 0);
SetScroller (arg0, EScroll::sc_floor, 0, 0);
}
if (arg3 > 0)
{
SetScroller (arg0, DScroller::sc_carry, dx, dy);
SetScroller (arg0, EScroll::sc_carry, dx, dy);
}
else
{
SetScroller (arg0, DScroller::sc_carry, 0, 0);
SetScroller (arg0, EScroll::sc_carry, 0, 0);
}
return true;
}
@ -2427,7 +2316,7 @@ FUNC(LS_Scroll_Ceiling)
fixed_t dx = arg1 * FRACUNIT/32;
fixed_t dy = arg2 * FRACUNIT/32;
SetScroller (arg0, DScroller::sc_ceiling, -dx, dy);
SetScroller (arg0, EScroll::sc_ceiling, -dx, dy);
return true;
}

719
src/p_scroll.cpp Normal file
View file

@ -0,0 +1,719 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Initializes and implements BOOM linedef triggers for
// Scrollers/Conveyors
//
//-----------------------------------------------------------------------------
#include <stdlib.h>
#include "actor.h"
#include "p_spec.h"
#include "farchive.h"
#include "p_lnspec.h"
#include "r_data/r_interpolate.h"
//-----------------------------------------------------------------------------
//
// killough 3/7/98: Add generalized scroll effects
//
//-----------------------------------------------------------------------------
class DScroller : public DThinker
{
DECLARE_CLASS (DScroller, DThinker)
HAS_OBJECT_POINTERS
public:
DScroller (EScroll type, fixed_t dx, fixed_t dy, int control, int affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
DScroller (fixed_t dx, fixed_t dy, const line_t *l, int control, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
void Destroy();
void Serialize (FArchive &arc);
void Tick ();
bool AffectsWall (int wallnum) const { return m_Type == EScroll::sc_side && m_Affectee == wallnum; }
int GetWallNum () const { return m_Type == EScroll::sc_side ? m_Affectee : -1; }
void SetRate (fixed_t dx, fixed_t dy) { m_dx = dx; m_dy = dy; }
bool IsType (EScroll type) const { return type == m_Type; }
int GetAffectee () const { return m_Affectee; }
EScrollPos GetScrollParts() const { return m_Parts; }
protected:
EScroll m_Type; // Type of scroll effect
fixed_t m_dx, m_dy; // (dx,dy) scroll speeds
int m_Affectee; // Number of affected sidedef, sector, tag, or whatever
int m_Control; // Control sector (-1 if none) used to control scrolling
fixed_t m_LastHeight; // Last known height of control sector
fixed_t m_vdx, m_vdy; // Accumulated velocity if accelerative
int m_Accel; // Whether it's accelerative
EScrollPos m_Parts; // Which parts of a sidedef are being scrolled?
TObjPtr<DInterpolation> m_Interpolations[3];
private:
DScroller ()
{
}
};
IMPLEMENT_POINTY_CLASS (DScroller)
DECLARE_POINTER (m_Interpolations[0])
DECLARE_POINTER (m_Interpolations[1])
DECLARE_POINTER (m_Interpolations[2])
END_POINTERS
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
inline FArchive &operator<< (FArchive &arc, EScroll &type)
{
BYTE val = (BYTE)type;
arc << val;
type = (EScroll)val;
return arc;
}
inline FArchive &operator<< (FArchive &arc, EScrollPos &type)
{
int val = (int)type;
arc << val;
type = (EScrollPos)val;
return arc;
}
EScrollPos operator &(EScrollPos one, EScrollPos two)
{
return EScrollPos(int(one) & int(two));
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
void DScroller::Serialize (FArchive &arc)
{
Super::Serialize (arc);
arc << m_Type
<< m_dx << m_dy
<< m_Affectee
<< m_Control
<< m_LastHeight
<< m_vdx << m_vdy
<< m_Accel
<< m_Parts
<< m_Interpolations[0]
<< m_Interpolations[1]
<< m_Interpolations[2];
}
//-----------------------------------------------------------------------------
//
// [RH] Compensate for rotated sector textures by rotating the scrolling
// in the opposite direction.
//
//-----------------------------------------------------------------------------
static void RotationComp(const sector_t *sec, int which, fixed_t dx, fixed_t dy, fixed_t &tdx, fixed_t &tdy)
{
angle_t an = sec->GetAngle(which);
if (an == 0)
{
tdx = dx;
tdy = dy;
}
else
{
an = an >> ANGLETOFINESHIFT;
fixed_t ca = -finecosine[an];
fixed_t sa = -finesine[an];
tdx = DMulScale16(dx, ca, -dy, sa);
tdy = DMulScale16(dy, ca, dx, sa);
}
}
//-----------------------------------------------------------------------------
//
// killough 2/28/98:
//
// This function, with the help of r_plane.c and r_bsp.c, supports generalized
// scrolling floors and walls, with optional mobj-carrying properties, e.g.
// conveyor belts, rivers, etc. A linedef with a special type affects all
// tagged sectors the same way, by creating scrolling and/or object-carrying
// properties. Multiple linedefs may be used on the same sector and are
// cumulative, although the special case of scrolling a floor and carrying
// things on it, requires only one linedef. The linedef's direction determines
// the scrolling direction, and the linedef's length determines the scrolling
// speed. This was designed so that an edge around the sector could be used to
// control the direction of the sector's scrolling, which is usually what is
// desired.
//
// Process the active scrollers.
//
// This is the main scrolling code
// killough 3/7/98
//
//-----------------------------------------------------------------------------
void DScroller::Tick ()
{
fixed_t dx = m_dx, dy = m_dy, tdx, tdy;
if (m_Control != -1)
{ // compute scroll amounts based on a sector's height changes
fixed_t height = sectors[m_Control].CenterFloor () +
sectors[m_Control].CenterCeiling ();
fixed_t delta = height - m_LastHeight;
m_LastHeight = height;
dx = FixedMul(dx, delta);
dy = FixedMul(dy, delta);
}
// killough 3/14/98: Add acceleration
if (m_Accel)
{
m_vdx = dx += m_vdx;
m_vdy = dy += m_vdy;
}
if (!(dx | dy)) // no-op if both (x,y) offsets are 0
return;
switch (m_Type)
{
case EScroll::sc_side: // killough 3/7/98: Scroll wall texture
if (m_Parts & EScrollPos::scw_top)
{
sides[m_Affectee].AddTextureXOffset(side_t::top, dx);
sides[m_Affectee].AddTextureYOffset(side_t::top, dy);
}
if (m_Parts & EScrollPos::scw_mid && (sides[m_Affectee].linedef->backsector == NULL ||
!(sides[m_Affectee].linedef->flags&ML_3DMIDTEX)))
{
sides[m_Affectee].AddTextureXOffset(side_t::mid, dx);
sides[m_Affectee].AddTextureYOffset(side_t::mid, dy);
}
if (m_Parts & EScrollPos::scw_bottom)
{
sides[m_Affectee].AddTextureXOffset(side_t::bottom, dx);
sides[m_Affectee].AddTextureYOffset(side_t::bottom, dy);
}
break;
case EScroll::sc_floor: // killough 3/7/98: Scroll floor texture
RotationComp(&sectors[m_Affectee], sector_t::floor, dx, dy, tdx, tdy);
sectors[m_Affectee].AddXOffset(sector_t::floor, tdx);
sectors[m_Affectee].AddYOffset(sector_t::floor, tdy);
break;
case EScroll::sc_ceiling: // killough 3/7/98: Scroll ceiling texture
RotationComp(&sectors[m_Affectee], sector_t::ceiling, dx, dy, tdx, tdy);
sectors[m_Affectee].AddXOffset(sector_t::ceiling, tdx);
sectors[m_Affectee].AddYOffset(sector_t::ceiling, tdy);
break;
// [RH] Don't actually carry anything here. That happens later.
case EScroll::sc_carry:
level.Scrolls[m_Affectee].ScrollX += dx;
level.Scrolls[m_Affectee].ScrollY += dy;
break;
case EScroll::sc_carry_ceiling: // to be added later
break;
}
}
//-----------------------------------------------------------------------------
//
// Add_Scroller()
//
// Add a generalized scroller to the thinker list.
//
// type: the enumerated type of scrolling: floor, ceiling, floor carrier,
// wall, floor carrier & scroller
//
// (dx,dy): the direction and speed of the scrolling or its acceleration
//
// control: the sector whose heights control this scroller's effect
// remotely, or -1 if no control sector
//
// affectee: the index of the affected object (sector or sidedef)
//
// accel: non-zero if this is an accelerative effect
//
//-----------------------------------------------------------------------------
DScroller::DScroller (EScroll type, fixed_t dx, fixed_t dy,
int control, int affectee, int accel, EScrollPos scrollpos)
: DThinker (STAT_SCROLLER)
{
m_Type = type;
m_dx = dx;
m_dy = dy;
m_Accel = accel;
m_Parts = scrollpos;
m_vdx = m_vdy = 0;
if ((m_Control = control) != -1)
m_LastHeight =
sectors[control].CenterFloor () + sectors[control].CenterCeiling ();
m_Affectee = affectee;
m_Interpolations[0] = m_Interpolations[1] = m_Interpolations[2] = NULL;
switch (type)
{
case EScroll::sc_carry:
level.AddScroller (affectee);
break;
case EScroll::sc_side:
sides[affectee].Flags |= WALLF_NOAUTODECALS;
if (m_Parts & EScrollPos::scw_top)
{
m_Interpolations[0] = sides[m_Affectee].SetInterpolation(side_t::top);
}
if (m_Parts & EScrollPos::scw_mid && (sides[m_Affectee].linedef->backsector == NULL ||
!(sides[m_Affectee].linedef->flags&ML_3DMIDTEX)))
{
m_Interpolations[1] = sides[m_Affectee].SetInterpolation(side_t::mid);
}
if (m_Parts & EScrollPos::scw_bottom)
{
m_Interpolations[2] = sides[m_Affectee].SetInterpolation(side_t::bottom);
}
break;
case EScroll::sc_floor:
m_Interpolations[0] = sectors[affectee].SetInterpolation(sector_t::FloorScroll, false);
break;
case EScroll::sc_ceiling:
m_Interpolations[0] = sectors[affectee].SetInterpolation(sector_t::CeilingScroll, false);
break;
default:
break;
}
}
void DScroller::Destroy ()
{
for(int i=0;i<3;i++)
{
if (m_Interpolations[i] != NULL)
{
m_Interpolations[i]->DelRef();
m_Interpolations[i] = NULL;
}
}
Super::Destroy();
}
//-----------------------------------------------------------------------------
//
// Adds wall scroller. Scroll amount is rotated with respect to wall's
// linedef first, so that scrolling towards the wall in a perpendicular
// direction is translated into vertical motion, while scrolling along
// the wall in a parallel direction is translated into horizontal motion.
//
// killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff
//
//-----------------------------------------------------------------------------
DScroller::DScroller (fixed_t dx, fixed_t dy, const line_t *l,
int control, int accel, EScrollPos scrollpos)
: DThinker (STAT_SCROLLER)
{
fixed_t x = abs(l->dx), y = abs(l->dy), d;
if (y > x)
d = x, x = y, y = d;
d = FixedDiv (x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90)
>> ANGLETOFINESHIFT]);
x = -FixedDiv (FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d);
y = -FixedDiv (FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d);
m_Type = EScroll::sc_side;
m_dx = x;
m_dy = y;
m_vdx = m_vdy = 0;
m_Accel = accel;
m_Parts = scrollpos;
if ((m_Control = control) != -1)
m_LastHeight = sectors[control].CenterFloor() + sectors[control].CenterCeiling();
m_Affectee = int(l->sidedef[0] - sides);
sides[m_Affectee].Flags |= WALLF_NOAUTODECALS;
m_Interpolations[0] = m_Interpolations[1] = m_Interpolations[2] = NULL;
if (m_Parts & EScrollPos::scw_top)
{
m_Interpolations[0] = sides[m_Affectee].SetInterpolation(side_t::top);
}
if (m_Parts & EScrollPos::scw_mid && (sides[m_Affectee].linedef->backsector == NULL ||
!(sides[m_Affectee].linedef->flags&ML_3DMIDTEX)))
{
m_Interpolations[1] = sides[m_Affectee].SetInterpolation(side_t::mid);
}
if (m_Parts & EScrollPos::scw_bottom)
{
m_Interpolations[2] = sides[m_Affectee].SetInterpolation(side_t::bottom);
}
}
// Amount (dx,dy) vector linedef is shifted right to get scroll amount
#define SCROLL_SHIFT 5
#define SCROLLTYPE(i) EScrollPos(((i) <= 0) || ((i) & ~7) ? 7 : (i))
//-----------------------------------------------------------------------------
//
// Initialize the scrollers
//
//-----------------------------------------------------------------------------
void P_SpawnScrollers(void)
{
int i;
line_t *l = lines;
TArray<int> copyscrollers;
for (i = 0; i < numlines; i++)
{
if (lines[i].special == Sector_CopyScroller)
{
// don't allow copying the scroller if the sector has the same tag as it would just duplicate it.
if (!tagManager.SectorHasTag(lines[i].frontsector, lines[i].args[0]))
{
copyscrollers.Push(i);
}
lines[i].special = 0;
}
}
for (i = 0; i < numlines; i++, l++)
{
fixed_t dx; // direction and speed of scrolling
fixed_t dy;
int control = -1, accel = 0; // no control sector or acceleration
int special = l->special;
// Check for undefined parameters that are non-zero and output messages for them.
// We don't report for specials we don't understand.
FLineSpecial *spec = P_GetLineSpecialInfo(special);
if (spec != NULL)
{
int max = spec->map_args;
for (unsigned arg = max; arg < countof(l->args); ++arg)
{
if (l->args[arg] != 0)
{
Printf("Line %d (type %d:%s), arg %u is %d (should be 0)\n",
i, special, spec->name, arg+1, l->args[arg]);
}
}
}
// killough 3/7/98: Types 245-249 are same as 250-254 except that the
// first side's sector's heights cause scrolling when they change, and
// this linedef controls the direction and speed of the scrolling. The
// most complicated linedef since donuts, but powerful :)
//
// killough 3/15/98: Add acceleration. Types 214-218 are the same but
// are accelerative.
// [RH] Assume that it's a scroller and zero the line's special.
l->special = 0;
dx = dy = 0; // Shut up, GCC
if (special == Scroll_Ceiling ||
special == Scroll_Floor ||
special == Scroll_Texture_Model)
{
if (l->args[1] & 3)
{
// if 1, then displacement
// if 2, then accelerative (also if 3)
control = int(l->sidedef[0]->sector - sectors);
if (l->args[1] & 2)
accel = 1;
}
if (special == Scroll_Texture_Model ||
l->args[1] & 4)
{
// The line housing the special controls the
// direction and speed of scrolling.
dx = l->dx >> SCROLL_SHIFT;
dy = l->dy >> SCROLL_SHIFT;
}
else
{
// The speed and direction are parameters to the special.
dx = (l->args[3] - 128) * (FRACUNIT / 32);
dy = (l->args[4] - 128) * (FRACUNIT / 32);
}
}
switch (special)
{
int s;
case Scroll_Ceiling:
{
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
new DScroller(EScroll::sc_ceiling, -dx, dy, control, s, accel);
}
for (unsigned j = 0; j < copyscrollers.Size(); j++)
{
line_t *line = &lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 1))
{
new DScroller(EScroll::sc_ceiling, -dx, dy, control, int(line->frontsector - sectors), accel);
}
}
break;
}
case Scroll_Floor:
if (l->args[2] != 1)
{ // scroll the floor texture
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
new DScroller (EScroll::sc_floor, -dx, dy, control, s, accel);
}
for(unsigned j = 0;j < copyscrollers.Size(); j++)
{
line_t *line = &lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 2))
{
new DScroller (EScroll::sc_floor, -dx, dy, control, int(line->frontsector-sectors), accel);
}
}
}
if (l->args[2] > 0)
{ // carry objects on the floor
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
new DScroller (EScroll::sc_carry, dx, dy, control, s, accel);
}
for(unsigned j = 0;j < copyscrollers.Size(); j++)
{
line_t *line = &lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 4))
{
new DScroller (EScroll::sc_carry, dx, dy, control, int(line->frontsector-sectors), accel);
}
}
}
break;
// killough 3/1/98: scroll wall according to linedef
// (same direction and speed as scrolling floors)
case Scroll_Texture_Model:
{
FLineIdIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
if (s != i)
new DScroller(dx, dy, lines + s, control, accel);
}
break;
}
case Scroll_Texture_Offsets:
// killough 3/2/98: scroll according to sidedef offsets
s = int(lines[i].sidedef[0] - sides);
new DScroller (EScroll::sc_side, -sides[s].GetTextureXOffset(side_t::mid),
sides[s].GetTextureYOffset(side_t::mid), -1, s, accel, SCROLLTYPE(l->args[0]));
break;
case Scroll_Texture_Left:
l->special = special; // Restore the special, for compat_useblocking's benefit.
s = int(lines[i].sidedef[0] - sides);
new DScroller (EScroll::sc_side, l->args[0] * (FRACUNIT/64), 0,
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Right:
l->special = special;
s = int(lines[i].sidedef[0] - sides);
new DScroller (EScroll::sc_side, l->args[0] * (-FRACUNIT/64), 0,
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Up:
l->special = special;
s = int(lines[i].sidedef[0] - sides);
new DScroller (EScroll::sc_side, 0, l->args[0] * (FRACUNIT/64),
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Down:
l->special = special;
s = int(lines[i].sidedef[0] - sides);
new DScroller (EScroll::sc_side, 0, l->args[0] * (-FRACUNIT/64),
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Both:
s = int(lines[i].sidedef[0] - sides);
if (l->args[0] == 0) {
dx = (l->args[1] - l->args[2]) * (FRACUNIT/64);
dy = (l->args[4] - l->args[3]) * (FRACUNIT/64);
new DScroller (EScroll::sc_side, dx, dy, -1, s, accel);
}
break;
default:
// [RH] It wasn't a scroller after all, so restore the special.
l->special = special;
break;
}
}
}
//-----------------------------------------------------------------------------
//
// Modify a wall scroller
//
//-----------------------------------------------------------------------------
void SetWallScroller (int id, int sidechoice, fixed_t dx, fixed_t dy, EScrollPos Where)
{
Where = Where & scw_all;
if (Where == 0) return;
if ((dx | dy) == 0)
{
// Special case: Remove the scroller, because the deltas are both 0.
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
DScroller *scroller;
while ( (scroller = iterator.Next ()) )
{
int wallnum = scroller->GetWallNum ();
if (wallnum >= 0 && tagManager.LineHasID(sides[wallnum].linedef, id) &&
int(sides[wallnum].linedef->sidedef[sidechoice] - sides) == wallnum &&
Where == scroller->GetScrollParts())
{
scroller->Destroy ();
}
}
}
else
{
// Find scrollers already attached to the matching walls, and change
// their rates.
TArray<FThinkerCollection> Collection;
{
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
FThinkerCollection collect;
while ( (collect.Obj = iterator.Next ()) )
{
if ((collect.RefNum = ((DScroller *)collect.Obj)->GetWallNum ()) != -1 &&
tagManager.LineHasID(sides[collect.RefNum].linedef, id) &&
int(sides[collect.RefNum].linedef->sidedef[sidechoice] - sides) == collect.RefNum &&
Where == ((DScroller *)collect.Obj)->GetScrollParts())
{
((DScroller *)collect.Obj)->SetRate (dx, dy);
Collection.Push (collect);
}
}
}
size_t numcollected = Collection.Size ();
int linenum;
// Now create scrollers for any walls that don't already have them.
FLineIdIterator itr(id);
while ((linenum = itr.Next()) >= 0)
{
if (lines[linenum].sidedef[sidechoice] != NULL)
{
int sidenum = int(lines[linenum].sidedef[sidechoice] - sides);
unsigned int i;
for (i = 0; i < numcollected; i++)
{
if (Collection[i].RefNum == sidenum)
break;
}
if (i == numcollected)
{
new DScroller (EScroll::sc_side, dx, dy, -1, sidenum, 0, Where);
}
}
}
}
}
void SetScroller (int tag, EScroll type, fixed_t dx, fixed_t dy)
{
TThinkerIterator<DScroller> iterator (STAT_SCROLLER);
DScroller *scroller;
int i;
// Check if there is already a scroller for this tag
// If at least one sector with this tag is scrolling, then they all are.
// If the deltas are both 0, we don't remove the scroller, because a
// displacement/accelerative scroller might have been set up, and there's
// no way to create one after the level is fully loaded.
i = 0;
while ( (scroller = iterator.Next ()) )
{
if (scroller->IsType (type))
{
if (tagManager.SectorHasTag(scroller->GetAffectee (), tag))
{
i++;
scroller->SetRate (dx, dy);
}
}
}
if (i > 0 || (dx|dy) == 0)
{
return;
}
// Need to create scrollers for the sector(s)
FSectorTagIterator itr(tag);
while ((i = itr.Next()) >= 0)
{
new DScroller (type, dx, dy, -1, i, 0);
}
}
void P_CreateScroller(EScroll type, fixed_t dx, fixed_t dy, int control, int affectee, int accel, EScrollPos scrollpos)
{
new DScroller(type, dx, dy, control, affectee, accel, scrollpos);
}

View file

@ -84,44 +84,10 @@ static FRandom pr_playerinspecialsector ("PlayerInSpecialSector");
EXTERN_CVAR(Bool, cl_predict_specials)
IMPLEMENT_POINTY_CLASS (DScroller)
DECLARE_POINTER (m_Interpolations[0])
DECLARE_POINTER (m_Interpolations[1])
DECLARE_POINTER (m_Interpolations[2])
END_POINTERS
IMPLEMENT_POINTY_CLASS (DPusher)
DECLARE_POINTER (m_Source)
END_POINTERS
inline FArchive &operator<< (FArchive &arc, DScroller::EScrollType &type)
{
BYTE val = (BYTE)type;
arc << val;
type = (DScroller::EScrollType)val;
return arc;
}
DScroller::DScroller ()
{
}
void DScroller::Serialize (FArchive &arc)
{
Super::Serialize (arc);
arc << m_Type
<< m_dx << m_dy
<< m_Affectee
<< m_Control
<< m_LastHeight
<< m_vdx << m_vdy
<< m_Accel
<< m_Parts
<< m_Interpolations[0]
<< m_Interpolations[1]
<< m_Interpolations[2];
}
DPusher::DPusher ()
{
}
@ -149,7 +115,7 @@ void DPusher::Serialize (FArchive &arc)
}
// killough 3/7/98: Initialize generalized scrolling
static void P_SpawnScrollers();
void P_SpawnScrollers();
static void P_SpawnFriction (); // phares 3/16/98
static void P_SpawnPushers (); // phares 3/20/98
@ -1243,7 +1209,7 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers)
if (!nothinkers)
{
new DStrobe(sector, STROBEBRIGHT, FASTDARK, false);
new DScroller(DScroller::sc_floor, -((FRACUNIT / 2) << 3),
P_CreateScroller(EScroll::sc_floor, -((FRACUNIT / 2) << 3),
0, -1, int(sector - sectors), 0);
}
keepspecial = true;
@ -1304,13 +1270,13 @@ void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers)
int i = sector->special - Scroll_North_Slow;
fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2);
fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2);
if (!nothinkers) new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0);
if (!nothinkers) P_CreateScroller(EScroll::sc_floor, dx, dy, -1, int(sector-sectors), 0);
}
else if (sector->special >= Carry_East5 &&
sector->special <= Carry_East35)
{ // Heretic scroll special
// Only east scrollers also scroll the texture
if (!nothinkers) new DScroller (DScroller::sc_floor,
if (!nothinkers) P_CreateScroller(EScroll::sc_floor,
(-FRACUNIT/2)<<(sector->special - Carry_East5),
0, -1, int(sector-sectors), 0);
}
@ -1533,458 +1499,6 @@ void P_SpawnSpecials (void)
FBehavior::StaticStartTypedScripts (SCRIPT_Open, NULL, false);
}
// killough 2/28/98:
//
// This function, with the help of r_plane.c and r_bsp.c, supports generalized
// scrolling floors and walls, with optional mobj-carrying properties, e.g.
// conveyor belts, rivers, etc. A linedef with a special type affects all
// tagged sectors the same way, by creating scrolling and/or object-carrying
// properties. Multiple linedefs may be used on the same sector and are
// cumulative, although the special case of scrolling a floor and carrying
// things on it, requires only one linedef. The linedef's direction determines
// the scrolling direction, and the linedef's length determines the scrolling
// speed. This was designed so that an edge around the sector could be used to
// control the direction of the sector's scrolling, which is usually what is
// desired.
//
// Process the active scrollers.
//
// This is the main scrolling code
// killough 3/7/98
// [RH] Compensate for rotated sector textures by rotating the scrolling
// in the opposite direction.
static void RotationComp(const sector_t *sec, int which, fixed_t dx, fixed_t dy, fixed_t &tdx, fixed_t &tdy)
{
angle_t an = sec->GetAngle(which);
if (an == 0)
{
tdx = dx;
tdy = dy;
}
else
{
an = an >> ANGLETOFINESHIFT;
fixed_t ca = -finecosine[an];
fixed_t sa = -finesine[an];
tdx = DMulScale16(dx, ca, -dy, sa);
tdy = DMulScale16(dy, ca, dx, sa);
}
}
void DScroller::Tick ()
{
fixed_t dx = m_dx, dy = m_dy, tdx, tdy;
if (m_Control != -1)
{ // compute scroll amounts based on a sector's height changes
fixed_t height = sectors[m_Control].CenterFloor () +
sectors[m_Control].CenterCeiling ();
fixed_t delta = height - m_LastHeight;
m_LastHeight = height;
dx = FixedMul(dx, delta);
dy = FixedMul(dy, delta);
}
// killough 3/14/98: Add acceleration
if (m_Accel)
{
m_vdx = dx += m_vdx;
m_vdy = dy += m_vdy;
}
if (!(dx | dy)) // no-op if both (x,y) offsets are 0
return;
switch (m_Type)
{
case sc_side: // killough 3/7/98: Scroll wall texture
if (m_Parts & scw_top)
{
sides[m_Affectee].AddTextureXOffset(side_t::top, dx);
sides[m_Affectee].AddTextureYOffset(side_t::top, dy);
}
if (m_Parts & scw_mid && (sides[m_Affectee].linedef->backsector == NULL ||
!(sides[m_Affectee].linedef->flags&ML_3DMIDTEX)))
{
sides[m_Affectee].AddTextureXOffset(side_t::mid, dx);
sides[m_Affectee].AddTextureYOffset(side_t::mid, dy);
}
if (m_Parts & scw_bottom)
{
sides[m_Affectee].AddTextureXOffset(side_t::bottom, dx);
sides[m_Affectee].AddTextureYOffset(side_t::bottom, dy);
}
break;
case sc_floor: // killough 3/7/98: Scroll floor texture
RotationComp(&sectors[m_Affectee], sector_t::floor, dx, dy, tdx, tdy);
sectors[m_Affectee].AddXOffset(sector_t::floor, tdx);
sectors[m_Affectee].AddYOffset(sector_t::floor, tdy);
break;
case sc_ceiling: // killough 3/7/98: Scroll ceiling texture
RotationComp(&sectors[m_Affectee], sector_t::ceiling, dx, dy, tdx, tdy);
sectors[m_Affectee].AddXOffset(sector_t::ceiling, tdx);
sectors[m_Affectee].AddYOffset(sector_t::ceiling, tdy);
break;
// [RH] Don't actually carry anything here. That happens later.
case sc_carry:
level.Scrolls[m_Affectee].ScrollX += dx;
level.Scrolls[m_Affectee].ScrollY += dy;
break;
case sc_carry_ceiling: // to be added later
break;
}
}
//
// Add_Scroller()
//
// Add a generalized scroller to the thinker list.
//
// type: the enumerated type of scrolling: floor, ceiling, floor carrier,
// wall, floor carrier & scroller
//
// (dx,dy): the direction and speed of the scrolling or its acceleration
//
// control: the sector whose heights control this scroller's effect
// remotely, or -1 if no control sector
//
// affectee: the index of the affected object (sector or sidedef)
//
// accel: non-zero if this is an accelerative effect
//
DScroller::DScroller (EScrollType type, fixed_t dx, fixed_t dy,
int control, int affectee, int accel, int scrollpos)
: DThinker (STAT_SCROLLER)
{
m_Type = type;
m_dx = dx;
m_dy = dy;
m_Accel = accel;
m_Parts = scrollpos;
m_vdx = m_vdy = 0;
if ((m_Control = control) != -1)
m_LastHeight =
sectors[control].CenterFloor () + sectors[control].CenterCeiling ();
m_Affectee = affectee;
m_Interpolations[0] = m_Interpolations[1] = m_Interpolations[2] = NULL;
switch (type)
{
case sc_carry:
level.AddScroller (this, affectee);
break;
case sc_side:
sides[affectee].Flags |= WALLF_NOAUTODECALS;
if (m_Parts & scw_top)
{
m_Interpolations[0] = sides[m_Affectee].SetInterpolation(side_t::top);
}
if (m_Parts & scw_mid && (sides[m_Affectee].linedef->backsector == NULL ||
!(sides[m_Affectee].linedef->flags&ML_3DMIDTEX)))
{
m_Interpolations[1] = sides[m_Affectee].SetInterpolation(side_t::mid);
}
if (m_Parts & scw_bottom)
{
m_Interpolations[2] = sides[m_Affectee].SetInterpolation(side_t::bottom);
}
break;
case sc_floor:
m_Interpolations[0] = sectors[affectee].SetInterpolation(sector_t::FloorScroll, false);
break;
case sc_ceiling:
m_Interpolations[0] = sectors[affectee].SetInterpolation(sector_t::CeilingScroll, false);
break;
default:
break;
}
}
void DScroller::Destroy ()
{
for(int i=0;i<3;i++)
{
if (m_Interpolations[i] != NULL)
{
m_Interpolations[i]->DelRef();
m_Interpolations[i] = NULL;
}
}
Super::Destroy();
}
// Adds wall scroller. Scroll amount is rotated with respect to wall's
// linedef first, so that scrolling towards the wall in a perpendicular
// direction is translated into vertical motion, while scrolling along
// the wall in a parallel direction is translated into horizontal motion.
//
// killough 5/25/98: cleaned up arithmetic to avoid drift due to roundoff
DScroller::DScroller (fixed_t dx, fixed_t dy, const line_t *l,
int control, int accel, int scrollpos)
: DThinker (STAT_SCROLLER)
{
fixed_t x = abs(l->dx), y = abs(l->dy), d;
if (y > x)
d = x, x = y, y = d;
d = FixedDiv (x, finesine[(tantoangle[FixedDiv(y,x) >> DBITS] + ANG90)
>> ANGLETOFINESHIFT]);
x = -FixedDiv (FixedMul(dy, l->dy) + FixedMul(dx, l->dx), d);
y = -FixedDiv (FixedMul(dx, l->dy) - FixedMul(dy, l->dx), d);
m_Type = sc_side;
m_dx = x;
m_dy = y;
m_vdx = m_vdy = 0;
m_Accel = accel;
m_Parts = scrollpos;
if ((m_Control = control) != -1)
m_LastHeight = sectors[control].CenterFloor() + sectors[control].CenterCeiling();
m_Affectee = int(l->sidedef[0] - sides);
sides[m_Affectee].Flags |= WALLF_NOAUTODECALS;
m_Interpolations[0] = m_Interpolations[1] = m_Interpolations[2] = NULL;
if (m_Parts & scw_top)
{
m_Interpolations[0] = sides[m_Affectee].SetInterpolation(side_t::top);
}
if (m_Parts & scw_mid && (sides[m_Affectee].linedef->backsector == NULL ||
!(sides[m_Affectee].linedef->flags&ML_3DMIDTEX)))
{
m_Interpolations[1] = sides[m_Affectee].SetInterpolation(side_t::mid);
}
if (m_Parts & scw_bottom)
{
m_Interpolations[2] = sides[m_Affectee].SetInterpolation(side_t::bottom);
}
}
// Amount (dx,dy) vector linedef is shifted right to get scroll amount
#define SCROLL_SHIFT 5
#define SCROLLTYPE(i) (((i) <= 0) || ((i) & ~7) ? 7 : (i))
// Initialize the scrollers
static void P_SpawnScrollers(void)
{
int i;
line_t *l = lines;
TArray<int> copyscrollers;
for (i = 0; i < numlines; i++)
{
if (lines[i].special == Sector_CopyScroller)
{
// don't allow copying the scroller if the sector has the same tag as it would just duplicate it.
if (!tagManager.SectorHasTag(lines[i].frontsector, lines[i].args[0]))
{
copyscrollers.Push(i);
}
lines[i].special = 0;
}
}
for (i = 0; i < numlines; i++, l++)
{
fixed_t dx; // direction and speed of scrolling
fixed_t dy;
int control = -1, accel = 0; // no control sector or acceleration
int special = l->special;
// Check for undefined parameters that are non-zero and output messages for them.
// We don't report for specials we don't understand.
FLineSpecial *spec = P_GetLineSpecialInfo(special);
if (spec != NULL)
{
int max = spec->map_args;
for (unsigned arg = max; arg < countof(l->args); ++arg)
{
if (l->args[arg] != 0)
{
Printf("Line %d (type %d:%s), arg %u is %d (should be 0)\n",
i, special, spec->name, arg+1, l->args[arg]);
}
}
}
// killough 3/7/98: Types 245-249 are same as 250-254 except that the
// first side's sector's heights cause scrolling when they change, and
// this linedef controls the direction and speed of the scrolling. The
// most complicated linedef since donuts, but powerful :)
//
// killough 3/15/98: Add acceleration. Types 214-218 are the same but
// are accelerative.
// [RH] Assume that it's a scroller and zero the line's special.
l->special = 0;
dx = dy = 0; // Shut up, GCC
if (special == Scroll_Ceiling ||
special == Scroll_Floor ||
special == Scroll_Texture_Model)
{
if (l->args[1] & 3)
{
// if 1, then displacement
// if 2, then accelerative (also if 3)
control = int(l->sidedef[0]->sector - sectors);
if (l->args[1] & 2)
accel = 1;
}
if (special == Scroll_Texture_Model ||
l->args[1] & 4)
{
// The line housing the special controls the
// direction and speed of scrolling.
dx = l->dx >> SCROLL_SHIFT;
dy = l->dy >> SCROLL_SHIFT;
}
else
{
// The speed and direction are parameters to the special.
dx = (l->args[3] - 128) * (FRACUNIT / 32);
dy = (l->args[4] - 128) * (FRACUNIT / 32);
}
}
switch (special)
{
int s;
case Scroll_Ceiling:
{
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
new DScroller(DScroller::sc_ceiling, -dx, dy, control, s, accel);
}
for (unsigned j = 0; j < copyscrollers.Size(); j++)
{
line_t *line = &lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 1))
{
new DScroller(DScroller::sc_ceiling, -dx, dy, control, int(line->frontsector - sectors), accel);
}
}
break;
}
case Scroll_Floor:
if (l->args[2] != 1)
{ // scroll the floor texture
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
new DScroller (DScroller::sc_floor, -dx, dy, control, s, accel);
}
for(unsigned j = 0;j < copyscrollers.Size(); j++)
{
line_t *line = &lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 2))
{
new DScroller (DScroller::sc_floor, -dx, dy, control, int(line->frontsector-sectors), accel);
}
}
}
if (l->args[2] > 0)
{ // carry objects on the floor
FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
new DScroller (DScroller::sc_carry, dx, dy, control, s, accel);
}
for(unsigned j = 0;j < copyscrollers.Size(); j++)
{
line_t *line = &lines[copyscrollers[j]];
if (line->args[0] == l->args[0] && (line->args[1] & 4))
{
new DScroller (DScroller::sc_carry, dx, dy, control, int(line->frontsector-sectors), accel);
}
}
}
break;
// killough 3/1/98: scroll wall according to linedef
// (same direction and speed as scrolling floors)
case Scroll_Texture_Model:
{
FLineIdIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0)
{
if (s != i)
new DScroller(dx, dy, lines + s, control, accel);
}
break;
}
case Scroll_Texture_Offsets:
// killough 3/2/98: scroll according to sidedef offsets
s = int(lines[i].sidedef[0] - sides);
new DScroller (DScroller::sc_side, -sides[s].GetTextureXOffset(side_t::mid),
sides[s].GetTextureYOffset(side_t::mid), -1, s, accel, SCROLLTYPE(l->args[0]));
break;
case Scroll_Texture_Left:
l->special = special; // Restore the special, for compat_useblocking's benefit.
s = int(lines[i].sidedef[0] - sides);
new DScroller (DScroller::sc_side, l->args[0] * (FRACUNIT/64), 0,
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Right:
l->special = special;
s = int(lines[i].sidedef[0] - sides);
new DScroller (DScroller::sc_side, l->args[0] * (-FRACUNIT/64), 0,
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Up:
l->special = special;
s = int(lines[i].sidedef[0] - sides);
new DScroller (DScroller::sc_side, 0, l->args[0] * (FRACUNIT/64),
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Down:
l->special = special;
s = int(lines[i].sidedef[0] - sides);
new DScroller (DScroller::sc_side, 0, l->args[0] * (-FRACUNIT/64),
-1, s, accel, SCROLLTYPE(l->args[1]));
break;
case Scroll_Texture_Both:
s = int(lines[i].sidedef[0] - sides);
if (l->args[0] == 0) {
dx = (l->args[1] - l->args[2]) * (FRACUNIT/64);
dy = (l->args[4] - l->args[3]) * (FRACUNIT/64);
new DScroller (DScroller::sc_side, dx, dy, -1, s, accel);
}
break;
default:
// [RH] It wasn't a scroller after all, so restore the special.
l->special = special;
break;
}
}
}
// killough 3/7/98 -- end generalized scroll effects
////////////////////////////////////////////////////////////////////////////
//
// FRICTION EFFECTS

View file

@ -32,6 +32,32 @@
class FScanner;
struct level_info_t;
struct FThinkerCollection
{
int RefNum;
DThinker *Obj;
};
enum class EScroll : int
{
sc_side,
sc_floor,
sc_ceiling,
sc_carry,
sc_carry_ceiling, // killough 4/11/98: carry objects hanging on ceilings
};
enum EScrollPos : int
{
scw_top = 1,
scw_mid = 2,
scw_bottom = 4,
scw_all = 7,
};
void P_CreateScroller(EScroll type, fixed_t dx, fixed_t dy, int control, int affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
//jff 2/23/98 identify the special classes that can share sectors
typedef enum
@ -41,58 +67,6 @@ typedef enum
lighting_special,
} special_e;
// killough 3/7/98: Add generalized scroll effects
class DScroller : public DThinker
{
DECLARE_CLASS (DScroller, DThinker)
HAS_OBJECT_POINTERS
public:
enum EScrollType
{
sc_side,
sc_floor,
sc_ceiling,
sc_carry,
sc_carry_ceiling, // killough 4/11/98: carry objects hanging on ceilings
};
enum EScrollPos
{
scw_top=1,
scw_mid=2,
scw_bottom=4,
scw_all=7,
};
DScroller (EScrollType type, fixed_t dx, fixed_t dy, int control, int affectee, int accel, int scrollpos = scw_all);
DScroller (fixed_t dx, fixed_t dy, const line_t *l, int control, int accel, int scrollpos = scw_all);
void Destroy();
void Serialize (FArchive &arc);
void Tick ();
bool AffectsWall (int wallnum) const { return m_Type == sc_side && m_Affectee == wallnum; }
int GetWallNum () const { return m_Type == sc_side ? m_Affectee : -1; }
void SetRate (fixed_t dx, fixed_t dy) { m_dx = dx; m_dy = dy; }
bool IsType (EScrollType type) const { return type == m_Type; }
int GetAffectee () const { return m_Affectee; }
int GetScrollParts() const { return m_Parts; }
protected:
EScrollType m_Type; // Type of scroll effect
fixed_t m_dx, m_dy; // (dx,dy) scroll speeds
int m_Affectee; // Number of affected sidedef, sector, tag, or whatever
int m_Control; // Control sector (-1 if none) used to control scrolling
fixed_t m_LastHeight; // Last known height of control sector
fixed_t m_vdx, m_vdy; // Accumulated velocity if accelerative
int m_Accel; // Whether it's accelerative
int m_Parts; // Which parts of a sidedef are being scrolled?
TObjPtr<DInterpolation> m_Interpolations[3];
private:
DScroller ();
};
// Factor to scale scrolling effect into mobj-carrying properties = 3/32.
// (This is so scrolling floors and objects on them can move at same speed.)
enum { CARRYFACTOR = (3*FRACUNIT >> 5) };

View file

@ -5,6 +5,7 @@
#include "r_defs.h"
#include "m_bbox.h"
class DPolyAction;
struct FPolyVertex
{