implemented DSDA's sector scrolling properties.

The major new additions are flags to specify which kind of actor is supposed to be scrolled and carrying ceiling scrollers.
This commit is contained in:
Christoph Oelckers 2023-10-29 10:38:02 +01:00
parent 2fb41a7956
commit 2b0731a5a7
6 changed files with 129 additions and 19 deletions

View file

@ -337,6 +337,20 @@ Note: All <bool> fields default to false unless mentioned otherwise.
healthfloorgroup = <int>; // ID of destructible object to synchronize hitpoints (optional, default is 0)
healthceiling = <int>; // Amount of hitpoints for this sector (includes ceiling and top-outside linedef sides)
healthceilinggroup = <int>; // ID of destructible object to synchronize hitpoints (optional, default is 0)
xscrollfloor = <float>; // X map units per frame to scroll the floor.
yscrollfloor = <float>; // Y map units per frame to scroll the floor.
scrollfloormode = <int>; // Floor scroll mode bit mask (1 = scroll textures, 2 = carry static objects, 4 = carry players, 8 = carry monsters.
xscrollceiling = <float>; // X map units per frame to scroll the ceiling.
yscrollceiling = <float>; // Y map units per frame to scroll the ceiling.
scrollceilingmode = <int>; // ceiling scroll mode bit mask (1 = scroll textures, 2 = carry static objects, 4 = carry players, 8 = carry monsters.
scroll_ceil_x = <float>; // deprecated Eternity based alternatives for the above.
scroll_ceil_y = <float>; // Due to using unintuitive units of measurement and a more limited feature set they should not be used anymore.
scroll_ceil_type = <string>;
scroll_floor_x = <float>;
scroll_floor_y = <float>;
scroll_floor_type = <string>;
* Note about dropactors

View file

@ -194,7 +194,7 @@ private:
void SpawnSpecials();
void InitSectorSpecial(sector_t *sector, int special);
void SpawnLights(sector_t *sector);
void CreateScroller(EScroll type, double dx, double dy, sector_t *affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
void CreateScroller(EScroll type, double dx, double dy, sector_t *affectee, int accel, EScrollPos scrollpos = EScrollPos::scw_all, int scrollmode = 15/*SCROLL_All*/);
void SpawnScrollers();
void SpawnFriction();
void SpawnPushers();

View file

@ -1466,7 +1466,7 @@ void MapLoader::SpawnScrollers()
}
void MapLoader::CreateScroller(EScroll type, double dx, double dy, sector_t *affectee, int accel, EScrollPos scrollpos)
void MapLoader::CreateScroller(EScroll type, double dx, double dy, sector_t *affectee, int accel, EScrollPos scrollpos, int scrollmode)
{
Level->CreateThinker<DScroller>(type, dx, dy, nullptr, affectee, nullptr, accel, scrollpos);
Level->CreateThinker<DScroller>(type, dx, dy, nullptr, affectee, nullptr, accel, scrollpos, scrollmode);
}

View file

