2016-03-28 15:27:55 +00:00
//-----------------------------------------------------------------------------
//
2017-04-17 11:33:19 +00:00
// Copyright 1998-1998 Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2016 Christoph Oelckers
2016-03-28 15:27:55 +00:00
//
2017-04-17 11:33:19 +00:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
2016-03-28 15:27:55 +00:00
//
2017-04-17 11:33:19 +00:00
// This program is distributed in the hope that it will be useful,
2016-03-28 15:27:55 +00:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
2017-04-17 11:33:19 +00:00
// 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, see http://www.gnu.org/licenses/
2016-03-28 15:27:55 +00:00
//
2017-04-17 11:33:19 +00:00
//-----------------------------------------------------------------------------
2016-03-28 15:27:55 +00:00
//
// DESCRIPTION:
// Initializes and implements BOOM linedef triggers for
// Scrollers/Conveyors
//
//-----------------------------------------------------------------------------
2017-04-17 11:33:19 +00:00
/* For code that originates from ZDoom the following applies:
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
2016-03-28 15:27:55 +00:00
# include <stdlib.h>
# include "actor.h"
# include "p_spec.h"
2016-09-19 22:41:22 +00:00
# include "serializer.h"
2016-03-28 15:27:55 +00:00
# include "p_lnspec.h"
# include "r_data/r_interpolate.h"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2016-03-28 15:27:55 +00:00
//-----------------------------------------------------------------------------
//
// killough 3/7/98: Add generalized scroll effects
//
//-----------------------------------------------------------------------------
class DScroller : public DThinker
{
DECLARE_CLASS ( DScroller , DThinker )
HAS_OBJECT_POINTERS
public :
2016-03-28 19:04:46 +00:00
DScroller ( EScroll type , double dx , double dy , int control , int affectee , int accel , EScrollPos scrollpos = EScrollPos : : scw_all ) ;
DScroller ( double dx , double dy , const line_t * l , int control , int accel , EScrollPos scrollpos = EScrollPos : : scw_all ) ;
2017-01-12 21:49:18 +00:00
void OnDestroy ( ) override ;
2016-03-28 15:27:55 +00:00
2016-09-19 22:41:22 +00:00
void Serialize ( FSerializer & arc ) ;
2016-03-28 15:27:55 +00:00
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 ; }
2016-03-28 19:04:46 +00:00
void SetRate ( double dx , double dy ) { m_dx = dx ; m_dy = dy ; }
2016-03-28 15:27:55 +00:00
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
2016-03-28 19:04:46 +00:00
double m_dx , m_dy ; // (dx,dy) scroll speeds
2016-03-28 15:27:55 +00:00
int m_Affectee ; // Number of affected sidedef, sector, tag, or whatever
int m_Control ; // Control sector (-1 if none) used to control scrolling
2016-03-28 19:04:46 +00:00
double m_LastHeight ; // Last known height of control sector
double m_vdx , m_vdy ; // Accumulated velocity if accelerative
2016-03-28 15:27:55 +00:00
int m_Accel ; // Whether it's accelerative
EScrollPos m_Parts ; // Which parts of a sidedef are being scrolled?
2017-03-08 12:34:26 +00:00
TObjPtr < DInterpolation * > m_Interpolations [ 3 ] ;
2016-03-28 15:27:55 +00:00
private :
DScroller ( )
{
}
} ;
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( DScroller , false , true )
2016-03-28 15:27:55 +00:00
2016-11-05 16:08:54 +00:00
IMPLEMENT_POINTERS_START ( DScroller )
IMPLEMENT_POINTER ( m_Interpolations [ 0 ] )
IMPLEMENT_POINTER ( m_Interpolations [ 1 ] )
IMPLEMENT_POINTER ( m_Interpolations [ 2 ] )
IMPLEMENT_POINTERS_END
2016-03-28 15:27:55 +00:00
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
EScrollPos operator & ( EScrollPos one , EScrollPos two )
{
return EScrollPos ( int ( one ) & int ( two ) ) ;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
2016-09-19 22:41:22 +00:00
void DScroller : : Serialize ( FSerializer & arc )
2016-03-28 15:27:55 +00:00
{
Super : : Serialize ( arc ) ;
2016-09-19 22:41:22 +00:00
arc . Enum ( " type " , m_Type )
( " dx " , m_dx )
( " dy " , m_dy )
( " affectee " , m_Affectee )
( " control " , m_Control )
( " lastheight " , m_LastHeight )
( " vdx " , m_vdx )
( " vdy " , m_vdy )
( " accel " , m_Accel )
. Enum ( " parts " , m_Parts )
. Array ( " interpolations " , m_Interpolations , 3 ) ;
2016-03-28 15:27:55 +00:00
}
//-----------------------------------------------------------------------------
//
// [RH] Compensate for rotated sector textures by rotating the scrolling
// in the opposite direction.
//
//-----------------------------------------------------------------------------
2016-03-28 19:04:46 +00:00
static void RotationComp ( const sector_t * sec , int which , double dx , double dy , double & tdx , double & tdy )
2016-03-28 15:27:55 +00:00
{
2016-04-23 11:40:02 +00:00
DAngle an = sec - > GetAngle ( which ) ;
2016-03-28 15:27:55 +00:00
if ( an = = 0 )
{
tdx = dx ;
tdy = dy ;
}
else
{
2016-08-14 19:55:20 +00:00
double ca = - an . Cos ( ) ;
double sa = - an . Sin ( ) ;
2016-03-28 19:04:46 +00:00
tdx = dx * ca - dy * sa ;
tdy = dy * ca + dx * sa ;
2016-03-28 15:27:55 +00:00
}
}
//-----------------------------------------------------------------------------
//
// 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 ( )
{
2016-03-28 19:04:46 +00:00
double dx = m_dx , dy = m_dy , tdx , tdy ;
2016-03-28 15:27:55 +00:00
if ( m_Control ! = - 1 )
{ // compute scroll amounts based on a sector's height changes
2017-01-07 18:32:24 +00:00
double height = level . sectors [ m_Control ] . CenterFloor ( ) +
level . sectors [ m_Control ] . CenterCeiling ( ) ;
2016-03-28 19:04:46 +00:00
double delta = height - m_LastHeight ;
2016-03-28 15:27:55 +00:00
m_LastHeight = height ;
2016-03-28 19:04:46 +00:00
dx * = delta ;
dy * = delta ;
2016-03-28 15:27:55 +00:00
}
// killough 3/14/98: Add acceleration
if ( m_Accel )
{
m_vdx = dx + = m_vdx ;
m_vdy = dy + = m_vdy ;
}
2016-03-28 19:04:46 +00:00
if ( dx = = 0 & & dy = = 0 )
2016-03-28 15:27:55 +00:00
return ;
switch ( m_Type )
{
case EScroll : : sc_side : // killough 3/7/98: Scroll wall texture
if ( m_Parts & EScrollPos : : scw_top )
{
2017-01-08 17:45:30 +00:00
level . sides [ m_Affectee ] . AddTextureXOffset ( side_t : : top , dx ) ;
level . sides [ m_Affectee ] . AddTextureYOffset ( side_t : : top , dy ) ;
2016-03-28 15:27:55 +00:00
}
2017-01-08 17:45:30 +00:00
if ( m_Parts & EScrollPos : : scw_mid & & ( level . sides [ m_Affectee ] . linedef - > backsector = = NULL | |
! ( level . sides [ m_Affectee ] . linedef - > flags & ML_3DMIDTEX ) ) )
2016-03-28 15:27:55 +00:00
{
2017-01-08 17:45:30 +00:00
level . sides [ m_Affectee ] . AddTextureXOffset ( side_t : : mid , dx ) ;
level . sides [ m_Affectee ] . AddTextureYOffset ( side_t : : mid , dy ) ;
2016-03-28 15:27:55 +00:00
}
if ( m_Parts & EScrollPos : : scw_bottom )
{
2017-01-08 17:45:30 +00:00
level . sides [ m_Affectee ] . AddTextureXOffset ( side_t : : bottom , dx ) ;
level . sides [ m_Affectee ] . AddTextureYOffset ( side_t : : bottom , dy ) ;
2016-03-28 15:27:55 +00:00
}
break ;
case EScroll : : sc_floor : // killough 3/7/98: Scroll floor texture
2017-01-07 18:32:24 +00:00
RotationComp ( & level . sectors [ m_Affectee ] , sector_t : : floor , dx , dy , tdx , tdy ) ;
level . sectors [ m_Affectee ] . AddXOffset ( sector_t : : floor , tdx ) ;
level . sectors [ m_Affectee ] . AddYOffset ( sector_t : : floor , tdy ) ;
2016-03-28 15:27:55 +00:00
break ;
case EScroll : : sc_ceiling : // killough 3/7/98: Scroll ceiling texture
2017-01-07 18:32:24 +00:00
RotationComp ( & level . sectors [ m_Affectee ] , sector_t : : ceiling , dx , dy , tdx , tdy ) ;
level . sectors [ m_Affectee ] . AddXOffset ( sector_t : : ceiling , tdx ) ;
level . sectors [ m_Affectee ] . AddYOffset ( sector_t : : ceiling , tdy ) ;
2016-03-28 15:27:55 +00:00
break ;
// [RH] Don't actually carry anything here. That happens later.
case EScroll : : sc_carry :
2016-09-20 07:11:13 +00:00
level . Scrolls [ m_Affectee ] . X + = dx ;
level . Scrolls [ m_Affectee ] . Y + = dy ;
2017-05-19 14:31:44 +00:00
// mark all potentially affected things here so that the very expensive calculation loop in AActor::Tick does not need to run for actors which do not touch a scrolling sector.
for ( auto n = level . sectors [ m_Affectee ] . touching_thinglist ; n ; n = n - > m_snext )
{
n - > m_thing - > flags8 | = MF8_INSCROLLSEC ;
}
2016-03-28 15:27:55 +00:00
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
//
//-----------------------------------------------------------------------------
2016-03-28 19:04:46 +00:00
DScroller : : DScroller ( EScroll type , double dx , double dy ,
2016-03-28 15:27:55 +00:00
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 ;
2016-09-28 09:58:12 +00:00
m_LastHeight = 0 ;
2016-03-28 15:27:55 +00:00
if ( ( m_Control = control ) ! = - 1 )
2017-01-07 18:32:24 +00:00
{
2016-03-28 15:27:55 +00:00
m_LastHeight =
2017-01-07 18:32:24 +00:00
level . sectors [ control ] . CenterFloor ( ) + level . sectors [ control ] . CenterCeiling ( ) ;
}
2016-03-28 15:27:55 +00:00
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 :
2017-01-08 17:45:30 +00:00
level . sides [ affectee ] . Flags | = WALLF_NOAUTODECALS ;
2016-03-28 15:27:55 +00:00
if ( m_Parts & EScrollPos : : scw_top )
{
2017-01-08 17:45:30 +00:00
m_Interpolations [ 0 ] = level . sides [ m_Affectee ] . SetInterpolation ( side_t : : top ) ;
2016-03-28 15:27:55 +00:00
}
2017-01-08 17:45:30 +00:00
if ( m_Parts & EScrollPos : : scw_mid & & ( level . sides [ m_Affectee ] . linedef - > backsector = = nullptr | |
! ( level . sides [ m_Affectee ] . linedef - > flags & ML_3DMIDTEX ) ) )
2016-03-28 15:27:55 +00:00
{
2017-01-08 17:45:30 +00:00
m_Interpolations [ 1 ] = level . sides [ m_Affectee ] . SetInterpolation ( side_t : : mid ) ;
2016-03-28 15:27:55 +00:00
}
if ( m_Parts & EScrollPos : : scw_bottom )
{
2017-01-08 17:45:30 +00:00
m_Interpolations [ 2 ] = level . sides [ m_Affectee ] . SetInterpolation ( side_t : : bottom ) ;
2016-03-28 15:27:55 +00:00
}
break ;
case EScroll : : sc_floor :
2017-01-07 18:32:24 +00:00
m_Interpolations [ 0 ] = level . sectors [ affectee ] . SetInterpolation ( sector_t : : FloorScroll , false ) ;
2016-03-28 15:27:55 +00:00
break ;
case EScroll : : sc_ceiling :
2017-01-07 18:32:24 +00:00
m_Interpolations [ 0 ] = level . sectors [ affectee ] . SetInterpolation ( sector_t : : CeilingScroll , false ) ;
2016-03-28 15:27:55 +00:00
break ;
default :
break ;
}
}
2017-01-12 21:49:18 +00:00
void DScroller : : OnDestroy ( )
2016-03-28 15:27:55 +00:00
{
for ( int i = 0 ; i < 3 ; i + + )
{
if ( m_Interpolations [ i ] ! = NULL )
{
m_Interpolations [ i ] - > DelRef ( ) ;
m_Interpolations [ i ] = NULL ;
}
}
2017-01-12 21:49:18 +00:00
Super : : OnDestroy ( ) ;
2016-03-28 15:27:55 +00:00
}
//-----------------------------------------------------------------------------
//
// 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
//
//-----------------------------------------------------------------------------
2016-03-28 19:04:46 +00:00
DScroller : : DScroller ( double dx , double dy , const line_t * l ,
2016-03-28 15:27:55 +00:00
int control , int accel , EScrollPos scrollpos )
: DThinker ( STAT_SCROLLER )
{
2016-03-28 19:04:46 +00:00
double x = fabs ( l - > Delta ( ) . X ) , y = fabs ( l - > Delta ( ) . Y ) , d ;
if ( y > x ) d = x , x = y , y = d ;
d = x / g_sin ( g_atan2 ( y , x ) + M_PI / 2 ) ;
2016-08-14 20:10:44 +00:00
x = - ( dy * l - > Delta ( ) . Y + dx * l - > Delta ( ) . X ) / d ;
y = - ( dx * l - > Delta ( ) . Y - dy * l - > Delta ( ) . X ) / d ;
2016-03-28 15:27:55 +00:00
m_Type = EScroll : : sc_side ;
m_dx = x ;
m_dy = y ;
m_vdx = m_vdy = 0 ;
m_Accel = accel ;
m_Parts = scrollpos ;
2016-09-28 09:58:12 +00:00
m_LastHeight = 0 ;
2016-03-28 15:27:55 +00:00
if ( ( m_Control = control ) ! = - 1 )
2017-01-07 18:32:24 +00:00
m_LastHeight = level . sectors [ control ] . CenterFloor ( ) + level . sectors [ control ] . CenterCeiling ( ) ;
2017-01-08 17:45:30 +00:00
m_Affectee = l - > sidedef [ 0 ] - > Index ( ) ;
level . sides [ m_Affectee ] . Flags | = WALLF_NOAUTODECALS ;
2016-03-28 15:27:55 +00:00
m_Interpolations [ 0 ] = m_Interpolations [ 1 ] = m_Interpolations [ 2 ] = NULL ;
if ( m_Parts & EScrollPos : : scw_top )
{
2017-01-08 17:45:30 +00:00
m_Interpolations [ 0 ] = level . sides [ m_Affectee ] . SetInterpolation ( side_t : : top ) ;
2016-03-28 15:27:55 +00:00
}
2017-01-08 17:45:30 +00:00
if ( m_Parts & EScrollPos : : scw_mid & & ( level . sides [ m_Affectee ] . linedef - > backsector = = NULL | |
! ( level . sides [ m_Affectee ] . linedef - > flags & ML_3DMIDTEX ) ) )
2016-03-28 15:27:55 +00:00
{
2017-01-08 17:45:30 +00:00
m_Interpolations [ 1 ] = level . sides [ m_Affectee ] . SetInterpolation ( side_t : : mid ) ;
2016-03-28 15:27:55 +00:00
}
if ( m_Parts & EScrollPos : : scw_bottom )
{
2017-01-08 17:45:30 +00:00
m_Interpolations [ 2 ] = level . sides [ m_Affectee ] . SetInterpolation ( side_t : : bottom ) ;
2016-03-28 15:27:55 +00:00
}
}
// 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 )
{
2017-01-08 13:39:16 +00:00
line_t * l = & level . lines [ 0 ] ;
2016-03-28 15:27:55 +00:00
TArray < int > copyscrollers ;
2017-01-08 13:39:16 +00:00
for ( auto & line : level . lines )
2016-03-28 15:27:55 +00:00
{
2017-01-08 13:39:16 +00:00
if ( line . special = = Sector_CopyScroller )
2016-03-28 15:27:55 +00:00
{
// don't allow copying the scroller if the sector has the same tag as it would just duplicate it.
2017-01-08 13:39:16 +00:00
if ( ! tagManager . SectorHasTag ( line . frontsector , line . args [ 0 ] ) )
2016-03-28 15:27:55 +00:00
{
2017-01-08 13:39:16 +00:00
copyscrollers . Push ( line . Index ( ) ) ;
2016-03-28 15:27:55 +00:00
}
2017-01-08 13:39:16 +00:00
line . special = 0 ;
2016-03-28 15:27:55 +00:00
}
}
2017-01-08 13:39:16 +00:00
for ( unsigned i = 0 ; i < level . lines . Size ( ) ; i + + , l + + )
2016-03-28 15:27:55 +00:00
{
2016-03-28 19:04:46 +00:00
double dx ; // direction and speed of scrolling
double dy ;
2016-03-28 15:27:55 +00:00
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)
2017-01-07 19:02:25 +00:00
control = l - > sidedef [ 0 ] - > sector - > Index ( ) ;
2016-03-28 15:27:55 +00:00
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.
2016-03-28 19:04:46 +00:00
dx = l - > Delta ( ) . X / 32. ;
dy = l - > Delta ( ) . Y / 32. ;
2016-03-28 15:27:55 +00:00
}
else
{
// The speed and direction are parameters to the special.
2016-03-28 19:04:46 +00:00
dx = ( l - > args [ 3 ] - 128 ) / 32. ;
dy = ( l - > args [ 4 ] - 128 ) / 32. ;
2016-03-28 15:27:55 +00:00
}
}
switch ( special )
{
int s ;
case Scroll_Ceiling :
{
FSectorTagIterator itr ( l - > args [ 0 ] ) ;
while ( ( s = itr . Next ( ) ) > = 0 )
{
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_ceiling , - dx , dy , control , s , accel ) ;
2016-03-28 15:27:55 +00:00
}
for ( unsigned j = 0 ; j < copyscrollers . Size ( ) ; j + + )
{
2017-01-08 13:39:16 +00:00
line_t * line = & level . lines [ copyscrollers [ j ] ] ;
2016-03-28 15:27:55 +00:00
if ( line - > args [ 0 ] = = l - > args [ 0 ] & & ( line - > args [ 1 ] & 1 ) )
{
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_ceiling , - dx , dy , control , line - > frontsector - > Index ( ) , accel ) ;
2016-03-28 15:27:55 +00:00
}
}
break ;
}
case Scroll_Floor :
if ( l - > args [ 2 ] ! = 1 )
{ // scroll the floor texture
FSectorTagIterator itr ( l - > args [ 0 ] ) ;
while ( ( s = itr . Next ( ) ) > = 0 )
{
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_floor , - dx , dy , control , s , accel ) ;
2016-03-28 15:27:55 +00:00
}
for ( unsigned j = 0 ; j < copyscrollers . Size ( ) ; j + + )
{
2017-01-08 13:39:16 +00:00
line_t * line = & level . lines [ copyscrollers [ j ] ] ;
2016-03-28 15:27:55 +00:00
if ( line - > args [ 0 ] = = l - > args [ 0 ] & & ( line - > args [ 1 ] & 2 ) )
{
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_floor , - dx , dy , control , line - > frontsector - > Index ( ) , accel ) ;
2016-03-28 15:27:55 +00:00
}
}
}
if ( l - > args [ 2 ] > 0 )
{ // carry objects on the floor
FSectorTagIterator itr ( l - > args [ 0 ] ) ;
while ( ( s = itr . Next ( ) ) > = 0 )
{
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_carry , dx , dy , control , s , accel ) ;
2016-03-28 15:27:55 +00:00
}
for ( unsigned j = 0 ; j < copyscrollers . Size ( ) ; j + + )
{
2017-01-08 13:39:16 +00:00
line_t * line = & level . lines [ copyscrollers [ j ] ] ;
2016-03-28 15:27:55 +00:00
if ( line - > args [ 0 ] = = l - > args [ 0 ] & & ( line - > args [ 1 ] & 4 ) )
{
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_carry , dx , dy , control , line - > frontsector - > Index ( ) , accel ) ;
2016-03-28 15:27:55 +00:00
}
}
}
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 )
{
2017-01-14 11:35:23 +00:00
if ( s ! = ( int ) i )
2017-04-14 11:31:58 +00:00
Create < DScroller > ( dx , dy , & level . lines [ s ] , control , accel ) ;
2016-03-28 15:27:55 +00:00
}
break ;
}
case Scroll_Texture_Offsets :
// killough 3/2/98: scroll according to sidedef offsets
2017-01-08 17:45:30 +00:00
s = level . lines [ i ] . sidedef [ 0 ] - > Index ( ) ;
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_side , - level . sides [ s ] . GetTextureXOffset ( side_t : : mid ) ,
2017-01-08 17:45:30 +00:00
level . sides [ s ] . GetTextureYOffset ( side_t : : mid ) , - 1 , s , accel , SCROLLTYPE ( l - > args [ 0 ] ) ) ;
2016-03-28 15:27:55 +00:00
break ;
case Scroll_Texture_Left :
l - > special = special ; // Restore the special, for compat_useblocking's benefit.
2017-01-08 17:45:30 +00:00
s = level . lines [ i ] . sidedef [ 0 ] - > Index ( ) ;
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_side , l - > args [ 0 ] / 64. , 0 ,
2016-03-28 15:27:55 +00:00
- 1 , s , accel , SCROLLTYPE ( l - > args [ 1 ] ) ) ;
break ;
case Scroll_Texture_Right :
l - > special = special ;
2017-01-08 17:45:30 +00:00
s = level . lines [ i ] . sidedef [ 0 ] - > Index ( ) ;
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_side , - l - > args [ 0 ] / 64. , 0 ,
2016-03-28 15:27:55 +00:00
- 1 , s , accel , SCROLLTYPE ( l - > args [ 1 ] ) ) ;
break ;
case Scroll_Texture_Up :
l - > special = special ;
2017-01-08 17:45:30 +00:00
s = level . lines [ i ] . sidedef [ 0 ] - > Index ( ) ;
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_side , 0 , l - > args [ 0 ] / 64. ,
2016-03-28 15:27:55 +00:00
- 1 , s , accel , SCROLLTYPE ( l - > args [ 1 ] ) ) ;
break ;
case Scroll_Texture_Down :
l - > special = special ;
2017-01-08 17:45:30 +00:00
s = level . lines [ i ] . sidedef [ 0 ] - > Index ( ) ;
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_side , 0 , - l - > args [ 0 ] / 64. ,
2016-03-28 15:27:55 +00:00
- 1 , s , accel , SCROLLTYPE ( l - > args [ 1 ] ) ) ;
break ;
case Scroll_Texture_Both :
2017-01-08 17:45:30 +00:00
s = level . lines [ i ] . sidedef [ 0 ] - > Index ( ) ;
2016-03-28 15:27:55 +00:00
if ( l - > args [ 0 ] = = 0 ) {
2016-03-28 19:04:46 +00:00
dx = ( l - > args [ 1 ] - l - > args [ 2 ] ) / 64. ;
dy = ( l - > args [ 4 ] - l - > args [ 3 ] ) / 64. ;
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_side , dx , dy , - 1 , s , accel ) ;
2016-03-28 15:27:55 +00:00
}
break ;
default :
// [RH] It wasn't a scroller after all, so restore the special.
l - > special = special ;
break ;
}
}
}
//-----------------------------------------------------------------------------
//
// Modify a wall scroller
//
//-----------------------------------------------------------------------------
2016-03-28 19:04:46 +00:00
void SetWallScroller ( int id , int sidechoice , double dx , double dy , EScrollPos Where )
2016-03-28 15:27:55 +00:00
{
Where = Where & scw_all ;
if ( Where = = 0 ) return ;
2016-03-28 19:04:46 +00:00
if ( dx = = 0 & & dy = = 0 )
2016-03-28 15:27:55 +00:00
{
// 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 ( ) ;
2017-01-08 17:45:30 +00:00
if ( wallnum > = 0 & & tagManager . LineHasID ( level . sides [ wallnum ] . linedef , id ) & &
level . sides [ wallnum ] . linedef - > sidedef [ sidechoice ] - > Index ( ) = = wallnum & &
2016-03-28 15:27:55 +00:00
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 & &
2017-01-08 17:45:30 +00:00
tagManager . LineHasID ( level . sides [ collect . RefNum ] . linedef , id ) & &
level . sides [ collect . RefNum ] . linedef - > sidedef [ sidechoice ] - > Index ( ) = = collect . RefNum & &
2016-03-28 15:27:55 +00:00
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 )
{
2017-01-08 13:39:16 +00:00
if ( level . lines [ linenum ] . sidedef [ sidechoice ] ! = NULL )
2016-03-28 15:27:55 +00:00
{
2017-01-08 17:45:30 +00:00
int sidenum = level . lines [ linenum ] . sidedef [ sidechoice ] - > Index ( ) ;
2016-03-28 15:27:55 +00:00
unsigned int i ;
for ( i = 0 ; i < numcollected ; i + + )
{
if ( Collection [ i ] . RefNum = = sidenum )
break ;
}
if ( i = = numcollected )
{
2017-04-14 11:31:58 +00:00
Create < DScroller > ( EScroll : : sc_side , dx , dy , - 1 , sidenum , 0 , Where ) ;
2016-03-28 15:27:55 +00:00
}
}
}
}
}
2016-03-28 19:04:46 +00:00
void SetScroller ( int tag , EScroll type , double dx , double dy )
2016-03-28 15:27:55 +00:00
{
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 ) ;
}
}
}
2016-03-28 19:04:46 +00:00
if ( i > 0 | | ( dx = = 0 & & dy = = 0 ) )
2016-03-28 15:27:55 +00:00
{
return ;
}
// Need to create scrollers for the sector(s)
FSectorTagIterator itr ( tag ) ;
while ( ( i = itr . Next ( ) ) > = 0 )
{
2017-04-14 11:31:58 +00:00
Create < DScroller > ( type , dx , dy , - 1 , i , 0 ) ;
2016-03-28 15:27:55 +00:00
}
}
2016-03-28 19:04:46 +00:00
void P_CreateScroller ( EScroll type , double dx , double dy , int control , int affectee , int accel , EScrollPos scrollpos )
2016-03-28 15:27:55 +00:00
{
2017-04-14 11:31:58 +00:00
Create < DScroller > ( type , dx , dy , control , affectee , accel , scrollpos ) ;
2016-03-28 15:27:55 +00:00
}