1 //**************************************************************************
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
25 //**************************************************************************
26 #ifndef VAVOOM_PSIM_LEVELINFO_HEADER
27 #define VAVOOM_PSIM_LEVELINFO_HEADER
29 #include "../mapinfo.h"
30 #include "p_thinker.h"
33 extern VCvarI compat_nopassover
;
34 extern VCvarI compat_notossdrops
;
35 extern VCvarI compat_limitpain
;
37 class VLevelInfo
: public VThinker
{
38 DECLARE_CLASS(VLevelInfo
, VThinker
, 0)
39 NO_DEFAULT_CONSTRUCTOR(VLevelInfo
)
41 //enum { TID_HASH_SIZE = 1021 };
42 enum { TID_HASH_SIZE
= 1024 };
59 float Sky1ScrollDelta
;
60 float Sky2ScrollDelta
;
70 LIF_DoubleSky
= 0x00000001u
, // parallax sky: sky2 behind sky1
71 LIF_Lightning
= 0x00000002u
, // use of lightning on the level flashes from sky1 to sky2
72 LIF_Map07Special
= 0x00000004u
,
73 LIF_BaronSpecial
= 0x00000008u
,
74 LIF_CyberDemonSpecial
= 0x00000010u
,
75 LIF_SpiderMastermindSpecial
= 0x00000020u
,
76 LIF_MinotaurSpecial
= 0x00000040u
,
77 LIF_DSparilSpecial
= 0x00000080u
,
78 LIF_IronLichSpecial
= 0x00000100u
,
79 LIF_SpecialActionOpenDoor
= 0x00000200u
,
80 LIF_SpecialActionLowerFloor
= 0x00000400u
,
81 LIF_SpecialActionKillMonsters
= 0x00000800u
,
82 LIF_NoIntermission
= 0x00001000u
,
83 LIF_AllowMonsterTelefrags
= 0x00002000u
,
84 LIF_NoAllies
= 0x00004000u
,
85 LIF_DeathSlideShow
= 0x00008000u
,
86 LIF_ForceNoSkyStretch
= 0x00010000u
,
87 LIF_LookupName
= 0x00020000u
,
88 LIF_FallingDamage
= 0x00040000u
,
89 LIF_OldFallingDamage
= 0x00080000u
,
90 LIF_StrifeFallingDamage
= 0x00100000u
,
91 LIF_MonsterFallingDamage
= 0x00200000u
,
92 LIF_NoFreelook
= 0x00400000u
,
93 LIF_NoJump
= 0x00800000u
,
94 LIF_NoAutoSndSeq
= 0x01000000u
,
95 LIF_ActivateOwnSpecial
= 0x02000000u
,
96 LIF_MissilesActivateImpact
= 0x04000000u
,
97 LIF_FilterStarts
= 0x08000000u
,
98 LIF_InfiniteFlightPowerup
= 0x10000000u
,
99 LIF_ClipMidTex
= 0x20000000u
,
100 LIF_WrapMidTex
= 0x40000000u
,
101 LIF_KeepFullInventory
= 0x80000000u
,
103 vuint32 LevelInfoFlags
;
105 LIF2_CompatShortTex
= 0x00000001u
,
106 LIF2_CompatStairs
= 0x00000002u
,
107 LIF2_CompatLimitPain
= 0x00000004u
,
108 LIF2_CompatNoPassOver
= 0x00000008u
,
109 LIF2_CompatNoTossDrops
= 0x00000010u
,
110 LIF2_CompatUseBlocking
= 0x00000020u
,
111 LIF2_CompatNoDoorLight
= 0x00000040u
,
112 LIF2_CompatRavenScroll
= 0x00000080u
,
113 LIF2_CompatSoundTarget
= 0x00000100u
,
114 LIF2_CompatDehHealth
= 0x00000200u
,
115 LIF2_CompatTrace
= 0x00000400u
,
116 LIF2_CompatDropOff
= 0x00000800u
,
117 LIF2_CompatBoomScroll
= 0x00001000u
,
118 LIF2_CompatInvisibility
= 0x00002000u
,
119 LIF2_LaxMonsterActivation
= 0x00004000u
,
120 LIF2_HaveMonsterActivation
= 0x00008000u
,
121 LIF2_ClusterHub
= 0x00010000u
,
122 LIF2_BegunPlay
= 0x00020000u
,
123 LIF2_Frozen
= 0x00040000u
,
124 LIF2_NoCrouch
= 0x00080000u
,
125 LIF2_ResetHealth
= 0x00100000u
,
126 LIF2_ResetInventory
= 0x00200000u
,
127 LIF2_ResetItems
= 0x00400000u
,
128 LIF2_CheckSwitchRange
= 0x00800000u
, // force "check switch range" flag
129 LIF2_NoCheckSwitchRange
= 0x01000000u
, // ignore "check switch range" flag
131 vuint32 LevelInfoFlags2
;
135 vint32 TotalSecret
; // for intermission
138 vint32 CurrentSecret
;
140 float CompletitionTime
; // for intermission
142 // maintain single and multi player starting spots
143 TArray
<mthing_t
> DeathmatchStarts
; // player spawn spots for deathmatch
144 TArray
<mthing_t
> PlayerStarts
; // player spawn spots
146 VEntity
*TIDHash
[TID_HASH_SIZE
];
148 float Gravity
; // level gravity
151 TArray
<VMapSpecialAction
> SpecialActions
;
153 vint32 PerfectHatredMode
;
156 static inline int TIDHashBucket (int tid
) noexcept
{ return (int)(hashU32((unsigned)tid
)%TID_HASH_SIZE
); }
160 virtual void PostCtor () override
;
162 void SetMapInfo (VLevel
*Level
, const VMapInfo
&);
164 // if `org` is `nullptr`, use sector sound origin
165 void SectorStartSound (const sector_t
*Sector
, int SoundId
, int Channel
, float Volume
, float Attenuation
, const TVec
*org
=nullptr);
166 void SectorStopSound (const sector_t
*sector
, int channel
);
167 void SectorStartSequence (const sector_t
*Sector
, VName Name
, int ModeNum
);
168 void SectorStopSequence (const sector_t
*sector
);
169 void PolyobjStartSequence (const polyobj_t
*Poly
, VName Name
, int ModeNum
);
170 void PolyobjStopSequence (const polyobj_t
*poly
);
172 void ExitLevel (int Position
);
173 void SecretExitLevel (int Position
);
174 void Completed (int Map
, int Position
, int SaveAngle
);
176 static bool IsSwitchTexture (int texid
);
177 // `line` is used to calculate sound origin; can be `nullptr1
178 // `sidenum` is side index in `Sides` array
179 bool ChangeSwitchTexture (line_t
*line
, VEntity
*activator
, int sidenum
, bool useAgain
, VName DefaultSound
, bool &Quest
, const TVec
*org
=nullptr);
180 bool StartButton (line_t
*line
, VEntity
*activator
, int sidenum
, vuint8 w
, int SwitchDef
, VName DefaultSound
, bool UseAgain
, TVec
&outsndorg
);
182 VEntity
*FindMobjFromTID (int, VEntity
*);
184 void ChangeMusic (VName
);
186 VStr
GetLevelName () const;
188 int FindFreeTID (int tidstart
, int limit
=0) const;
189 bool IsTIDUsed (int tid
, bool allowdead
=false) const;
191 void ChangeSky (VStr skytex1
, VStr skytex2
);
194 DECLARE_FUNCTION(AddStaticLight
)
195 DECLARE_FUNCTION(AddStaticLightRGB
)
196 DECLARE_FUNCTION(AddStaticLightRGBSector
)
197 DECLARE_FUNCTION(MoveStaticLightByOwner
)
198 DECLARE_FUNCTION(RemoveStaticLightByOwner
)
201 DECLARE_FUNCTION(SectorStartSequence
)
202 DECLARE_FUNCTION(SectorStopSequence
)
203 DECLARE_FUNCTION(PolyobjStartSequence
)
204 DECLARE_FUNCTION(PolyobjStopSequence
)
207 DECLARE_FUNCTION(ExitLevel
)
208 DECLARE_FUNCTION(SecretExitLevel
)
209 DECLARE_FUNCTION(Completed
)
211 // special thinker utilites
212 DECLARE_FUNCTION(IsSwitchTexture
)
213 DECLARE_FUNCTION(ChangeSwitchTexture
)
214 DECLARE_FUNCTION(FindMobjFromTID
)
215 DECLARE_FUNCTION(AutoSave
)
217 DECLARE_FUNCTION(ChangeMusic
)
219 DECLARE_FUNCTION(FindFreeTID
)
220 DECLARE_FUNCTION(IsTIDUsed
)
222 DECLARE_FUNCTION(ChangeSky
)
224 DECLARE_FUNCTION(GetLevelName
)
226 DECLARE_FUNCTION (get_CompatShortTex
)
227 DECLARE_FUNCTION (get_CompatStairs
)
228 DECLARE_FUNCTION (get_CompatLimitPain
)
229 DECLARE_FUNCTION (get_CompatNoPassOver
)
230 DECLARE_FUNCTION (get_CompatNoTossDrops
)
231 DECLARE_FUNCTION (get_CompatUseBlocking
)
232 DECLARE_FUNCTION (get_CompatNoDoorLight
)
233 DECLARE_FUNCTION (get_CompatRavenScroll
)
234 DECLARE_FUNCTION (get_CompatSoundTarget
)
235 DECLARE_FUNCTION (get_CompatDehHealth
)
236 DECLARE_FUNCTION (get_CompatTrace
)
237 DECLARE_FUNCTION (get_CompatDropOff
)
238 DECLARE_FUNCTION (get_CompatBoomScroll
)
239 DECLARE_FUNCTION (get_CompatInvisibility
)
242 static float GZSizeToRadius (float Val
, bool attenuated
, float attmult
=1.04f
) {
243 static VMethodProxy
method("GZSizeToRadius");
244 vobjPutParam(Val
, attenuated
, VOptPutParamFloat(attmult
, true));
245 VSTATIC_RET_FLOAT(method
);
248 // EntityEx PickActor (optional TVec Origin, TVec dir, float distance, optional int actorMask, optional int wallMask) {
249 // final bool CheckLock (Entity user, int lock, bool door)
250 bool eventCheckLock (VEntity
*user
, int lock
, bool door
) { static VMethodProxy
method("CheckLock"); vobjPutParamSelf(user
, lock
, door
); VMT_RET_BOOL(method
); }
251 void eventSpawnSpecials () { static VMethodProxy
method("SpawnSpecials"); vobjPutParamSelf(); VMT_RET_VOID(method
); }
252 void eventUpdateSpecials () { static VMethodProxy
method("UpdateSpecials"); vobjPutParamSelf(); VMT_RET_VOID(method
); }
253 void eventAfterUnarchiveThinkers () { static VMethodProxy
method("AfterUnarchiveThinkers"); vobjPutParamSelf(); VMT_RET_VOID(method
); }
255 bool eventPolyThrustMobj (VEntity
*A
, TVec thrustDir
, polyobj_t
*po
, bool vertical
) { static VMethodProxy
method("PolyThrustMobj"); vobjPutParamSelf(A
, thrustDir
, po
, vertical
); VMT_RET_BOOL(method
); }
256 void eventPolyCrushMobj (VEntity
*A
, polyobj_t
*po
) { static VMethodProxy
method("PolyCrushMobj"); vobjPutParamSelf(A
, po
); VMT_RET_VOID(method
); }
258 void eventPolyRotateMobj (VEntity
*A
, float dangle
) { static VMethodProxy
method("PolyRotateMobj"); vobjPutParamSelf(A
, dangle
); VMT_RET_VOID(method
); }
259 //bool eventPolyMoveMobjBy (VEntity *A, vuint32 poflags, float dx, float dy) { static VMethodProxy method("PolyMoveMobjBy"); vobjPutParamSelf(A, poflags, dx, dy); VMT_RET_BOOL(method); }
261 bool eventTagBusy (int tag
) { static VMethodProxy
method("TagBusy"); vobjPutParamSelf(tag
); VMT_RET_BOOL(method
); }
262 bool eventPolyBusy (int polyobj
) { static VMethodProxy
method("PolyBusy"); vobjPutParamSelf(polyobj
); VMT_RET_BOOL(method
); }
263 float eventPolyAngle (int polyobj
) { static VMethodProxy
method("PolyAngle"); vobjPutParamSelf(polyobj
); VMT_RET_FLOAT(method
); }
264 int eventThingCount (int type
, VName TypeName
, int tid
, int SectorTag
) { static VMethodProxy
method("ThingCount"); vobjPutParamSelf(type
, TypeName
, tid
, SectorTag
); VMT_RET_INT(method
); }
265 int eventExecuteActionSpecial (int Special
, int Arg1
, int Arg2
, int Arg3
,
266 int Arg4
, int Arg5
, line_t
*Line
, int Side
, VEntity
*A
)
268 static VMethodProxy
method("ExecuteActionSpecial");
269 vobjPutParamSelf(Special
, Arg1
, Arg2
, Arg3
, Arg4
, Arg5
, Line
, Side
, A
);
272 int eventEV_ThingProjectile (int tid
, int type
, int angle
, int speed
,
273 int vspeed
, int gravity
, int newtid
,
274 VName TypeName
, VEntity
*Activator
)
276 static VMethodProxy
method("EV_ThingProjectile");
277 vobjPutParamSelf(tid
, type
, angle
, speed
, vspeed
, gravity
, newtid
, TypeName
, Activator
);
280 void eventStartPlaneWatcher (VEntity
*it
, line_t
*line
, int lineSide
,
281 bool ceiling
, int tag
, int height
, int special
,
282 int arg1
, int arg2
, int arg3
, int arg4
, int arg5
)
284 static VMethodProxy
method("StartPlaneWatcher");
285 vobjPutParamSelf(it
, line
, lineSide
, ceiling
, tag
, height
, special
, arg1
, arg2
, arg3
, arg4
, arg5
);
286 VMT_RET_VOID(method
);
288 void eventSpawnMapThing (mthing_t
*mthing
) { static VMethodProxy
method("SpawnMapThing"); vobjPutParamSelf(mthing
); VMT_RET_VOID(method
); }
289 void eventUpdateParticle (particle_t
*p
, float DeltaTime
) { if (DeltaTime
<= 0.0f
) return; static VMethodProxy
method("UpdateParticle"); vobjPutParamSelf(p
, DeltaTime
); VMT_RET_VOID(method
); }
290 //final override int AcsSpawnThing(name Name, TVec Org, int Tid, float Angle, bool forced)
291 int eventAcsSpawnThing (VName Name
, TVec Org
, int Tid
, float Angle
, bool forced
=false) {
292 static VMethodProxy
method("AcsSpawnThing");
293 vobjPutParamSelf(Name
, Org
, Tid
, Angle
, forced
);
296 int eventAcsSpawnSpot (VName Name
, int SpotTid
, int Tid
, float Angle
, bool forced
=false) {
297 static VMethodProxy
method("AcsSpawnSpot");
298 vobjPutParamSelf(Name
, SpotTid
, Tid
, Angle
, forced
);
301 int eventAcsSpawnSpotFacing (VName Name
, int SpotTid
, int Tid
, bool forced
=false) {
302 static VMethodProxy
method("AcsSpawnSpotFacing");
303 vobjPutParamSelf(Name
, SpotTid
, Tid
, forced
);
306 int eventAcsDamageActor (int targettid
, int targetptr
, int inflictortid
, int inflictorptr
, int damage
, VName damagetype
, VEntity
*Activator
) {
307 static VMethodProxy
method("AcsDamageActor");
308 vobjPutParamSelf(targettid
, targetptr
, inflictortid
, inflictorptr
, damage
, damagetype
, Activator
);
312 int AcsSpawnDecal (VEntity
*ent
, VName decalname
, TVec org
, float dist
, float angle
, bool permanent
) {
313 static VMethodProxy
method("AcsSpawnDecal");
314 vobjPutParamSelf(ent
, decalname
, org
, dist
, angle
, permanent
);
318 int eventAcsPolyMoveRotateEx (int po
, int hspeed
, int yawangle
, int dist
, int vspeed
, int vdist
, float deltaangle
, int moveflags
, VEntity
*Activator
) {
319 static VMethodProxy
method("AcsPolyMoveRotateEx");
320 vobjPutParamSelf(po
, hspeed
, yawangle
, dist
, vspeed
, vdist
, deltaangle
, moveflags
, Activator
);
323 int eventAcsPolyMoveToRotateEx (int po
, int speed
, int x
, int y
, int z
, float deltaangle
, int moveflags
, VEntity
*Activator
) {
324 static VMethodProxy
method("AcsPolyMoveToRotateEx");
325 vobjPutParamSelf(po
, speed
, x
, y
, z
, deltaangle
, moveflags
, Activator
);
328 int eventAcsPolyMoveToSpotRotateEx (int po
, int speed
, int targettid
, float deltaangle
, int moveflags
, VEntity
*Activator
) {
329 static VMethodProxy
method("AcsPolyMoveToSpotRotateEx");
330 vobjPutParamSelf(po
, speed
, targettid
, deltaangle
, moveflags
, Activator
);
333 int eventAcsPolyRotateEx (int po
, int speed
, float deltaangle
, int moveflags
, VEntity
*Activator
) {
334 static VMethodProxy
method("AcsPolyRotateEx");
335 vobjPutParamSelf(po
, speed
, deltaangle
, moveflags
, Activator
);
339 void eventSectorDamage (int Tag
, int Amount
, VName DamageType
, VName ProtectionType
, int Flags
) {
340 static VMethodProxy
method("SectorDamage");
341 vobjPutParamSelf(Tag
, Amount
, DamageType
, ProtectionType
, Flags
);
342 VMT_RET_VOID(method
);
344 int eventDoThingDamage (int Tid
, int Amount
, VName DmgType
, VEntity
*Activator
) {
345 static VMethodProxy
method("DoThingDamage");
346 vobjPutParamSelf(Tid
, Amount
, DmgType
, Activator
);
349 void eventSetMarineWeapon (int Tid
, int Weapon
, VEntity
*Activator
) {
350 static VMethodProxy
method("SetMarineWeapon");
351 vobjPutParamSelf(Tid
, Weapon
, Activator
);
352 VMT_RET_VOID(method
);
354 void eventSetMarineSprite (int Tid
, VName SrcClass
, VEntity
*Activator
) {
355 static VMethodProxy
method("SetMarineSprite");
356 vobjPutParamSelf(Tid
, SrcClass
, Activator
);
357 VMT_RET_VOID(method
);
359 void eventAcsFadeRange (float BlendR1
, float BlendG1
, float BlendB1
,
360 float BlendA1
, float BlendR2
, float BlendG2
, float BlendB2
,
361 float BlendA2
, float Duration
, VEntity
*Activator
)
363 static VMethodProxy
method("AcsFadeRange");
364 vobjPutParamSelf(BlendR1
, BlendG1
, BlendB1
, BlendA1
, BlendR2
, BlendG2
, BlendB2
, BlendA2
, Duration
, Activator
);
365 VMT_RET_VOID(method
);
367 void eventAcsCancelFade (VEntity
*Activator
) {
368 static VMethodProxy
method("AcsCancelFade");
369 vobjPutParamSelf(Activator
);
370 VMT_RET_VOID(method
);
372 void eventAcsRadiusQuake2 (VEntity
*Activator
, int tid
, int intensity
, int duration
, int damrad
, int tremrad
, VName sound
) {
373 static VMethodProxy
method("AcsRadiusQuake2");
374 vobjPutParamSelf(Activator
, tid
, intensity
, duration
, damrad
, tremrad
, sound
);
375 VMT_RET_VOID(method
);
377 void eventAcsWarp (VEntity
*Activator
, int tid
, float xofs
, float yofs
, float zofs
, float angle
, int flags
, VName succState
, bool exact
, float heightoffset
, float radiusoffset
, float pitch
) {
378 static VMethodProxy
method("AcsWarp");
379 vobjPutParamSelf(Activator
, tid
, xofs
, yofs
, zofs
, angle
, flags
, succState
, exact
, heightoffset
, radiusoffset
, pitch
);
380 VMT_RET_VOID(method
);
383 void eventAfterSetMapInfo (VLevel
*Level
) { static VMethodProxy
method("AfterSetMapInfo"); vobjPutParamSelf(Level
); VMT_RET_VOID(method
); }
385 #define CREATE_COMPAT_GETTER(name_,cvar_,flagvar_,flagname_) \
386 VVA_CHECKRESULT inline bool name_ () const noexcept { \
387 switch (cvar_.asInt()) { \
388 case 1: return true; /* always on */ \
389 case 2: return false; /* always off */ \
390 default: return !!(flagvar_&flagname_); /* map default */ \
394 CREATE_COMPAT_GETTER(GetNoPassOver
,compat_nopassover
,LevelInfoFlags2
,LIF2_CompatNoPassOver
)
395 CREATE_COMPAT_GETTER(GetNoTossDrops
,compat_notossdrops
,LevelInfoFlags2
,LIF2_CompatNoTossDrops
)
396 CREATE_COMPAT_GETTER(GetLimitPain
,compat_limitpain
,LevelInfoFlags2
,LIF2_CompatLimitPain
)
398 #undef CREATE_COMPAT_GETTER