@ -52,6 +52,7 @@
#include "xlat/xlat.h"
#include "maploader.h"
#include "texturemanager.h"
#include "a_scroll.h"
//===========================================================================
//
@ -431,7 +432,7 @@ struct UDMFScroll
bool ceiling;
int index;
double x, y;
FName type;
int scrolltype;
};
class UDMFParser : public UDMFParserBase
@ -1589,11 +1590,13 @@ public:
// Brand new UDMF scroller properties
double scroll_ceil_x = 0;
double scroll_ceil_y = 0;
FName scroll_ceil_type = NAME_None;
int scroll_ceil_type = 0;
double scroll_floor_x = 0;
double scroll_floor_y = 0;
FName scroll_floor_type = NAME_None;
int scroll_floor_type = 0;
const double scrollfactor = 1 / 3.2; // I hope this is correct, it's just a guess taken from Eternity's code.
memset(sec, 0, sizeof(*sec));
sec->Level = Level;
@ -2007,29 +2010,65 @@ public:
break;
case NAME_scroll_ceil_x:
scroll_ceil_x = CheckFloat(key) * scrollfactor;
break;
case NAME_xscrollceiling:
scroll_ceil_x = CheckFloat(key);
break;
case NAME_scroll_ceil_y:
scroll_ceil_y = CheckFloat(key) * scrollfactor;
break;
case NAME_yscrollceiling:
scroll_ceil_y = CheckFloat(key);
break;
case NAME_scroll_ceil_type:
scroll_ceil_type = CheckString(key);
case NAME_scrollceilingmode:
scroll_ceil_type = CheckInt(key);
break;
case NAME_scroll_ceil_type:
{
const char* val = CheckString(key);
if (!stricmp(val, "both")) scroll_ceil_type = SCROLL_All;
else if (!stricmp(val, "visual")) scroll_ceil_type = SCROLL_Textures;
if (!stricmp(val, "physical")) scroll_ceil_type = SCROLL_All & ~SCROLL_Textures;
else scroll_ceil_type = 0;
break;
}
case NAME_scroll_floor_x:
scroll_floor_x = CheckFloat(key) * scrollfactor;
break;
case NAME_xscrollfloor:
scroll_floor_x = CheckFloat(key);
break;
case NAME_scroll_floor_y:
scroll_floor_y = CheckFloat(key) * scrollfactor;
break;
case NAME_yscrollfloor:
scroll_floor_y = CheckFloat(key);
break;
case NAME_scroll_floor_type:
scroll_floor_type = CheckString(key);
case NAME_scrollfloormode:
scroll_floor_type = CheckInt(key);
break;
case NAME_scroll_floor_type:
{
const char* val = CheckString(key);
if (!stricmp(val, "both")) scroll_floor_type = SCROLL_All;
else if (!stricmp(val, "visual")) scroll_floor_type = SCROLL_Textures;
if (!stricmp(val, "physical")) scroll_floor_type = SCROLL_All & ~SCROLL_Textures;
else scroll_floor_type = 0;
break;
}
// These two are used by Eternity for something I do not understand.
//case NAME_portal_ceil_useglobaltex:
//case NAME_portal_floor_useglobaltex:
@ -2470,15 +2509,13 @@ public:
// Now create the scrollers.
for (auto &scroll : UDMFScrollers)
{
const double scrollfactor = 1 / 3.2; // I hope this is correct, it's just a guess taken from Eternity's code.
if (scroll.type == NAME_Both || scroll.type == NAME_Visual)
if (scroll.scrolltype & SCROLL_Textures)
{
loader->CreateScroller(scroll.ceiling ? EScroll::sc_ceiling : EScroll::sc_floor, scroll.x * scrollfactor, scroll.y * scrollfactor, &Level->sectors[scroll.index], 0);
loader->CreateScroller(scroll.ceiling ? EScroll::sc_ceiling : EScroll::sc_floor, -scroll.x, scroll.y, &Level->sectors[scroll.index], 0);
}
if (scroll.type == NAME_Both || scroll.type == NAME_Physical)
if (scroll.scrolltype & (SCROLL_StaticObjects | SCROLL_Players | SCROLL_Monsters))
{
// sc_carry_ceiling doesn't do anything yet.
loader->CreateScroller(scroll.ceiling ? EScroll::sc_carry_ceiling : EScroll::sc_carry, scroll.x * scrollfactor, scroll.y * scrollfactor, &Level->sectors[scroll.index], 0);
loader->CreateScroller(scroll.ceiling ? EScroll::sc_carry_ceiling : EScroll::sc_carry, scroll.x, scroll.y, &Level->sectors[scroll.index], 0, scw_all, scroll.scrolltype);
}
}

View file

