From ad778b0bcce8f4bbcdc7cb6da0b252e067bc1ba3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 29 Oct 2023 23:18:06 +0100 Subject: [PATCH] added DSDA's thrust properties for UDMF --- specs/udmf_zdoom.txt | 6 + src/CMakeLists.txt | 1 + src/maploader/udmf.cpp | 32 ++++- src/playsim/mapthinkers/a_pusher.h | 15 +++ src/playsim/mapthinkers/a_thruster.cpp | 155 +++++++++++++++++++++++++ 5 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 src/playsim/mapthinkers/a_thruster.cpp diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index b3762cba78..ebc831d574 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -371,6 +371,12 @@ Note: All fields default to false unless mentioned otherwise. skyceiling2 = // defines secondary upper sky for this sector. colormap = ; // only provided for backwards compatibility. Do not use in GZDoom projects. + + xthrust = ; // applies thrust to actors - x-magnitude + ythrust = ; // applies thrust to actors - y-magnitude + thrustgroup = ; // specifies which actors get thrusted. Bitfield with (1 = static objects, 2 = player, 4 = monsters, 8 = projectiles, 16 = actors with +WINDTHRUST) + thrustlocation = ; // specifies where in the sector actors get thrusted: (1 = on the ground, 2 = in the air, 4 = on the ceiling) + * Note about dropactors diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5b0a3eac80..34d6344d5d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -872,6 +872,7 @@ set (PCH_SOURCES playsim/mapthinkers/a_pillar.cpp playsim/mapthinkers/a_plats.cpp playsim/mapthinkers/a_pusher.cpp + playsim/mapthinkers/a_thruster.cpp playsim/mapthinkers/a_scroll.cpp playsim/mapthinkers/dsectoreffect.cpp playsim/a_pickups.cpp diff --git a/src/maploader/udmf.cpp b/src/maploader/udmf.cpp index 4f79115310..ea3e03b878 100644 --- a/src/maploader/udmf.cpp +++ b/src/maploader/udmf.cpp @@ -53,6 +53,7 @@ #include "maploader.h" #include "texturemanager.h" #include "a_scroll.h" +#include "p_spec_thinkers.h" //=========================================================================== // @@ -450,6 +451,7 @@ class UDMFParser : public UDMFParserBase TArray ParsedVertices; TArray UDMFSectorScrollers; TArray UDMFWallScrollers; + TArray UDMFThrusters; FDynamicColormap *fogMap = nullptr, *normMap = nullptr; FMissingTextureTracker &missingTex; @@ -1639,6 +1641,10 @@ public: double friction = -FLT_MAX, movefactor = -FLT_MAX; + DVector2 thrust = { 0,0 }; + int thrustgroup = 0; + int thrustlocation = 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)); @@ -2140,6 +2146,22 @@ public: sec->planes[sector_t::ceiling].skytexture[1] = TexMan.CheckForTexture(CheckString(key), ETextureType::Wall, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst); break; + case NAME_xthrust: + thrust.X = CheckFloat(key); + break; + + case NAME_ythrust: + thrust.Y = CheckFloat(key); + break; + + case NAME_thrustgroup: + thrustgroup = CheckInt(key); + break; + + case NAME_thrustlocation: + thrustlocation = CheckInt(key); + break; + // These two are used by Eternity for something I do not understand. //case NAME_portal_ceil_useglobaltex: //case NAME_portal_floor_useglobaltex: @@ -2205,7 +2227,7 @@ public: sec->Flags &= ~SECF_DAMAGEFLAGS; } - // Cannot be initialized yet because they need the final sector array. + // These cannot be initialized yet because they need the final sector array. if (scroll_ceil_type != NAME_None) { UDMFSectorScrollers.Push({ true, index, scroll_ceil_x, scroll_ceil_y, scroll_ceil_type }); @@ -2214,6 +2236,10 @@ public: { UDMFSectorScrollers.Push({ false, index, scroll_floor_x, scroll_floor_y, scroll_floor_type }); } + if (!thrust.isZero()) + { + UDMFThrusters.Push({ thrustlocation, index, thrust.X, thrust.Y, thrustgroup }); + } // Reset the planes to their defaults if not all of the plane equation's parameters were found. @@ -2613,6 +2639,10 @@ public: loader->CreateScroller(EScroll::sc_side, scroll.x, scroll.y, nullptr, &Level->sides[sd], 0); } } + for (auto& scroll : UDMFThrusters) + { + Level->CreateThinker(&Level->sectors[scroll.index], scroll.x, scroll.y, scroll.scrolltype, scroll.where); + } } }; diff --git a/src/playsim/mapthinkers/a_pusher.h b/src/playsim/mapthinkers/a_pusher.h index 36c9cfab6f..4ce7c73a5a 100644 --- a/src/playsim/mapthinkers/a_pusher.h +++ b/src/playsim/mapthinkers/a_pusher.h @@ -44,3 +44,18 @@ protected: friend bool PIT_PushThing (AActor *thing); }; +class DThruster : public DThinker +{ + DECLARE_CLASS(DThruster, DThinker) + + DVector2 m_PushVec; + sector_t* m_Sector; + int m_Type; + int m_Location; + +public: + void Construct(sector_t* sec, double dx, double dy, int type, int location); + void Serialize(FSerializer& arc); + void Tick(); + +}; diff --git a/src/playsim/mapthinkers/a_thruster.cpp b/src/playsim/mapthinkers/a_thruster.cpp new file mode 100644 index 0000000000..ca052678bd --- /dev/null +++ b/src/playsim/mapthinkers/a_thruster.cpp @@ -0,0 +1,155 @@ +//----------------------------------------------------------------------------- +// +// Copyright 2023 Ryan Krafnick +// Copyright 2023 Christoph Oelckers +// +// 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 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. +// +// +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// UDMF-style thruster +// +//----------------------------------------------------------------------------- + + +#include +#include "actor.h" +#include "p_spec.h" +#include "serializer.h" +#include "serializer_doom.h" +#include "p_spec_thinkers.h" + +EXTERN_CVAR(Bool, var_pushers); + +IMPLEMENT_CLASS(DThruster, false, false) + +enum +{ + THRUST_STATIC = 0x01, + THRUST_PLAYER = 0x02, + THRUST_MONSTER = 0x04, + THRUST_PROJECTILE = 0x08, + THRUST_WINDTHRUST = 0x10, + + THRUST_GROUNDED = 1, + THRUST_AIRBORNE = 2, + THRUST_CEILING = 4 +}; + + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void DThruster::Serialize(FSerializer &arc) +{ + Super::Serialize (arc); + arc("type", m_Type) + ("location", m_Location) + ("pushvec", m_PushVec) + ("sector", m_Sector); +} + + +//----------------------------------------------------------------------------- +// +// Add a thrust thinker to the thinker list +// +//----------------------------------------------------------------------------- + +void DThruster::Construct(sector_t* sec, double dx, double dy, int type, int location) +{ + m_Type = type; + m_Location = location; + m_Sector = sec; + m_PushVec = { dx, dy }; +} + +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void DThruster::Tick () +{ + sector_t* sec = m_Sector; + + if (m_PushVec.isZero()) + return; + + for (auto node = sec->touching_thinglist; node; node = node->m_snext) + { + bool thrust_it = false; + AActor* thing = node->m_thing; + + if (thing->flags & MF_NOCLIP) + continue; + + if (!(thing->flags & MF_NOGRAVITY) && thing->Z() <= thing->floorz) + { + if (m_Location & THRUST_GROUNDED) + thrust_it = true; + } + else if ( + thing->flags & MF_SPAWNCEILING && + thing->flags & MF_NOGRAVITY && + thing->Top() == thing->ceilingz + ) + { + if (m_Location & THRUST_CEILING) + thrust_it = true; + } + else if (thing->flags & MF_NOGRAVITY || thing->Z() > thing->floorz) + { + if (m_Location & THRUST_AIRBORNE) + thrust_it = true; + } + + if (thrust_it) + { + thrust_it = false; + + if (thing->flags2 & MF2_WINDTHRUST && m_Type & THRUST_WINDTHRUST) + thrust_it = true; + else if (thing->flags3 & MF3_ISMONSTER) + { + if (m_Type & THRUST_MONSTER) + thrust_it = true; + } + else if (thing->player) + { + if (m_Type & THRUST_PLAYER) + thrust_it = true; + } + else if (thing->flags & MF_MISSILE) + { + if (m_Type & THRUST_PROJECTILE) + thrust_it = true; + } + else + { + if (m_Type & THRUST_STATIC) + thrust_it = true; + } + + if (thrust_it) + { + thing->Vel += m_PushVec; + } + } + } +} +