@ -105,8 +105,11 @@ void DScroller::Serialize(FSerializer &arc)
("vdx", m_vdx)
("vdy", m_vdy)
("accel", m_Accel)
("affect", m_Affect)
.Enum("parts", m_Parts)
.Array("interpolations", m_Interpolations, 3);
if (arc.isReading() && m_Affect == 0) m_Affect = SCROLL_All;
}
//-----------------------------------------------------------------------------
@ -218,11 +221,55 @@ void DScroller::Tick ()
// 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 = m_Sector->touching_thinglist; n; n = n->m_snext)
{
AActor* actor = n->m_thing;
if (actor->player)
{
if (!(m_Affect & SCROLL_Players))
continue;
}
else if (actor->flags3 & MF3_ISMONSTER)
{
if (!(m_Affect & SCROLL_Monsters))
continue;
}
else if (!(m_Affect & SCROLL_StaticObjects))
continue;
n->m_thing->flags8 |= MF8_INSCROLLSEC;
}
break;
case EScroll::sc_carry_ceiling: // to be added later
case EScroll::sc_carry_ceiling:
// this just copies DSDA's implementation. Usability is limited.
for (auto n = m_Sector->touching_thinglist; n; n = n->m_snext)
{
AActor* actor = n->m_thing;
if (
!(actor->flags & MF_NOCLIP) &&
actor->flags & MF_SPAWNCEILING &&
actor->flags & MF_NOGRAVITY &&
actor->Top() == m_Sector->ceilingplane.ZatPoint(actor->Pos().XY())
)
{
if (actor->player)
{
if (!(m_Affect & SCROLL_Players))
continue;
}
else if (actor->flags3 & MF3_ISMONSTER)
{
if (!(m_Affect & SCROLL_Monsters))
continue;
}
else if (!(m_Affect & SCROLL_StaticObjects))
continue;
n->m_thing->Vel.X = m_dx;
n->m_thing->Vel.Y = m_dy;
}
}
break;
}
}
@ -247,7 +294,7 @@ void DScroller::Tick ()
//
//-----------------------------------------------------------------------------
void DScroller::Construct (EScroll type, double dx, double dy, sector_t *ctrl, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos)
void DScroller::Construct (EScroll type, double dx, double dy, sector_t *ctrl, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos, int aff)
{
m_Type = type;
m_dx = dx;
@ -256,6 +303,7 @@ void DScroller::Construct (EScroll type, double dx, double dy, sector_t *ctrl,
m_Parts = scrollpos;
m_vdx = m_vdy = 0;
m_LastHeight = 0;
m_Affect = aff;
if ((m_Controller = ctrl) != nullptr)
{
m_LastHeight = m_Controller->CenterFloor() + m_Controller->CenterCeiling();
@ -344,6 +392,7 @@ void DScroller::Construct(double dx, double dy, const line_t *l, sector_t * cont
m_Accel = accel;
m_Parts = scrollpos;
m_LastHeight = 0;
m_Affect = SCROLL_All; // not really relevant, so use the default.
if ((m_Controller = control) != nullptr)
{
m_LastHeight = m_Controller->CenterFloor() + m_Controller->CenterCeiling();

View file

@ -1,5 +1,14 @@
#pragma once
enum EScrollAffect
{
SCROLL_Textures = 1,
SCROLL_StaticObjects = 2,
SCROLL_Players = 4,
SCROLL_Monsters = 8,
SCROLL_All = 15
};
//-----------------------------------------------------------------------------
//
// killough 3/7/98: Add generalized scroll effects
@ -13,7 +22,7 @@ class DScroller : public DThinker
public:
static const int DEFAULT_STAT = STAT_SCROLLER;
void Construct(EScroll type, double dx, double dy, sector_t *control, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
void Construct(EScroll type, double dx, double dy, sector_t *control, sector_t *sec, side_t *side, int accel, EScrollPos scrollpos = EScrollPos::scw_all, int aff = SCROLL_All);
void Construct(double dx, double dy, const line_t *l, sector_t *control, int accel, EScrollPos scrollpos = EScrollPos::scw_all);
void OnDestroy() override;
@ -29,6 +38,7 @@ public:
protected:
EScroll m_Type; // Type of scroll effect
int m_Affect;
double m_dx, m_dy; // (dx,dy) scroll speeds
sector_t *m_Sector; // Affected sector
side_t *m_Side; // ... or side