diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000..d12f3a703
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,26 @@
+* text=auto
+
+*.h text
+*.c text
+*.cc text
+*.cpp text
+*.mm text
+*.lemon text
+*.y text
+*.re text
+*.i text
+*.asm text
+*.S text
+
+*.vcproj text eol=crlf
+*.sln text eol=crlf
+*.bat text eol=crlf
+
+*.txt text
+language.* text
+
+*.png binary
+*.imgz binary
+*.lmp binary
+*.flac binary
+*.dat binary
diff --git a/.gitignore b/.gitignore
index df5c6663b..1b078ed63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
*.pdb
*.ilk
*.aps
+/fmodapi*/
/Release
/wadsrc_wad
*.user
@@ -45,3 +46,4 @@
/build_vc2015
/build_vc2015-32
/build_vc2015-64
+/build
diff --git a/bzip2/bzip2.vcproj b/bzip2/bzip2.vcproj
deleted file mode 100644
index 4b8aef564..000000000
--- a/bzip2/bzip2.vcproj
+++ /dev/null
@@ -1,330 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dumb/vc6/dumb/dumb.vcproj b/dumb/vc6/dumb/dumb.vcproj
deleted file mode 100644
index 525bc56fc..000000000
--- a/dumb/vc6/dumb/dumb.vcproj
+++ /dev/null
@@ -1,2007 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dumb/vc6/dumb_static/dumb_static.vcproj b/dumb/vc6/dumb_static/dumb_static.vcproj
deleted file mode 100644
index 6d6736259..000000000
--- a/dumb/vc6/dumb_static/dumb_static.vcproj
+++ /dev/null
@@ -1,2069 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/game-music-emu/game-music-emu.vcproj b/game-music-emu/game-music-emu.vcproj
deleted file mode 100644
index e521ab01d..000000000
--- a/game-music-emu/game-music-emu.vcproj
+++ /dev/null
@@ -1,874 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/gdtoa/gdtoa.vcproj b/gdtoa/gdtoa.vcproj
deleted file mode 100644
index 12a3e40b3..000000000
--- a/gdtoa/gdtoa.vcproj
+++ /dev/null
@@ -1,1728 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/jpeg-6b/jpeg-6b.vcproj b/jpeg-6b/jpeg-6b.vcproj
deleted file mode 100644
index b46f4150d..000000000
--- a/jpeg-6b/jpeg-6b.vcproj
+++ /dev/null
@@ -1,420 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lzma/lzmalib.vcproj b/lzma/lzmalib.vcproj
deleted file mode 100644
index f1e085f3d..000000000
--- a/lzma/lzmalib.vcproj
+++ /dev/null
@@ -1,463 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/actor.h b/src/actor.h
index 2de96d84c..8695986b2 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -743,6 +743,7 @@ public:
inline bool IsNoClip2() const;
void CheckPortalTransition(bool islinked);
+ fixedvec3 GetPortalTransition(fixed_t byoffset);
// What species am I?
virtual FName GetSpecies();
@@ -893,7 +894,7 @@ public:
fixedvec2 ret = { X() + dx, Y() + dy };
return ret;
}
- else return P_GetOffsetPosition(this, dx, dy);
+ else return P_GetOffsetPosition(X(), Y(), dx, dy);
}
@@ -905,7 +906,7 @@ public:
Y() + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) };
return ret;
}
- else return P_GetOffsetPosition(this, FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]));
+ else return P_GetOffsetPosition(X(), Y(), FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]));
}
fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false)
@@ -917,7 +918,7 @@ public:
}
else
{
- fixedvec2 op = P_GetOffsetPosition(this, dx, dy);
+ fixedvec2 op = P_GetOffsetPosition(X(), Y(), dx, dy);
fixedvec3 pos = { op.x, op.y, Z() + dz };
return pos;
}
@@ -933,7 +934,7 @@ public:
}
else
{
- fixedvec2 op = P_GetOffsetPosition(this, FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]));
+ fixedvec2 op = P_GetOffsetPosition(X(), Y(), FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]), FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]));
fixedvec3 pos = { op.x, op.y, Z() + dz };
return pos;
}
@@ -1404,6 +1405,28 @@ inline fixedvec2 Vec2Angle(fixed_t length, angle_t angle)
void PrintMiscActorInfo(AActor * query);
AActor *P_LinePickActor(AActor *t1, angle_t angle, fixed_t distance, int pitch, ActorFlags actorMask, DWORD wallMask);
+// If we want to make P_AimLineAttack capable of handling arbitrary portals, it needs to pass a lot more info than just the linetarget actor.
+struct FTranslatedLineTarget
+{
+ AActor *linetarget;
+ angle_t hitangle;
+ fixedvec3 targetPosFromSrc;
+ angle_t targetAngleFromSrc;
+ fixedvec3 sourcePosFromTarget;
+ angle_t sourceAngleFromTarget;
+ bool unlinked; // found by a trace that went through an unlinked portal.
+
+ angle_t SourceAngleToTarget() const
+ {
+ return R_PointToAngle2(sourcePosFromTarget.x, sourcePosFromTarget.y, linetarget->X(), linetarget->Y());
+ }
+ angle_t TargetAngleToSource() const
+ {
+ return R_PointToAngle2(linetarget->X(), linetarget->Y(), sourcePosFromTarget.x, sourcePosFromTarget.y);
+ }
+};
+
+
#define S_FREETARGMOBJ 1
#endif // __P_MOBJ_H__
diff --git a/src/actorptrselect.cpp b/src/actorptrselect.cpp
index 54c41e6ba..a93ecd6a1 100644
--- a/src/actorptrselect.cpp
+++ b/src/actorptrselect.cpp
@@ -2,6 +2,7 @@
#include "actor.h"
#include "d_player.h"
#include "p_pspr.h"
+#include "p_local.h"
//==========================================================================
//
@@ -34,6 +35,8 @@ AActor *COPY_AAPTR(AActor *origin, int selector)
{
if (selector == AAPTR_DEFAULT) return origin;
+ FTranslatedLineTarget t;
+
if (origin)
{
if (origin->player)
@@ -41,11 +44,9 @@ AActor *COPY_AAPTR(AActor *origin, int selector)
switch (selector & AAPTR_PLAYER_SELECTORS)
{
case AAPTR_PLAYER_GETTARGET:
- {
- AActor *gettarget = NULL;
- P_BulletSlope(origin, &gettarget);
- return gettarget;
- }
+ P_BulletSlope(origin, &t, ALF_PORTALRESTRICT);
+ return t.linetarget;
+
case AAPTR_PLAYER_GETCONVERSATION:
return origin->player->ConversationNPC;
}
@@ -60,11 +61,8 @@ AActor *COPY_AAPTR(AActor *origin, int selector)
return origin->FriendPlayer ? AAPTR_RESOLVE_PLAYERNUM(origin->FriendPlayer - 1) : NULL;
case AAPTR_GET_LINETARGET:
- {
- AActor *gettarget = NULL;
- P_BulletSlope(origin, &gettarget);
- return gettarget;
- }
+ P_BulletSlope(origin, &t, ALF_PORTALRESTRICT);
+ return t.linetarget;
}
}
diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp
index 70f36bea9..1e4516b27 100644
--- a/src/c_cmds.cpp
+++ b/src/c_cmds.cpp
@@ -872,16 +872,16 @@ CCMD (wdir)
//-----------------------------------------------------------------------------
CCMD(linetarget)
{
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (CheckCheatmode () || players[consoleplayer].mo == NULL) return;
- P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->angle,MISSILERANGE, &linetarget, 0);
- if (linetarget)
+ P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->angle,MISSILERANGE, &t, 0);
+ if (t.linetarget)
{
Printf("Target=%s, Health=%d, Spawnhealth=%d\n",
- linetarget->GetClass()->TypeName.GetChars(),
- linetarget->health,
- linetarget->SpawnHealth());
+ t.linetarget->GetClass()->TypeName.GetChars(),
+ t.linetarget->health,
+ t.linetarget->SpawnHealth());
}
else Printf("No target found\n");
}
@@ -889,18 +889,18 @@ CCMD(linetarget)
// As linetarget, but also give info about non-shootable actors
CCMD(info)
{
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (CheckCheatmode () || players[consoleplayer].mo == NULL) return;
P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->angle,MISSILERANGE,
- &linetarget, 0, ALF_CHECKNONSHOOTABLE|ALF_FORCENOSMART);
- if (linetarget)
+ &t, 0, ALF_CHECKNONSHOOTABLE|ALF_FORCENOSMART);
+ if (t.linetarget)
{
Printf("Target=%s, Health=%d, Spawnhealth=%d\n",
- linetarget->GetClass()->TypeName.GetChars(),
- linetarget->health,
- linetarget->SpawnHealth());
- PrintMiscActorInfo(linetarget);
+ t.linetarget->GetClass()->TypeName.GetChars(),
+ t.linetarget->health,
+ t.linetarget->SpawnHealth());
+ PrintMiscActorInfo(t.linetarget);
}
else Printf("No target found. Info cannot find actors that have "
"the NOBLOCKMAP flag or have height/radius of 0.\n");
diff --git a/src/dobjtype.h b/src/dobjtype.h
index 1e982e74b..ba2634f08 100644
--- a/src/dobjtype.h
+++ b/src/dobjtype.h
@@ -5,7 +5,6 @@
#error You must #include "dobject.h" to get dobjtype.h
#endif
-#include "thingdef/thingdef_type.h"
#include "vm.h"
// Variable/parameter/field flags -------------------------------------------
diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp
index 73fda96b3..08eb018f9 100644
--- a/src/g_doom/a_doomweaps.cpp
+++ b/src/g_doom/a_doomweaps.cpp
@@ -33,7 +33,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch)
angle_t angle;
int damage;
int pitch;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (self->player != NULL)
{
@@ -53,15 +53,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch)
angle = self->angle;
angle += pr_punch.Random2() << 18;
- pitch = P_AimLineAttack (self, angle, MELEERANGE, &linetarget);
+ pitch = P_AimLineAttack (self, angle, MELEERANGE);
- P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, LAF_ISMELEEATTACK, &linetarget);
+ P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, LAF_ISMELEEATTACK, &t);
// turn to face target
- if (linetarget)
+ if (t.linetarget)
{
S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM);
- self->angle = self->AngleTo(linetarget);
+ self->angle = t.SourceAngleToTarget();
}
return 0;
}
@@ -133,7 +133,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
angle_t angle;
angle_t slope;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
int actualdamage;
if (NULL == (player = self->player))
@@ -159,18 +159,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
}
angle = self->angle + (pr_saw.Random2() * (spread_xy / 255));
- slope = P_AimLineAttack (self, angle, range, &linetarget) + (pr_saw.Random2() * (spread_z / 255));
+ slope = P_AimLineAttack (self, angle, range, &t) + (pr_saw.Random2() * (spread_z / 255));
AWeapon *weapon = self->player->ReadyWeapon;
- if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!linetarget && (flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_WEAPON())
+ if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!t.linetarget && (flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_WEAPON())
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
- P_LineAttack (self, angle, range, slope, damage, NAME_Melee, pufftype, false, &linetarget, &actualdamage);
+ P_LineAttack (self, angle, range, slope, damage, NAME_Melee, pufftype, false, &t, &actualdamage);
- if (!linetarget)
+ if (!t.linetarget)
{
if ((flags & SF_RANDOMLIGHTMISS) && (pr_saw() > 64))
{
@@ -197,7 +197,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
}
}
- if (lifesteal && !(linetarget->flags5 & MF5_DONTDRAIN))
+ if (lifesteal && !(t.linetarget->flags5 & MF5_DONTDRAIN))
{
if (flags & SF_STEALARMOR)
{
@@ -232,7 +232,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
// turn to face target
if (!(flags & SF_NOTURN))
{
- angle = self->AngleTo(linetarget);
+ angle = t.SourceAngleToTarget();
if (angle - self->angle > ANG180)
{
if (angle - self->angle < (angle_t)(-ANG90 / 20))
@@ -643,7 +643,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
int j;
int damage;
angle_t an;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (spraytype == NULL) spraytype = PClass::FindActor("BFGExtra");
if (numrays <= 0) numrays = 40;
@@ -662,18 +662,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
an = self->angle - angle / 2 + angle / numrays*i;
// self->target is the originator (player) of the missile
- P_AimLineAttack(self->target, an, distance, &linetarget, vrange);
+ P_AimLineAttack(self->target, an, distance, &t, vrange);
- if (linetarget != NULL)
+ if (t.linetarget != NULL)
{
- AActor *spray = Spawn(spraytype, linetarget->PosPlusZ(linetarget->height >> 2), ALLOW_REPLACE);
+ AActor *spray = Spawn(spraytype, t.linetarget->PosPlusZ(t.linetarget->height >> 2), ALLOW_REPLACE);
int dmgFlags = 0;
FName dmgType = NAME_BFGSplash;
if (spray != NULL)
{
- if (spray->flags6 & MF6_MTHRUSPECIES && self->target->GetSpecies() == linetarget->GetSpecies())
+ if (spray->flags6 & MF6_MTHRUSPECIES && self->target->GetSpecies() == t.linetarget->GetSpecies())
{
spray->Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them.
continue;
@@ -696,8 +696,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
damage = defdamage;
}
- int newdam = P_DamageMobj(linetarget, self->target, self->target, damage, dmgType, dmgFlags);
- P_TraceBleed(newdam > 0 ? newdam : damage, linetarget, self->target);
+ int newdam = P_DamageMobj(t.linetarget, self->target, self->target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.SourceAngleToTarget());
+ P_TraceBleed(newdam > 0 ? newdam : damage, &t, self);
}
}
return 0;
diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp
index 43eec76e1..5051a4b94 100644
--- a/src/g_doom/a_scriptedmarine.cpp
+++ b/src/g_doom/a_scriptedmarine.cpp
@@ -276,16 +276,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw)
if (self->CheckMeleeRange ())
{
angle_t angle;
- AActor *linetarget;
+ FTranslatedLineTarget t;
damage *= (pr_m_saw()%10+1);
angle = self->angle + (pr_m_saw.Random2() << 18);
P_LineAttack (self, angle, MELEERANGE+1,
- P_AimLineAttack (self, angle, MELEERANGE+1, &linetarget), damage,
- NAME_Melee, pufftype, false, &linetarget);
+ P_AimLineAttack (self, angle, MELEERANGE+1), damage,
+ NAME_Melee, pufftype, false, &t);
- if (!linetarget)
+ if (!t.linetarget)
{
S_Sound (self, CHAN_WEAPON, fullsound, 1, ATTN_NORM);
return 0;
@@ -293,7 +293,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_M_Saw)
S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM);
// turn to face target
- angle = self->AngleTo(linetarget);
+ angle = t.SourceAngleToTarget();
if (angle - self->angle > ANG180)
{
if (angle - self->angle < (angle_t)(-ANG90/20))
@@ -328,7 +328,7 @@ static void MarinePunch(AActor *self, int damagemul)
angle_t angle;
int damage;
int pitch;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (self->target == NULL)
return;
@@ -337,15 +337,14 @@ static void MarinePunch(AActor *self, int damagemul)
A_FaceTarget (self);
angle = self->angle + (pr_m_punch.Random2() << 18);
- pitch = P_AimLineAttack (self, angle, MELEERANGE, &linetarget);
- P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true, &linetarget);
+ pitch = P_AimLineAttack (self, angle, MELEERANGE);
+ P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true, &t);
// turn to face target
- if (linetarget)
+ if (t.linetarget)
{
S_Sound (self, CHAN_WEAPON, "*fist", 1, ATTN_NORM);
- self->angle = self->AngleTo(linetarget);
-
+ self->angle = t.SourceAngleToTarget();
}
}
diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp
index dcc3e1774..9ebdaf169 100644
--- a/src/g_heretic/a_chicken.cpp
+++ b/src/g_heretic/a_chicken.cpp
@@ -176,7 +176,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1)
int damage;
int slope;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -185,11 +185,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1)
damage = 1 + (pr_beakatkpl1()&3);
angle = player->mo->angle;
- slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget);
- P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget);
- if (linetarget)
+ slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
+ P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t);
+ if (t.linetarget)
{
- player->mo->angle = player->mo->AngleTo(linetarget);
+ player->mo->angle = t.SourceAngleToTarget();
}
P_PlayPeck (player->mo);
player->chickenPeck = 12;
@@ -211,7 +211,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2)
int damage;
int slope;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -220,11 +220,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2)
damage = pr_beakatkpl2.HitDice (4);
angle = player->mo->angle;
- slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget);
- P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &linetarget);
- if (linetarget)
+ slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
+ P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t);
+ if (t.linetarget)
{
- player->mo->angle = player->mo->AngleTo(linetarget);
+ player->mo->angle = t.SourceAngleToTarget();
}
P_PlayPeck (player->mo);
player->chickenPeck = 12;
diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp
index f51de13e1..4ff89d9d2 100644
--- a/src/g_heretic/a_hereticweaps.cpp
+++ b/src/g_heretic/a_hereticweaps.cpp
@@ -66,7 +66,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack)
angle_t angle;
int slope;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -88,13 +88,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StaffAttack)
}
angle = self->angle;
angle += pr_sap.Random2() << 18;
- slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget);
- P_LineAttack (self, angle, MELEERANGE, slope, damage, NAME_Melee, puff, true, &linetarget);
- if (linetarget)
+ slope = P_AimLineAttack (self, angle, MELEERANGE);
+ P_LineAttack (self, angle, MELEERANGE, slope, damage, NAME_Melee, puff, true, &t);
+ if (t.linetarget)
{
//S_StartSound(player->mo, sfx_stfhit);
// turn to face target
- self->angle = self->AngleTo(linetarget);
+ self->angle = t.SourceAngleToTarget();
}
return 0;
}
@@ -257,7 +257,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack)
fixed_t dist;
player_t *player;
PClassActor *pufftype;
- AActor *linetarget;
+ FTranslatedLineTarget t;
int actualdamage = 0;
if (NULL == (player = self->player))
@@ -290,9 +290,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack)
angle += pr_gatk.Random2() << 18;
pufftype = PClass::FindActor("GauntletPuff1");
}
- slope = P_AimLineAttack (self, angle, dist, &linetarget);
- P_LineAttack (self, angle, dist, slope, damage, NAME_Melee, pufftype, false, &linetarget, &actualdamage);
- if (!linetarget)
+ slope = P_AimLineAttack (self, angle, dist);
+ P_LineAttack (self, angle, dist, slope, damage, NAME_Melee, pufftype, false, &t, &actualdamage);
+ if (!t.linetarget)
{
if (pr_gatk() > 64)
{
@@ -316,7 +316,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack)
}
if (power)
{
- if (!(linetarget->flags5 & MF5_DONTDRAIN)) P_GiveBody (self, actualdamage>>1);
+ if (!(t.linetarget->flags5 & MF5_DONTDRAIN)) P_GiveBody (self, actualdamage>>1);
S_Sound (self, CHAN_AUTO, "weapons/gauntletspowhit", 1, ATTN_NORM);
}
else
@@ -324,7 +324,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack)
S_Sound (self, CHAN_AUTO, "weapons/gauntletshit", 1, ATTN_NORM);
}
// turn to face target
- angle = self->AngleTo(linetarget);
+ angle = t.SourceAngleToTarget();
if (angle-self->angle > ANG180)
{
if ((int)(angle-self->angle) < -ANG90/20)
@@ -594,7 +594,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2)
AActor *mo;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -607,16 +607,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL2)
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
- mo = P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AMaceFX4), self->angle, &linetarget);
+ mo = P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AMaceFX4), self->angle, &t);
if (mo)
{
mo->velx += self->velx;
mo->vely += self->vely;
mo->velz = 2*FRACUNIT+
clamp(finetangent[FINEANGLES/4-(self->pitch>>ANGLETOFINESHIFT)], -5*FRACUNIT, 5*FRACUNIT);
- if (linetarget)
+ if (t.linetarget && !t.unlinked)
{
- mo->tracer = linetarget;
+ mo->tracer = t.linetarget;
}
}
S_Sound (self, CHAN_WEAPON, "weapons/maceshoot", 1, ATTN_NORM);
@@ -637,7 +637,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact)
AActor *target;
angle_t angle = 0;
bool newAngle;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if ((self->Z() <= self->floorz) && P_HitFloor (self))
{ // Landed in some sort of liquid
@@ -671,11 +671,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact)
angle = 0;
for (i = 0; i < 16; i++)
{
- P_AimLineAttack (self, angle, 10*64*FRACUNIT, &linetarget, 0, ALF_NOFRIENDS, NULL, self->target);
- if (linetarget && self->target != linetarget)
+ P_AimLineAttack (self, angle, 10*64*FRACUNIT, &t, 0, ALF_NOFRIENDS|ALF_PORTALRESTRICT, NULL, self->target);
+ if (t.linetarget && self->target != t.linetarget)
{
- self->tracer = linetarget;
- angle = self->AngleTo(linetarget);
+ self->tracer = t.linetarget;
+ angle = t.SourceAngleToTarget();
newAngle = true;
break;
}
@@ -943,7 +943,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2)
player_t *player;
AActor *MissileActor;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -955,16 +955,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSkullRodPL2)
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
- P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AHornRodFX2), self->angle, &linetarget, &MissileActor);
+ P_SpawnPlayerMissile (self, 0,0,0, RUNTIME_CLASS(AHornRodFX2), self->angle, &t, &MissileActor);
// Use MissileActor instead of the return value from
// P_SpawnPlayerMissile because we need to give info to the mobj
// even if it exploded immediately.
if (MissileActor != NULL)
{
MissileActor->special2 = (int)(player - players);
- if (linetarget)
+ if (t.linetarget && !t.unlinked)
{
- MissileActor->tracer = linetarget;
+ MissileActor->tracer = t.linetarget;
}
S_Sound (MissileActor, CHAN_WEAPON, "weapons/hornrodpowshoot", 1, ATTN_NORM);
}
diff --git a/src/g_hexen/a_blastradius.cpp b/src/g_hexen/a_blastradius.cpp
index c83211585..bfaec55d0 100644
--- a/src/g_hexen/a_blastradius.cpp
+++ b/src/g_hexen/a_blastradius.cpp
@@ -151,6 +151,11 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast)
{ // Out of range
continue;
}
+ if (mo->Sector->PortalGroup != self->Sector->PortalGroup && !P_CheckSight(self, mo))
+ {
+ // in another region and cannot be seen.
+ continue;
+ }
BlastActor (mo, strength, speed, self, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE));
}
return 0;
diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp
index 466c0f7c8..f87c2dd7d 100644
--- a/src/g_hexen/a_clericholy.cpp
+++ b/src/g_hexen/a_clericholy.cpp
@@ -213,7 +213,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack)
PARAM_ACTION_PROLOGUE;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -225,10 +225,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack)
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
- AActor *missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HolyMissile"), self->angle, &linetarget);
- if (missile != NULL)
+ AActor *missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HolyMissile"), self->angle, &t);
+ if (missile != NULL && !t.unlinked)
{
- missile->tracer = linetarget;
+ missile->tracer = t.linetarget;
}
weapon->CHolyCount = 3;
diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp
index ecd28da4f..05698c086 100644
--- a/src/g_hexen/a_clericmace.cpp
+++ b/src/g_hexen/a_clericmace.cpp
@@ -5,8 +5,6 @@
#include "thingdef/thingdef.h"
*/
-extern void AdjustPlayerAngle (AActor *pmo, AActor *linetarget);
-
static FRandom pr_maceatk ("CMaceAttack");
//===========================================================================
@@ -24,7 +22,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack)
int slope;
int i;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -36,26 +34,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack)
damage = 25+(pr_maceatk()&15);
for (i = 0; i < 16; i++)
{
- angle = player->mo->angle+i*(ANG45/16);
- slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget);
- if (linetarget)
+ for (int j = 1; j >= -1; j -= 2)
{
- P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget);
- if (linetarget != NULL)
+ angle = player->mo->angle + j*i*(ANG45 / 16);
+ slope = P_AimLineAttack(player->mo, angle, 2 * MELEERANGE, &t);
+ if (t.linetarget)
{
- AdjustPlayerAngle (player->mo, linetarget);
- goto macedone;
- }
- }
- angle = player->mo->angle-i*(ANG45/16);
- slope = P_AimLineAttack (player->mo, angle, 2*MELEERANGE, &linetarget);
- if (linetarget)
- {
- P_LineAttack (player->mo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget);
- if (linetarget != NULL)
- {
- AdjustPlayerAngle (player->mo, linetarget);
- goto macedone;
+ P_LineAttack(player->mo, angle, 2 * MELEERANGE, slope, damage, NAME_Melee, hammertime, true, &t);
+ if (t.linetarget != NULL)
+ {
+ AdjustPlayerAngle(player->mo, &t);
+ goto macedone;
+ }
}
}
}
@@ -63,7 +53,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CMaceAttack)
player->mo->weaponspecial = 0;
angle = player->mo->angle;
- slope = P_AimLineAttack (player->mo, angle, MELEERANGE, &linetarget);
+ slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, hammertime);
macedone:
return 0;
diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp
index 964a78503..2644b29b0 100644
--- a/src/g_hexen/a_clericstaff.cpp
+++ b/src/g_hexen/a_clericstaff.cpp
@@ -55,7 +55,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck)
int slope;
int i;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
PClassActor *puff;
if (NULL == (player = self->player))
@@ -70,57 +70,38 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck)
puff = PClass::FindActor("CStaffPuff");
for (i = 0; i < 3; i++)
{
- angle = pmo->angle + i*(ANG45 / 16);
- slope = P_AimLineAttack(pmo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D);
- if (linetarget)
+ for (int j = 1; j >= -1; j -= 2)
{
- P_LineAttack(pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, puff, false, &linetarget);
- if (linetarget != NULL)
+ angle = pmo->angle + j*i*(ANG45 / 16);
+ slope = P_AimLineAttack(pmo, angle, fixed_t(1.5*MELEERANGE), &t, 0, ALF_CHECK3D);
+ if (t.linetarget)
{
- pmo->angle = pmo->AngleTo(linetarget);
- if (((linetarget->player && (!linetarget->IsTeammate(pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER)
- && (!(linetarget->flags2&(MF2_DORMANT | MF2_INVULNERABLE))))
+ P_LineAttack(pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, puff, false, &t);
+ if (t.linetarget != NULL)
{
- newLife = player->health + (damage >> 3);
- newLife = newLife > max ? max : newLife;
- if (newLife > player->health)
+ pmo->angle = t.SourceAngleToTarget();
+ if (((t.linetarget->player && (!t.linetarget->IsTeammate(pmo) || level.teamdamage != 0)) || t.linetarget->flags3&MF3_ISMONSTER)
+ && (!(t.linetarget->flags2&(MF2_DORMANT | MF2_INVULNERABLE))))
{
- pmo->health = player->health = newLife;
+ newLife = player->health + (damage >> 3);
+ newLife = newLife > max ? max : newLife;
+ if (newLife > player->health)
+ {
+ pmo->health = player->health = newLife;
+ }
+ if (weapon != NULL)
+ {
+ FState * newstate = weapon->FindState("Drain");
+ if (newstate != NULL) P_SetPsprite(player, ps_weapon, newstate);
+ }
}
if (weapon != NULL)
{
- FState * newstate = weapon->FindState("Drain");
- if (newstate != NULL) P_SetPsprite(player, ps_weapon, newstate);
+ weapon->DepleteAmmo(weapon->bAltFire, false);
}
}
- if (weapon != NULL)
- {
- weapon->DepleteAmmo(weapon->bAltFire, false);
- }
+ return 0;
}
- break;
- }
- angle = pmo->angle - i*(ANG45 / 16);
- slope = P_AimLineAttack(player->mo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D);
- if (linetarget)
- {
- P_LineAttack(pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, puff, false, &linetarget);
- if (linetarget != NULL)
- {
- pmo->angle = pmo->AngleTo(linetarget);
- if ((linetarget->player && (!linetarget->IsTeammate(pmo) || level.teamdamage != 0)) || linetarget->flags3&MF3_ISMONSTER)
- {
- newLife = player->health + (damage >> 4);
- newLife = newLife > max ? max : newLife;
- pmo->health = player->health = newLife;
- P_SetPsprite(player, ps_weapon, weapon->FindState("Drain"));
- }
- if (weapon != NULL)
- {
- weapon->DepleteAmmo(weapon->bAltFire, false);
- }
- }
- break;
}
}
return 0;
diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp
index 575b8d8c1..1681efe9f 100644
--- a/src/g_hexen/a_fighteraxe.cpp
+++ b/src/g_hexen/a_fighteraxe.cpp
@@ -24,8 +24,6 @@ void A_FAxeCheckReadyG (AActor *actor);
void A_FAxeCheckUpG (AActor *actor);
void A_FAxeAttack (AActor *actor);
-extern void AdjustPlayerAngle (AActor *pmo, AActor *linetarget);
-
// The Fighter's Axe --------------------------------------------------------
class AFWeapAxe : public AFighterWeapon
@@ -210,7 +208,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack)
player_t *player;
AWeapon *weapon;
PClassActor *pufftype;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -236,36 +234,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack)
}
for (i = 0; i < 16; i++)
{
- angle = pmo->angle+i*(ANG45/16);
- slope = P_AimLineAttack (pmo, angle, AXERANGE, &linetarget);
- if (linetarget)
+ for (int j = 1; j >= -1; j -= 2)
{
- P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget);
- if (linetarget != NULL)
+ angle = pmo->angle + j*i*(ANG45 / 16);
+ slope = P_AimLineAttack(pmo, angle, AXERANGE, &t);
+ if (t.linetarget)
{
- if (linetarget->flags3&MF3_ISMONSTER || linetarget->player)
+ P_LineAttack(pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &t);
+ if (t.linetarget != NULL)
{
- P_ThrustMobj (linetarget, angle, power);
+ if (t.linetarget->flags3&MF3_ISMONSTER || t.linetarget->player)
+ {
+ P_ThrustMobj(t.linetarget, t.hitangle, power);
+ }
+ AdjustPlayerAngle(pmo, &t);
+ useMana++;
+ goto axedone;
}
- AdjustPlayerAngle (pmo, linetarget);
- useMana++;
- goto axedone;
- }
- }
- angle = pmo->angle-i*(ANG45/16);
- slope = P_AimLineAttack (pmo, angle, AXERANGE, &linetarget);
- if (linetarget)
- {
- P_LineAttack (pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget);
- if (linetarget != NULL)
- {
- if (linetarget->flags3&MF3_ISMONSTER)
- {
- P_ThrustMobj (linetarget, angle, power);
- }
- AdjustPlayerAngle (pmo, linetarget);
- useMana++;
- goto axedone;
}
}
}
@@ -273,7 +258,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack)
pmo->weaponspecial = 0;
angle = pmo->angle;
- slope = P_AimLineAttack (pmo, angle, MELEERANGE, &linetarget);
+ slope = P_AimLineAttack (pmo, angle, MELEERANGE);
P_LineAttack (pmo, angle, MELEERANGE, slope, damage, NAME_Melee, pufftype, true);
axedone:
diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp
index 2980dec7a..836f6e4b7 100644
--- a/src/g_hexen/a_fighterhammer.cpp
+++ b/src/g_hexen/a_fighterhammer.cpp
@@ -17,8 +17,6 @@ const fixed_t HAMMER_RANGE = MELEERANGE+MELEERANGE/2;
static FRandom pr_hammeratk ("FHammerAtk");
-extern void AdjustPlayerAngle (AActor *pmo, AActor *linetarget);
-
//============================================================================
//
// A_FHammerAttack
@@ -35,7 +33,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
int slope;
int i;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
PClassActor *hammertime;
if (NULL == (player = self->player))
@@ -50,32 +48,32 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
for (i = 0; i < 16; i++)
{
angle = pmo->angle + i*(ANG45/32);
- slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D);
- if (linetarget != NULL)
+ slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &t, 0, ALF_CHECK3D);
+ if (t.linetarget != NULL)
{
- P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget);
- if (linetarget != NULL)
+ P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &t);
+ if (t.linetarget != NULL)
{
- AdjustPlayerAngle(pmo, linetarget);
- if (linetarget->flags3 & MF3_ISMONSTER || linetarget->player)
+ AdjustPlayerAngle(pmo, &t);
+ if (t.linetarget->flags3 & MF3_ISMONSTER || t.linetarget->player)
{
- P_ThrustMobj(linetarget, angle, power);
+ P_ThrustMobj(t.linetarget, t.hitangle, power);
}
pmo->weaponspecial = false; // Don't throw a hammer
goto hammerdone;
}
}
angle = pmo->angle-i*(ANG45/32);
- slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D);
- if (linetarget != NULL)
+ slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &t, 0, ALF_CHECK3D);
+ if (t.linetarget != NULL)
{
- P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &linetarget);
- if (linetarget != NULL)
+ P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true, &t);
+ if (t.linetarget != NULL)
{
- AdjustPlayerAngle(pmo, linetarget);
- if (linetarget->flags3 & MF3_ISMONSTER || linetarget->player)
+ AdjustPlayerAngle(pmo, &t);
+ if (t.linetarget->flags3 & MF3_ISMONSTER || t.linetarget->player)
{
- P_ThrustMobj(linetarget, angle, power);
+ P_ThrustMobj(t.linetarget, t.hitangle, power);
}
pmo->weaponspecial = false; // Don't throw a hammer
goto hammerdone;
@@ -84,7 +82,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack)
}
// didn't find any targets in meleerange, so set to throw out a hammer
angle = pmo->angle;
- slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D);
+ slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, NULL, 0, ALF_CHECK3D);
if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL)
{
pmo->weaponspecial = false;
diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp
index 944a4aa45..dfbc43be2 100644
--- a/src/g_hexen/a_fighterplayer.cpp
+++ b/src/g_hexen/a_fighterplayer.cpp
@@ -25,12 +25,12 @@ static FRandom pr_fpatk ("FPunchAttack");
#define MAX_ANGLE_ADJUST (5*ANGLE_1)
-void AdjustPlayerAngle (AActor *pmo, AActor *linetarget)
+void AdjustPlayerAngle (AActor *pmo, FTranslatedLineTarget *t)
{
angle_t angle;
int difference;
- angle = pmo->AngleTo(linetarget);
+ angle = t->SourceAngleToTarget();
difference = (int)angle - (int)pmo->angle;
if (abs(difference) > MAX_ANGLE_ADJUST)
{
@@ -60,11 +60,11 @@ void AdjustPlayerAngle (AActor *pmo, AActor *linetarget)
static bool TryPunch(APlayerPawn *pmo, angle_t angle, int damage, fixed_t power)
{
PClassActor *pufftype;
- AActor *linetarget;
+ FTranslatedLineTarget t;
int slope;
- slope = P_AimLineAttack (pmo, angle, 2*MELEERANGE, &linetarget);
- if (linetarget != NULL)
+ slope = P_AimLineAttack (pmo, angle, 2*MELEERANGE, &t);
+ if (t.linetarget != NULL)
{
if (++pmo->weaponspecial >= 3)
{
@@ -76,15 +76,15 @@ static bool TryPunch(APlayerPawn *pmo, angle_t angle, int damage, fixed_t power)
{
pufftype = PClass::FindActor("PunchPuff");
}
- P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &linetarget);
- if (linetarget != NULL)
+ P_LineAttack (pmo, angle, 2*MELEERANGE, slope, damage, NAME_Melee, pufftype, true, &t);
+ if (t.linetarget != NULL)
{
- if (linetarget->player != NULL ||
- (linetarget->Mass != INT_MAX && (linetarget->flags3 & MF3_ISMONSTER)))
+ if (t.linetarget->player != NULL ||
+ (t.linetarget->Mass != INT_MAX && (t.linetarget->flags3 & MF3_ISMONSTER)))
{
- P_ThrustMobj (linetarget, angle, power);
+ P_ThrustMobj (t.linetarget, t.hitangle, power);
}
- AdjustPlayerAngle (pmo, linetarget);
+ AdjustPlayerAngle (pmo, &t);
return true;
}
}
@@ -131,8 +131,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack)
// didn't find any creatures, so try to strike any walls
pmo->weaponspecial = 0;
- AActor *linetarget;
- int slope = P_AimLineAttack (pmo, pmo->angle, MELEERANGE, &linetarget);
+ int slope = P_AimLineAttack (pmo, pmo->angle, MELEERANGE);
P_LineAttack (pmo, pmo->angle, MELEERANGE, slope, damage, NAME_Melee, PClass::FindActor("PunchPuff"), true);
return 0;
}
diff --git a/src/g_hexen/a_hexenglobal.h b/src/g_hexen/a_hexenglobal.h
index ba68a9988..94b03d45d 100644
--- a/src/g_hexen/a_hexenglobal.h
+++ b/src/g_hexen/a_hexenglobal.h
@@ -3,6 +3,8 @@
#include "d_player.h"
+void AdjustPlayerAngle(AActor *pmo, FTranslatedLineTarget *t);
+
class AHolySpirit : public AActor
{
DECLARE_CLASS (AHolySpirit, AActor)
diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp
index 86addb2cb..302048998 100644
--- a/src/g_hexen/a_hexenspecialdecs.cpp
+++ b/src/g_hexen/a_hexenspecialdecs.cpp
@@ -350,7 +350,7 @@ void AZBell::Activate (AActor *activator)
{
if (health > 0)
{
- P_DamageMobj (this, activator, activator, 10, NAME_Melee); // 'ring' the bell
+ P_DamageMobj (this, activator, activator, 10, NAME_Melee, DMG_THRUSTLESS); // 'ring' the bell
}
}
diff --git a/src/g_hexen/a_magecone.cpp b/src/g_hexen/a_magecone.cpp
index 154c76524..c157c02c0 100644
--- a/src/g_hexen/a_magecone.cpp
+++ b/src/g_hexen/a_magecone.cpp
@@ -60,7 +60,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1)
AActor *mo;
bool conedone=false;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -79,10 +79,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1)
for (i = 0; i < 16; i++)
{
angle = self->angle+i*(ANG45/16);
- slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget, 0, ALF_CHECK3D);
- if (linetarget)
+ slope = P_AimLineAttack (self, angle, MELEERANGE, &t, 0, ALF_CHECK3D);
+ if (t.linetarget)
{
- P_DamageMobj (linetarget, self, self, damage, NAME_Ice);
+ P_DamageMobj (t.linetarget, self, self, damage, NAME_Ice, DMG_USEANGLE, t.SourceAngleToTarget());
conedone = true;
break;
}
diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp
index d1ca7e75c..832ae96d1 100644
--- a/src/g_hexen/a_magestaff.cpp
+++ b/src/g_hexen/a_magestaff.cpp
@@ -97,17 +97,20 @@ bool AMageStaffFX2::SpecialBlastHandling (AActor *source, fixed_t strength)
//
//============================================================================
-void MStaffSpawn (AActor *pmo, angle_t angle)
+void MStaffSpawn (AActor *pmo, angle_t angle, AActor *alttarget)
{
AActor *mo;
- AActor *linetarget;
+ FTranslatedLineTarget t;
mo = P_SpawnPlayerMissile (pmo, 0, 0, 8*FRACUNIT,
- RUNTIME_CLASS(AMageStaffFX2), angle, &linetarget);
+ RUNTIME_CLASS(AMageStaffFX2), angle, &t);
if (mo)
{
mo->target = pmo;
- mo->tracer = linetarget;
+ if (t.linetarget && !t.unlinked)
+ mo->tracer = t.linetarget;
+ else
+ mo->tracer = alttarget;
}
}
@@ -123,7 +126,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack)
angle_t angle;
player_t *player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -139,18 +142,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffAttack)
angle = self->angle;
// [RH] Let's try and actually track what the player aimed at
- P_AimLineAttack (self, angle, PLAYERMISSILERANGE, &linetarget, ANGLE_1*32);
- if (linetarget == NULL)
+ P_AimLineAttack (self, angle, PLAYERMISSILERANGE, &t, ANGLE_1*32);
+ if (t.linetarget == NULL)
{
BlockCheckLine.x = self->X();
BlockCheckLine.y = self->Y();
BlockCheckLine.dx = -finesine[angle >> ANGLETOFINESHIFT];
BlockCheckLine.dy = -finecosine[angle >> ANGLETOFINESHIFT];
- linetarget = P_BlockmapSearch (self, 10, FrontBlockCheck);
+ t.linetarget = P_BlockmapSearch (self, 10, FrontBlockCheck);
}
- MStaffSpawn (self, angle);
- MStaffSpawn (self, angle-ANGLE_1*5);
- MStaffSpawn (self, angle+ANGLE_1*5);
+ MStaffSpawn (self, angle, t.linetarget);
+ MStaffSpawn (self, angle-ANGLE_1*5, t.linetarget);
+ MStaffSpawn (self, angle+ANGLE_1*5, t.linetarget);
S_Sound (self, CHAN_WEAPON, "MageStaffFire", 1, ATTN_NORM);
weapon->MStaffCount = 3;
return 0;
diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp
index 8ce394a28..b07bfc4a0 100644
--- a/src/g_hexen/a_pig.cpp
+++ b/src/g_hexen/a_pig.cpp
@@ -18,8 +18,6 @@ static FRandom pr_snoutattack ("SnoutAttack");
static FRandom pr_pigattack ("PigAttack");
static FRandom pr_pigplayerthink ("PigPlayerThink");
-extern void AdjustPlayerAngle (AActor *, AActor *);
-
// Pig player ---------------------------------------------------------------
class APigPlayer : public APlayerPawn
@@ -67,7 +65,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack)
int slope;
player_t *player;
AActor *puff;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
@@ -76,12 +74,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack)
damage = 3+(pr_snoutattack()&3);
angle = player->mo->angle;
- slope = P_AimLineAttack(player->mo, angle, MELEERANGE, &linetarget);
- puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true, &linetarget);
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true, &t);
S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM);
- if(linetarget)
+ if(t.linetarget)
{
- AdjustPlayerAngle(player->mo, linetarget);
+ AdjustPlayerAngle(player->mo, &t);
if(puff != NULL)
{ // Bit something
S_Sound(player->mo, CHAN_VOICE, "PigAttack", 1, ATTN_NORM);
diff --git a/src/g_hexen/a_spike.cpp b/src/g_hexen/a_spike.cpp
index f1538d3d9..4af4e2d54 100644
--- a/src/g_hexen/a_spike.cpp
+++ b/src/g_hexen/a_spike.cpp
@@ -154,6 +154,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ThrustImpale)
PARAM_ACTION_PROLOGUE;
AActor *thing;
+ // This doesn't need to iterate through portals.
FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), self->radius));
while ((thing = it.Next()))
{
diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp
index 561f52746..60e86a34b 100644
--- a/src/g_strife/a_strifeweapons.cpp
+++ b/src/g_strife/a_strifeweapons.cpp
@@ -100,7 +100,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger)
int damage;
int pitch;
int power;
- AActor *linetarget;
+ FTranslatedLineTarget t;
power = MIN(10, self->player->mo->stamina / 10);
damage = (pr_jabdagger() % (power + 8)) * (power + 2);
@@ -111,18 +111,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_JabDagger)
}
angle = self->angle + (pr_jabdagger.Random2() << 18);
- pitch = P_AimLineAttack (self, angle, 80*FRACUNIT, &linetarget);
- P_LineAttack (self, angle, 80*FRACUNIT, pitch, damage, NAME_Melee, "StrifeSpark", true, &linetarget);
+ pitch = P_AimLineAttack (self, angle, 80*FRACUNIT);
+ P_LineAttack (self, angle, 80*FRACUNIT, pitch, damage, NAME_Melee, "StrifeSpark", true, &t);
// turn to face target
- if (linetarget)
+ if (t.linetarget)
{
S_Sound (self, CHAN_WEAPON,
- linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit",
+ t.linetarget->flags & MF_NOBLOOD ? "misc/metalhit" : "misc/meathit",
1, ATTN_NORM);
- self->angle = self->AngleTo(linetarget);
+ self->angle = t.SourceAngleToTarget();
self->flags |= MF_JUSTATTACKED;
- P_DaggerAlert (self, linetarget);
+ P_DaggerAlert (self, t.linetarget);
}
else
{
@@ -978,7 +978,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1)
AActor *spot;
player_t *player = self->player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (player == NULL || player->ReadyWeapon == NULL)
return 0;
@@ -986,13 +986,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1)
P_DamageMobj (self, self, NULL, 1*4, 0, DMG_NO_ARMOR);
S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
- P_BulletSlope (self, &linetarget);
- if (linetarget != NULL)
+ P_BulletSlope (self, &t, ALF_PORTALRESTRICT);
+ if (t.linetarget != NULL)
{
- spot = Spawn("SpectralLightningSpot", linetarget->X(), linetarget->Y(), linetarget->floorz, ALLOW_REPLACE);
+ spot = Spawn("SpectralLightningSpot", t.linetarget->X(), t.linetarget->Y(), t.linetarget->floorz, ALLOW_REPLACE);
if (spot != NULL)
{
- spot->tracer = linetarget;
+ spot->tracer = t.linetarget;
}
}
else
@@ -1080,7 +1080,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4)
AActor *spot;
player_t *player = self->player;
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (player == NULL || player->ReadyWeapon == NULL)
return 0;
@@ -1088,13 +1088,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4)
P_DamageMobj (self, self, NULL, 4*4, 0, DMG_NO_ARMOR);
S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
- P_BulletSlope (self, &linetarget);
- if (linetarget != NULL)
+ P_BulletSlope (self, &t, ALF_PORTALRESTRICT);
+ if (t.linetarget != NULL)
{
- spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("SpectralLightningBigV1"), self->angle, &linetarget);
+ spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("SpectralLightningBigV1"), self->angle, &t, NULL, false, false, ALF_PORTALRESTRICT);
if (spot != NULL)
{
- spot->tracer = linetarget;
+ spot->tracer = t.linetarget;
}
}
else
diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp
index 04c10760e..ebd002b4e 100644
--- a/src/menu/menudef.cpp
+++ b/src/menu/menudef.cpp
@@ -60,6 +60,7 @@ static FListMenuDescriptor DefaultListMenuSettings; // contains common settings
static FOptionMenuDescriptor DefaultOptionMenuSettings; // contains common settings for all Option menus
FOptionMenuSettings OptionSettings;
FOptionMap OptionValues;
+bool mustPrintErrors;
void I_BuildALDeviceList(FOptionValues *opt);
@@ -99,7 +100,7 @@ static FTextureID GetMenuTexture(const char* const name)
{
const FTextureID texture = TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch);
- if (!texture.Exists())
+ if (!texture.Exists() && mustPrintErrors)
{
Printf("Missing menu texture: \"%s\"\n", name);
}
@@ -956,10 +957,14 @@ void M_ParseMenuDefs()
atterm( DeinitMenus);
DeinitMenus();
+
+ int IWADMenu = Wads.CheckNumForName("MENUDEF", ns_global, FWadCollection::IWAD_FILENUM);
+
while ((lump = Wads.FindLump ("MENUDEF", &lastlump)) != -1)
{
FScanner sc(lump);
+ mustPrintErrors = lump >= IWADMenu;
sc.SetCMode(true);
while (sc.GetString())
{
diff --git a/src/p_acs.cpp b/src/p_acs.cpp
index 52e11ee8b..b6a718f65 100644
--- a/src/p_acs.cpp
+++ b/src/p_acs.cpp
@@ -4939,7 +4939,9 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
{
if (actor->player != NULL && actor->player->playerstate == PST_LIVE)
{
- P_BulletSlope(actor, &actor);
+ FTranslatedLineTarget t;
+ P_BulletSlope(actor, &t, ALF_PORTALRESTRICT);
+ actor = t.linetarget;
}
else
{
diff --git a/src/p_effect.cpp b/src/p_effect.cpp
index ffd1f303c..0b4fe0e55 100644
--- a/src/p_effect.cpp
+++ b/src/p_effect.cpp
@@ -205,9 +205,9 @@ void P_FindParticleSubsectors ()
}
for (WORD i = ActiveParticles; i != NO_PARTICLE; i = Particles[i].tnext)
{
- subsector_t *ssec = R_PointInSubsector (Particles[i].x, Particles[i].y);
- int ssnum = int(ssec-subsectors);
- Particles[i].subsector = ssec;
+ // Try to reuse the subsector from the last portal check, if still valid.
+ if (Particles[i].subsector == NULL) Particles[i].subsector = R_PointInSubsector(Particles[i].x, Particles[i].y);
+ int ssnum = int(Particles[i].subsector - subsectors);
Particles[i].snext = ParticlesInSubsec[ssnum];
ParticlesInSubsec[ssnum] = i;
}
@@ -278,12 +278,37 @@ void P_ThinkParticles ()
InactiveParticles = (int)(particle - Particles);
continue;
}
- particle->x += particle->velx;
- particle->y += particle->vely;
+
+ fixedvec2 newxy = P_GetOffsetPosition(particle->x, particle->y, particle->velx, particle->vely);
+ particle->x = newxy.x;
+ particle->y = newxy.y;
+ //particle->x += particle->velx;
+ //particle->y += particle->vely;
particle->z += particle->velz;
particle->velx += particle->accx;
particle->vely += particle->accy;
particle->velz += particle->accz;
+ particle->subsector = R_PointInSubsector(particle->x, particle->y);
+ if (!particle->subsector->sector->PortalBlocksMovement(sector_t::ceiling))
+ {
+ AActor *skybox = particle->subsector->sector->SkyBoxes[sector_t::ceiling];
+ if (particle->z > skybox->threshold)
+ {
+ particle->x += skybox->scaleX;
+ particle->y += skybox->scaleY;
+ particle->subsector = NULL;
+ }
+ }
+ else if (!particle->subsector->sector->PortalBlocksMovement(sector_t::floor))
+ {
+ AActor *skybox = particle->subsector->sector->SkyBoxes[sector_t::floor];
+ if (particle->z < skybox->threshold)
+ {
+ particle->x += skybox->scaleX;
+ particle->y += skybox->scaleY;
+ particle->subsector = NULL;
+ }
+ }
prev = particle;
}
}
diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp
index ed9abdcb9..af4a9042d 100644
--- a/src/p_enemy.cpp
+++ b/src/p_enemy.cpp
@@ -150,9 +150,40 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun
}
}
+ bool checkabove = !sec->PortalBlocksSound(sector_t::ceiling);
+ bool checkbelow = !sec->PortalBlocksSound(sector_t::floor);
+
for (i = 0; i < sec->linecount; i++)
{
check = sec->lines[i];
+
+ // I wish there was a better method to do this than randomly looking through the portal at a few places...
+ if (checkabove)
+ {
+ sector_t *upper =
+ P_PointInSector(check->v1->x + check->dx / 2 + sec->SkyBoxes[sector_t::ceiling]->scaleX,
+ check->v1->y + check->dy / 2 + sec->SkyBoxes[sector_t::ceiling]->scaleY);
+
+ P_RecursiveSound(upper, soundtarget, splash, soundblocks, emitter, maxdist);
+ }
+ if (checkbelow)
+ {
+ sector_t *lower =
+ P_PointInSector(check->v1->x + check->dx / 2 + sec->SkyBoxes[sector_t::floor]->scaleX,
+ check->v1->y + check->dy / 2 + sec->SkyBoxes[sector_t::floor]->scaleY);
+
+ P_RecursiveSound(lower, soundtarget, splash, soundblocks, emitter, maxdist);
+ }
+ FLinePortal *port = check->getPortal();
+ if (port && (port->mFlags & PORTF_SOUNDTRAVERSE))
+ {
+ if (port->mDestination)
+ {
+ P_RecursiveSound(port->mDestination->frontsector, soundtarget, splash, soundblocks, emitter, maxdist);
+ }
+ }
+
+
if (check->sidedef[1] == NULL ||
!(check->flags & ML_TWOSIDED))
{
@@ -394,16 +425,16 @@ bool AActor::SuggestMissileAttack (fixed_t dist)
bool P_HitFriend(AActor * self)
{
- AActor *linetarget;
+ FTranslatedLineTarget t;
if (self->flags&MF_FRIENDLY && self->target != NULL)
{
angle_t angle = self->AngleTo(self->target);
fixed_t dist = self->AproxDistance (self->target);
- P_AimLineAttack (self, angle, dist, &linetarget, 0, true);
- if (linetarget != NULL && linetarget != self->target)
+ P_AimLineAttack (self, angle, dist, &t, 0, true);
+ if (t.linetarget != NULL && t.linetarget != self->target)
{
- return self->IsFriend (linetarget);
+ return self->IsFriend (t.linetarget);
}
}
return false;
@@ -2573,40 +2604,48 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
fixedvec2 viletry = self->Vec2Offset(
FixedMul (absSpeed, xspeed[self->movedir]),
FixedMul (absSpeed, yspeed[self->movedir]), true);
- AActor *corpsehit;
- FBlockThingsIterator it(FBoundingBox(viletry.x, viletry.y, 32*FRACUNIT));
- while ((corpsehit = it.Next()))
+ FPortalGroupArray check(FPortalGroupArray::PGA_Full3d);
+
+ FMultiBlockThingsIterator it(check, viletry.x, viletry.y, self->Z() - 64* FRACUNIT, self->Top() + 64 * FRACUNIT, 32 * FRACUNIT);
+ FMultiBlockThingsIterator::CheckResult cres;
+ while (it.Next(&cres))
{
+ AActor *corpsehit = cres.thing;
FState *raisestate = corpsehit->GetRaiseState();
if (raisestate != NULL)
{
// use the current actor's radius instead of the Arch Vile's default.
fixed_t maxdist = corpsehit->GetDefault()->radius + self->radius;
- if (abs(corpsehit->X() - viletry.x) > maxdist ||
- abs(corpsehit->Y() - viletry.y) > maxdist)
+ if (abs(cres.position.x - viletry.x) > maxdist ||
+ abs(cres.position.y - viletry.y) > maxdist)
continue; // not actually touching
// Let's check if there are floors in between the archvile and its target
- // if in a different section of the map, only consider possible if a line of sight exists.
- if (corpsehit->Sector->PortalGroup != self->Sector->PortalGroup && !P_CheckSight(self, corpsehit))
- continue;
-
- sector_t *vilesec = self->Sector;
- sector_t *corpsec = corpsehit->Sector;
- // We only need to test if at least one of the sectors has a 3D floor.
- sector_t *testsec = vilesec->e->XFloor.ffloors.Size() ? vilesec :
- (vilesec != corpsec && corpsec->e->XFloor.ffloors.Size()) ? corpsec : NULL;
- if (testsec)
+ if (corpsehit->Sector->PortalGroup != self->Sector->PortalGroup)
{
- fixed_t zdist1, zdist2;
- if (P_Find3DFloor(testsec, corpsehit->Pos(), false, true, zdist1)
- != P_Find3DFloor(testsec, self->Pos(), false, true, zdist2))
+ // if in a different section of the map, only consider possible if a line of sight exists.
+ if (!P_CheckSight(self, corpsehit))
+ continue;
+ }
+ else
+ {
+ sector_t *vilesec = self->Sector;
+ sector_t *corpsec = corpsehit->Sector;
+ // We only need to test if at least one of the sectors has a 3D floor.
+ sector_t *testsec = vilesec->e->XFloor.ffloors.Size() ? vilesec :
+ (vilesec != corpsec && corpsec->e->XFloor.ffloors.Size()) ? corpsec : NULL;
+ if (testsec)
{
- // Not on same floor
- if (vilesec == corpsec || abs(zdist1 - self->Z()) > self->height)
- continue;
+ fixed_t zdist1, zdist2;
+ if (P_Find3DFloor(testsec, corpsehit->Pos(), false, true, zdist1)
+ != P_Find3DFloor(testsec, self->Pos(), false, true, zdist2))
+ {
+ // Not on same floor
+ if (vilesec == corpsec || abs(zdist1 - self->Z()) > self->height)
+ continue;
+ }
}
}
@@ -2951,7 +2990,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail)
return 0;
fixed_t saved_pitch = self->pitch;
- AActor *linetarget;
+ FTranslatedLineTarget t;
// [RH] Andy Baker's stealth monsters
if (self->flags & MF_STEALTH)
@@ -2963,8 +3002,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail)
self->angle = self->AngleTo(self->target);
- self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, self->target);
- if (linetarget == NULL)
+ self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &t, ANGLE_1*60, 0, self->target);
+ if (t.linetarget == NULL)
{
// We probably won't hit the target, but aim at it anyway so we don't look stupid.
fixedvec2 pos = self->Vec2To(self->target);
diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp
index 98d08832e..313531425 100644
--- a/src/p_interaction.cpp
+++ b/src/p_interaction.cpp
@@ -927,7 +927,7 @@ static inline bool isFakePain(AActor *target, AActor *inflictor, int damage)
// Returns the amount of damage actually inflicted upon the target, or -1 if
// the damage was cancelled.
-int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags)
+int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags, angle_t angle)
{
unsigned ang;
player_t *player = NULL;
@@ -1151,11 +1151,15 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
{
AActor *origin = (source && (flags & DMG_INFLICTOR_IS_PUFF))? source : inflictor;
- // If the origin and target are in exactly the same spot, choose a random direction.
- // (Most likely cause is from telefragging somebody during spawning because they
- // haven't moved from their spawn spot at all.)
- if (origin->X() == target->X() && origin->Y() == target->Y())
+ if (flags & DMG_USEANGLE)
{
+ ang = angle;
+ }
+ else if (origin->X() == target->X() && origin->Y() == target->Y())
+ {
+ // If the origin and target are in exactly the same spot, choose a random direction.
+ // (Most likely cause is from telefragging somebody during spawning because they
+ // haven't moved from their spawn spot at all.)
ang = pr_kickbackdir.GenRand32();
}
else
diff --git a/src/p_local.h b/src/p_local.h
index 7e11010c5..75ee1e695 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -37,6 +37,7 @@ struct sector_t;
struct msecnode_t;
struct secplane_t;
struct FCheckPosition;
+struct FTranslatedLineTarget;
#include
@@ -173,7 +174,7 @@ AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, PClassAct
AActor *P_SpawnPlayerMissile (AActor* source, PClassActor *type);
AActor *P_SpawnPlayerMissile (AActor *source, PClassActor *type, angle_t angle);
AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, PClassActor *type, angle_t angle,
- AActor **pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false, bool noautoaim = false);
+ FTranslatedLineTarget *pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false, bool noautoaim = false, int aimflags = 0);
void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheight=false);
@@ -304,7 +305,7 @@ void P_FindFloorCeiling (AActor *actor, int flags=0);
bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, bool isreset);
-fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, int flags = 0, AActor *target=NULL, AActor *friender=NULL);
+fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, FTranslatedLineTarget *pLineTarget = NULL, fixed_t vrange=0, int flags = 0, AActor *target=NULL, AActor *friender=NULL);
enum // P_AimLineAttack flags
{
@@ -313,6 +314,7 @@ enum // P_AimLineAttack flags
ALF_CHECKNONSHOOTABLE = 4,
ALF_CHECKCONVERSATION = 8,
ALF_NOFRIENDS = 16,
+ ALF_PORTALRESTRICT = 32, // only work through portals with a global offset (to be used for stuff that cannot remember the calculated FTranslatedLineTarget info)
};
enum // P_LineAttack flags
@@ -322,11 +324,12 @@ enum // P_LineAttack flags
LAF_NOIMPACTDECAL = 4
};
-AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL);
-AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL);
+AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL);
+AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, FTranslatedLineTarget *victim = NULL, int *actualdamage = NULL);
void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch);
void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch);
void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version
+void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff); // hitscan version
void P_TraceBleed (int damage, AActor *target); // random direction version
bool P_HitFloor (AActor *thing);
bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true, bool force = false);
@@ -382,7 +385,7 @@ extern BYTE* rejectmatrix; // for fast sight rejection
// P_INTER
//
void P_TouchSpecialThing (AActor *special, AActor *toucher);
-int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0);
+int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0, angle_t angle = 0);
void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type);
bool P_GiveBody (AActor *actor, int num, int max=0);
bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison);
@@ -399,6 +402,7 @@ enum EDmgFlags
DMG_FOILINVUL = 64,
DMG_FOILBUDDHA = 128,
DMG_NO_PROTECT = 256,
+ DMG_USEANGLE = 512,
};
diff --git a/src/p_map.cpp b/src/p_map.cpp
index 7908ce4a9..150348fc3 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -162,11 +162,22 @@ static inline fixed_t GetCoefficientClosestPointInLine24(line_t *ld, fixedvec2 p
static inline fixedvec2 FindRefPoint(line_t *ld, fixedvec2 pos)
{
- if (!((((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) |
- (ld->backsector->floorplane.a | ld->backsector->floorplane.b) |
- (ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) |
- (ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) == 0)
- && ld->backsector->e->XFloor.ffloors.Size() == 0 && ld->frontsector->e->XFloor.ffloors.Size() == 0))
+ // If there's any chance of slopes getting in the way we need to get a proper refpoint, otherwise we can save the work.
+ // Slopes can get in here when:
+ // - the actual sector planes are sloped
+ // - there's 3D floors in this sector
+ // - there's a crossable floor portal (for which the dropoff needs to be calculated within P_LineOpening, and the lower sector can easily have slopes)
+ if (
+ (((ld->frontsector->floorplane.a | ld->frontsector->floorplane.b) |
+ (ld->backsector->floorplane.a | ld->backsector->floorplane.b) |
+ (ld->frontsector->ceilingplane.a | ld->frontsector->ceilingplane.b) |
+ (ld->backsector->ceilingplane.a | ld->backsector->ceilingplane.b)) != 0)
+ ||
+ ld->backsector->e->XFloor.ffloors.Size() != 0
+ ||
+ ld->frontsector->e->XFloor.ffloors.Size() != 0
+ ||
+ !ld->frontsector->PortalBlocksMovement(sector_t::floor))
{
fixed_t r = GetCoefficientClosestPointInLine24(ld, pos);
if (r <= 0)
@@ -809,8 +820,8 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
if (!ld->backsector)
{ // One sided line
- // Needed for polyobject portals. Having two-sided lines just for portals on otherwise solid polyobjects is a messy subject.
- if ((cres.line->sidedef[0]->Flags & WALLF_POLYOBJ) && cres.line->isLinePortal())
+ // Needed for polyobject portals.
+ if (cres.line->isLinePortal())
{
spechit_t spec;
spec.line = ld;
@@ -921,7 +932,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
// If the floor planes on both sides match we should recalculate open.bottom at the actual position we are checking
// This is to avoid bumpy movement when crossing a linedef with the same slope on both sides.
- if (open.frontfloorplane == open.backfloorplane)
+ if (open.frontfloorplane == open.backfloorplane && open.bottom > FIXED_MIN)
{
open.bottom = open.frontfloorplane.ZatPoint(cres.position.x, cres.position.y);
}
@@ -972,7 +983,9 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
}
if (open.lowfloor < tm.dropoffz)
+ {
tm.dropoffz = open.lowfloor;
+ }
}
// if contacted a special line, add it to the list
@@ -3774,7 +3787,7 @@ void aim_t::AimTraverse(fixed_t startx, fixed_t starty, fixed_t endx, fixed_t en
//
//============================================================================
-fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget, fixed_t vrange,
+fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, FTranslatedLineTarget *pLineTarget, fixed_t vrange,
int flags, AActor *target, AActor *friender)
{
fixed_t x2;
@@ -3868,7 +3881,18 @@ fixed_t P_AimLineAttack(AActor *t1, angle_t angle, fixed_t distance, AActor **pL
}
if (pLineTarget)
{
- *pLineTarget = aim.linetarget;
+ if (aim.linetarget)
+ {
+ pLineTarget->linetarget = aim.linetarget;
+ pLineTarget->hitangle = angle;
+ pLineTarget->targetPosFromSrc = aim.linetarget->Pos();
+ pLineTarget->targetAngleFromSrc = aim.linetarget->angle;
+ pLineTarget->sourcePosFromTarget = t1->Pos();
+ pLineTarget->sourceAngleFromTarget = t1->angle;
+ pLineTarget->unlinked = false;
+ }
+ else
+ memset(pLineTarget, 0, sizeof(*pLineTarget));
}
return aim.linetarget ? aim.aimpitch : t1->pitch;
}
@@ -3923,7 +3947,7 @@ static ETraceStatus CheckForActor(FTraceResults &res, void *userdata)
//==========================================================================
AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
- int pitch, int damage, FName damageType, PClassActor *pufftype, int flags, AActor **victim, int *actualdamage)
+ int pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage)
{
fixed_t vx, vy, vz, shootz;
FTraceResults trace;
@@ -3940,7 +3964,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
if (victim != NULL)
{
- *victim = NULL;
+ memset(victim, 0, sizeof(*victim));
}
if (actualdamage != NULL)
{
@@ -4123,6 +4147,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING | PF_TEMPORARY);
killPuff = true;
}
+#pragma message("damage angle")
newdam = P_DamageMobj(trace.Actor, puff ? puff : t1, t1, damage, damageType, dmgflags);
if (actualdamage != NULL)
{
@@ -4162,7 +4187,13 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
}
if (victim != NULL)
{
- *victim = trace.Actor;
+ victim->linetarget = trace.Actor;
+ victim->hitangle = angle;
+ victim->targetPosFromSrc = trace.Actor->Pos();
+ victim->targetAngleFromSrc = trace.Actor->angle;
+ victim->sourcePosFromTarget = t1->Pos();
+ victim->sourceAngleFromTarget = t1->angle;
+ victim->unlinked = false;
}
}
if (trace.Crossed3DWater || trace.CrossedWater)
@@ -4185,22 +4216,22 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
}
AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance,
- int pitch, int damage, FName damageType, FName pufftype, int flags, AActor **victim, int *actualdamage)
+ int pitch, int damage, FName damageType, FName pufftype, int flags, FTranslatedLineTarget *victim, int *actualdamage)
{
PClassActor *type = PClass::FindActor(pufftype);
- if (victim != NULL)
- {
- *victim = NULL;
- }
if (type == NULL)
{
+ if (victim != NULL)
+ {
+ memset(victim, 0, sizeof(*victim));
+ }
Printf("Attempt to spawn unknown actor type '%s'\n", pufftype.GetChars());
+ return NULL;
}
else
{
return P_LineAttack(t1, angle, distance, pitch, damage, damageType, type, flags, victim, actualdamage);
}
- return NULL;
}
//==========================================================================
@@ -4382,6 +4413,24 @@ void P_TraceBleed(int damage, AActor *target, AActor *missile)
//
//==========================================================================
+void P_TraceBleed(int damage, FTranslatedLineTarget *t, AActor *puff)
+{
+ if (t->linetarget == NULL || puff->flags3 & MF3_BLOODLESSIMPACT)
+ {
+ return;
+ }
+
+ fixed_t randpitch = (pr_tracebleed() - 128) << 16;
+ P_TraceBleed(damage, t->linetarget->X(), t->linetarget->Y(), t->linetarget->Z() + t->linetarget->height / 2,
+ t->linetarget, t->SourceAngleToTarget(), 0);
+}
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
void P_TraceBleed(int damage, AActor *target)
{
if (target != NULL)
@@ -4560,6 +4609,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
if (puffDefaults->flags3 & MF3_FOILINVUL) dmgFlagPass |= DMG_FOILINVUL;
if (puffDefaults->flags7 & MF7_FOILBUDDHA) dmgFlagPass |= DMG_FOILBUDDHA;
}
+#pragma message("damage angle")
int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass);
if (bleed)
@@ -4677,38 +4727,26 @@ void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &Camera
bool P_TalkFacing(AActor *player)
{
- AActor *linetarget;
+ static const int angleofs[] = { 0, ANGLE_90 >> 4, - ANGLE_90 >> 4 };
+ FTranslatedLineTarget t;
- P_AimLineAttack(player, player->angle, TALKRANGE, &linetarget, ANGLE_1 * 35, ALF_FORCENOSMART | ALF_CHECKCONVERSATION);
- if (linetarget == NULL)
+ for (int angle : angleofs)
{
- P_AimLineAttack(player, player->angle + (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1 * 35, ALF_FORCENOSMART | ALF_CHECKCONVERSATION);
- if (linetarget == NULL)
+ P_AimLineAttack(player, player->angle + angle, TALKRANGE, &t, ANGLE_1 * 35, ALF_FORCENOSMART | ALF_CHECKCONVERSATION | ALF_PORTALRESTRICT);
+ if (t.linetarget != NULL)
{
- P_AimLineAttack(player, player->angle - (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1 * 35, ALF_FORCENOSMART | ALF_CHECKCONVERSATION);
- if (linetarget == NULL)
+ if (t.linetarget->health > 0 && // Dead things can't talk.
+ t.linetarget->flags4 & MF4_INCOMBAT && // Fighting things don't talk either.
+ t.linetarget->Conversation != NULL)
{
- return false;
+ // Give the NPC a chance to play a brief animation
+ t.linetarget->ConversationAnimation(0);
+ P_StartConversation(t.linetarget, player, true, true);
+ return true;
}
+ return false;
}
}
- // Dead things can't talk.
- if (linetarget->health <= 0)
- {
- return false;
- }
- // Fighting things don't talk either.
- if (linetarget->flags4 & MF4_INCOMBAT)
- {
- return false;
- }
- if (linetarget->Conversation != NULL)
- {
- // Give the NPC a chance to play a brief animation
- linetarget->ConversationAnimation(0);
- P_StartConversation(linetarget, player, true, true);
- return true;
- }
return false;
}
@@ -4718,10 +4756,11 @@ bool P_TalkFacing(AActor *player)
//
//==========================================================================
-bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline)
+bool P_UseTraverse(AActor *usething, fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, bool &foundline)
{
- FPathTraverse it(usething->X(), usething->Y(), endx, endy, PT_ADDLINES | PT_ADDTHINGS);
+ FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES | PT_ADDTHINGS);
intercept_t *in;
+ fixedvec3 xpos = { startx, starty, usething->Z() };
while ((in = it.Next()))
{
@@ -4741,6 +4780,10 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
}
continue;
}
+ if (it.PortalRelocate(in, PT_ADDLINES | PT_ADDTHINGS, &xpos))
+ {
+ continue;
+ }
FLineOpening open;
if (in->d.line->special == 0 || !(in->d.line->activation & (SPAC_Use | SPAC_UseThrough | SPAC_UseBack)))
@@ -4769,7 +4812,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
return true;
}
- sec = P_PointOnLineSide(usething->X(), usething->Y(), in->d.line) == 0 ?
+ sec = P_PointOnLineSide(xpos.x, xpos.y, in->d.line) == 0 ?
in->d.line->frontsector : in->d.line->backsector;
if (sec != NULL && sec->SecActTarget &&
@@ -4788,7 +4831,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
continue; // not a special line, but keep checking
}
- if (P_PointOnLineSide(usething->X(), usething->Y(), in->d.line) == 1)
+ if (P_PointOnLineSide(xpos.x, xpos.y, in->d.line) == 1)
{
if (!(in->d.line->activation & SPAC_UseBack))
{
@@ -4798,7 +4841,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
}
else
{
- P_ActivateLine(in->d.line, usething, 1, SPAC_UseBack);
+ P_ActivateLine(in->d.line, usething, 1, SPAC_UseBack, &xpos);
return true;
}
}
@@ -4809,7 +4852,7 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
goto blocked; // Line cannot be used from front side so treat it as a non-trigger line
}
- P_ActivateLine(in->d.line, usething, 0, SPAC_Use);
+ P_ActivateLine(in->d.line, usething, 0, SPAC_Use, &xpos);
//WAS can't use more than one special line in a row
//jff 3/21/98 NOW multiple use allowed with enabling line flag
@@ -4846,9 +4889,9 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline
//
//==========================================================================
-bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy)
+bool P_NoWayTraverse(AActor *usething, fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy)
{
- FPathTraverse it(usething->X(), usething->Y(), endx, endy, PT_ADDLINES);
+ FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES);
intercept_t *in;
while ((in = it.Next()))
@@ -4859,6 +4902,7 @@ bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy)
// [GrafZahl] de-obfuscated. Was I the only one who was unable to make sense out of
// this convoluted mess?
if (ld->special) continue;
+ if (ld->isLinePortal()) return false;
if (ld->flags&(ML_BLOCKING | ML_BLOCKEVERYTHING | ML_BLOCK_PLAYERS)) return true;
P_LineOpening(open, NULL, ld, it.Trace().x + FixedMul(it.Trace().dx, in->frac),
it.Trace().y + FixedMul(it.Trace().dy, in->frac));
@@ -4877,12 +4921,16 @@ bool P_NoWayTraverse(AActor *usething, fixed_t endx, fixed_t endy)
//
//==========================================================================
+CVAR(Int, userange, 0, 0);
+
void P_UseLines(player_t *player)
{
bool foundline = false;
+ // If the player is transitioning a portal, use the group that is at its vertical center.
+ fixedvec2 start = player->mo->GetPortalTransition(player->mo->height / 2);
// [NS] Now queries the Player's UseRange.
- fixedvec2 end = player->mo->Vec2Angle(player->mo->UseRange, player->mo->angle, true);
+ fixedvec2 end = start + Vec2Angle(userange > 0? fixed_t(userange<mo->UseRange, player->mo->angle);
// old code:
//
@@ -4890,13 +4938,13 @@ void P_UseLines(player_t *player)
//
// This added test makes the "oof" sound work on 2s lines -- killough:
- if (!P_UseTraverse(player->mo, end.x, end.y, foundline))
+ if (!P_UseTraverse(player->mo, start.x, start.y, end.x, end.y, foundline))
{ // [RH] Give sector a chance to eat the use
sector_t *sec = player->mo->Sector;
int spac = SECSPAC_Use;
if (foundline) spac |= SECSPAC_UseWall;
if ((!sec->SecActTarget || !sec->SecActTarget->TriggerAction(player->mo, spac)) &&
- P_NoWayTraverse(player->mo, end.x, end.y))
+ P_NoWayTraverse(player->mo, start.x, start.y, end.x, end.y))
{
S_Sound(player->mo, CHAN_VOICE, "*usefail", 1, ATTN_IDLE);
}
diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp
index 057c4329c..c84d6d5e2 100644
--- a/src/p_maputl.cpp
+++ b/src/p_maputl.cpp
@@ -150,7 +150,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
if (!(flags & FFCF_ONLY3DFLOORS))
{
sector_t *front, *back;
- fixed_t fc, ff, bc, bf;
+ fixed_t fc = 0, ff = 0, bc = 0, bf = 0;
if (linedef->backsector == NULL)
{
@@ -162,29 +162,20 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
front = linedef->frontsector;
back = linedef->backsector;
- if (!(flags & FFCF_NOPORTALS) && !linedef->frontsector->PortalBlocksMovement(sector_t::ceiling) &&
- linedef->backsector->SkyBoxes[sector_t::ceiling] &&
- linedef->frontsector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup == linedef->backsector->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup)
+ if (!(flags & FFCF_NOPORTALS))
{
- fc = bc = FIXED_MAX;
- }
- else
- {
- fc = front->ceilingplane.ZatPoint(x, y);
- bc = back->ceilingplane.ZatPoint(x, y);
- }
- if (!(flags & FFCF_NOPORTALS) && !linedef->frontsector->PortalBlocksMovement(sector_t::floor) &&
- linedef->backsector->SkyBoxes[sector_t::floor] &&
- linedef->frontsector->SkyBoxes[sector_t::floor]->Sector->PortalGroup == linedef->backsector->SkyBoxes[sector_t::floor]->Sector->PortalGroup)
- {
- ff = bf = FIXED_MIN;
- }
- else
- {
- ff = front->floorplane.ZatPoint(x, y);
- bf = back->floorplane.ZatPoint(x, y);
+ if (!linedef->frontsector->PortalBlocksMovement(sector_t::ceiling)) fc = FIXED_MAX;
+ if (!linedef->backsector->PortalBlocksMovement(sector_t::ceiling)) bc = FIXED_MAX;
+ if (!linedef->frontsector->PortalBlocksMovement(sector_t::floor)) ff = FIXED_MIN;
+ if (!linedef->backsector->PortalBlocksMovement(sector_t::floor)) bf = FIXED_MIN;
}
+ if (fc == 0) fc = front->ceilingplane.ZatPoint(x, y);
+ if (bc == 0) bc = back->ceilingplane.ZatPoint(x, y);
+ if (ff == 0) ff = front->floorplane.ZatPoint(x, y);
+ if (bf == 0) bf = back->floorplane.ZatPoint(x, y);
+
+
/*Printf ("]]]]]] %d %d\n", ff, bf);*/
open.topsec = fc < bc? front : back;
@@ -198,8 +189,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
// that imprecisions in the plane equation mean there is a
// good chance that even if a slope and non-slope look like
// they line up, they won't be perfectly aligned.
- if (refx == FIXED_MIN ||
- abs (ff-bf) > 256)
+ if (ff == FIXED_MIN || bf == FIXED_MIN || (refx == FIXED_MIN || abs (ff-bf) > 256))
{
usefront = (ff > bf);
}
@@ -219,7 +209,13 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
open.bottomsec = front;
open.floorpic = front->GetTexture(sector_t::floor);
open.floorterrain = front->GetTerrain(sector_t::floor);
- open.lowfloor = bf;
+ if (bf != FIXED_MIN) open.lowfloor = bf;
+ else
+ {
+ // We must check through the portal for the actual dropoff.
+ // If there's no lines in the lower sections we'd never get a usable value otherwise.
+ open.lowfloor = back->NextLowestFloorAt(refx, refy, back->SkyBoxes[sector_t::floor]->threshold-1);
+ }
}
else
{
@@ -227,7 +223,13 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
open.bottomsec = back;
open.floorpic = back->GetTexture(sector_t::floor);
open.floorterrain = back->GetTerrain(sector_t::floor);
- open.lowfloor = ff;
+ if (ff != FIXED_MIN) open.lowfloor = ff;
+ else
+ {
+ // We must check through the portal for the actual dropoff.
+ // If there's no lines in the lower sections we'd never get a usable value otherwise.
+ open.lowfloor = front->NextLowestFloorAt(refx, refy, front->SkyBoxes[sector_t::floor]->threshold - 1);
+ }
}
open.frontfloorplane = front->floorplane;
open.backfloorplane = back->floorplane;
@@ -1201,7 +1203,7 @@ void FPathTraverse::AddLineIntercepts(int bx, int by)
P_MakeDivline (ld, &dl);
frac = P_InterceptVector (&trace, &dl);
- if (frac < 0 || frac > FRACUNIT) continue; // behind source or beyond end point
+ if (frac < startfrac || frac > FRACUNIT) continue; // behind source or beyond end point
intercept_t newintercept;
@@ -1282,7 +1284,7 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it
{
// It's a hit
fixed_t frac = P_InterceptVector (&trace, &line);
- if (frac < 0)
+ if (frac < startfrac)
{ // behind source
continue;
}
@@ -1350,7 +1352,7 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it
frac = P_InterceptVector (&trace, &dl);
- if (frac >= 0)
+ if (frac >= startfrac)
{
intercept_t newintercept;
newintercept.frac = frac;
@@ -1398,7 +1400,7 @@ intercept_t *FPathTraverse::Next()
//
//===========================================================================
-void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags)
+void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, fixed_t startfrac)
{
fixed_t xt1, xt2;
fixed_t yt1, yt2;
@@ -1422,6 +1424,7 @@ void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int fl
validcount++;
intercept_index = intercepts.Size();
+ this->startfrac = startfrac;
if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
x1 += FRACUNIT; // don't side exactly on a line
@@ -1442,8 +1445,8 @@ void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int fl
trace.dy = y2 - y1;
}
- _x1 = (long long)x1 - bmaporgx;
- _y1 = (long long)y1 - bmaporgy;
+ _x1 = (long long)x1 + FixedMul(trace.dx, startfrac) - bmaporgx;
+ _y1 = (long long)y1 + FixedMul(trace.dy, startfrac) - bmaporgy;
x1 -= bmaporgx;
y1 -= bmaporgy;
xt1 = int(_x1 >> MAPBLOCKSHIFT);
@@ -1606,6 +1609,41 @@ void FPathTraverse::init (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int fl
}
}
+//===========================================================================
+//
+// Relocates the trace when going through a line portal
+//
+//===========================================================================
+
+bool FPathTraverse::PortalRelocate(intercept_t *in, int flags, fixedvec3 *optpos)
+{
+ if (!in->isaline || !in->d.line->isLinePortal()) return false;
+ if (P_PointOnLineSidePrecise(trace.x, trace.y, in->d.line) == 1) return false;
+
+ fixed_t hitx = trace.x;
+ fixed_t hity = trace.y;
+ fixed_t endx = trace.x + trace.dx;
+ fixed_t endy = trace.y + trace.dy;
+ line_t *out = in->d.line->getPortalDestination();
+
+ P_TranslatePortalXY(in->d.line, out, hitx, hity);
+ P_TranslatePortalXY(in->d.line, out, endx, endy);
+ if (optpos != NULL)
+ {
+ P_TranslatePortalXY(in->d.line, out, optpos->x, optpos->y);
+ P_TranslatePortalZ(in->d.line, out, optpos->z);
+ }
+ intercepts.Resize(intercept_index);
+ init(hitx, hity, endx, endy, flags, in->frac);
+ return true;
+}
+
+//===========================================================================
+//
+//
+//
+//===========================================================================
+
FPathTraverse::~FPathTraverse()
{
intercepts.Resize(intercept_index);
diff --git a/src/p_maputl.h b/src/p_maputl.h
index 838c4e775..b4155995f 100644
--- a/src/p_maputl.h
+++ b/src/p_maputl.h
@@ -129,6 +129,14 @@ struct polyblock_t;
struct FPortalGroupArray
{
+ // Controls how groups are connected
+ enum
+ {
+ PGA_NoSectorPortals,// only collect line portals
+ PGA_CheckPosition, // only collects sector portals at the actual position
+ PGA_Full3d, // Goes up and down sector portals at any linedef within the bounding box (this is a lot slower and should only be done if really needed.)
+ };
+
enum
{
LOWER = 0x4000,
@@ -141,8 +149,9 @@ struct FPortalGroupArray
MAX_STATIC = 4
};
- FPortalGroupArray()
+ FPortalGroupArray(int collectionmethod = PGA_CheckPosition)
{
+ method = collectionmethod;
varused = 0;
inited = false;
}
@@ -171,6 +180,7 @@ struct FPortalGroupArray
}
bool inited;
+ int method;
private:
WORD entry[MAX_STATIC];
@@ -329,6 +339,7 @@ protected:
static TArray intercepts;
divline_t trace;
+ fixed_t startfrac;
unsigned int intercept_index;
unsigned int intercept_count;
unsigned int count;
@@ -344,7 +355,8 @@ public:
{
init(x1, y1, x2, y2, flags);
}
- void init(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags);
+ void init(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, fixed_t startfrac = 0);
+ bool PortalRelocate(intercept_t *in, int flags, fixedvec3 *optpos = NULL);
virtual ~FPathTraverse();
const divline_t &Trace() const { return trace; }
};
@@ -384,5 +396,4 @@ fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1);
#define PT_COMPATIBLE 4
#define PT_DELTA 8 // x2,y2 is passed as a delta, not as an endpoint
-
#endif
\ No newline at end of file
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 51a671369..fbceb5d3f 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -3286,6 +3286,42 @@ void AActor::SetRoll(angle_t r, bool interpolate)
}
+fixedvec3 AActor::GetPortalTransition(fixed_t byoffset)
+{
+ bool moved = false;
+ sector_t *sec = Sector;
+ fixed_t testz = Z() + byoffset;
+ fixedvec3 pos = Pos();
+
+ while (!sec->PortalBlocksMovement(sector_t::ceiling))
+ {
+ AActor *port = sec->SkyBoxes[sector_t::ceiling];
+ if (testz > port->threshold)
+ {
+ pos = PosRelative(port->Sector);
+ sec = P_PointInSector(pos.x, pos.y);
+ moved = true;
+ }
+ else break;
+ }
+ if (!moved)
+ {
+ while (!sec->PortalBlocksMovement(sector_t::floor))
+ {
+ AActor *port = sec->SkyBoxes[sector_t::floor];
+ if (testz <= port->threshold)
+ {
+ pos = PosRelative(port->Sector);
+ sec = P_PointInSector(pos.x, pos.y);
+ }
+ else break;
+ }
+ }
+ return pos;
+}
+
+
+
void AActor::CheckPortalTransition(bool islinked)
{
bool moved = false;
@@ -6128,13 +6164,13 @@ AActor *P_SpawnPlayerMissile (AActor *source, PClassActor *type, angle_t angle)
}
AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z,
- PClassActor *type, angle_t angle, AActor **pLineTarget, AActor **pMissileActor,
- bool nofreeaim, bool noautoaim)
+ PClassActor *type, angle_t angle, FTranslatedLineTarget *pLineTarget, AActor **pMissileActor,
+ bool nofreeaim, bool noautoaim, int aimflags)
{
static const int angdiff[3] = { -(1<<26), 1<<26, 0 };
angle_t an = angle;
angle_t pitch;
- AActor *linetarget;
+ FTranslatedLineTarget scratch;
AActor *defaultobject = GetDefaultByType(type);
int vrange = nofreeaim ? ANGLE_1*35 : 0;
@@ -6142,12 +6178,13 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z,
{
return NULL;
}
+ if (!pLineTarget) pLineTarget = &scratch;
if (source->player && source->player->ReadyWeapon && ((source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM) || noautoaim))
{
// Keep exactly the same angle and pitch as the player's own aim
an = angle;
pitch = source->pitch;
- linetarget = NULL;
+ pLineTarget->linetarget = NULL;
}
else // see which target is to be aimed at
{
@@ -6160,7 +6197,7 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z,
do
{
an = angle + angdiff[i];
- pitch = P_AimLineAttack (source, an, linetargetrange, &linetarget, vrange);
+ pitch = P_AimLineAttack (source, an, linetargetrange, pLineTarget, vrange, aimflags);
if (source->player != NULL &&
!nofreeaim &&
@@ -6169,9 +6206,9 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z,
{
break;
}
- } while (linetarget == NULL && --i >= 0);
+ } while (pLineTarget->linetarget == NULL && --i >= 0);
- if (linetarget == NULL)
+ if (pLineTarget->linetarget == NULL)
{
an = angle;
if (nofreeaim || !level.IsFreelookAllowed())
@@ -6180,7 +6217,6 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z,
}
}
}
- if (pLineTarget) *pLineTarget = linetarget;
if (z != ONFLOORZ && z != ONCEILINGZ)
{
diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp
index ec6c38f77..2f2af36c3 100644
--- a/src/p_pspr.cpp
+++ b/src/p_pspr.cpp
@@ -919,20 +919,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_GunFlash)
// the height of the intended target
//
-angle_t P_BulletSlope (AActor *mo, AActor **pLineTarget)
+angle_t P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget, int aimflags)
{
static const int angdiff[3] = { -(1<<26), 1<<26, 0 };
int i;
angle_t an;
angle_t pitch;
- AActor *linetarget;
+ FTranslatedLineTarget scratch;
+ if (pLineTarget == NULL) pLineTarget = &scratch;
// see which target is to be aimed at
i = 2;
do
{
an = mo->angle + angdiff[i];
- pitch = P_AimLineAttack (mo, an, 16*64*FRACUNIT, &linetarget);
+ pitch = P_AimLineAttack (mo, an, 16*64*FRACUNIT, pLineTarget, 0, aimflags);
if (mo->player != NULL &&
level.IsFreelookAllowed() &&
@@ -940,11 +941,8 @@ angle_t P_BulletSlope (AActor *mo, AActor **pLineTarget)
{
break;
}
- } while (linetarget == NULL && --i >= 0);
- if (pLineTarget != NULL)
- {
- *pLineTarget = linetarget;
- }
+ } while (pLineTarget->linetarget == NULL && --i >= 0);
+
return pitch;
}
diff --git a/src/p_pspr.h b/src/p_pspr.h
index a9eec48b6..8fb6d455b 100644
--- a/src/p_pspr.h
+++ b/src/p_pspr.h
@@ -88,7 +88,7 @@ void P_BringUpWeapon (player_t *player);
void P_FireWeapon (player_t *player);
void P_DropWeapon (player_t *player);
void P_BobWeapon (player_t *player, pspdef_t *psp, fixed_t *x, fixed_t *y);
-angle_t P_BulletSlope (AActor *mo, AActor **pLineTarget = NULL);
+angle_t P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget = NULL, int aimflags = 0);
void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, angle_t pitch);
void DoReadyWeapon(AActor *self);
diff --git a/src/p_spec.cpp b/src/p_spec.cpp
index 9252abe1d..76c5036a0 100644
--- a/src/p_spec.cpp
+++ b/src/p_spec.cpp
@@ -1,2494 +1,2497 @@
-// 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:
-// Implements special effects:
-// Texture animation, height or lighting changes
-// according to adjacent sectors, respective
-// utility functions, etc.
-// Line Tag handling. Line and Sector triggers.
-// Implements donut linedef triggers
-// Initializes and implements BOOM linedef triggers for
-// Scrollers/Conveyors
-// Friction
-// Wind/Current
-//
-//-----------------------------------------------------------------------------
-
-
-#include
-
-#include "templates.h"
-#include "doomdef.h"
-#include "doomstat.h"
-#include "d_event.h"
-#include "gstrings.h"
-
-#include "i_system.h"
-#include "m_argv.h"
-#include "m_random.h"
-#include "m_bbox.h"
-#include "w_wad.h"
-
-#include "p_local.h"
-#include "p_spec.h"
-#include "p_blockmap.h"
-#include "p_lnspec.h"
-#include "p_terrain.h"
-#include "p_acs.h"
-#include "p_3dmidtex.h"
-
-#include "g_game.h"
-
-#include "s_sound.h"
-#include "sc_man.h"
-#include "gi.h"
-#include "statnums.h"
-#include "g_level.h"
-#include "v_font.h"
-#include "a_sharedglobal.h"
-#include "farchive.h"
-#include "a_keys.h"
-#include "c_dispatch.h"
-#include "r_sky.h"
-#include "d_player.h"
-#include "p_maputl.h"
-#include "p_blockmap.h"
-#ifndef NO_EDATA
-#include "edata.h"
-#endif
-
-// State.
-#include "r_state.h"
-
-#include "c_console.h"
-
-#include "r_data/r_interpolate.h"
-
-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 ()
-{
-}
-
-inline FArchive &operator<< (FArchive &arc, DPusher::EPusher &type)
-{
- BYTE val = (BYTE)type;
- arc << val;
- type = (DPusher::EPusher)val;
- return arc;
-}
-
-void DPusher::Serialize (FArchive &arc)
-{
- Super::Serialize (arc);
- arc << m_Type
- << m_Source
- << m_Xmag
- << m_Ymag
- << m_Magnitude
- << m_Radius
- << m_X
- << m_Y
- << m_Affectee;
-}
-
-// killough 3/7/98: Initialize generalized scrolling
-static void P_SpawnScrollers();
-static void P_SpawnFriction (); // phares 3/16/98
-static void P_SpawnPushers (); // phares 3/20/98
-
-
-// [RH] Check dmflags for noexit and respond accordingly
-bool CheckIfExitIsGood (AActor *self, level_info_t *info)
-{
- cluster_info_t *cluster;
-
- // The world can always exit itself.
- if (self == NULL)
- return true;
-
- // We must kill all monsters to exit the level.
- if ((dmflags2 & DF2_KILL_MONSTERS) && level.killed_monsters != level.total_monsters)
- return false;
-
- // Is this a deathmatch game and we're not allowed to exit?
- if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT))
- {
- P_DamageMobj (self, self, self, TELEFRAG_DAMAGE, NAME_Exit);
- return false;
- }
- // Is this a singleplayer game and the next map is part of the same hub and we're dead?
- if (self->health <= 0 &&
- !multiplayer &&
- info != NULL &&
- info->cluster == level.cluster &&
- (cluster = FindClusterInfo(level.cluster)) != NULL &&
- cluster->flags & CLUSTER_HUB)
- {
- return false;
- }
- if (deathmatch && gameaction != ga_completed)
- {
- Printf ("%s exited the level.\n", self->player->userinfo.GetName());
- }
- return true;
-}
-
-
-//
-// UTILITIES
-//
-
-//============================================================================
-//
-// P_ActivateLine
-//
-//============================================================================
-
-bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType)
-{
- int lineActivation;
- INTBOOL repeat;
- INTBOOL buttonSuccess;
- BYTE special;
-
- if (!P_TestActivateLine (line, mo, side, activationType))
- {
- return false;
- }
- bool remote = (line->special != 7 && line->special != 8 && (line->special < 11 || line->special > 14));
- if (line->locknumber > 0 && !P_CheckKeys (mo, line->locknumber, remote)) return false;
- lineActivation = line->activation;
- repeat = line->flags & ML_REPEAT_SPECIAL;
- buttonSuccess = false;
- buttonSuccess = P_ExecuteSpecial(line->special,
- line, mo, side == 1, line->args[0],
- line->args[1], line->args[2],
- line->args[3], line->args[4]);
-
- special = line->special;
- if (!repeat && buttonSuccess)
- { // clear the special on non-retriggerable lines
- line->special = 0;
- }
-
- if (buttonSuccess)
- {
- if (activationType == SPAC_Use || activationType == SPAC_Impact || activationType == SPAC_Push)
- {
- P_ChangeSwitchTexture (line->sidedef[0], repeat, special);
- }
- }
- // some old WADs use this method to create walls that change the texture when shot.
- else if (activationType == SPAC_Impact && // only for shootable triggers
- (level.flags2 & LEVEL2_DUMMYSWITCHES) && // this is only a compatibility setting for an old hack!
- !repeat && // only non-repeatable triggers
- (specialGeneric_Crusher) && // not for Boom's generalized linedefs
- special && // not for lines without a special
- tagManager.LineHasID(line, line->args[0]) && // Safety check: exclude edited UDMF linedefs or ones that don't map the tag to args[0]
- line->args[0] && // only if there's a tag (which is stored in the first arg)
- P_FindFirstSectorFromTag (line->args[0]) == -1) // only if no sector is tagged to this linedef
- {
- P_ChangeSwitchTexture (line->sidedef[0], repeat, special);
- line->special = 0;
- }
-// end of changed code
- if (developer && buttonSuccess)
- {
- Printf ("Line special %d activated on line %i\n", special, int(line - lines));
- }
- return true;
-}
-
-//============================================================================
-//
-// P_TestActivateLine
-//
-//============================================================================
-
-bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType)
-{
- int lineActivation = line->activation;
-
- if (line->flags & ML_FIRSTSIDEONLY && side == 1)
- {
- return false;
- }
-
- if (lineActivation & SPAC_UseThrough)
- {
- lineActivation |= SPAC_Use;
- }
- else if (line->special == Teleport &&
- (lineActivation & SPAC_Cross) &&
- activationType == SPAC_PCross &&
- mo != NULL &&
- mo->flags & MF_MISSILE)
- { // Let missiles use regular player teleports
- lineActivation |= SPAC_PCross;
- }
- // BOOM's generalized line types that allow monster use can actually be
- // activated by anything except projectiles.
- if (lineActivation & SPAC_AnyCross)
- {
- lineActivation |= SPAC_Cross|SPAC_MCross;
- }
- if (activationType == SPAC_Use || activationType == SPAC_UseBack)
- {
- if (!P_CheckSwitchRange(mo, line, side))
- {
- return false;
- }
- }
-
- if (activationType == SPAC_Use && (lineActivation & SPAC_MUse) && !mo->player && mo->flags4 & MF4_CANUSEWALLS)
- {
- return true;
- }
- if (activationType == SPAC_Push && (lineActivation & SPAC_MPush) && !mo->player && mo->flags2 & MF2_PUSHWALL)
- {
- return true;
- }
- if ((lineActivation & activationType) == 0)
- {
- if (activationType != SPAC_MCross || lineActivation != SPAC_Cross)
- {
- return false;
- }
- }
- if (activationType == SPAC_AnyCross && (lineActivation & activationType))
- {
- return true;
- }
- if (mo && !mo->player &&
- !(mo->flags & MF_MISSILE) &&
- !(line->flags & ML_MONSTERSCANACTIVATE) &&
- (activationType != SPAC_MCross || (!(lineActivation & SPAC_MCross))))
- {
- // [RH] monsters' ability to activate this line depends on its type
- // In Hexen, only MCROSS lines could be activated by monsters. With
- // lax activation checks, monsters can also activate certain lines
- // even without them being marked as monster activate-able. This is
- // the default for non-Hexen maps in Hexen format.
- if (!(level.flags2 & LEVEL2_LAXMONSTERACTIVATION))
- {
- return false;
- }
- if ((activationType == SPAC_Use || activationType == SPAC_Push)
- && (line->flags & ML_SECRET))
- return false; // never open secret doors
-
- bool noway = true;
-
- switch (activationType)
- {
- case SPAC_Use:
- case SPAC_Push:
- switch (line->special)
- {
- case Door_Raise:
- if (line->args[0] == 0 && line->args[1] < 64)
- noway = false;
- break;
- case Teleport:
- case Teleport_NoFog:
- noway = false;
- }
- break;
-
- case SPAC_MCross:
- if (!(lineActivation & SPAC_MCross))
- {
- switch (line->special)
- {
- case Door_Raise:
- if (line->args[1] >= 64)
- {
- break;
- }
- case Teleport:
- case Teleport_NoFog:
- case Teleport_Line:
- case Plat_DownWaitUpStayLip:
- case Plat_DownWaitUpStay:
- noway = false;
- }
- }
- else noway = false;
- break;
-
- default:
- noway = false;
- }
- return !noway;
- }
- if (activationType == SPAC_MCross && !(lineActivation & SPAC_MCross) &&
- !(line->flags & ML_MONSTERSCANACTIVATE))
- {
- return false;
- }
- return true;
-}
-
-//============================================================================
-//
-// P_PredictLine
-//
-//============================================================================
-
-bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType)
-{
- int lineActivation;
- INTBOOL buttonSuccess;
- BYTE special;
-
- // Only predict a very specifc section of specials
- if (line->special != Teleport_Line &&
- line->special != Teleport)
- {
- return false;
- }
-
- if (!P_TestActivateLine(line, mo, side, activationType) || !cl_predict_specials)
- {
- return false;
- }
-
- if (line->locknumber > 0) return false;
- lineActivation = line->activation;
- buttonSuccess = false;
- buttonSuccess = P_ExecuteSpecial(line->special,
- line, mo, side == 1, line->args[0],
- line->args[1], line->args[2],
- line->args[3], line->args[4]);
-
- special = line->special;
-
- // end of changed code
- if (developer && buttonSuccess)
- {
- Printf("Line special %d predicted on line %i\n", special, int(line - lines));
- }
- return true;
-}
-
-//
-// P_PlayerInSpecialSector
-// Called every tic frame
-// that the player origin is in a special sector
-//
-void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
-{
- if (sector == NULL)
- {
- // Falling, not all the way down yet?
- sector = player->mo->Sector;
- if (player->mo->Z() != sector->LowestFloorAt(player->mo)
- && !player->mo->waterlevel)
- {
- return;
- }
- }
-
- // Has hit ground.
- AInventory *ironfeet;
-
- // [RH] Apply any customizable damage
- if (sector->damageamount > 0)
- {
- // Allow subclasses. Better would be to implement it as armor and let that reduce
- // the damage as part of the normal damage procedure. Unfortunately, I don't have
- // different damage types yet, so that's not happening for now.
- for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
- {
- if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet)))
- break;
- }
-
- if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE;
- if ((ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage))
- {
- if (sector->Flags & SECF_HAZARD)
- {
- player->hazardcount += sector->damageamount;
- player->hazardtype = sector->damagetype;
- player->hazardinterval = sector->damageinterval;
- }
- else if (level.time % sector->damageinterval == 0)
- {
- if (!(player->cheats & (CF_GODMODE|CF_GODMODE2))) P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype);
- if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT)))
- {
- G_ExitLevel(0, false);
- }
- if (sector->Flags & SECF_DMGTERRAINFX)
- {
- P_HitWater(player->mo, player->mo->Sector, INT_MIN, INT_MIN, INT_MIN, false, true, true);
- }
- }
- }
- }
- else if (sector->damageamount < 0)
- {
- if (level.time % sector->damageinterval == 0)
- {
- P_GiveBody(player->mo, -sector->damageamount, 100);
- }
- }
-
- if (sector->isSecret())
- {
- sector->ClearSecret();
- P_GiveSecret(player->mo, true, true, int(sector - sectors));
- }
-}
-
-//============================================================================
-//
-// P_SectorDamage
-//
-//============================================================================
-
-static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type, PClassActor *protectClass, int flags)
-{
- if (!(actor->flags & MF_SHOOTABLE))
- return;
-
- if (!(flags & DAMAGE_NONPLAYERS) && actor->player == NULL)
- return;
-
- if (!(flags & DAMAGE_PLAYERS) && actor->player != NULL)
- return;
-
- if (!(flags & DAMAGE_IN_AIR) && actor->Z() != sec->floorplane.ZatPoint(actor) && !actor->waterlevel)
- return;
-
- if (protectClass != NULL)
- {
- if (actor->FindInventory(protectClass, !!(flags & DAMAGE_SUBCLASSES_PROTECT)))
- return;
- }
-
- P_DamageMobj (actor, NULL, NULL, amount, type);
-}
-
-void P_SectorDamage(int tag, int amount, FName type, PClassActor *protectClass, int flags)
-{
- FSectorTagIterator itr(tag);
- int secnum;
- while ((secnum = itr.Next()) >= 0)
- {
- AActor *actor, *next;
- sector_t *sec = §ors[secnum];
-
- // Do for actors in this sector.
- for (actor = sec->thinglist; actor != NULL; actor = next)
- {
- next = actor->snext;
- DoSectorDamage(actor, sec, amount, type, protectClass, flags);
- }
- // If this is a 3D floor control sector, also do for anything in/on
- // those 3D floors.
- for (unsigned i = 0; i < sec->e->XFloor.attached.Size(); ++i)
- {
- sector_t *sec2 = sec->e->XFloor.attached[i];
-
- for (actor = sec2->thinglist; actor != NULL; actor = next)
- {
- next = actor->snext;
- // Only affect actors touching the 3D floor
- fixed_t z1 = sec->floorplane.ZatPoint(actor);
- fixed_t z2 = sec->ceilingplane.ZatPoint(actor);
- if (z2 < z1)
- {
- // Account for Vavoom-style 3D floors
- fixed_t zz = z1;
- z1 = z2;
- z2 = zz;
- }
- if (actor->Z() + actor->height > z1)
- {
- // If DAMAGE_IN_AIR is used, anything not beneath the 3D floor will be
- // damaged (so, anything touching it or above it). Other 3D floors between
- // the actor and this one will not stop this effect.
- if ((flags & DAMAGE_IN_AIR) || actor->Z() <= z2)
- {
- // Here we pass the DAMAGE_IN_AIR flag to disable the floor check, since it
- // only works with the real sector's floor. We did the appropriate height checks
- // for 3D floors already.
- DoSectorDamage(actor, NULL, amount, type, protectClass, flags | DAMAGE_IN_AIR);
- }
- }
- }
- }
- }
-}
-
-//============================================================================
-//
-// P_GiveSecret
-//
-//============================================================================
-
-CVAR(Bool, showsecretsector, false, 0)
-CVAR(Bool, cl_showsecretmessage, true, CVAR_ARCHIVE)
-
-void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornum)
-{
- if (actor != NULL)
- {
- if (actor->player != NULL)
- {
- actor->player->secretcount++;
- }
- if (cl_showsecretmessage && actor->CheckLocalView(consoleplayer))
- {
- if (printmessage)
- {
- if (!showsecretsector || sectornum < 0) C_MidPrint(SmallFont, GStrings["SECRETMESSAGE"]);
- else
- {
- FString s = GStrings["SECRETMESSAGE"];
- s.AppendFormat(" (Sector %d)", sectornum);
- C_MidPrint(SmallFont, s);
- }
- }
- if (playsound) S_Sound (CHAN_AUTO | CHAN_UI, "misc/secret", 1, ATTN_NORM);
- }
- }
- level.found_secrets++;
-}
-
-//============================================================================
-//
-// P_PlayerOnSpecialFlat
-//
-//============================================================================
-
-void P_PlayerOnSpecialFlat (player_t *player, int floorType)
-{
- if (Terrains[floorType].DamageAmount &&
- !(level.time & Terrains[floorType].DamageTimeMask))
- {
- AInventory *ironfeet = NULL;
-
- if (Terrains[floorType].AllowProtection)
- {
- for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
- {
- if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet)))
- break;
- }
- }
-
- int damage = 0;
- if (ironfeet == NULL)
- {
- damage = P_DamageMobj (player->mo, NULL, NULL, Terrains[floorType].DamageAmount,
- Terrains[floorType].DamageMOD);
- }
- if (damage > 0 && Terrains[floorType].Splash != -1)
- {
- S_Sound (player->mo, CHAN_AUTO,
- Splashes[Terrains[floorType].Splash].NormalSplashSound, 1,
- ATTN_IDLE);
- }
- }
-}
-
-
-
-//
-// P_UpdateSpecials
-// Animate planes, scroll walls, etc.
-//
-EXTERN_CVAR (Float, timelimit)
-
-void P_UpdateSpecials ()
-{
- // LEVEL TIMER
- if (deathmatch && timelimit)
- {
- if (level.maptime >= (int)(timelimit * TICRATE * 60))
- {
- Printf ("%s\n", GStrings("TXT_TIMELIMIT"));
- G_ExitLevel(0, false);
- }
- }
-}
-
-
-
-//
-// SPECIAL SPAWNING
-//
-
-CUSTOM_CVAR (Bool, forcewater, false, CVAR_ARCHIVE|CVAR_SERVERINFO)
-{
- if (gamestate == GS_LEVEL)
- {
- int i;
-
- for (i = 0; i < numsectors; i++)
- {
- sector_t *hsec = sectors[i].GetHeightSec();
- if (hsec &&
- !(sectors[i].heightsec->MoreFlags & SECF_UNDERWATER))
- {
- if (self)
- {
- hsec->MoreFlags |= SECF_FORCEDUNDERWATER;
- }
- else
- {
- hsec->MoreFlags &= ~SECF_FORCEDUNDERWATER;
- }
- }
- }
- }
-}
-
-class DLightTransfer : public DThinker
-{
- DECLARE_CLASS (DLightTransfer, DThinker)
-
- DLightTransfer() {}
-public:
- DLightTransfer (sector_t *srcSec, int target, bool copyFloor);
- void Serialize (FArchive &arc);
- void Tick ();
-
-protected:
- static void DoTransfer (int level, int target, bool floor);
-
- sector_t *Source;
- int TargetTag;
- bool CopyFloor;
- short LastLight;
-};
-
-IMPLEMENT_CLASS (DLightTransfer)
-
-void DLightTransfer::Serialize (FArchive &arc)
-{
- Super::Serialize (arc);
- if (SaveVersion < 3223)
- {
- BYTE bytelight;
- arc << bytelight;
- LastLight = bytelight;
- }
- else
- {
- arc << LastLight;
- }
- arc << Source << TargetTag << CopyFloor;
-}
-
-DLightTransfer::DLightTransfer (sector_t *srcSec, int target, bool copyFloor)
-{
- int secnum;
-
- Source = srcSec;
- TargetTag = target;
- CopyFloor = copyFloor;
- DoTransfer (LastLight = srcSec->lightlevel, target, copyFloor);
-
- if (copyFloor)
- {
- FSectorTagIterator itr(target);
- while ((secnum = itr.Next()) >= 0)
- sectors[secnum].ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING);
- }
- else
- {
- FSectorTagIterator itr(target);
- while ((secnum = itr.Next()) >= 0)
- sectors[secnum].ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING);
- }
- ChangeStatNum (STAT_LIGHTTRANSFER);
-}
-
-void DLightTransfer::Tick ()
-{
- int light = Source->lightlevel;
-
- if (light != LastLight)
- {
- LastLight = light;
- DoTransfer (light, TargetTag, CopyFloor);
- }
-}
-
-void DLightTransfer::DoTransfer (int level, int target, bool floor)
-{
- int secnum;
-
- if (floor)
- {
- FSectorTagIterator itr(target);
- while ((secnum = itr.Next()) >= 0)
- sectors[secnum].SetPlaneLight(sector_t::floor, level);
- }
- else
- {
- FSectorTagIterator itr(target);
- while ((secnum = itr.Next()) >= 0)
- sectors[secnum].SetPlaneLight(sector_t::ceiling, level);
- }
-}
-
-
-class DWallLightTransfer : public DThinker
-{
- enum
- {
- WLF_SIDE1=1,
- WLF_SIDE2=2,
- WLF_NOFAKECONTRAST=4
- };
-
- DECLARE_CLASS (DWallLightTransfer, DThinker)
- DWallLightTransfer() {}
-public:
- DWallLightTransfer (sector_t *srcSec, int target, BYTE flags);
- void Serialize (FArchive &arc);
- void Tick ();
-
-protected:
- static void DoTransfer (short level, int target, BYTE flags);
-
- sector_t *Source;
- int TargetID;
- short LastLight;
- BYTE Flags;
-};
-
-IMPLEMENT_CLASS (DWallLightTransfer)
-
-void DWallLightTransfer::Serialize (FArchive &arc)
-{
- Super::Serialize (arc);
- if (SaveVersion < 3223)
- {
- BYTE bytelight;
- arc << bytelight;
- LastLight = bytelight;
- }
- else
- {
- arc << LastLight;
- }
- arc << Source << TargetID << Flags;
-}
-
-DWallLightTransfer::DWallLightTransfer (sector_t *srcSec, int target, BYTE flags)
-{
- int linenum;
- int wallflags;
-
- Source = srcSec;
- TargetID = target;
- Flags = flags;
- DoTransfer (LastLight = srcSec->GetLightLevel(), target, Flags);
-
- if (!(flags & WLF_NOFAKECONTRAST))
- {
- wallflags = WALLF_ABSLIGHTING;
- }
- else
- {
- wallflags = WALLF_ABSLIGHTING | WALLF_NOFAKECONTRAST;
- }
-
- FLineIdIterator itr(target);
- while ((linenum = itr.Next()) >= 0)
- {
- if (flags & WLF_SIDE1 && lines[linenum].sidedef[0] != NULL)
- {
- lines[linenum].sidedef[0]->Flags |= wallflags;
- }
-
- if (flags & WLF_SIDE2 && lines[linenum].sidedef[1] != NULL)
- {
- lines[linenum].sidedef[1]->Flags |= wallflags;
- }
- }
- ChangeStatNum(STAT_LIGHTTRANSFER);
-}
-
-void DWallLightTransfer::Tick ()
-{
- short light = sector_t::ClampLight(Source->lightlevel);
-
- if (light != LastLight)
- {
- LastLight = light;
- DoTransfer (light, TargetID, Flags);
- }
-}
-
-void DWallLightTransfer::DoTransfer (short lightlevel, int target, BYTE flags)
-{
- int linenum;
-
- FLineIdIterator itr(target);
- while ((linenum = itr.Next()) >= 0)
- {
- line_t *line = &lines[linenum];
-
- if (flags & WLF_SIDE1 && line->sidedef[0] != NULL)
- {
- line->sidedef[0]->SetLight(lightlevel);
- }
-
- if (flags & WLF_SIDE2 && line->sidedef[1] != NULL)
- {
- line->sidedef[1]->SetLight(lightlevel);
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-//
-// Portals
-//
-//-----------------------------------------------------------------------------
-
-//---------------------------------------------------------------------------
-// Upper stacks go in the top sector. Lower stacks go in the bottom sector.
-
-static void SetupFloorPortal (AStackPoint *point)
-{
- NActorIterator it (NAME_LowerStackLookOnly, point->tid);
- sector_t *Sector = point->Sector;
- ASkyViewpoint *skyv = static_cast(it.Next());
- Sector->SkyBoxes[sector_t::floor] = skyv;
- if (skyv != NULL && skyv->bAlways)
- {
- skyv->Mate = point;
- if (Sector->GetAlpha(sector_t::floor) == OPAQUE)
- Sector->SetAlpha(sector_t::floor, Scale (point->args[0], OPAQUE, 255));
- }
-}
-
-static void SetupCeilingPortal (AStackPoint *point)
-{
- NActorIterator it (NAME_UpperStackLookOnly, point->tid);
- sector_t *Sector = point->Sector;
- ASkyViewpoint *skyv = static_cast(it.Next());
- Sector->SkyBoxes[sector_t::ceiling] = skyv;
- if (skyv != NULL && skyv->bAlways)
- {
- skyv->Mate = point;
- if (Sector->GetAlpha(sector_t::ceiling) == OPAQUE)
- Sector->SetAlpha(sector_t::ceiling, Scale(point->args[0], OPAQUE, 255));
- }
-}
-
-void P_SetupPortals()
-{
- TThinkerIterator it;
- AStackPoint *pt;
- TArray points;
-
- while ((pt = it.Next()))
- {
- FName nm = pt->GetClass()->TypeName;
- if (nm == NAME_UpperStackLookOnly)
- {
- SetupFloorPortal(pt);
- }
- else if (nm == NAME_LowerStackLookOnly)
- {
- SetupCeilingPortal(pt);
- }
- pt->special1 = 0;
- points.Push(pt);
- }
-}
-
-static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_t alpha)
-{
- // plane: 0=floor, 1=ceiling, 2=both
- if (plane > 0)
- {
- if (sector->SkyBoxes[sector_t::ceiling] == NULL || !barrier_cast(sector->SkyBoxes[sector_t::ceiling])->bAlways)
- {
- sector->SkyBoxes[sector_t::ceiling] = portal;
- if (sector->GetAlpha(sector_t::ceiling) == OPAQUE)
- sector->SetAlpha(sector_t::ceiling, alpha);
-
- if (!portal->bAlways) sector->SetTexture(sector_t::ceiling, skyflatnum);
- }
- }
- if (plane == 2 || plane == 0)
- {
- if (sector->SkyBoxes[sector_t::floor] == NULL || !barrier_cast(sector->SkyBoxes[sector_t::floor])->bAlways)
- {
- sector->SkyBoxes[sector_t::floor] = portal;
- }
- if (sector->GetAlpha(sector_t::floor) == OPAQUE)
- sector->SetAlpha(sector_t::floor, alpha);
-
- if (!portal->bAlways) sector->SetTexture(sector_t::floor, skyflatnum);
- }
-}
-
-static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, fixed_t alpha, bool tolines)
-{
- int s;
- FSectorTagIterator itr(sectortag);
- while ((s = itr.Next()) >= 0)
- {
- SetPortal(§ors[s], plane, origin, alpha);
- }
-
- for (int j=0;j= 0)
- {
- SetPortal(§ors[s], plane, origin, alpha);
- }
- }
- }
- if (tolines && lines[j].special == Sector_SetPortal &&
- lines[j].args[1] == 5 &&
- lines[j].args[3] == sectortag)
- {
- if (lines[j].args[0] == 0)
- {
- lines[j].skybox = origin;
- }
- else
- {
- FLineIdIterator itr(lines[j].args[0]);
- while ((s = itr.Next()) >= 0)
- {
- lines[s].skybox = origin;
- }
- }
- }
- }
-}
-
-void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha, int linked)
-{
- if (plane < 0 || plane > 2 || (linked && plane == 2)) return;
- for (int i=0;iv1->x) + SQWORD(line->v2->x)) >> 1);
- fixed_t y1 = fixed_t((SQWORD(line->v1->y) + SQWORD(line->v2->y)) >> 1);
- fixed_t x2 = fixed_t((SQWORD(lines[i].v1->x) + SQWORD(lines[i].v2->x)) >> 1);
- fixed_t y2 = fixed_t((SQWORD(lines[i].v1->y) + SQWORD(lines[i].v2->y)) >> 1);
- fixed_t z = linked ? line->frontsector->planes[plane].TexZ : 0; // the map's sector height defines the portal plane for linked portals
-
- fixed_t alpha = Scale (lines[i].args[4], OPAQUE, 255);
-
- AStackPoint *anchor = Spawn(x1, y1, 0, NO_REPLACE);
- AStackPoint *reference = Spawn(x2, y2, 0, NO_REPLACE);
- reference->special1 = linked ? SKYBOX_LINKEDPORTAL : SKYBOX_PORTAL;
- anchor->special1 = SKYBOX_ANCHOR;
- // store the portal displacement in the unused scaleX/Y members of the portal reference actor.
- anchor->scaleX = -(reference->scaleX = x2 - x1);
- anchor->scaleY = -(reference->scaleY = y2 - y1);
- anchor->threshold = reference->threshold = z;
-
- reference->Mate = anchor;
- anchor->Mate = reference;
-
- // This is so that the renderer can distinguish these portals from
- // the ones spawned with the '*StackLookOnly' things.
- reference->flags |= MF_JUSTATTACKED;
- anchor->flags |= MF_JUSTATTACKED;
-
- CopyPortal(sectortag, plane, reference, alpha, false);
- return;
- }
- }
-}
-
-// This searches the viewpoint's sector
-// for a skybox line special, gets its tag and transfers the skybox to all tagged sectors.
-void P_SpawnSkybox(ASkyViewpoint *origin)
-{
- sector_t *Sector = origin->Sector;
- if (Sector == NULL)
- {
- Printf("Sector not initialized for SkyCamCompat\n");
- origin->Sector = Sector = P_PointInSector(origin->X(), origin->Y());
- }
- if (Sector)
- {
- line_t * refline = NULL;
- for (short i = 0; i < Sector->linecount; i++)
- {
- refline = Sector->lines[i];
- if (refline->special == Sector_SetPortal && refline->args[1] == 2)
- {
- // We found the setup linedef for this skybox, so let's use it for our init.
- CopyPortal(refline->args[0], refline->args[2], origin, 0, true);
- return;
- }
- }
- }
-}
-
-
-
-//
-// P_SetSectorDamage
-//
-// Sets damage properties for one sector. Allows combination of original specials with explicit use of the damage properties
-//
-
-static void P_SetupSectorDamage(sector_t *sector, int damage, int interval, int leakchance, FName type, int flags)
-{
- // Only set if damage is not yet initialized. This ensures that UDMF takes precedence over sector specials.
- if (sector->damageamount == 0)
- {
- sector->damageamount = damage;
- sector->damageinterval = MAX(1, interval);
- sector->leakydamage = leakchance;
- sector->damagetype = type;
- sector->Flags = (sector->Flags & ~SECF_DAMAGEFLAGS) | (flags & SECF_DAMAGEFLAGS);
- }
-}
-
-//
-// P_InitSectorSpecial
-//
-// Sets up everything derived from 'sector->special' for one sector
-// ('fromload' is necessary to allow conversion upon savegame load.)
-//
-
-void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers)
-{
- // [RH] All secret sectors are marked with a BOOM-ish bitfield
- if (sector->special & SECRET_MASK)
- {
- sector->Flags |= SECF_SECRET | SECF_WASSECRET;
- level.total_secrets++;
- }
- if (sector->special & FRICTION_MASK)
- {
- sector->Flags |= SECF_FRICTION;
- }
- if (sector->special & PUSH_MASK)
- {
- sector->Flags |= SECF_PUSH;
- }
- if ((sector->special & DAMAGE_MASK) == 0x100)
- {
- P_SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0);
- }
- else if ((sector->special & DAMAGE_MASK) == 0x200)
- {
- P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0);
- }
- else if ((sector->special & DAMAGE_MASK) == 0x300)
- {
- P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
- }
- sector->special &= 0xff;
-
- // [RH] Normal DOOM special or BOOM specialized?
- bool keepspecial = false;
- switch (sector->special)
- {
- case Light_Phased:
- if (!nothinkers) new DPhased (sector, 48, 63 - (sector->lightlevel & 63));
- break;
-
- // [RH] Hexen-like phased lighting
- case LightSequenceStart:
- if (!nothinkers) new DPhased (sector);
- break;
-
- case dLight_Flicker:
- if (!nothinkers) new DLightFlash (sector);
- break;
-
- case dLight_StrobeFast:
- if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
- break;
-
- case dLight_StrobeSlow:
- if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false);
- break;
-
- case dLight_Strobe_Hurt:
- if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
- P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
- break;
-
- case dDamage_Hellslime:
- P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0);
- break;
-
- case dDamage_Nukage:
- P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0);
- break;
-
- case dLight_Glow:
- if (!nothinkers) new DGlow (sector);
- break;
-
- case dSector_DoorCloseIn30:
- new DDoor(sector, DDoor::doorWaitClose, FRACUNIT * 2, 0, 0, 30 * TICRATE);
- break;
-
- case dDamage_End:
- P_SetupSectorDamage(sector, 20, 32, 256, NAME_None, SECF_ENDGODMODE|SECF_ENDLEVEL);
- break;
-
- case dLight_StrobeSlowSync:
- if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true);
- break;
-
- case dLight_StrobeFastSync:
- if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, true);
- break;
-
- case dSector_DoorRaiseIn5Mins:
- new DDoor (sector, DDoor::doorWaitRaise, 2*FRACUNIT, TICRATE*30/7, 5*60*TICRATE, 0);
- break;
-
- case dFriction_Low:
- sector->friction = FRICTION_LOW;
- sector->movefactor = 0x269;
- sector->Flags |= SECF_FRICTION;
- break;
-
- case dDamage_SuperHellslime:
- P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
- break;
-
- case dLight_FireFlicker:
- if (!nothinkers) new DFireFlicker (sector);
- break;
-
- case dDamage_LavaWimpy:
- P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
- break;
-
- case dDamage_LavaHefty:
- P_SetupSectorDamage(sector, 8, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
- break;
-
- case dScroll_EastLavaDamage:
- P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
- if (!nothinkers)
- {
- new DStrobe(sector, STROBEBRIGHT, FASTDARK, false);
- new DScroller(DScroller::sc_floor, -((FRACUNIT / 2) << 3),
- 0, -1, int(sector - sectors), 0);
- }
- keepspecial = true;
- break;
-
- case hDamage_Sludge:
- P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, 0);
- break;
-
- case sLight_Strobe_Hurt:
- P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0);
- if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
- break;
-
- case sDamage_Hellslime:
- P_SetupSectorDamage(sector, 2, 32, 0, NAME_Slime, SECF_HAZARD);
- break;
-
- case Damage_InstantDeath:
- // Strife's instant death sector
- P_SetupSectorDamage(sector, TELEFRAG_DAMAGE, 1, 256, NAME_InstantDeath, 0);
- break;
-
- case sDamage_SuperHellslime:
- P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, SECF_HAZARD);
- break;
-
- case Sector_Hidden:
- sector->MoreFlags |= SECF_HIDDEN;
- break;
-
- case Sector_Heal:
- // CoD's healing sector
- P_SetupSectorDamage(sector, -1, 32, 0, NAME_None, 0);
- break;
-
- case Sky2:
- sector->sky = PL_SKYFLAT;
- break;
-
- default:
- if (sector->special >= Scroll_North_Slow &&
- sector->special <= Scroll_SouthWest_Fast)
- { // Hexen scroll special
- static const char hexenScrollies[24][2] =
- {
- { 0, 1 }, { 0, 2 }, { 0, 4 },
- { -1, 0 }, { -2, 0 }, { -4, 0 },
- { 0, -1 }, { 0, -2 }, { 0, -4 },
- { 1, 0 }, { 2, 0 }, { 4, 0 },
- { 1, 1 }, { 2, 2 }, { 4, 4 },
- { -1, 1 }, { -2, 2 }, { -4, 4 },
- { -1, -1 }, { -2, -2 }, { -4, -4 },
- { 1, -1 }, { 2, -2 }, { 4, -4 }
- };
-
-
- 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);
- }
- 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,
- (-FRACUNIT/2)<<(sector->special - Carry_East5),
- 0, -1, int(sector-sectors), 0);
- }
- keepspecial = true;
- break;
- }
- if (!keepspecial) sector->special = 0;
-}
-
-//
-// P_SpawnSpecials
-//
-// After the map has been loaded, scan for specials that spawn thinkers
-//
-
-void P_SpawnSpecials (void)
-{
- sector_t *sector;
- int i;
-
- P_SetupPortals();
-
- // Init special SECTORs.
- sector = sectors;
-
- for (i = 0; i < numsectors; i++, sector++)
- {
- if (sector->special == 0)
- continue;
-
- P_InitSectorSpecial(sector, sector->special, false);
- }
-
-#ifndef NO_EDATA
- ProcessEDSectors();
-#endif
-
-
- // Init other misc stuff
-
- P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers
- P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs
- P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs
-
- TThinkerIterator it2;
- ASkyCamCompat *pt2;
- while ((pt2 = it2.Next()))
- {
- P_SpawnSkybox(pt2);
- }
-
- for (i = 0; i < numlines; i++)
- {
- switch (lines[i].special)
- {
- int s;
- sector_t *sec;
-
- // killough 3/7/98:
- // support for drawn heights coming from different sector
- case Transfer_Heights:
- {
- sec = lines[i].frontsector;
- if (lines[i].args[1] & 2)
- {
- sec->MoreFlags |= SECF_FAKEFLOORONLY;
- }
- if (lines[i].args[1] & 4)
- {
- sec->MoreFlags |= SECF_CLIPFAKEPLANES;
- }
- if (lines[i].args[1] & 8)
- {
- sec->MoreFlags |= SECF_UNDERWATER;
- }
- else if (forcewater)
- {
- sec->MoreFlags |= SECF_FORCEDUNDERWATER;
- }
- if (lines[i].args[1] & 16)
- {
- sec->MoreFlags |= SECF_IGNOREHEIGHTSEC;
- }
- if (lines[i].args[1] & 32)
- {
- sec->MoreFlags |= SECF_NOFAKELIGHT;
- }
- FSectorTagIterator itr(lines[i].args[0]);
- while ((s = itr.Next()) >= 0)
- {
- sectors[s].heightsec = sec;
- sec->e->FakeFloor.Sectors.Push(§ors[s]);
- sectors[s].AdjustFloorClip();
- }
- break;
- }
-
- // killough 3/16/98: Add support for setting
- // floor lighting independently (e.g. lava)
- case Transfer_FloorLight:
- new DLightTransfer (lines[i].frontsector, lines[i].args[0], true);
- break;
-
- // killough 4/11/98: Add support for setting
- // ceiling lighting independently
- case Transfer_CeilingLight:
- new DLightTransfer (lines[i].frontsector, lines[i].args[0], false);
- break;
-
- // [Graf Zahl] Add support for setting lighting
- // per wall independently
- case Transfer_WallLight:
- new DWallLightTransfer (lines[i].frontsector, lines[i].args[0], lines[i].args[1]);
- break;
-
- case Sector_Attach3dMidtex:
- P_Attach3dMidtexLinesToSector(lines[i].frontsector, lines[i].args[0], lines[i].args[1], !!lines[i].args[2]);
- break;
-
- case Sector_SetLink:
- if (lines[i].args[0] == 0)
- {
- P_AddSectorLinks(lines[i].frontsector, lines[i].args[1], lines[i].args[2], lines[i].args[3]);
- }
- break;
-
- case Sector_SetPortal:
- // arg 0 = sector tag
- // arg 1 = type
- // - 0: normal (handled here)
- // - 1: copy (handled by the portal they copy)
- // - 2: EE-style skybox (handled by the camera object)
- // - 3: EE-style flat portal (GZDoom HW renderer only for now)
- // - 4: EE-style horizon portal (GZDoom HW renderer only for now)
- // - 5: copy portal to line (GZDoom HW renderer only for now)
- // - 6: linked portal
- // other values reserved for later use
- // arg 2 = 0:floor, 1:ceiling, 2:both
- // arg 3 = 0: anchor, 1: reference line
- // arg 4 = for the anchor only: alpha
- if ((lines[i].args[1] == 0 || lines[i].args[1] == 6) && lines[i].args[3] == 0)
- {
- P_SpawnPortal(&lines[i], lines[i].args[0], lines[i].args[2], lines[i].args[4], lines[i].args[1]);
- }
- else if (lines[i].args[1] == 3 || lines[i].args[1] == 4)
- {
- line_t *line = &lines[i];
- ASkyViewpoint *origin = Spawn(0, 0, 0, NO_REPLACE);
- origin->Sector = line->frontsector;
- origin->special1 = line->args[1] == 3? SKYBOX_PLANE:SKYBOX_HORIZON;
-
- CopyPortal(line->args[0], line->args[2], origin, 0, true);
- }
- break;
-
- case Line_SetPortal:
- P_SpawnLinePortal(&lines[i]);
- break;
-
- // [RH] ZDoom Static_Init settings
- case Static_Init:
- switch (lines[i].args[1])
- {
- case Init_Gravity:
- {
- float grav = ((float)P_AproxDistance (lines[i].dx, lines[i].dy)) / (FRACUNIT * 100.0f);
- FSectorTagIterator itr(lines[i].args[0]);
- while ((s = itr.Next()) >= 0)
- sectors[s].gravity = grav;
- }
- break;
-
- //case Init_Color:
- // handled in P_LoadSideDefs2()
-
- case Init_Damage:
- {
- int damage = P_AproxDistance (lines[i].dx, lines[i].dy) >> FRACBITS;
- FSectorTagIterator itr(lines[i].args[0]);
- while ((s = itr.Next()) >= 0)
- {
- sector_t *sec = §ors[s];
- sec->damageamount = damage;
- sec->damagetype = NAME_None;
- if (sec->damageamount < 20)
- {
- sec->leakydamage = 0;
- sec->damageinterval = 32;
- }
- else if (sec->damageamount < 50)
- {
- sec->leakydamage = 5;
- sec->damageinterval = 32;
- }
- else
- {
- sec->leakydamage = 256;
- sec->damageinterval = 1;
- }
- }
- }
- break;
-
- case Init_SectorLink:
- if (lines[i].args[3] == 0)
- P_AddSectorLinksByID(lines[i].frontsector, lines[i].args[0], lines[i].args[2]);
- break;
-
- // killough 10/98:
- //
- // Support for sky textures being transferred from sidedefs.
- // Allows scrolling and other effects (but if scrolling is
- // used, then the same sector tag needs to be used for the
- // sky sector, the sky-transfer linedef, and the scroll-effect
- // linedef). Still requires user to use F_SKY1 for the floor
- // or ceiling texture, to distinguish floor and ceiling sky.
-
- case Init_TransferSky:
- {
- FSectorTagIterator itr(lines[i].args[0]);
- while ((s = itr.Next()) >= 0)
- sectors[s].sky = (i + 1) | PL_SKYFLAT;
- break;
- }
- }
- break;
- }
- }
- // [RH] Start running any open scripts on this map
- 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(§ors[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(§ors[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 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
-//
-// phares 3/12/98: Start of friction effects
-
-// As the player moves, friction is applied by decreasing the x and y
-// velocity values on each tic. By varying the percentage of decrease,
-// we can simulate muddy or icy conditions. In mud, the player slows
-// down faster. In ice, the player slows down more slowly.
-//
-// The amount of friction change is controlled by the length of a linedef
-// with type 223. A length < 100 gives you mud. A length > 100 gives you ice.
-//
-// Also, each sector where these effects are to take place is given a
-// new special type _______. Changing the type value at runtime allows
-// these effects to be turned on or off.
-//
-// Sector boundaries present problems. The player should experience these
-// friction changes only when his feet are touching the sector floor. At
-// sector boundaries where floor height changes, the player can find
-// himself still 'in' one sector, but with his feet at the floor level
-// of the next sector (steps up or down). To handle this, Thinkers are used
-// in icy/muddy sectors. These thinkers examine each object that is touching
-// their sectors, looking for players whose feet are at the same level as
-// their floors. Players satisfying this condition are given new friction
-// values that are applied by the player movement code later.
-
-//
-// killough 8/28/98:
-//
-// Completely redid code, which did not need thinkers, and which put a heavy
-// drag on CPU. Friction is now a property of sectors, NOT objects inside
-// them. All objects, not just players, are affected by it, if they touch
-// the sector's floor. Code simpler and faster, only calling on friction
-// calculations when an object needs friction considered, instead of doing
-// friction calculations on every sector during every tic.
-//
-// Although this -might- ruin Boom demo sync involving friction, it's the only
-// way, short of code explosion, to fix the original design bug. Fixing the
-// design bug in Boom's original friction code, while maintaining demo sync
-// under every conceivable circumstance, would double or triple code size, and
-// would require maintenance of buggy legacy code which is only useful for old
-// demos. Doom demos, which are more important IMO, are not affected by this
-// change.
-//
-// [RH] On the other hand, since I've given up on trying to maintain demo
-// sync between versions, these considerations aren't a big deal to me.
-//
-/////////////////////////////
-//
-// Initialize the sectors where friction is increased or decreased
-
-static void P_SpawnFriction(void)
-{
- int i;
- line_t *l = lines;
-
- for (i = 0 ; i < numlines ; i++,l++)
- {
- if (l->special == Sector_SetFriction)
- {
- int length;
-
- if (l->args[1])
- { // [RH] Allow setting friction amount from parameter
- length = l->args[1] <= 200 ? l->args[1] : 200;
- }
- else
- {
- length = P_AproxDistance(l->dx,l->dy)>>FRACBITS;
- }
-
- P_SetSectorFriction (l->args[0], length, false);
- l->special = 0;
- }
- }
-}
-
-void P_SetSectorFriction (int tag, int amount, bool alterFlag)
-{
- int s;
- fixed_t friction, movefactor;
-
- // An amount of 100 should result in a friction of
- // ORIG_FRICTION (0xE800)
- friction = (0x1EB8*amount)/0x80 + 0xD001;
-
- // killough 8/28/98: prevent odd situations
- friction = clamp(friction, 0, FRACUNIT);
-
- // The following check might seem odd. At the time of movement,
- // the move distance is multiplied by 'friction/0x10000', so a
- // higher friction value actually means 'less friction'.
- movefactor = FrictionToMoveFactor(friction);
-
- FSectorTagIterator itr(tag);
- while ((s = itr.Next()) >= 0)
- {
- // killough 8/28/98:
- //
- // Instead of spawning thinkers, which are slow and expensive,
- // modify the sector's own friction values. Friction should be
- // a property of sectors, not objects which reside inside them.
- // Original code scanned every object in every friction sector
- // on every tic, adjusting its friction, putting unnecessary
- // drag on CPU. New code adjusts friction of sector only once
- // at level startup, and then uses this friction value.
-
- sectors[s].friction = friction;
- sectors[s].movefactor = movefactor;
- if (alterFlag)
- {
- // When used inside a script, the sectors' friction flags
- // can be enabled and disabled at will.
- if (friction == ORIG_FRICTION)
- {
- sectors[s].Flags &= ~SECF_FRICTION;
- }
- else
- {
- sectors[s].Flags |= SECF_FRICTION;
- }
- }
- }
-}
-
-//
-// phares 3/12/98: End of friction effects
-//
-////////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////////////
-//
-// PUSH/PULL EFFECT
-//
-// phares 3/20/98: Start of push/pull effects
-//
-// This is where push/pull effects are applied to objects in the sectors.
-//
-// There are four kinds of push effects
-//
-// 1) Pushing Away
-//
-// Pushes you away from a point source defined by the location of an
-// MT_PUSH Thing. The force decreases linearly with distance from the
-// source. This force crosses sector boundaries and is felt w/in a circle
-// whose center is at the MT_PUSH. The force is felt only if the point
-// MT_PUSH can see the target object.
-//
-// 2) Pulling toward
-//
-// Same as Pushing Away except you're pulled toward an MT_PULL point
-// source. This force crosses sector boundaries and is felt w/in a circle
-// whose center is at the MT_PULL. The force is felt only if the point
-// MT_PULL can see the target object.
-//
-// 3) Wind
-//
-// Pushes you in a constant direction. Full force above ground, half
-// force on the ground, nothing if you're below it (water).
-//
-// 4) Current
-//
-// Pushes you in a constant direction. No force above ground, full
-// force if on the ground or below it (water).
-//
-// The magnitude of the force is controlled by the length of a controlling
-// linedef. The force vector for types 3 & 4 is determined by the angle
-// of the linedef, and is constant.
-//
-// For each sector where these effects occur, the sector special type has
-// to have the PUSH_MASK bit set. If this bit is turned off by a switch
-// at run-time, the effect will not occur. The controlling sector for
-// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing.
-
-
-#define PUSH_FACTOR 7
-
-/////////////////////////////
-//
-// Add a push thinker to the thinker list
-
-DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle,
- AActor *source, int affectee)
-{
- m_Source = source;
- m_Type = type;
- if (l)
- {
- m_Xmag = l->dx>>FRACBITS;
- m_Ymag = l->dy>>FRACBITS;
- m_Magnitude = P_AproxDistance (m_Xmag, m_Ymag);
- }
- else
- { // [RH] Allow setting magnitude and angle with parameters
- ChangeValues (magnitude, angle);
- }
- if (source) // point source exist?
- {
- m_Radius = (m_Magnitude) << (FRACBITS+1); // where force goes to zero
- m_X = m_Source->X();
- m_Y = m_Source->Y();
- }
- m_Affectee = affectee;
-}
-
-int DPusher::CheckForSectorMatch (EPusher type, int tag)
-{
- if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag))
- return m_Affectee;
- else
- return -1;
-}
-
-
-/////////////////////////////
-//
-// T_Pusher looks for all objects that are inside the radius of
-// the effect.
-//
-void DPusher::Tick ()
-{
- sector_t *sec;
- AActor *thing;
- msecnode_t *node;
- int xspeed,yspeed;
- int ht;
-
- if (!var_pushers)
- return;
-
- sec = sectors + m_Affectee;
-
- // Be sure the special sector type is still turned on. If so, proceed.
- // Else, bail out; the sector type has been changed on us.
-
- if (!(sec->Flags & SECF_PUSH))
- return;
-
- // For constant pushers (wind/current) there are 3 situations:
- //
- // 1) Affected Thing is above the floor.
- //
- // Apply the full force if wind, no force if current.
- //
- // 2) Affected Thing is on the ground.
- //
- // Apply half force if wind, full force if current.
- //
- // 3) Affected Thing is below the ground (underwater effect).
- //
- // Apply no force if wind, full force if current.
- //
- // Apply the effect to clipped players only for now.
- //
- // In Phase II, you can apply these effects to Things other than players.
- // [RH] No Phase II, but it works with anything having MF2_WINDTHRUST now.
-
- if (m_Type == p_push)
- {
- // Seek out all pushable things within the force radius of this
- // point pusher. Crosses sectors, so use blockmap.
-
- FBlockThingsIterator it(FBoundingBox(m_X, m_Y, m_Radius));
- AActor *thing;
-
- while ((thing = it.Next()))
- {
- // Normal ZDoom is based only on the WINDTHRUST flag, with the noclip cheat as an exemption.
- bool pusharound = ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP));
-
- // MBF allows any sentient or shootable thing to be affected, but players with a fly cheat aren't.
- if (compatflags & COMPATF_MBFMONSTERMOVE)
- {
- pusharound = ((pusharound || (thing->IsSentient()) || (thing->flags & MF_SHOOTABLE)) // Add categories here
- && (!(thing->player && (thing->flags & (MF_NOGRAVITY))))); // Exclude flying players here
- }
-
- if ((pusharound) )
- {
- int sx = m_X;
- int sy = m_Y;
- int dist = thing->AproxDistance (sx, sy);
- int speed = (m_Magnitude - ((dist>>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1);
-
- // If speed <= 0, you're outside the effective radius. You also have
- // to be able to see the push/pull source point.
-
- if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY)))
- {
- angle_t pushangle = thing->AngleTo(sx, sy);
- if (m_Source->GetClass()->TypeName == NAME_PointPusher)
- pushangle += ANG180; // away
- pushangle >>= ANGLETOFINESHIFT;
- thing->velx += FixedMul (speed, finecosine[pushangle]);
- thing->vely += FixedMul (speed, finesine[pushangle]);
- }
- }
- }
- return;
- }
-
- // constant pushers p_wind and p_current
-
- node = sec->touching_thinglist; // things touching this sector
- for ( ; node ; node = node->m_snext)
- {
- thing = node->m_thing;
- if (!(thing->flags2 & MF2_WINDTHRUST) || (thing->flags & MF_NOCLIP))
- continue;
-
- sector_t *hsec = sec->GetHeightSec();
- fixedvec3 pos = thing->PosRelative(sec);
- if (m_Type == p_wind)
- {
- if (hsec == NULL)
- { // NOT special water sector
- if (thing->Z() > thing->floorz) // above ground
- {
- xspeed = m_Xmag; // full force
- yspeed = m_Ymag;
- }
- else // on ground
- {
- xspeed = (m_Xmag)>>1; // half force
- yspeed = (m_Ymag)>>1;
- }
- }
- else // special water sector
- {
- ht = hsec->floorplane.ZatPoint(pos);
- if (thing->Z() > ht) // above ground
- {
- xspeed = m_Xmag; // full force
- yspeed = m_Ymag;
- }
- else if (thing->player->viewz < ht) // underwater
- {
- xspeed = yspeed = 0; // no force
- }
- else // wading in water
- {
- xspeed = (m_Xmag)>>1; // half force
- yspeed = (m_Ymag)>>1;
- }
- }
- }
- else // p_current
- {
- const secplane_t *floor;
-
- if (hsec == NULL)
- { // NOT special water sector
- floor = &sec->floorplane;
- }
- else
- { // special water sector
- floor = &hsec->floorplane;
- }
- if (thing->Z() > floor->ZatPoint(pos))
- { // above ground
- xspeed = yspeed = 0; // no force
- }
- else
- { // on ground/underwater
- xspeed = m_Xmag; // full force
- yspeed = m_Ymag;
- }
- }
- thing->velx += xspeed<<(FRACBITS-PUSH_FACTOR);
- thing->vely += yspeed<<(FRACBITS-PUSH_FACTOR);
- }
-}
-
-/////////////////////////////
-//
-// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing,
-// NULL otherwise.
-
-AActor *P_GetPushThing (int s)
-{
- AActor* thing;
- sector_t* sec;
-
- sec = sectors + s;
- thing = sec->thinglist;
-
- while (thing &&
- thing->GetClass()->TypeName != NAME_PointPusher &&
- thing->GetClass()->TypeName != NAME_PointPuller)
- {
- thing = thing->snext;
- }
- return thing;
-}
-
-/////////////////////////////
-//
-// Initialize the sectors where pushers are present
-//
-
-static void P_SpawnPushers ()
-{
- int i;
- line_t *l = lines;
- int s;
-
- for (i = 0; i < numlines; i++, l++)
- {
- switch (l->special)
- {
- case Sector_SetWind: // wind
- {
- FSectorTagIterator itr(l->args[0]);
- while ((s = itr.Next()) >= 0)
- new DPusher(DPusher::p_wind, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s);
- l->special = 0;
- break;
- }
-
- case Sector_SetCurrent: // current
- {
- FSectorTagIterator itr(l->args[0]);
- while ((s = itr.Next()) >= 0)
- new DPusher(DPusher::p_current, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s);
- l->special = 0;
- break;
- }
-
- case PointPush_SetForce: // push/pull
- if (l->args[0]) { // [RH] Find thing by sector
- FSectorTagIterator itr(l->args[0]);
- while ((s = itr.Next()) >= 0)
- {
- AActor *thing = P_GetPushThing (s);
- if (thing) { // No MT_P* means no effect
- // [RH] Allow narrowing it down by tid
- if (!l->args[1] || l->args[1] == thing->tid)
- new DPusher (DPusher::p_push, l->args[3] ? l : NULL, l->args[2],
- 0, thing, s);
- }
- }
- } else { // [RH] Find thing by tid
- AActor *thing;
- FActorIterator iterator (l->args[1]);
-
- while ( (thing = iterator.Next ()) )
- {
- if (thing->GetClass()->TypeName == NAME_PointPusher ||
- thing->GetClass()->TypeName == NAME_PointPuller)
- {
- new DPusher (DPusher::p_push, l->args[3] ? l : NULL, l->args[2],
- 0, thing, int(thing->Sector - sectors));
- }
- }
- }
- l->special = 0;
- break;
- }
- }
-}
-
-//
-// phares 3/20/98: End of Pusher effects
-//
-////////////////////////////////////////////////////////////////////////////
-
-void sector_t::AdjustFloorClip () const
-{
- msecnode_t *node;
-
- for (node = touching_thinglist; node; node = node->m_snext)
- {
- if (node->m_thing->flags2 & MF2_FLOORCLIP)
- {
- node->m_thing->AdjustFloorClip();
- }
- }
-}
+// 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:
+// Implements special effects:
+// Texture animation, height or lighting changes
+// according to adjacent sectors, respective
+// utility functions, etc.
+// Line Tag handling. Line and Sector triggers.
+// Implements donut linedef triggers
+// Initializes and implements BOOM linedef triggers for
+// Scrollers/Conveyors
+// Friction
+// Wind/Current
+//
+//-----------------------------------------------------------------------------
+
+
+#include
+
+#include "templates.h"
+#include "doomdef.h"
+#include "doomstat.h"
+#include "d_event.h"
+#include "gstrings.h"
+
+#include "i_system.h"
+#include "m_argv.h"
+#include "m_random.h"
+#include "m_bbox.h"
+#include "w_wad.h"
+
+#include "p_local.h"
+#include "p_spec.h"
+#include "p_blockmap.h"
+#include "p_lnspec.h"
+#include "p_terrain.h"
+#include "p_acs.h"
+#include "p_3dmidtex.h"
+
+#include "g_game.h"
+
+#include "s_sound.h"
+#include "sc_man.h"
+#include "gi.h"
+#include "statnums.h"
+#include "g_level.h"
+#include "v_font.h"
+#include "a_sharedglobal.h"
+#include "farchive.h"
+#include "a_keys.h"
+#include "c_dispatch.h"
+#include "r_sky.h"
+#include "d_player.h"
+#include "p_maputl.h"
+#include "p_blockmap.h"
+#ifndef NO_EDATA
+#include "edata.h"
+#endif
+
+// State.
+#include "r_state.h"
+
+#include "c_console.h"
+
+#include "r_data/r_interpolate.h"
+
+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 ()
+{
+}
+
+inline FArchive &operator<< (FArchive &arc, DPusher::EPusher &type)
+{
+ BYTE val = (BYTE)type;
+ arc << val;
+ type = (DPusher::EPusher)val;
+ return arc;
+}
+
+void DPusher::Serialize (FArchive &arc)
+{
+ Super::Serialize (arc);
+ arc << m_Type
+ << m_Source
+ << m_Xmag
+ << m_Ymag
+ << m_Magnitude
+ << m_Radius
+ << m_X
+ << m_Y
+ << m_Affectee;
+}
+
+// killough 3/7/98: Initialize generalized scrolling
+static void P_SpawnScrollers();
+static void P_SpawnFriction (); // phares 3/16/98
+static void P_SpawnPushers (); // phares 3/20/98
+
+
+// [RH] Check dmflags for noexit and respond accordingly
+bool CheckIfExitIsGood (AActor *self, level_info_t *info)
+{
+ cluster_info_t *cluster;
+
+ // The world can always exit itself.
+ if (self == NULL)
+ return true;
+
+ // We must kill all monsters to exit the level.
+ if ((dmflags2 & DF2_KILL_MONSTERS) && level.killed_monsters != level.total_monsters)
+ return false;
+
+ // Is this a deathmatch game and we're not allowed to exit?
+ if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT))
+ {
+ P_DamageMobj (self, self, self, TELEFRAG_DAMAGE, NAME_Exit);
+ return false;
+ }
+ // Is this a singleplayer game and the next map is part of the same hub and we're dead?
+ if (self->health <= 0 &&
+ !multiplayer &&
+ info != NULL &&
+ info->cluster == level.cluster &&
+ (cluster = FindClusterInfo(level.cluster)) != NULL &&
+ cluster->flags & CLUSTER_HUB)
+ {
+ return false;
+ }
+ if (deathmatch && gameaction != ga_completed)
+ {
+ Printf ("%s exited the level.\n", self->player->userinfo.GetName());
+ }
+ return true;
+}
+
+
+//
+// UTILITIES
+//
+
+//============================================================================
+//
+// P_ActivateLine
+//
+//============================================================================
+
+bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType, fixedvec3 *optpos)
+{
+ int lineActivation;
+ INTBOOL repeat;
+ INTBOOL buttonSuccess;
+ BYTE special;
+
+ if (!P_TestActivateLine (line, mo, side, activationType, optpos))
+ {
+ return false;
+ }
+ bool remote = (line->special != 7 && line->special != 8 && (line->special < 11 || line->special > 14));
+ if (line->locknumber > 0 && !P_CheckKeys (mo, line->locknumber, remote)) return false;
+ lineActivation = line->activation;
+ repeat = line->flags & ML_REPEAT_SPECIAL;
+ buttonSuccess = false;
+ buttonSuccess = P_ExecuteSpecial(line->special,
+ line, mo, side == 1, line->args[0],
+ line->args[1], line->args[2],
+ line->args[3], line->args[4]);
+
+ special = line->special;
+ if (!repeat && buttonSuccess)
+ { // clear the special on non-retriggerable lines
+ line->special = 0;
+ }
+
+ if (buttonSuccess)
+ {
+ if (activationType == SPAC_Use || activationType == SPAC_Impact || activationType == SPAC_Push)
+ {
+ P_ChangeSwitchTexture (line->sidedef[0], repeat, special);
+ }
+ }
+ // some old WADs use this method to create walls that change the texture when shot.
+ else if (activationType == SPAC_Impact && // only for shootable triggers
+ (level.flags2 & LEVEL2_DUMMYSWITCHES) && // this is only a compatibility setting for an old hack!
+ !repeat && // only non-repeatable triggers
+ (specialGeneric_Crusher) && // not for Boom's generalized linedefs
+ special && // not for lines without a special
+ tagManager.LineHasID(line, line->args[0]) && // Safety check: exclude edited UDMF linedefs or ones that don't map the tag to args[0]
+ line->args[0] && // only if there's a tag (which is stored in the first arg)
+ P_FindFirstSectorFromTag (line->args[0]) == -1) // only if no sector is tagged to this linedef
+ {
+ P_ChangeSwitchTexture (line->sidedef[0], repeat, special);
+ line->special = 0;
+ }
+// end of changed code
+ if (developer && buttonSuccess)
+ {
+ Printf ("Line special %d activated on line %i\n", special, int(line - lines));
+ }
+ return true;
+}
+
+//============================================================================
+//
+// P_TestActivateLine
+//
+//============================================================================
+
+bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType, fixedvec3 *optpos)
+{
+ int lineActivation = line->activation;
+
+ if (line->flags & ML_FIRSTSIDEONLY && side == 1)
+ {
+ return false;
+ }
+
+ if (lineActivation & SPAC_UseThrough)
+ {
+ lineActivation |= SPAC_Use;
+ }
+ else if (line->special == Teleport &&
+ (lineActivation & SPAC_Cross) &&
+ activationType == SPAC_PCross &&
+ mo != NULL &&
+ mo->flags & MF_MISSILE)
+ { // Let missiles use regular player teleports
+ lineActivation |= SPAC_PCross;
+ }
+ // BOOM's generalized line types that allow monster use can actually be
+ // activated by anything except projectiles.
+ if (lineActivation & SPAC_AnyCross)
+ {
+ lineActivation |= SPAC_Cross|SPAC_MCross;
+ }
+ if (activationType == SPAC_Use || activationType == SPAC_UseBack)
+ {
+ if (!P_CheckSwitchRange(mo, line, side, optpos))
+ {
+ return false;
+ }
+ }
+
+ if (activationType == SPAC_Use && (lineActivation & SPAC_MUse) && !mo->player && mo->flags4 & MF4_CANUSEWALLS)
+ {
+ return true;
+ }
+ if (activationType == SPAC_Push && (lineActivation & SPAC_MPush) && !mo->player && mo->flags2 & MF2_PUSHWALL)
+ {
+ return true;
+ }
+ if ((lineActivation & activationType) == 0)
+ {
+ if (activationType != SPAC_MCross || lineActivation != SPAC_Cross)
+ {
+ return false;
+ }
+ }
+ if (activationType == SPAC_AnyCross && (lineActivation & activationType))
+ {
+ return true;
+ }
+ if (mo && !mo->player &&
+ !(mo->flags & MF_MISSILE) &&
+ !(line->flags & ML_MONSTERSCANACTIVATE) &&
+ (activationType != SPAC_MCross || (!(lineActivation & SPAC_MCross))))
+ {
+ // [RH] monsters' ability to activate this line depends on its type
+ // In Hexen, only MCROSS lines could be activated by monsters. With
+ // lax activation checks, monsters can also activate certain lines
+ // even without them being marked as monster activate-able. This is
+ // the default for non-Hexen maps in Hexen format.
+ if (!(level.flags2 & LEVEL2_LAXMONSTERACTIVATION))
+ {
+ return false;
+ }
+ if ((activationType == SPAC_Use || activationType == SPAC_Push)
+ && (line->flags & ML_SECRET))
+ return false; // never open secret doors
+
+ bool noway = true;
+
+ switch (activationType)
+ {
+ case SPAC_Use:
+ case SPAC_Push:
+ switch (line->special)
+ {
+ case Door_Raise:
+ if (line->args[0] == 0 && line->args[1] < 64)
+ noway = false;
+ break;
+ case Teleport:
+ case Teleport_NoFog:
+ noway = false;
+ }
+ break;
+
+ case SPAC_MCross:
+ if (!(lineActivation & SPAC_MCross))
+ {
+ switch (line->special)
+ {
+ case Door_Raise:
+ if (line->args[1] >= 64)
+ {
+ break;
+ }
+ case Teleport:
+ case Teleport_NoFog:
+ case Teleport_Line:
+ case Plat_DownWaitUpStayLip:
+ case Plat_DownWaitUpStay:
+ noway = false;
+ }
+ }
+ else noway = false;
+ break;
+
+ default:
+ noway = false;
+ }
+ return !noway;
+ }
+ if (activationType == SPAC_MCross && !(lineActivation & SPAC_MCross) &&
+ !(line->flags & ML_MONSTERSCANACTIVATE))
+ {
+ return false;
+ }
+ return true;
+}
+
+//============================================================================
+//
+// P_PredictLine
+//
+//============================================================================
+
+bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType)
+{
+ int lineActivation;
+ INTBOOL buttonSuccess;
+ BYTE special;
+
+ // Only predict a very specifc section of specials
+ if (line->special != Teleport_Line &&
+ line->special != Teleport)
+ {
+ return false;
+ }
+
+ if (!P_TestActivateLine(line, mo, side, activationType) || !cl_predict_specials)
+ {
+ return false;
+ }
+
+ if (line->locknumber > 0) return false;
+ lineActivation = line->activation;
+ buttonSuccess = false;
+ buttonSuccess = P_ExecuteSpecial(line->special,
+ line, mo, side == 1, line->args[0],
+ line->args[1], line->args[2],
+ line->args[3], line->args[4]);
+
+ special = line->special;
+
+ // end of changed code
+ if (developer && buttonSuccess)
+ {
+ Printf("Line special %d predicted on line %i\n", special, int(line - lines));
+ }
+ return true;
+}
+
+//
+// P_PlayerInSpecialSector
+// Called every tic frame
+// that the player origin is in a special sector
+//
+void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
+{
+ if (sector == NULL)
+ {
+ // Falling, not all the way down yet?
+ sector = player->mo->Sector;
+ if (player->mo->Z() != sector->LowestFloorAt(player->mo)
+ && !player->mo->waterlevel)
+ {
+ return;
+ }
+ }
+
+ // Has hit ground.
+ AInventory *ironfeet;
+
+ // [RH] Apply any customizable damage
+ if (sector->damageamount > 0)
+ {
+ // Allow subclasses. Better would be to implement it as armor and let that reduce
+ // the damage as part of the normal damage procedure. Unfortunately, I don't have
+ // different damage types yet, so that's not happening for now.
+ for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
+ {
+ if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet)))
+ break;
+ }
+
+ if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE;
+ if ((ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage))
+ {
+ if (sector->Flags & SECF_HAZARD)
+ {
+ player->hazardcount += sector->damageamount;
+ player->hazardtype = sector->damagetype;
+ player->hazardinterval = sector->damageinterval;
+ }
+ else if (level.time % sector->damageinterval == 0)
+ {
+ if (!(player->cheats & (CF_GODMODE|CF_GODMODE2))) P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype);
+ if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT)))
+ {
+ G_ExitLevel(0, false);
+ }
+ if (sector->Flags & SECF_DMGTERRAINFX)
+ {
+ P_HitWater(player->mo, player->mo->Sector, INT_MIN, INT_MIN, INT_MIN, false, true, true);
+ }
+ }
+ }
+ }
+ else if (sector->damageamount < 0)
+ {
+ if (level.time % sector->damageinterval == 0)
+ {
+ P_GiveBody(player->mo, -sector->damageamount, 100);
+ }
+ }
+
+ if (sector->isSecret())
+ {
+ sector->ClearSecret();
+ P_GiveSecret(player->mo, true, true, int(sector - sectors));
+ }
+}
+
+//============================================================================
+//
+// P_SectorDamage
+//
+//============================================================================
+
+static void DoSectorDamage(AActor *actor, sector_t *sec, int amount, FName type, PClassActor *protectClass, int flags)
+{
+ if (!(actor->flags & MF_SHOOTABLE))
+ return;
+
+ if (!(flags & DAMAGE_NONPLAYERS) && actor->player == NULL)
+ return;
+
+ if (!(flags & DAMAGE_PLAYERS) && actor->player != NULL)
+ return;
+
+ if (!(flags & DAMAGE_IN_AIR) && actor->Z() != sec->floorplane.ZatPoint(actor) && !actor->waterlevel)
+ return;
+
+ if (protectClass != NULL)
+ {
+ if (actor->FindInventory(protectClass, !!(flags & DAMAGE_SUBCLASSES_PROTECT)))
+ return;
+ }
+
+ P_DamageMobj (actor, NULL, NULL, amount, type);
+}
+
+void P_SectorDamage(int tag, int amount, FName type, PClassActor *protectClass, int flags)
+{
+ FSectorTagIterator itr(tag);
+ int secnum;
+ while ((secnum = itr.Next()) >= 0)
+ {
+ AActor *actor, *next;
+ sector_t *sec = §ors[secnum];
+
+ // Do for actors in this sector.
+ for (actor = sec->thinglist; actor != NULL; actor = next)
+ {
+ next = actor->snext;
+ DoSectorDamage(actor, sec, amount, type, protectClass, flags);
+ }
+ // If this is a 3D floor control sector, also do for anything in/on
+ // those 3D floors.
+ for (unsigned i = 0; i < sec->e->XFloor.attached.Size(); ++i)
+ {
+ sector_t *sec2 = sec->e->XFloor.attached[i];
+
+ for (actor = sec2->thinglist; actor != NULL; actor = next)
+ {
+ next = actor->snext;
+ // Only affect actors touching the 3D floor
+ fixed_t z1 = sec->floorplane.ZatPoint(actor);
+ fixed_t z2 = sec->ceilingplane.ZatPoint(actor);
+ if (z2 < z1)
+ {
+ // Account for Vavoom-style 3D floors
+ fixed_t zz = z1;
+ z1 = z2;
+ z2 = zz;
+ }
+ if (actor->Z() + actor->height > z1)
+ {
+ // If DAMAGE_IN_AIR is used, anything not beneath the 3D floor will be
+ // damaged (so, anything touching it or above it). Other 3D floors between
+ // the actor and this one will not stop this effect.
+ if ((flags & DAMAGE_IN_AIR) || actor->Z() <= z2)
+ {
+ // Here we pass the DAMAGE_IN_AIR flag to disable the floor check, since it
+ // only works with the real sector's floor. We did the appropriate height checks
+ // for 3D floors already.
+ DoSectorDamage(actor, NULL, amount, type, protectClass, flags | DAMAGE_IN_AIR);
+ }
+ }
+ }
+ }
+ }
+}
+
+//============================================================================
+//
+// P_GiveSecret
+//
+//============================================================================
+
+CVAR(Bool, showsecretsector, false, 0)
+CVAR(Bool, cl_showsecretmessage, true, CVAR_ARCHIVE)
+
+void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornum)
+{
+ if (actor != NULL)
+ {
+ if (actor->player != NULL)
+ {
+ actor->player->secretcount++;
+ }
+ if (cl_showsecretmessage && actor->CheckLocalView(consoleplayer))
+ {
+ if (printmessage)
+ {
+ if (!showsecretsector || sectornum < 0) C_MidPrint(SmallFont, GStrings["SECRETMESSAGE"]);
+ else
+ {
+ FString s = GStrings["SECRETMESSAGE"];
+ s.AppendFormat(" (Sector %d)", sectornum);
+ C_MidPrint(SmallFont, s);
+ }
+ }
+ if (playsound) S_Sound (CHAN_AUTO | CHAN_UI, "misc/secret", 1, ATTN_NORM);
+ }
+ }
+ level.found_secrets++;
+}
+
+//============================================================================
+//
+// P_PlayerOnSpecialFlat
+//
+//============================================================================
+
+void P_PlayerOnSpecialFlat (player_t *player, int floorType)
+{
+ if (Terrains[floorType].DamageAmount &&
+ !(level.time & Terrains[floorType].DamageTimeMask))
+ {
+ AInventory *ironfeet = NULL;
+
+ if (Terrains[floorType].AllowProtection)
+ {
+ for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
+ {
+ if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet)))
+ break;
+ }
+ }
+
+ int damage = 0;
+ if (ironfeet == NULL)
+ {
+ damage = P_DamageMobj (player->mo, NULL, NULL, Terrains[floorType].DamageAmount,
+ Terrains[floorType].DamageMOD);
+ }
+ if (damage > 0 && Terrains[floorType].Splash != -1)
+ {
+ S_Sound (player->mo, CHAN_AUTO,
+ Splashes[Terrains[floorType].Splash].NormalSplashSound, 1,
+ ATTN_IDLE);
+ }
+ }
+}
+
+
+
+//
+// P_UpdateSpecials
+// Animate planes, scroll walls, etc.
+//
+EXTERN_CVAR (Float, timelimit)
+
+void P_UpdateSpecials ()
+{
+ // LEVEL TIMER
+ if (deathmatch && timelimit)
+ {
+ if (level.maptime >= (int)(timelimit * TICRATE * 60))
+ {
+ Printf ("%s\n", GStrings("TXT_TIMELIMIT"));
+ G_ExitLevel(0, false);
+ }
+ }
+}
+
+
+
+//
+// SPECIAL SPAWNING
+//
+
+CUSTOM_CVAR (Bool, forcewater, false, CVAR_ARCHIVE|CVAR_SERVERINFO)
+{
+ if (gamestate == GS_LEVEL)
+ {
+ int i;
+
+ for (i = 0; i < numsectors; i++)
+ {
+ sector_t *hsec = sectors[i].GetHeightSec();
+ if (hsec &&
+ !(sectors[i].heightsec->MoreFlags & SECF_UNDERWATER))
+ {
+ if (self)
+ {
+ hsec->MoreFlags |= SECF_FORCEDUNDERWATER;
+ }
+ else
+ {
+ hsec->MoreFlags &= ~SECF_FORCEDUNDERWATER;
+ }
+ }
+ }
+ }
+}
+
+class DLightTransfer : public DThinker
+{
+ DECLARE_CLASS (DLightTransfer, DThinker)
+
+ DLightTransfer() {}
+public:
+ DLightTransfer (sector_t *srcSec, int target, bool copyFloor);
+ void Serialize (FArchive &arc);
+ void Tick ();
+
+protected:
+ static void DoTransfer (int level, int target, bool floor);
+
+ sector_t *Source;
+ int TargetTag;
+ bool CopyFloor;
+ short LastLight;
+};
+
+IMPLEMENT_CLASS (DLightTransfer)
+
+void DLightTransfer::Serialize (FArchive &arc)
+{
+ Super::Serialize (arc);
+ if (SaveVersion < 3223)
+ {
+ BYTE bytelight;
+ arc << bytelight;
+ LastLight = bytelight;
+ }
+ else
+ {
+ arc << LastLight;
+ }
+ arc << Source << TargetTag << CopyFloor;
+}
+
+DLightTransfer::DLightTransfer (sector_t *srcSec, int target, bool copyFloor)
+{
+ int secnum;
+
+ Source = srcSec;
+ TargetTag = target;
+ CopyFloor = copyFloor;
+ DoTransfer (LastLight = srcSec->lightlevel, target, copyFloor);
+
+ if (copyFloor)
+ {
+ FSectorTagIterator itr(target);
+ while ((secnum = itr.Next()) >= 0)
+ sectors[secnum].ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING);
+ }
+ else
+ {
+ FSectorTagIterator itr(target);
+ while ((secnum = itr.Next()) >= 0)
+ sectors[secnum].ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING);
+ }
+ ChangeStatNum (STAT_LIGHTTRANSFER);
+}
+
+void DLightTransfer::Tick ()
+{
+ int light = Source->lightlevel;
+
+ if (light != LastLight)
+ {
+ LastLight = light;
+ DoTransfer (light, TargetTag, CopyFloor);
+ }
+}
+
+void DLightTransfer::DoTransfer (int level, int target, bool floor)
+{
+ int secnum;
+
+ if (floor)
+ {
+ FSectorTagIterator itr(target);
+ while ((secnum = itr.Next()) >= 0)
+ sectors[secnum].SetPlaneLight(sector_t::floor, level);
+ }
+ else
+ {
+ FSectorTagIterator itr(target);
+ while ((secnum = itr.Next()) >= 0)
+ sectors[secnum].SetPlaneLight(sector_t::ceiling, level);
+ }
+}
+
+
+class DWallLightTransfer : public DThinker
+{
+ enum
+ {
+ WLF_SIDE1=1,
+ WLF_SIDE2=2,
+ WLF_NOFAKECONTRAST=4
+ };
+
+ DECLARE_CLASS (DWallLightTransfer, DThinker)
+ DWallLightTransfer() {}
+public:
+ DWallLightTransfer (sector_t *srcSec, int target, BYTE flags);
+ void Serialize (FArchive &arc);
+ void Tick ();
+
+protected:
+ static void DoTransfer (short level, int target, BYTE flags);
+
+ sector_t *Source;
+ int TargetID;
+ short LastLight;
+ BYTE Flags;
+};
+
+IMPLEMENT_CLASS (DWallLightTransfer)
+
+void DWallLightTransfer::Serialize (FArchive &arc)
+{
+ Super::Serialize (arc);
+ if (SaveVersion < 3223)
+ {
+ BYTE bytelight;
+ arc << bytelight;
+ LastLight = bytelight;
+ }
+ else
+ {
+ arc << LastLight;
+ }
+ arc << Source << TargetID << Flags;
+}
+
+DWallLightTransfer::DWallLightTransfer (sector_t *srcSec, int target, BYTE flags)
+{
+ int linenum;
+ int wallflags;
+
+ Source = srcSec;
+ TargetID = target;
+ Flags = flags;
+ DoTransfer (LastLight = srcSec->GetLightLevel(), target, Flags);
+
+ if (!(flags & WLF_NOFAKECONTRAST))
+ {
+ wallflags = WALLF_ABSLIGHTING;
+ }
+ else
+ {
+ wallflags = WALLF_ABSLIGHTING | WALLF_NOFAKECONTRAST;
+ }
+
+ FLineIdIterator itr(target);
+ while ((linenum = itr.Next()) >= 0)
+ {
+ if (flags & WLF_SIDE1 && lines[linenum].sidedef[0] != NULL)
+ {
+ lines[linenum].sidedef[0]->Flags |= wallflags;
+ }
+
+ if (flags & WLF_SIDE2 && lines[linenum].sidedef[1] != NULL)
+ {
+ lines[linenum].sidedef[1]->Flags |= wallflags;
+ }
+ }
+ ChangeStatNum(STAT_LIGHTTRANSFER);
+}
+
+void DWallLightTransfer::Tick ()
+{
+ short light = sector_t::ClampLight(Source->lightlevel);
+
+ if (light != LastLight)
+ {
+ LastLight = light;
+ DoTransfer (light, TargetID, Flags);
+ }
+}
+
+void DWallLightTransfer::DoTransfer (short lightlevel, int target, BYTE flags)
+{
+ int linenum;
+
+ FLineIdIterator itr(target);
+ while ((linenum = itr.Next()) >= 0)
+ {
+ line_t *line = &lines[linenum];
+
+ if (flags & WLF_SIDE1 && line->sidedef[0] != NULL)
+ {
+ line->sidedef[0]->SetLight(lightlevel);
+ }
+
+ if (flags & WLF_SIDE2 && line->sidedef[1] != NULL)
+ {
+ line->sidedef[1]->SetLight(lightlevel);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+//
+// Portals
+//
+//-----------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+// Upper stacks go in the top sector. Lower stacks go in the bottom sector.
+
+static void SetupFloorPortal (AStackPoint *point)
+{
+ NActorIterator it (NAME_LowerStackLookOnly, point->tid);
+ sector_t *Sector = point->Sector;
+ ASkyViewpoint *skyv = static_cast(it.Next());
+ Sector->SkyBoxes[sector_t::floor] = skyv;
+ if (skyv != NULL && skyv->bAlways)
+ {
+ skyv->Mate = point;
+ if (Sector->GetAlpha(sector_t::floor) == OPAQUE)
+ Sector->SetAlpha(sector_t::floor, Scale (point->args[0], OPAQUE, 255));
+ }
+}
+
+static void SetupCeilingPortal (AStackPoint *point)
+{
+ NActorIterator it (NAME_UpperStackLookOnly, point->tid);
+ sector_t *Sector = point->Sector;
+ ASkyViewpoint *skyv = static_cast(it.Next());
+ Sector->SkyBoxes[sector_t::ceiling] = skyv;
+ if (skyv != NULL && skyv->bAlways)
+ {
+ skyv->Mate = point;
+ if (Sector->GetAlpha(sector_t::ceiling) == OPAQUE)
+ Sector->SetAlpha(sector_t::ceiling, Scale(point->args[0], OPAQUE, 255));
+ }
+}
+
+void P_SetupPortals()
+{
+ TThinkerIterator it;
+ AStackPoint *pt;
+ TArray points;
+
+ while ((pt = it.Next()))
+ {
+ FName nm = pt->GetClass()->TypeName;
+ if (nm == NAME_UpperStackLookOnly)
+ {
+ SetupFloorPortal(pt);
+ }
+ else if (nm == NAME_LowerStackLookOnly)
+ {
+ SetupCeilingPortal(pt);
+ }
+ pt->special1 = 0;
+ points.Push(pt);
+ }
+}
+
+static void SetPortal(sector_t *sector, int plane, ASkyViewpoint *portal, fixed_t alpha)
+{
+ // plane: 0=floor, 1=ceiling, 2=both
+ if (plane > 0)
+ {
+ if (sector->SkyBoxes[sector_t::ceiling] == NULL || !barrier_cast(sector->SkyBoxes[sector_t::ceiling])->bAlways)
+ {
+ sector->SkyBoxes[sector_t::ceiling] = portal;
+ if (sector->GetAlpha(sector_t::ceiling) == OPAQUE)
+ sector->SetAlpha(sector_t::ceiling, alpha);
+
+ if (!portal->bAlways) sector->SetTexture(sector_t::ceiling, skyflatnum);
+ }
+ }
+ if (plane == 2 || plane == 0)
+ {
+ if (sector->SkyBoxes[sector_t::floor] == NULL || !barrier_cast(sector->SkyBoxes[sector_t::floor])->bAlways)
+ {
+ sector->SkyBoxes[sector_t::floor] = portal;
+ }
+ if (sector->GetAlpha(sector_t::floor) == OPAQUE)
+ sector->SetAlpha(sector_t::floor, alpha);
+
+ if (!portal->bAlways) sector->SetTexture(sector_t::floor, skyflatnum);
+ }
+}
+
+static void CopyPortal(int sectortag, int plane, ASkyViewpoint *origin, fixed_t alpha, bool tolines)
+{
+ int s;
+ FSectorTagIterator itr(sectortag);
+ while ((s = itr.Next()) >= 0)
+ {
+ SetPortal(§ors[s], plane, origin, alpha);
+ }
+
+ for (int j=0;j= 0)
+ {
+ SetPortal(§ors[s], plane, origin, alpha);
+ }
+ }
+ }
+ if (tolines && lines[j].special == Sector_SetPortal &&
+ lines[j].args[1] == 5 &&
+ lines[j].args[3] == sectortag)
+ {
+ if (lines[j].args[0] == 0)
+ {
+ lines[j].skybox = origin;
+ }
+ else
+ {
+ FLineIdIterator itr(lines[j].args[0]);
+ while ((s = itr.Next()) >= 0)
+ {
+ lines[s].skybox = origin;
+ }
+ }
+ }
+ }
+}
+
+void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha, int linked)
+{
+ if (plane < 0 || plane > 2 || (linked && plane == 2)) return;
+ for (int i=0;iv1->x) + SQWORD(line->v2->x)) >> 1);
+ fixed_t y1 = fixed_t((SQWORD(line->v1->y) + SQWORD(line->v2->y)) >> 1);
+ fixed_t x2 = fixed_t((SQWORD(lines[i].v1->x) + SQWORD(lines[i].v2->x)) >> 1);
+ fixed_t y2 = fixed_t((SQWORD(lines[i].v1->y) + SQWORD(lines[i].v2->y)) >> 1);
+ fixed_t z = linked ? line->frontsector->planes[plane].TexZ : 0; // the map's sector height defines the portal plane for linked portals
+
+ fixed_t alpha = Scale (lines[i].args[4], OPAQUE, 255);
+
+ AStackPoint *anchor = Spawn(x1, y1, 0, NO_REPLACE);
+ AStackPoint *reference = Spawn(x2, y2, 0, NO_REPLACE);
+ reference->special1 = linked ? SKYBOX_LINKEDPORTAL : SKYBOX_PORTAL;
+ anchor->special1 = SKYBOX_ANCHOR;
+ // store the portal displacement in the unused scaleX/Y members of the portal reference actor.
+ anchor->scaleX = -(reference->scaleX = x2 - x1);
+ anchor->scaleY = -(reference->scaleY = y2 - y1);
+ anchor->threshold = reference->threshold = z;
+
+ reference->Mate = anchor;
+ anchor->Mate = reference;
+
+ // This is so that the renderer can distinguish these portals from
+ // the ones spawned with the '*StackLookOnly' things.
+ reference->flags |= MF_JUSTATTACKED;
+ anchor->flags |= MF_JUSTATTACKED;
+
+ CopyPortal(sectortag, plane, reference, alpha, false);
+ return;
+ }
+ }
+}
+
+// This searches the viewpoint's sector
+// for a skybox line special, gets its tag and transfers the skybox to all tagged sectors.
+void P_SpawnSkybox(ASkyViewpoint *origin)
+{
+ sector_t *Sector = origin->Sector;
+ if (Sector == NULL)
+ {
+ Printf("Sector not initialized for SkyCamCompat\n");
+ origin->Sector = Sector = P_PointInSector(origin->X(), origin->Y());
+ }
+ if (Sector)
+ {
+ line_t * refline = NULL;
+ for (short i = 0; i < Sector->linecount; i++)
+ {
+ refline = Sector->lines[i];
+ if (refline->special == Sector_SetPortal && refline->args[1] == 2)
+ {
+ // We found the setup linedef for this skybox, so let's use it for our init.
+ CopyPortal(refline->args[0], refline->args[2], origin, 0, true);
+ return;
+ }
+ }
+ }
+}
+
+
+
+//
+// P_SetSectorDamage
+//
+// Sets damage properties for one sector. Allows combination of original specials with explicit use of the damage properties
+//
+
+static void P_SetupSectorDamage(sector_t *sector, int damage, int interval, int leakchance, FName type, int flags)
+{
+ // Only set if damage is not yet initialized. This ensures that UDMF takes precedence over sector specials.
+ if (sector->damageamount == 0)
+ {
+ sector->damageamount = damage;
+ sector->damageinterval = MAX(1, interval);
+ sector->leakydamage = leakchance;
+ sector->damagetype = type;
+ sector->Flags = (sector->Flags & ~SECF_DAMAGEFLAGS) | (flags & SECF_DAMAGEFLAGS);
+ }
+}
+
+//
+// P_InitSectorSpecial
+//
+// Sets up everything derived from 'sector->special' for one sector
+// ('fromload' is necessary to allow conversion upon savegame load.)
+//
+
+void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers)
+{
+ // [RH] All secret sectors are marked with a BOOM-ish bitfield
+ if (sector->special & SECRET_MASK)
+ {
+ sector->Flags |= SECF_SECRET | SECF_WASSECRET;
+ level.total_secrets++;
+ }
+ if (sector->special & FRICTION_MASK)
+ {
+ sector->Flags |= SECF_FRICTION;
+ }
+ if (sector->special & PUSH_MASK)
+ {
+ sector->Flags |= SECF_PUSH;
+ }
+ if ((sector->special & DAMAGE_MASK) == 0x100)
+ {
+ P_SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0);
+ }
+ else if ((sector->special & DAMAGE_MASK) == 0x200)
+ {
+ P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0);
+ }
+ else if ((sector->special & DAMAGE_MASK) == 0x300)
+ {
+ P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
+ }
+ sector->special &= 0xff;
+
+ // [RH] Normal DOOM special or BOOM specialized?
+ bool keepspecial = false;
+ switch (sector->special)
+ {
+ case Light_Phased:
+ if (!nothinkers) new DPhased (sector, 48, 63 - (sector->lightlevel & 63));
+ break;
+
+ // [RH] Hexen-like phased lighting
+ case LightSequenceStart:
+ if (!nothinkers) new DPhased (sector);
+ break;
+
+ case dLight_Flicker:
+ if (!nothinkers) new DLightFlash (sector);
+ break;
+
+ case dLight_StrobeFast:
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
+ break;
+
+ case dLight_StrobeSlow:
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false);
+ break;
+
+ case dLight_Strobe_Hurt:
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
+ P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
+ break;
+
+ case dDamage_Hellslime:
+ P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0);
+ break;
+
+ case dDamage_Nukage:
+ P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0);
+ break;
+
+ case dLight_Glow:
+ if (!nothinkers) new DGlow (sector);
+ break;
+
+ case dSector_DoorCloseIn30:
+ new DDoor(sector, DDoor::doorWaitClose, FRACUNIT * 2, 0, 0, 30 * TICRATE);
+ break;
+
+ case dDamage_End:
+ P_SetupSectorDamage(sector, 20, 32, 256, NAME_None, SECF_ENDGODMODE|SECF_ENDLEVEL);
+ break;
+
+ case dLight_StrobeSlowSync:
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true);
+ break;
+
+ case dLight_StrobeFastSync:
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, true);
+ break;
+
+ case dSector_DoorRaiseIn5Mins:
+ new DDoor (sector, DDoor::doorWaitRaise, 2*FRACUNIT, TICRATE*30/7, 5*60*TICRATE, 0);
+ break;
+
+ case dFriction_Low:
+ sector->friction = FRICTION_LOW;
+ sector->movefactor = 0x269;
+ sector->Flags |= SECF_FRICTION;
+ break;
+
+ case dDamage_SuperHellslime:
+ P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
+ break;
+
+ case dLight_FireFlicker:
+ if (!nothinkers) new DFireFlicker (sector);
+ break;
+
+ case dDamage_LavaWimpy:
+ P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
+ break;
+
+ case dDamage_LavaHefty:
+ P_SetupSectorDamage(sector, 8, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
+ break;
+
+ case dScroll_EastLavaDamage:
+ P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
+ if (!nothinkers)
+ {
+ new DStrobe(sector, STROBEBRIGHT, FASTDARK, false);
+ new DScroller(DScroller::sc_floor, -((FRACUNIT / 2) << 3),
+ 0, -1, int(sector - sectors), 0);
+ }
+ keepspecial = true;
+ break;
+
+ case hDamage_Sludge:
+ P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, 0);
+ break;
+
+ case sLight_Strobe_Hurt:
+ P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0);
+ if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
+ break;
+
+ case sDamage_Hellslime:
+ P_SetupSectorDamage(sector, 2, 32, 0, NAME_Slime, SECF_HAZARD);
+ break;
+
+ case Damage_InstantDeath:
+ // Strife's instant death sector
+ P_SetupSectorDamage(sector, TELEFRAG_DAMAGE, 1, 256, NAME_InstantDeath, 0);
+ break;
+
+ case sDamage_SuperHellslime:
+ P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, SECF_HAZARD);
+ break;
+
+ case Sector_Hidden:
+ sector->MoreFlags |= SECF_HIDDEN;
+ break;
+
+ case Sector_Heal:
+ // CoD's healing sector
+ P_SetupSectorDamage(sector, -1, 32, 0, NAME_None, 0);
+ break;
+
+ case Sky2:
+ sector->sky = PL_SKYFLAT;
+ break;
+
+ default:
+ if (sector->special >= Scroll_North_Slow &&
+ sector->special <= Scroll_SouthWest_Fast)
+ { // Hexen scroll special
+ static const char hexenScrollies[24][2] =
+ {
+ { 0, 1 }, { 0, 2 }, { 0, 4 },
+ { -1, 0 }, { -2, 0 }, { -4, 0 },
+ { 0, -1 }, { 0, -2 }, { 0, -4 },
+ { 1, 0 }, { 2, 0 }, { 4, 0 },
+ { 1, 1 }, { 2, 2 }, { 4, 4 },
+ { -1, 1 }, { -2, 2 }, { -4, 4 },
+ { -1, -1 }, { -2, -2 }, { -4, -4 },
+ { 1, -1 }, { 2, -2 }, { 4, -4 }
+ };
+
+
+ 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);
+ }
+ 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,
+ (-FRACUNIT/2)<<(sector->special - Carry_East5),
+ 0, -1, int(sector-sectors), 0);
+ }
+ keepspecial = true;
+ break;
+ }
+ if (!keepspecial) sector->special = 0;
+}
+
+//
+// P_SpawnSpecials
+//
+// After the map has been loaded, scan for specials that spawn thinkers
+//
+
+void P_SpawnSpecials (void)
+{
+ sector_t *sector;
+ int i;
+
+ P_SetupPortals();
+
+ // Init special SECTORs.
+ sector = sectors;
+
+ for (i = 0; i < numsectors; i++, sector++)
+ {
+ if (sector->special == 0)
+ continue;
+
+ P_InitSectorSpecial(sector, sector->special, false);
+ }
+
+#ifndef NO_EDATA
+ ProcessEDSectors();
+#endif
+
+
+ // Init other misc stuff
+
+ P_SpawnScrollers(); // killough 3/7/98: Add generalized scrollers
+ P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs
+ P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs
+
+ TThinkerIterator it2;
+ ASkyCamCompat *pt2;
+ while ((pt2 = it2.Next()))
+ {
+ P_SpawnSkybox(pt2);
+ }
+
+ for (i = 0; i < numlines; i++)
+ {
+ switch (lines[i].special)
+ {
+ int s;
+ sector_t *sec;
+
+ // killough 3/7/98:
+ // support for drawn heights coming from different sector
+ case Transfer_Heights:
+ {
+ sec = lines[i].frontsector;
+ if (lines[i].args[1] & 2)
+ {
+ sec->MoreFlags |= SECF_FAKEFLOORONLY;
+ }
+ if (lines[i].args[1] & 4)
+ {
+ sec->MoreFlags |= SECF_CLIPFAKEPLANES;
+ }
+ if (lines[i].args[1] & 8)
+ {
+ sec->MoreFlags |= SECF_UNDERWATER;
+ }
+ else if (forcewater)
+ {
+ sec->MoreFlags |= SECF_FORCEDUNDERWATER;
+ }
+ if (lines[i].args[1] & 16)
+ {
+ sec->MoreFlags |= SECF_IGNOREHEIGHTSEC;
+ }
+ if (lines[i].args[1] & 32)
+ {
+ sec->MoreFlags |= SECF_NOFAKELIGHT;
+ }
+ FSectorTagIterator itr(lines[i].args[0]);
+ while ((s = itr.Next()) >= 0)
+ {
+ sectors[s].heightsec = sec;
+ sec->e->FakeFloor.Sectors.Push(§ors[s]);
+ sectors[s].AdjustFloorClip();
+ }
+ break;
+ }
+
+ // killough 3/16/98: Add support for setting
+ // floor lighting independently (e.g. lava)
+ case Transfer_FloorLight:
+ new DLightTransfer (lines[i].frontsector, lines[i].args[0], true);
+ break;
+
+ // killough 4/11/98: Add support for setting
+ // ceiling lighting independently
+ case Transfer_CeilingLight:
+ new DLightTransfer (lines[i].frontsector, lines[i].args[0], false);
+ break;
+
+ // [Graf Zahl] Add support for setting lighting
+ // per wall independently
+ case Transfer_WallLight:
+ new DWallLightTransfer (lines[i].frontsector, lines[i].args[0], lines[i].args[1]);
+ break;
+
+ case Sector_Attach3dMidtex:
+ P_Attach3dMidtexLinesToSector(lines[i].frontsector, lines[i].args[0], lines[i].args[1], !!lines[i].args[2]);
+ break;
+
+ case Sector_SetLink:
+ if (lines[i].args[0] == 0)
+ {
+ P_AddSectorLinks(lines[i].frontsector, lines[i].args[1], lines[i].args[2], lines[i].args[3]);
+ }
+ break;
+
+ case Sector_SetPortal:
+ // arg 0 = sector tag
+ // arg 1 = type
+ // - 0: normal (handled here)
+ // - 1: copy (handled by the portal they copy)
+ // - 2: EE-style skybox (handled by the camera object)
+ // - 3: EE-style flat portal (GZDoom HW renderer only for now)
+ // - 4: EE-style horizon portal (GZDoom HW renderer only for now)
+ // - 5: copy portal to line (GZDoom HW renderer only for now)
+ // - 6: linked portal
+ // other values reserved for later use
+ // arg 2 = 0:floor, 1:ceiling, 2:both
+ // arg 3 = 0: anchor, 1: reference line
+ // arg 4 = for the anchor only: alpha
+ if ((lines[i].args[1] == 0 || lines[i].args[1] == 6) && lines[i].args[3] == 0)
+ {
+ P_SpawnPortal(&lines[i], lines[i].args[0], lines[i].args[2], lines[i].args[4], lines[i].args[1]);
+ }
+ else if (lines[i].args[1] == 3 || lines[i].args[1] == 4)
+ {
+ line_t *line = &lines[i];
+ ASkyViewpoint *origin = Spawn(0, 0, 0, NO_REPLACE);
+ origin->Sector = line->frontsector;
+ origin->special1 = line->args[1] == 3? SKYBOX_PLANE:SKYBOX_HORIZON;
+
+ CopyPortal(line->args[0], line->args[2], origin, 0, true);
+ }
+ break;
+
+ case Line_SetPortal:
+ P_SpawnLinePortal(&lines[i]);
+ break;
+
+ // [RH] ZDoom Static_Init settings
+ case Static_Init:
+ switch (lines[i].args[1])
+ {
+ case Init_Gravity:
+ {
+ float grav = ((float)P_AproxDistance (lines[i].dx, lines[i].dy)) / (FRACUNIT * 100.0f);
+ FSectorTagIterator itr(lines[i].args[0]);
+ while ((s = itr.Next()) >= 0)
+ sectors[s].gravity = grav;
+ }
+ break;
+
+ //case Init_Color:
+ // handled in P_LoadSideDefs2()
+
+ case Init_Damage:
+ {
+ int damage = P_AproxDistance (lines[i].dx, lines[i].dy) >> FRACBITS;
+ FSectorTagIterator itr(lines[i].args[0]);
+ while ((s = itr.Next()) >= 0)
+ {
+ sector_t *sec = §ors[s];
+ sec->damageamount = damage;
+ sec->damagetype = NAME_None;
+ if (sec->damageamount < 20)
+ {
+ sec->leakydamage = 0;
+ sec->damageinterval = 32;
+ }
+ else if (sec->damageamount < 50)
+ {
+ sec->leakydamage = 5;
+ sec->damageinterval = 32;
+ }
+ else
+ {
+ sec->leakydamage = 256;
+ sec->damageinterval = 1;
+ }
+ }
+ }
+ break;
+
+ case Init_SectorLink:
+ if (lines[i].args[3] == 0)
+ P_AddSectorLinksByID(lines[i].frontsector, lines[i].args[0], lines[i].args[2]);
+ break;
+
+ // killough 10/98:
+ //
+ // Support for sky textures being transferred from sidedefs.
+ // Allows scrolling and other effects (but if scrolling is
+ // used, then the same sector tag needs to be used for the
+ // sky sector, the sky-transfer linedef, and the scroll-effect
+ // linedef). Still requires user to use F_SKY1 for the floor
+ // or ceiling texture, to distinguish floor and ceiling sky.
+
+ case Init_TransferSky:
+ {
+ FSectorTagIterator itr(lines[i].args[0]);
+ while ((s = itr.Next()) >= 0)
+ sectors[s].sky = (i + 1) | PL_SKYFLAT;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ // [RH] Start running any open scripts on this map
+ 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(§ors[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(§ors[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 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
+//
+// phares 3/12/98: Start of friction effects
+
+// As the player moves, friction is applied by decreasing the x and y
+// velocity values on each tic. By varying the percentage of decrease,
+// we can simulate muddy or icy conditions. In mud, the player slows
+// down faster. In ice, the player slows down more slowly.
+//
+// The amount of friction change is controlled by the length of a linedef
+// with type 223. A length < 100 gives you mud. A length > 100 gives you ice.
+//
+// Also, each sector where these effects are to take place is given a
+// new special type _______. Changing the type value at runtime allows
+// these effects to be turned on or off.
+//
+// Sector boundaries present problems. The player should experience these
+// friction changes only when his feet are touching the sector floor. At
+// sector boundaries where floor height changes, the player can find
+// himself still 'in' one sector, but with his feet at the floor level
+// of the next sector (steps up or down). To handle this, Thinkers are used
+// in icy/muddy sectors. These thinkers examine each object that is touching
+// their sectors, looking for players whose feet are at the same level as
+// their floors. Players satisfying this condition are given new friction
+// values that are applied by the player movement code later.
+
+//
+// killough 8/28/98:
+//
+// Completely redid code, which did not need thinkers, and which put a heavy
+// drag on CPU. Friction is now a property of sectors, NOT objects inside
+// them. All objects, not just players, are affected by it, if they touch
+// the sector's floor. Code simpler and faster, only calling on friction
+// calculations when an object needs friction considered, instead of doing
+// friction calculations on every sector during every tic.
+//
+// Although this -might- ruin Boom demo sync involving friction, it's the only
+// way, short of code explosion, to fix the original design bug. Fixing the
+// design bug in Boom's original friction code, while maintaining demo sync
+// under every conceivable circumstance, would double or triple code size, and
+// would require maintenance of buggy legacy code which is only useful for old
+// demos. Doom demos, which are more important IMO, are not affected by this
+// change.
+//
+// [RH] On the other hand, since I've given up on trying to maintain demo
+// sync between versions, these considerations aren't a big deal to me.
+//
+/////////////////////////////
+//
+// Initialize the sectors where friction is increased or decreased
+
+static void P_SpawnFriction(void)
+{
+ int i;
+ line_t *l = lines;
+
+ for (i = 0 ; i < numlines ; i++,l++)
+ {
+ if (l->special == Sector_SetFriction)
+ {
+ int length;
+
+ if (l->args[1])
+ { // [RH] Allow setting friction amount from parameter
+ length = l->args[1] <= 200 ? l->args[1] : 200;
+ }
+ else
+ {
+ length = P_AproxDistance(l->dx,l->dy)>>FRACBITS;
+ }
+
+ P_SetSectorFriction (l->args[0], length, false);
+ l->special = 0;
+ }
+ }
+}
+
+void P_SetSectorFriction (int tag, int amount, bool alterFlag)
+{
+ int s;
+ fixed_t friction, movefactor;
+
+ // An amount of 100 should result in a friction of
+ // ORIG_FRICTION (0xE800)
+ friction = (0x1EB8*amount)/0x80 + 0xD001;
+
+ // killough 8/28/98: prevent odd situations
+ friction = clamp(friction, 0, FRACUNIT);
+
+ // The following check might seem odd. At the time of movement,
+ // the move distance is multiplied by 'friction/0x10000', so a
+ // higher friction value actually means 'less friction'.
+ movefactor = FrictionToMoveFactor(friction);
+
+ FSectorTagIterator itr(tag);
+ while ((s = itr.Next()) >= 0)
+ {
+ // killough 8/28/98:
+ //
+ // Instead of spawning thinkers, which are slow and expensive,
+ // modify the sector's own friction values. Friction should be
+ // a property of sectors, not objects which reside inside them.
+ // Original code scanned every object in every friction sector
+ // on every tic, adjusting its friction, putting unnecessary
+ // drag on CPU. New code adjusts friction of sector only once
+ // at level startup, and then uses this friction value.
+
+ sectors[s].friction = friction;
+ sectors[s].movefactor = movefactor;
+ if (alterFlag)
+ {
+ // When used inside a script, the sectors' friction flags
+ // can be enabled and disabled at will.
+ if (friction == ORIG_FRICTION)
+ {
+ sectors[s].Flags &= ~SECF_FRICTION;
+ }
+ else
+ {
+ sectors[s].Flags |= SECF_FRICTION;
+ }
+ }
+ }
+}
+
+//
+// phares 3/12/98: End of friction effects
+//
+////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////
+//
+// PUSH/PULL EFFECT
+//
+// phares 3/20/98: Start of push/pull effects
+//
+// This is where push/pull effects are applied to objects in the sectors.
+//
+// There are four kinds of push effects
+//
+// 1) Pushing Away
+//
+// Pushes you away from a point source defined by the location of an
+// MT_PUSH Thing. The force decreases linearly with distance from the
+// source. This force crosses sector boundaries and is felt w/in a circle
+// whose center is at the MT_PUSH. The force is felt only if the point
+// MT_PUSH can see the target object.
+//
+// 2) Pulling toward
+//
+// Same as Pushing Away except you're pulled toward an MT_PULL point
+// source. This force crosses sector boundaries and is felt w/in a circle
+// whose center is at the MT_PULL. The force is felt only if the point
+// MT_PULL can see the target object.
+//
+// 3) Wind
+//
+// Pushes you in a constant direction. Full force above ground, half
+// force on the ground, nothing if you're below it (water).
+//
+// 4) Current
+//
+// Pushes you in a constant direction. No force above ground, full
+// force if on the ground or below it (water).
+//
+// The magnitude of the force is controlled by the length of a controlling
+// linedef. The force vector for types 3 & 4 is determined by the angle
+// of the linedef, and is constant.
+//
+// For each sector where these effects occur, the sector special type has
+// to have the PUSH_MASK bit set. If this bit is turned off by a switch
+// at run-time, the effect will not occur. The controlling sector for
+// types 1 & 2 is the sector containing the MT_PUSH/MT_PULL Thing.
+
+
+#define PUSH_FACTOR 7
+
+/////////////////////////////
+//
+// Add a push thinker to the thinker list
+
+DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle,
+ AActor *source, int affectee)
+{
+ m_Source = source;
+ m_Type = type;
+ if (l)
+ {
+ m_Xmag = l->dx>>FRACBITS;
+ m_Ymag = l->dy>>FRACBITS;
+ m_Magnitude = P_AproxDistance (m_Xmag, m_Ymag);
+ }
+ else
+ { // [RH] Allow setting magnitude and angle with parameters
+ ChangeValues (magnitude, angle);
+ }
+ if (source) // point source exist?
+ {
+ m_Radius = (m_Magnitude) << (FRACBITS+1); // where force goes to zero
+ m_X = m_Source->X();
+ m_Y = m_Source->Y();
+ }
+ m_Affectee = affectee;
+}
+
+int DPusher::CheckForSectorMatch (EPusher type, int tag)
+{
+ if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag))
+ return m_Affectee;
+ else
+ return -1;
+}
+
+
+/////////////////////////////
+//
+// T_Pusher looks for all objects that are inside the radius of
+// the effect.
+//
+void DPusher::Tick ()
+{
+ sector_t *sec;
+ AActor *thing;
+ msecnode_t *node;
+ int xspeed,yspeed;
+ int ht;
+
+ if (!var_pushers)
+ return;
+
+ sec = sectors + m_Affectee;
+
+ // Be sure the special sector type is still turned on. If so, proceed.
+ // Else, bail out; the sector type has been changed on us.
+
+ if (!(sec->Flags & SECF_PUSH))
+ return;
+
+ // For constant pushers (wind/current) there are 3 situations:
+ //
+ // 1) Affected Thing is above the floor.
+ //
+ // Apply the full force if wind, no force if current.
+ //
+ // 2) Affected Thing is on the ground.
+ //
+ // Apply half force if wind, full force if current.
+ //
+ // 3) Affected Thing is below the ground (underwater effect).
+ //
+ // Apply no force if wind, full force if current.
+ //
+ // Apply the effect to clipped players only for now.
+ //
+ // In Phase II, you can apply these effects to Things other than players.
+ // [RH] No Phase II, but it works with anything having MF2_WINDTHRUST now.
+
+ if (m_Type == p_push)
+ {
+ // Seek out all pushable things within the force radius of this
+ // point pusher. Crosses sectors, so use blockmap.
+
+ FPortalGroupArray check(FPortalGroupArray::PGA_NoSectorPortals); // no sector portals because this thing is utterly z-unaware.
+ FMultiBlockThingsIterator it(check, m_X, m_Y, 0, 0, m_Radius);
+ FMultiBlockThingsIterator::CheckResult cres;
+
+
+ while (it.Next(&cres))
+ {
+ AActor *thing = cres.thing;
+ // Normal ZDoom is based only on the WINDTHRUST flag, with the noclip cheat as an exemption.
+ bool pusharound = ((thing->flags2 & MF2_WINDTHRUST) && !(thing->flags & MF_NOCLIP));
+
+ // MBF allows any sentient or shootable thing to be affected, but players with a fly cheat aren't.
+ if (compatflags & COMPATF_MBFMONSTERMOVE)
+ {
+ pusharound = ((pusharound || (thing->IsSentient()) || (thing->flags & MF_SHOOTABLE)) // Add categories here
+ && (!(thing->player && (thing->flags & (MF_NOGRAVITY))))); // Exclude flying players here
+ }
+
+ if ((pusharound) )
+ {
+ int sx = m_X;
+ int sy = m_Y;
+ int dist = thing->AproxDistance (sx, sy);
+ int speed = (m_Magnitude - ((dist>>FRACBITS)>>1))<<(FRACBITS-PUSH_FACTOR-1);
+
+ // If speed <= 0, you're outside the effective radius. You also have
+ // to be able to see the push/pull source point.
+
+ if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY)))
+ {
+ angle_t pushangle = thing->AngleTo(sx, sy);
+ if (m_Source->GetClass()->TypeName == NAME_PointPusher)
+ pushangle += ANG180; // away
+ pushangle >>= ANGLETOFINESHIFT;
+ thing->velx += FixedMul (speed, finecosine[pushangle]);
+ thing->vely += FixedMul (speed, finesine[pushangle]);
+ }
+ }
+ }
+ return;
+ }
+
+ // constant pushers p_wind and p_current
+
+ node = sec->touching_thinglist; // things touching this sector
+ for ( ; node ; node = node->m_snext)
+ {
+ thing = node->m_thing;
+ if (!(thing->flags2 & MF2_WINDTHRUST) || (thing->flags & MF_NOCLIP))
+ continue;
+
+ sector_t *hsec = sec->GetHeightSec();
+ fixedvec3 pos = thing->PosRelative(sec);
+ if (m_Type == p_wind)
+ {
+ if (hsec == NULL)
+ { // NOT special water sector
+ if (thing->Z() > thing->floorz) // above ground
+ {
+ xspeed = m_Xmag; // full force
+ yspeed = m_Ymag;
+ }
+ else // on ground
+ {
+ xspeed = (m_Xmag)>>1; // half force
+ yspeed = (m_Ymag)>>1;
+ }
+ }
+ else // special water sector
+ {
+ ht = hsec->floorplane.ZatPoint(pos);
+ if (thing->Z() > ht) // above ground
+ {
+ xspeed = m_Xmag; // full force
+ yspeed = m_Ymag;
+ }
+ else if (thing->player->viewz < ht) // underwater
+ {
+ xspeed = yspeed = 0; // no force
+ }
+ else // wading in water
+ {
+ xspeed = (m_Xmag)>>1; // half force
+ yspeed = (m_Ymag)>>1;
+ }
+ }
+ }
+ else // p_current
+ {
+ const secplane_t *floor;
+
+ if (hsec == NULL)
+ { // NOT special water sector
+ floor = &sec->floorplane;
+ }
+ else
+ { // special water sector
+ floor = &hsec->floorplane;
+ }
+ if (thing->Z() > floor->ZatPoint(pos))
+ { // above ground
+ xspeed = yspeed = 0; // no force
+ }
+ else
+ { // on ground/underwater
+ xspeed = m_Xmag; // full force
+ yspeed = m_Ymag;
+ }
+ }
+ thing->velx += xspeed<<(FRACBITS-PUSH_FACTOR);
+ thing->vely += yspeed<<(FRACBITS-PUSH_FACTOR);
+ }
+}
+
+/////////////////////////////
+//
+// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing,
+// NULL otherwise.
+
+AActor *P_GetPushThing (int s)
+{
+ AActor* thing;
+ sector_t* sec;
+
+ sec = sectors + s;
+ thing = sec->thinglist;
+
+ while (thing &&
+ thing->GetClass()->TypeName != NAME_PointPusher &&
+ thing->GetClass()->TypeName != NAME_PointPuller)
+ {
+ thing = thing->snext;
+ }
+ return thing;
+}
+
+/////////////////////////////
+//
+// Initialize the sectors where pushers are present
+//
+
+static void P_SpawnPushers ()
+{
+ int i;
+ line_t *l = lines;
+ int s;
+
+ for (i = 0; i < numlines; i++, l++)
+ {
+ switch (l->special)
+ {
+ case Sector_SetWind: // wind
+ {
+ FSectorTagIterator itr(l->args[0]);
+ while ((s = itr.Next()) >= 0)
+ new DPusher(DPusher::p_wind, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s);
+ l->special = 0;
+ break;
+ }
+
+ case Sector_SetCurrent: // current
+ {
+ FSectorTagIterator itr(l->args[0]);
+ while ((s = itr.Next()) >= 0)
+ new DPusher(DPusher::p_current, l->args[3] ? l : NULL, l->args[1], l->args[2], NULL, s);
+ l->special = 0;
+ break;
+ }
+
+ case PointPush_SetForce: // push/pull
+ if (l->args[0]) { // [RH] Find thing by sector
+ FSectorTagIterator itr(l->args[0]);
+ while ((s = itr.Next()) >= 0)
+ {
+ AActor *thing = P_GetPushThing (s);
+ if (thing) { // No MT_P* means no effect
+ // [RH] Allow narrowing it down by tid
+ if (!l->args[1] || l->args[1] == thing->tid)
+ new DPusher (DPusher::p_push, l->args[3] ? l : NULL, l->args[2],
+ 0, thing, s);
+ }
+ }
+ } else { // [RH] Find thing by tid
+ AActor *thing;
+ FActorIterator iterator (l->args[1]);
+
+ while ( (thing = iterator.Next ()) )
+ {
+ if (thing->GetClass()->TypeName == NAME_PointPusher ||
+ thing->GetClass()->TypeName == NAME_PointPuller)
+ {
+ new DPusher (DPusher::p_push, l->args[3] ? l : NULL, l->args[2],
+ 0, thing, int(thing->Sector - sectors));
+ }
+ }
+ }
+ l->special = 0;
+ break;
+ }
+ }
+}
+
+//
+// phares 3/20/98: End of Pusher effects
+//
+////////////////////////////////////////////////////////////////////////////
+
+void sector_t::AdjustFloorClip () const
+{
+ msecnode_t *node;
+
+ for (node = touching_thinglist; node; node = node->m_snext)
+ {
+ if (node->m_thing->flags2 & MF2_FLOORCLIP)
+ {
+ node->m_thing->AdjustFloorClip();
+ }
+ }
+}
diff --git a/src/p_spec.h b/src/p_spec.h
index 0548a6b51..560ec9acd 100644
--- a/src/p_spec.h
+++ b/src/p_spec.h
@@ -165,8 +165,8 @@ void P_SpawnSpecials (void);
void P_UpdateSpecials (void);
// when needed
-bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType);
-bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType);
+bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType, fixedvec3 *optpos = NULL);
+bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType, fixedvec3 *optpos = NULL);
bool P_PredictLine (line_t *ld, AActor *mo, int side, int activationType);
void P_PlayerInSpecialSector (player_t *player, sector_t * sector=NULL);
@@ -404,7 +404,7 @@ void EV_StartLightFading (int tag, int value, int tics);
#define BUTTONTIME TICRATE // 1 second, in ticks.
bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *quest=NULL);
-bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno);
+bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno, fixedvec3 *optpos = NULL);
//
// P_PLATS
diff --git a/src/p_switch.cpp b/src/p_switch.cpp
index 0c9d37ccc..98630705c 100644
--- a/src/p_switch.cpp
+++ b/src/p_switch.cpp
@@ -112,7 +112,7 @@ static bool P_StartButton (side_t *side, int Where, FSwitchDef *Switch, fixed_t
//
//==========================================================================
-bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno)
+bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno, fixedvec3 *optpos)
{
// Activated from an empty side -> always succeed
side_t *side = line->sidedef[sideno];
@@ -140,7 +140,7 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno)
P_MakeDivline (line, &dll);
- fixedvec3 pos = user->PosRelative(line);
+ fixedvec3 pos = optpos? *optpos : user->PosRelative(line);
dlu.x = pos.x;
dlu.y = pos.y;
dlu.dx = finecosine[user->angle >> ANGLETOFINESHIFT];
diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp
index b7f9c4fd5..594ad7cc2 100644
--- a/src/p_teleport.cpp
+++ b/src/p_teleport.cpp
@@ -106,7 +106,6 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
fixedvec3 old;
fixed_t aboveFloor;
player_t *player;
- angle_t an;
sector_t *destsect;
bool resetpitch = false;
fixed_t floorheight, ceilingheight;
@@ -193,8 +192,9 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
if (!predicting)
{
fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
- an = angle >> ANGLETOFINESHIFT;
- P_SpawnTeleportFog(thing, x + 20 * finecosine[an], y + 20 * finesine[an], thing->Z() + fogDelta, false, true);
+ fixedvec2 vector = Vec2Angle(20 * FRACUNIT, angle);
+ fixedvec2 fogpos = P_GetOffsetPosition(x, y, vector.x, vector.y);
+ P_SpawnTeleportFog(thing, fogpos.x, fogpos.y, thing->Z() + fogDelta, false, true);
}
if (thing->player)
diff --git a/src/portal.cpp b/src/portal.cpp
index cd501513a..6f7192a52 100644
--- a/src/portal.cpp
+++ b/src/portal.cpp
@@ -277,7 +277,7 @@ void P_SpawnLinePortal(line_t* line)
for (int i = 0; i < numlines; i++)
{
- if (tagManager.GetFirstLineID(&lines[i]) == mytag && lines[i].args[0] == 1)
+ if (tagManager.GetFirstLineID(&lines[i]) == mytag && lines[i].args[0] == 1 && lines[i].special == Line_SetPortal)
{
line->portalindex = linePortals.Reserve(1);
FLinePortal *port = &linePortals.Last();
@@ -323,12 +323,6 @@ void P_UpdatePortal(FLinePortal *port)
// Portal has no destination: switch it off
port->mFlags = 0;
}
- else if ((port->mOrigin->backsector == NULL && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ)) ||
- (port->mDestination->backsector == NULL && !(port->mOrigin->sidedef[0]->Flags & WALLF_POLYOBJ)))
- {
- // disable teleporting capability if a portal is or links to a one-sided wall (unless part of a polyobject.)
- port->mFlags = PORTF_VISIBLE;
- }
else if (port->mDestination->getPortalDestination() != port->mOrigin)
{
//portal doesn't link back. This will be a simple teleporter portal.
@@ -562,24 +556,17 @@ void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y)
// Get the angle between the two linedefs, for rotating
// orientation and velocity. Rotate 180 degrees, and flip
// the position across the exit linedef, if reversed.
- angle_t angle =
- R_PointToAngle2(0, 0, dst->dx, dst->dy) -
- R_PointToAngle2(0, 0, src->dx, src->dy);
- angle += ANGLE_180;
-
- // Sine, cosine of angle adjustment
- fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
- fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
-
- fixed_t tx, ty;
+ double angle = atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx) + M_PI;
+ fixed_t s = FLOAT2FIXED(sin(angle));
+ fixed_t c = FLOAT2FIXED(cos(angle));
nposx = x - src->v1->x;
nposy = y - src->v1->y;
// Rotate position along normal to match exit linedef
- tx = FixedMul(nposx, c) - FixedMul(nposy, s);
- ty = FixedMul(nposy, c) + FixedMul(nposx, s);
+ fixed_t tx = FixedMul(nposx, c) - FixedMul(nposy, s);
+ fixed_t ty = FixedMul(nposy, c) + FixedMul(nposx, s);
tx += dst->v2->x;
ty += dst->v2->y;
@@ -596,15 +583,9 @@ void P_TranslatePortalXY(line_t* src, line_t* dst, fixed_t& x, fixed_t& y)
void P_TranslatePortalVXVY(line_t* src, line_t* dst, fixed_t& vx, fixed_t& vy)
{
- angle_t angle =
- R_PointToAngle2(0, 0, dst->dx, dst->dy) -
- R_PointToAngle2(0, 0, src->dx, src->dy);
-
- angle += ANGLE_180;
-
- // Sine, cosine of angle adjustment
- fixed_t s = finesine[angle>>ANGLETOFINESHIFT];
- fixed_t c = finecosine[angle>>ANGLETOFINESHIFT];
+ double angle = atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx) + M_PI;
+ fixed_t s = FLOAT2FIXED(sin(angle));
+ fixed_t c = FLOAT2FIXED(cos(angle));
fixed_t orig_velx = vx;
fixed_t orig_vely = vy;
@@ -626,12 +607,7 @@ void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle)
// Get the angle between the two linedefs, for rotating
// orientation and velocity. Rotate 180 degrees, and flip
// the position across the exit linedef, if reversed.
- angle_t xangle =
- R_PointToAngle2(0, 0, dst->dx, dst->dy) -
- R_PointToAngle2(0, 0, src->dx, src->dy);
-
- xangle += ANGLE_180;
- angle += xangle;
+ angle += RAD2ANGLE(atan2(dst->dy, dst->dx) - atan2(src->dy, src->dx)) + ANGLE_180;
}
//============================================================================
@@ -701,17 +677,17 @@ void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy)
//
//============================================================================
-fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy)
+fixedvec2 P_GetOffsetPosition(fixed_t x, fixed_t y, fixed_t dx, fixed_t dy)
{
- fixedvec2 dest = { actor->X() + dx, actor->Y() + dy };
+ fixedvec2 dest = { x + dx, y + dy };
if (PortalBlockmap.containsLines)
{
- fixed_t actx = actor->X(), acty = actor->Y();
+ fixed_t actx = x, acty = y;
// Try some easily discoverable early-out first. If we know that the trace cannot possibly find a portal, this saves us from calling the traverser completely for vast parts of the map.
if (dx < 128 * FRACUNIT && dy < 128 * FRACUNIT)
{
fixed_t blockx = GetSafeBlockX(actx - bmaporgx);
- fixed_t blocky = GetSafeBlockX(acty - bmaporgy);
+ fixed_t blocky = GetSafeBlockY(acty - bmaporgy);
if (blockx < 0 || blocky < 0 || blockx >= bmapwidth || blocky >= bmapheight || !PortalBlockmap(blockx, blocky).neighborContainsLines) return dest;
}
@@ -1117,87 +1093,157 @@ void P_CreateLinkedPortals()
//
//============================================================================
+
+static bool ProcessLayer()
+{
+}
+
bool P_CollectConnectedGroups(int startgroup, const fixedvec3 &position, fixed_t upperz, fixed_t checkradius, FPortalGroupArray &out)
{
// Keep this temporary work stuff static. This function can never be called recursively
// and this would have to be reallocated for each call otherwise.
static FPortalBits processMask;
static TArray foundPortals;
+ static TArray groupsToCheck;
bool retval = false;
out.inited = true;
- if (linkedPortals.Size() == 0)
+ if (linkedPortals.Size() != 0)
{
- // If there are no portals, all sectors are in group 0.
- return false;
- }
- processMask.setSize(linkedPortals.Size());
- processMask.clear();
- foundPortals.Clear();
+ processMask.setSize(linkedPortals.Size());
+ processMask.clear();
+ foundPortals.Clear();
- int thisgroup = startgroup;
- processMask.setBit(thisgroup);
- //out.Add(thisgroup);
+ int thisgroup = startgroup;
+ processMask.setBit(thisgroup);
+ //out.Add(thisgroup);
- for (unsigned i = 0; i < linkedPortals.Size(); i++)
- {
- line_t *ld = linkedPortals[i]->mOrigin;
- int othergroup = ld->frontsector->PortalGroup;
- FDisplacement &disp = Displacements(thisgroup, othergroup);
- if (!disp.isSet) continue; // no connection.
-
- FBoundingBox box(position.x + disp.pos.x, position.y + disp.pos.y, checkradius);
-
- if (box.Right() <= ld->bbox[BOXLEFT]
- || box.Left() >= ld->bbox[BOXRIGHT]
- || box.Top() <= ld->bbox[BOXBOTTOM]
- || box.Bottom() >= ld->bbox[BOXTOP])
- continue; // not touched
-
- if (box.BoxOnLineSide(linkedPortals[i]->mOrigin) != -1) continue; // not touched
- foundPortals.Push(linkedPortals[i]);
- }
- bool foundone = true;
- while (foundone)
- {
- foundone = false;
- for (int i = foundPortals.Size() - 1; i >= 0; i--)
+ for (unsigned i = 0; i < linkedPortals.Size(); i++)
{
- if (processMask.getBit(foundPortals[i]->mOrigin->frontsector->PortalGroup) &&
- !processMask.getBit(foundPortals[i]->mDestination->frontsector->PortalGroup))
+ line_t *ld = linkedPortals[i]->mOrigin;
+ int othergroup = ld->frontsector->PortalGroup;
+ FDisplacement &disp = Displacements(thisgroup, othergroup);
+ if (!disp.isSet) continue; // no connection.
+
+ FBoundingBox box(position.x + disp.pos.x, position.y + disp.pos.y, checkradius);
+
+ if (box.Right() <= ld->bbox[BOXLEFT]
+ || box.Left() >= ld->bbox[BOXRIGHT]
+ || box.Top() <= ld->bbox[BOXBOTTOM]
+ || box.Bottom() >= ld->bbox[BOXTOP])
+ continue; // not touched
+
+ if (box.BoxOnLineSide(linkedPortals[i]->mOrigin) != -1) continue; // not touched
+ foundPortals.Push(linkedPortals[i]);
+ }
+ bool foundone = true;
+ while (foundone)
+ {
+ foundone = false;
+ for (int i = foundPortals.Size() - 1; i >= 0; i--)
{
- processMask.setBit(foundPortals[i]->mDestination->frontsector->PortalGroup);
- out.Add(foundPortals[i]->mDestination->frontsector->PortalGroup);
- foundone = true;
- retval = true;
- foundPortals.Delete(i);
+ if (processMask.getBit(foundPortals[i]->mOrigin->frontsector->PortalGroup) &&
+ !processMask.getBit(foundPortals[i]->mDestination->frontsector->PortalGroup))
+ {
+ processMask.setBit(foundPortals[i]->mDestination->frontsector->PortalGroup);
+ out.Add(foundPortals[i]->mDestination->frontsector->PortalGroup);
+ foundone = true;
+ retval = true;
+ foundPortals.Delete(i);
+ }
}
}
}
- sector_t *sec = P_PointInSector(position.x, position.y);
- sector_t *wsec = sec;
- while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold)
+ if (out.method != FPortalGroupArray::PGA_NoSectorPortals)
{
- sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector;
- fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup);
- fixed_t dx = position.x + pos.x;
- fixed_t dy = position.y + pos.y;
- processMask.setBit(othersec->PortalGroup);
- out.Add(othersec->PortalGroup|FPortalGroupArray::UPPER);
- wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat
- retval = true;
- }
- wsec = sec;
- while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold)
- {
- sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector;
- fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup);
- fixed_t dx = position.x + pos.x;
- fixed_t dy = position.y + pos.y;
- processMask.setBit(othersec->PortalGroup|FPortalGroupArray::LOWER);
- out.Add(othersec->PortalGroup);
- wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat
- retval = true;
+ sector_t *sec = P_PointInSector(position.x, position.y);
+ sector_t *wsec = sec;
+ while (!wsec->PortalBlocksMovement(sector_t::ceiling) && upperz > wsec->SkyBoxes[sector_t::ceiling]->threshold)
+ {
+ sector_t *othersec = wsec->SkyBoxes[sector_t::ceiling]->Sector;
+ fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup);
+ fixed_t dx = position.x + pos.x;
+ fixed_t dy = position.y + pos.y;
+ processMask.setBit(othersec->PortalGroup);
+ out.Add(othersec->PortalGroup | FPortalGroupArray::UPPER);
+ wsec = P_PointInSector(dx, dy); // get upper sector at the exact spot we want to check and repeat
+ retval = true;
+ }
+ wsec = sec;
+ while (!wsec->PortalBlocksMovement(sector_t::floor) && position.z < wsec->SkyBoxes[sector_t::floor]->threshold)
+ {
+ sector_t *othersec = wsec->SkyBoxes[sector_t::floor]->Sector;
+ fixedvec2 pos = Displacements.getOffset(startgroup, othersec->PortalGroup);
+ fixed_t dx = position.x + pos.x;
+ fixed_t dy = position.y + pos.y;
+ processMask.setBit(othersec->PortalGroup | FPortalGroupArray::LOWER);
+ out.Add(othersec->PortalGroup);
+ wsec = P_PointInSector(dx, dy); // get lower sector at the exact spot we want to check and repeat
+ retval = true;
+ }
+ if (out.method == FPortalGroupArray::PGA_Full3d)
+ {
+ groupsToCheck.Clear();
+ groupsToCheck.Push(startgroup);
+ int thisgroup = startgroup;
+ for (unsigned i = 0; i < groupsToCheck.Size();i++)
+ {
+ fixedvec2 disp = Displacements.getOffset(startgroup, thisgroup & ~FPortalGroupArray::FLAT);
+ FBoundingBox box(position.x + disp.x, position.y + disp.y, checkradius);
+ FBlockLinesIterator it(box);
+ line_t *ld;
+ while ((ld = it.Next()))
+ {
+ if (box.Right() <= ld->bbox[BOXLEFT]
+ || box.Left() >= ld->bbox[BOXRIGHT]
+ || box.Top() <= ld->bbox[BOXBOTTOM]
+ || box.Bottom() >= ld->bbox[BOXTOP])
+ continue;
+
+ if (box.BoxOnLineSide(ld) != -1)
+ continue;
+
+ if (!(thisgroup & FPortalGroupArray::LOWER))
+ {
+ for (int s = 0; s < 2; s++)
+ {
+ sector_t *sec = s ? ld->backsector : ld->frontsector;
+ if (sec && !(sec->PortalBlocksMovement(sector_t::ceiling)))
+ {
+ if (sec->SkyBoxes[sector_t::ceiling]->threshold < upperz)
+ {
+ int grp = sec->SkyBoxes[sector_t::ceiling]->Sector->PortalGroup;
+ if (!(processMask.getBit(grp)))
+ {
+ processMask.setBit(grp);
+ groupsToCheck.Push(grp | FPortalGroupArray::UPPER);
+ }
+ }
+ }
+ }
+ }
+ if (!(thisgroup & FPortalGroupArray::UPPER))
+ {
+ for (int s = 0; s < 2; s++)
+ {
+ sector_t *sec = s ? ld->backsector : ld->frontsector;
+ if (sec && !(sec->PortalBlocksMovement(sector_t::floor)))
+ {
+ if (sec->SkyBoxes[sector_t::floor]->threshold > position.z)
+ {
+ int grp = sec->SkyBoxes[sector_t::floor]->Sector->PortalGroup;
+ if (!(processMask.getBit(grp)))
+ {
+ processMask.setBit(grp);
+ groupsToCheck.Push(grp | FPortalGroupArray::LOWER);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
return retval;
}
diff --git a/src/portal.h b/src/portal.h
index ef8cec98a..127a9ec3b 100644
--- a/src/portal.h
+++ b/src/portal.h
@@ -198,6 +198,6 @@ void P_TranslatePortalAngle(line_t* src, line_t* dst, angle_t& angle);
void P_TranslatePortalZ(line_t* src, line_t* dst, fixed_t& z);
void P_NormalizeVXVY(fixed_t& vx, fixed_t& vy);
fixed_t P_PointLineDistance(line_t* line, fixed_t x, fixed_t y);
-fixedvec2 P_GetOffsetPosition(AActor *actor, fixed_t dx, fixed_t dy);
+fixedvec2 P_GetOffsetPosition(fixed_t x, fixed_t y, fixed_t dx, fixed_t dy);
#endif
\ No newline at end of file
diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h
index c0986b90a..beff4a33d 100644
--- a/src/posix/cocoa/i_common.h
+++ b/src/posix/cocoa/i_common.h
@@ -145,6 +145,10 @@ enum
static const NSOpenGLPixelFormatAttribute NSOpenGLPFAAllowOfflineRenderers = NSOpenGLPixelFormatAttribute(96);
+@interface NSWindow(SetCollectionBehavior)
+- (void)setCollectionBehavior:(NSUInteger)collectionBehavior;
+@end
+
#endif // prior to 10.5
@@ -182,6 +186,8 @@ typedef NSInteger NSApplicationActivationPolicy;
- (NSRect)convertRectToBacking:(NSRect)aRect;
@end
+static const NSWindowCollectionBehavior NSWindowCollectionBehaviorFullScreenAuxiliary = NSWindowCollectionBehavior(1 << 8);
+
#endif // prior to 10.7
#endif // COCOA_I_COMMON_INCLUDED
diff --git a/src/posix/cocoa/st_console.h b/src/posix/cocoa/st_console.h
index 6b6f01820..b2af7bade 100644
--- a/src/posix/cocoa/st_console.h
+++ b/src/posix/cocoa/st_console.h
@@ -89,6 +89,8 @@ private:
void ExpandTextView(float height);
void AddText(const PalEntry& color, const char* message);
+
+ void ScrollTextToBottom();
};
#endif // COCOA_ST_CONSOLE_INCLUDED
diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm
index b990b9b33..b59502398 100644
--- a/src/posix/cocoa/st_console.mm
+++ b/src/posix/cocoa/st_console.mm
@@ -94,7 +94,7 @@ FConsoleWindow::FConsoleWindow()
[textContainer setContainerSize:NSMakeSize(initialWidth, FLT_MAX)];
[textContainer setWidthTracksTextView:YES];
- [m_scrollView initWithFrame:NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight)];
+ [m_scrollView initWithFrame:initialRect];
[m_scrollView setBorderType:NSNoBorder];
[m_scrollView setHasVerticalScroller:YES];
[m_scrollView setHasHorizontalScroller:NO];
@@ -113,6 +113,12 @@ FConsoleWindow::FConsoleWindow()
[m_window center];
[m_window exitAppOnClose];
+ if (NSAppKitVersionNumber >= AppKit10_7)
+ {
+ // Do not allow fullscreen mode for this window
+ [m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
+ }
+
[[m_window contentView] addSubview:m_scrollView];
[m_window makeKeyAndOrderFront:nil];
@@ -182,10 +188,45 @@ void FConsoleWindow::ShowFatalError(const char* const message)
AddText(PalEntry(255, 255, 170), message);
AddText("\n");
+ ScrollTextToBottom();
+
[NSApp runModalForWindow:m_window];
}
+static const unsigned int THIRTY_FPS = 33; // milliseconds per update
+
+
+template
+struct TimedUpdater
+{
+ explicit TimedUpdater(const Function& function)
+ {
+ const unsigned int currentTime = I_MSTime();
+
+ if (currentTime - m_previousTime > interval)
+ {
+ m_previousTime = currentTime;
+
+ function();
+
+ [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
+ }
+ }
+
+ static unsigned int m_previousTime;
+};
+
+template
+unsigned int TimedUpdater::m_previousTime;
+
+template
+static void UpdateTimed(const Function& function)
+{
+ TimedUpdater dummy(function);
+}
+
+
void FConsoleWindow::AddText(const char* message)
{
PalEntry color(223, 223, 223);
@@ -274,15 +315,17 @@ void FConsoleWindow::AddText(const char* message)
if ([m_window isVisible])
{
- [m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)];
-
- [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
+ UpdateTimed([&]()
+ {
+ [m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)];
+ });
}
}
void FConsoleWindow::AddText(const PalEntry& color, const char* const message)
{
- NSString* const text = [NSString stringWithUTF8String:message];
+ NSString* const text = [NSString stringWithCString:message
+ encoding:NSISOLatin1StringEncoding];
NSDictionary* const attributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSFont systemFontOfSize:14.0f], NSFontAttributeName,
@@ -298,6 +341,14 @@ void FConsoleWindow::AddText(const PalEntry& color, const char* const message)
}
+void FConsoleWindow::ScrollTextToBottom()
+{
+ [m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)];
+
+ [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
+}
+
+
void FConsoleWindow::SetTitleText()
{
static const CGFloat TITLE_TEXT_HEIGHT = 32.0f;
@@ -337,7 +388,12 @@ void FConsoleWindow::SetProgressBar(const bool visible)
{
ExpandTextView(-PROGRESS_BAR_HEIGHT);
- m_progressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(2.0f, 0.0f, 508.0f, 16.0f)];
+ static const CGFloat PROGRESS_BAR_X = 2.0f;
+ const NSRect PROGRESS_BAR_RECT = NSMakeRect(
+ PROGRESS_BAR_X, 0.0f,
+ [m_window frame].size.width - PROGRESS_BAR_X * 2, 16.0f);
+
+ m_progressBar = [[NSProgressIndicator alloc] initWithFrame:PROGRESS_BAR_RECT];
[m_progressBar setIndeterminate:NO];
[m_progressBar setAutoresizingMask:NSViewWidthSizable];
@@ -370,18 +426,11 @@ void FConsoleWindow::Progress(const int current, const int maximum)
return;
}
- static unsigned int previousTime = I_MSTime();
- unsigned int currentTime = I_MSTime();
-
- if (currentTime - previousTime > 33) // approx. 30 FPS
+ UpdateTimed([&]()
{
- previousTime = currentTime;
-
[m_progressBar setMaxValue:maximum];
[m_progressBar setDoubleValue:current];
-
- [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
- }
+ });
}
@@ -447,6 +496,8 @@ void FConsoleWindow::NetInit(const char* const message, const int playerCount)
[m_window setFrame:windowRect display:YES];
[[m_window contentView] addSubview:m_netView];
+
+ ScrollTextToBottom();
}
[m_netMessageText setStringValue:[NSString stringWithUTF8String:message]];
diff --git a/src/r_defs.h b/src/r_defs.h
index 088d253d1..9300ce71f 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -1,1409 +1,1409 @@
-// 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.
-//
-// DESCRIPTION:
-// Refresh/rendering module, shared data struct definitions.
-//
-//-----------------------------------------------------------------------------
-
-
-#ifndef __R_DEFS_H__
-#define __R_DEFS_H__
-
-#include "doomdef.h"
-#include "templates.h"
-#include "memarena.h"
-
-// Some more or less basic data types
-// we depend on.
-#include "m_fixed.h"
-
-// We rely on the thinker data struct
-// to handle sound origins in sectors.
-// SECTORS do store MObjs anyway.
-#include "actor.h"
-struct FLightNode;
-struct FGLSection;
-struct seg_t;
-
-#include "dthinker.h"
-
-#define MAXWIDTH 5760
-#define MAXHEIGHT 3600
-
-const WORD NO_INDEX = 0xffffu;
-const DWORD NO_SIDE = 0xffffffffu;
-
-// Silhouette, needed for clipping Segs (mainly)
-// and sprites representing things.
-enum
-{
- SIL_NONE,
- SIL_BOTTOM,
- SIL_TOP,
- SIL_BOTH
-};
-
-extern size_t MaxDrawSegs;
-struct FDisplacement;
-
-
-enum
-{
- SKYBOX_ANCHOR = -1,
- SKYBOX_SKYVIEWPOINT = 0, // a regular skybox
- SKYBOX_STACKEDSECTORTHING, // stacked sectors with the thing method
- SKYBOX_PORTAL, // stacked sectors with Sector_SetPortal
- SKYBOX_LINKEDPORTAL, // linked portal (interactive)
- SKYBOX_PLANE, // EE-style plane portal (not implemented in SW renderer)
- SKYBOX_HORIZON, // EE-style horizon portal (not implemented in SW renderer)
-};
-
-
-//
-// INTERNAL MAP TYPES
-// used by play and refresh
-//
-
-//
-// Your plain vanilla vertex.
-// Note: transformed values not buffered locally,
-// like some DOOM-alikes ("wt", "WebView") did.
-//
-enum
-{
- VERTEXFLAG_ZCeilingEnabled = 0x01,
- VERTEXFLAG_ZFloorEnabled = 0x02
-};
-struct vertexdata_t
-{
- fixed_t zCeiling, zFloor;
- DWORD flags;
-};
-struct vertex_t
-{
- fixed_t x, y;
-
- float fx, fy; // Floating point coordinates of this vertex (excluding polyoblect translation!)
- angle_t viewangle; // precalculated angle for clipping
- int angletime; // recalculation time for view angle
- bool dirty; // something has changed and needs to be recalculated
- int numheights;
- int numsectors;
- sector_t ** sectors;
- float * heightlist;
-
- vertex_t()
- {
- x = y = 0;
- fx = fy = 0;
- angletime = 0;
- viewangle = 0;
- dirty = true;
- numheights = numsectors = 0;
- sectors = NULL;
- heightlist = NULL;
- }
-
- bool operator== (const vertex_t &other)
- {
- return x == other.x && y == other.y;
- }
-
- bool operator!= (const vertex_t &other)
- {
- return x != other.x || y != other.y;
- }
-
- void clear()
- {
- x = y = 0;
- }
-
- angle_t GetClipAngle();
-};
-
-// Forward of LineDefs, for Sectors.
-struct line_t;
-
-class player_t;
-class FScanner;
-class FBitmap;
-struct FCopyInfo;
-class DInterpolation;
-class FArchive;
-
-enum
-{
- UDMF_Line,
- UDMF_Side,
- UDMF_Sector,
- UDMF_Thing
-};
-
-
-struct FUDMFKey
-{
- enum
- {
- UDMF_Int,
- UDMF_Float,
- UDMF_String
- };
-
- FName Key;
- int Type;
- int IntVal;
- double FloatVal;
- FString StringVal;
-
- FUDMFKey()
- {
- }
-
- FUDMFKey& operator =(int val)
- {
- Type = UDMF_Int;
- IntVal = val;
- FloatVal = val;
- StringVal = "";
- return *this;
- }
-
- FUDMFKey& operator =(double val)
- {
- Type = UDMF_Float;
- IntVal = int(val);
- FloatVal = val;
- StringVal = "";
- return *this;
- }
-
- FUDMFKey& operator =(const FString &val)
- {
- Type = UDMF_String;
- IntVal = strtol(val.GetChars(), NULL, 0);
- FloatVal = strtod(val.GetChars(), NULL);
- StringVal = val;
- return *this;
- }
-
-};
-
-class FUDMFKeys : public TArray
-{
-public:
- void Sort();
- FUDMFKey *Find(FName key);
-};
-
-//
-// The SECTORS record, at runtime.
-// Stores things/mobjs.
-//
-class DSectorEffect;
-struct sector_t;
-struct line_t;
-struct FRemapTable;
-
-enum
-{
- SECSPAC_Enter = 1, // Trigger when player enters
- SECSPAC_Exit = 2, // Trigger when player exits
- SECSPAC_HitFloor = 4, // Trigger when player hits floor
- SECSPAC_HitCeiling = 8, // Trigger when player hits ceiling
- SECSPAC_Use = 16, // Trigger when player uses
- SECSPAC_UseWall = 32, // Trigger when player uses a wall
- SECSPAC_EyesDive = 64, // Trigger when player eyes go below fake floor
- SECSPAC_EyesSurface = 128, // Trigger when player eyes go above fake floor
- SECSPAC_EyesBelowC = 256, // Trigger when player eyes go below fake ceiling
- SECSPAC_EyesAboveC = 512, // Trigger when player eyes go above fake ceiling
- SECSPAC_HitFakeFloor= 1024, // Trigger when player hits fake floor
-};
-
-class ASectorAction : public AActor
-{
- DECLARE_CLASS (ASectorAction, AActor)
-public:
- ASectorAction (bool activatedByUse = false);
- void Destroy ();
- void BeginPlay ();
- void Activate (AActor *source);
- void Deactivate (AActor *source);
- bool TriggerAction(AActor *triggerer, int activationType);
- bool CanTrigger (AActor *triggerer) const;
- bool IsActivatedByUse() const;
-protected:
- virtual bool DoTriggerAction(AActor *triggerer, int activationType);
- bool CheckTrigger(AActor *triggerer) const;
-private:
- bool ActivatedByUse;
-};
-
-class ASkyViewpoint;
-
-struct secplane_t
-{
- // the plane is defined as a*x + b*y + c*z + d = 0
- // ic is 1/c, for faster Z calculations
-
- fixed_t a, b, c, d, ic;
-
- // Returns < 0 : behind; == 0 : on; > 0 : in front
- int PointOnSide (fixed_t x, fixed_t y, fixed_t z) const
- {
- return TMulScale16(a,x, b,y, c,z) + d;
- }
-
- // Returns the value of z at (0,0) This is used by the 3D floor code which does not handle slopes
- fixed_t Zat0 () const
- {
- return ic < 0 ? d : -d;
- }
-
- fixed_t ZatPoint(const fixedvec2 &spot) const
- {
- return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y));
- }
-
- fixed_t ZatPoint(const fixedvec3 &spot) const
- {
- return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y));
- }
-
- // Returns the value of z at (x,y)
- fixed_t ZatPoint (fixed_t x, fixed_t y) const
- {
- return FixedMul (ic, -d - DMulScale16 (a, x, b, y));
- }
-
- // Returns the value of z at (x,y) as a double
- double ZatPoint (double x, double y) const
- {
- return (d + a*x + b*y) * ic / (-65536.0 * 65536.0);
- }
-
- // Returns the value of z at vertex v
- fixed_t ZatPoint (const vertex_t *v) const
- {
- return FixedMul (ic, -d - DMulScale16 (a, v->x, b, v->y));
- }
-
- fixed_t ZatPoint (const AActor *ac) const
- {
- return FixedMul (ic, -d - DMulScale16 (a, ac->X(), b, ac->Y()));
- }
-
- // Returns the value of z at (x,y) if d is equal to dist
- fixed_t ZatPointDist (fixed_t x, fixed_t y, fixed_t dist) const
- {
- return FixedMul (ic, -dist - DMulScale16 (a, x, b, y));
- }
-
- // Returns the value of z at vertex v if d is equal to dist
- fixed_t ZatPointDist (const vertex_t *v, fixed_t dist)
- {
- return FixedMul (ic, -dist - DMulScale16 (a, v->x, b, v->y));
- }
-
- // Flips the plane's vertical orientiation, so that if it pointed up,
- // it will point down, and vice versa.
- void FlipVert ()
- {
- a = -a;
- b = -b;
- c = -c;
- d = -d;
- ic = -ic;
- }
-
- // Returns true if 2 planes are the same
- bool operator== (const secplane_t &other) const
- {
- return a == other.a && b == other.b && c == other.c && d == other.d;
- }
-
- // Returns true if 2 planes are different
- bool operator!= (const secplane_t &other) const
- {
- return a != other.a || b != other.b || c != other.c || d != other.d;
- }
-
- // Moves a plane up/down by hdiff units
- void ChangeHeight (fixed_t hdiff)
- {
- d = d - FixedMul (hdiff, c);
- }
-
- // Moves a plane up/down by hdiff units
- fixed_t GetChangedHeight (fixed_t hdiff)
- {
- return d - FixedMul (hdiff, c);
- }
-
- // Returns how much this plane's height would change if d were set to oldd
- fixed_t HeightDiff (fixed_t oldd) const
- {
- return FixedMul (oldd - d, ic);
- }
-
- // Returns how much this plane's height would change if d were set to oldd
- fixed_t HeightDiff (fixed_t oldd, fixed_t newd) const
- {
- return FixedMul (oldd - newd, ic);
- }
-
- fixed_t PointToDist (fixed_t x, fixed_t y, fixed_t z) const
- {
- return -TMulScale16 (a, x, y, b, z, c);
- }
-
- fixed_t PointToDist(fixedvec2 xy, fixed_t z) const
- {
- return -TMulScale16(a, xy.x, xy.y, b, z, c);
- }
-
- fixed_t PointToDist (const vertex_t *v, fixed_t z) const
- {
- return -TMulScale16 (a, v->x, b, v->y, z, c);
- }
-
- void SetAtHeight(fixed_t height, int ceiling)
- {
- a = b = 0;
- if (ceiling)
- {
- c = ic = -FRACUNIT;
- d = height;
- }
- else
- {
- c = ic = FRACUNIT;
- d = -height;
- }
- }
-
- bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const;
-
-};
-
-FArchive &operator<< (FArchive &arc, secplane_t &plane);
-
-
-#include "p_3dfloors.h"
-struct subsector_t;
-struct sector_t;
-struct side_t;
-extern bool gl_plane_reflection_i;
-struct FPortal;
-
-// Ceiling/floor flags
-enum
-{
- PLANEF_ABSLIGHTING = 1, // floor/ceiling light is absolute, not relative
- PLANEF_BLOCKED = 2, // can not be moved anymore.
- PLANEF_ADDITIVE = 4, // rendered additive
-
- // linked portal stuff
- PLANEF_NORENDER = 8,
- PLANEF_NOPASS = 16,
- PLANEF_BLOCKSOUND = 32,
- PLANEF_DISABLED = 64,
- PLANEF_OBSTRUCTED = 128, // if the portal plane is beyond the sector's floor or ceiling.
-};
-
-// Internal sector flags
-enum
-{
- SECF_FAKEFLOORONLY = 2, // when used as heightsec in R_FakeFlat, only copies floor
- SECF_CLIPFAKEPLANES = 4, // as a heightsec, clip planes to target sector's planes
- SECF_NOFAKELIGHT = 8, // heightsec does not change lighting
- SECF_IGNOREHEIGHTSEC= 16, // heightsec is only for triggering sector actions
- SECF_UNDERWATER = 32, // sector is underwater
- SECF_FORCEDUNDERWATER= 64, // sector is forced to be underwater
- SECF_UNDERWATERMASK = 32+64,
- SECF_DRAWN = 128, // sector has been drawn at least once
- SECF_HIDDEN = 256, // Do not draw on textured automap
- SECF_NOFLOORSKYBOX = 512, // force use of regular sky
- SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky (do not separate from NOFLOORSKYBOX!!!)
-};
-
-enum
-{
- SECF_SILENT = 1, // actors in sector make no noise
- SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector
- SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast.
- SECF_NORESPAWN = 8, // players can not respawn in this sector
- SECF_FRICTION = 16, // sector has friction enabled
- SECF_PUSH = 32, // pushers enabled
- SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.)
- SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage
- SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode
- SECF_ENDLEVEL = 512, // ends level when health goes below 10
- SECF_HAZARD = 1024, // Change to Strife's delayed damage handling.
-
- SECF_WASSECRET = 1 << 30, // a secret that was discovered
- SECF_SECRET = 1 << 31, // a secret sector
-
- SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD,
- SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags
- SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers
-};
-
-enum
-{
- PL_SKYFLAT = 0x40000000
-};
-
-struct FDynamicColormap;
-
-
-struct FLinkedSector
-{
- sector_t *Sector;
- int Type;
-};
-
-
-// this substructure contains a few sector properties that are stored in dynamic arrays
-// These must not be copied by R_FakeFlat etc. or bad things will happen.
-struct extsector_t
-{
- // Boom sector transfer information
- struct fakefloor
- {
- TArray Sectors;
- } FakeFloor;
-
- // 3DMIDTEX information
- struct midtex
- {
- struct plane
- {
- TArray AttachedSectors; // all sectors containing 3dMidtex lines attached to this sector
- TArray AttachedLines; // all 3dMidtex lines attached to this sector
- } Floor, Ceiling;
- } Midtex;
-
- // Linked sector information
- struct linked
- {
- struct plane
- {
- TArray Sectors;
- } Floor, Ceiling;
- } Linked;
-
- // 3D floors
- struct xfloor
- {
- TDeletingArray ffloors; // 3D floors in this sector
- TArray lightlist; // 3D light list
- TArray attached; // 3D floors attached to this sector
- } XFloor;
-
- TArray vertices;
-
- void Serialize(FArchive &arc);
-};
-
-struct FTransform
-{
- // killough 3/7/98: floor and ceiling texture offsets
- fixed_t xoffs, yoffs;
-
- // [RH] floor and ceiling texture scales
- fixed_t xscale, yscale;
-
- // [RH] floor and ceiling texture rotation
- angle_t angle;
-
- // base values
- fixed_t base_angle, base_yoffs;
-};
-
-struct secspecial_t
-{
- FNameNoInit damagetype; // [RH] Means-of-death for applied damage
- int damageamount; // [RH] Damage to do while standing on floor
- short special;
- short damageinterval; // Interval for damage application
- short leakydamage; // chance of leaking through radiation suit
- int Flags;
-
- secspecial_t()
- {
- Clear();
- }
-
- void Clear()
- {
- memset(this, 0, sizeof(*this));
- }
-};
-
-FArchive &operator<< (FArchive &arc, secspecial_t &p);
-
-struct sector_t
-{
- // Member functions
- bool IsLinked(sector_t *other, bool ceiling) const;
- fixed_t FindLowestFloorSurrounding (vertex_t **v) const;
- fixed_t FindHighestFloorSurrounding (vertex_t **v) const;
- fixed_t FindNextHighestFloor (vertex_t **v) const;
- fixed_t FindNextLowestFloor (vertex_t **v) const;
- fixed_t FindLowestCeilingSurrounding (vertex_t **v) const; // jff 2/04/98
- fixed_t FindHighestCeilingSurrounding (vertex_t **v) const; // jff 2/04/98
- fixed_t FindNextLowestCeiling (vertex_t **v) const; // jff 2/04/98
- fixed_t FindNextHighestCeiling (vertex_t **v) const; // jff 2/04/98
- fixed_t FindShortestTextureAround () const; // jff 2/04/98
- fixed_t FindShortestUpperAround () const; // jff 2/04/98
- sector_t *FindModelFloorSector (fixed_t floordestheight) const; // jff 2/04/98
- sector_t *FindModelCeilingSector (fixed_t floordestheight) const; // jff 2/04/98
- int FindMinSurroundingLight (int max) const;
- sector_t *NextSpecialSector (int type, sector_t *prev) const; // [RH]
- fixed_t FindLowestCeilingPoint (vertex_t **v) const;
- fixed_t FindHighestFloorPoint (vertex_t **v) const;
- void AdjustFloorClip () const;
- void SetColor(int r, int g, int b, int desat);
- void SetFade(int r, int g, int b);
- void ClosestPoint(fixed_t x, fixed_t y, fixed_t &ox, fixed_t &oy) const;
- int GetFloorLight () const;
- int GetCeilingLight () const;
- sector_t *GetHeightSec() const;
-
- DInterpolation *SetInterpolation(int position, bool attach);
-
- ASkyViewpoint *GetSkyBox(int which);
- void CheckPortalPlane(int plane);
-
- enum
- {
- floor,
- ceiling
- };
-
- struct splane
- {
- FTransform xform;
- int Flags;
- int Light;
- fixed_t alpha;
- FTextureID Texture;
- fixed_t TexZ;
- };
-
-
- splane planes[2];
-
- void SetXOffset(int pos, fixed_t o)
- {
- planes[pos].xform.xoffs = o;
- }
-
- void AddXOffset(int pos, fixed_t o)
- {
- planes[pos].xform.xoffs += o;
- }
-
- fixed_t GetXOffset(int pos) const
- {
- return planes[pos].xform.xoffs;
- }
-
- void SetYOffset(int pos, fixed_t o)
- {
- planes[pos].xform.yoffs = o;
- }
-
- void AddYOffset(int pos, fixed_t o)
- {
- planes[pos].xform.yoffs += o;
- }
-
- fixed_t GetYOffset(int pos, bool addbase = true) const
- {
- if (!addbase)
- {
- return planes[pos].xform.yoffs;
- }
- else
- {
- return planes[pos].xform.yoffs + planes[pos].xform.base_yoffs;
- }
- }
-
- void SetXScale(int pos, fixed_t o)
- {
- planes[pos].xform.xscale = o;
- }
-
- fixed_t GetXScale(int pos) const
- {
- return planes[pos].xform.xscale;
- }
-
- void SetYScale(int pos, fixed_t o)
- {
- planes[pos].xform.yscale = o;
- }
-
- fixed_t GetYScale(int pos) const
- {
- return planes[pos].xform.yscale;
- }
-
- void SetAngle(int pos, angle_t o)
- {
- planes[pos].xform.angle = o;
- }
-
- angle_t GetAngle(int pos, bool addbase = true) const
- {
- if (!addbase)
- {
- return planes[pos].xform.angle;
- }
- else
- {
- return planes[pos].xform.angle + planes[pos].xform.base_angle;
- }
- }
-
- void SetBase(int pos, fixed_t y, angle_t o)
- {
- planes[pos].xform.base_yoffs = y;
- planes[pos].xform.base_angle = o;
- }
-
- void SetAlpha(int pos, fixed_t o)
- {
- planes[pos].alpha = o;
- }
-
- fixed_t GetAlpha(int pos) const
- {
- return planes[pos].alpha;
- }
-
- int GetFlags(int pos) const
- {
- return planes[pos].Flags;
- }
-
- void ChangeFlags(int pos, int And, int Or)
- {
- planes[pos].Flags &= ~And;
- planes[pos].Flags |= Or;
- }
-
- int GetPlaneLight(int pos) const
- {
- return planes[pos].Light;
- }
-
- void SetPlaneLight(int pos, int level)
- {
- planes[pos].Light = level;
- }
-
- FTextureID GetTexture(int pos) const
- {
- return planes[pos].Texture;
- }
-
- void SetTexture(int pos, FTextureID tex, bool floorclip = true)
- {
- FTextureID old = planes[pos].Texture;
- planes[pos].Texture = tex;
- if (floorclip && pos == floor && tex != old) AdjustFloorClip();
- }
-
- fixed_t GetPlaneTexZ(int pos) const
- {
- return planes[pos].TexZ;
- }
-
- void SetVerticesDirty()
- {
- for (unsigned i = 0; i < e->vertices.Size(); i++) e->vertices[i]->dirty = true;
- }
-
- void SetAllVerticesDirty()
- {
- SetVerticesDirty();
- for (unsigned i = 0; i < e->FakeFloor.Sectors.Size(); i++) e->FakeFloor.Sectors[i]->SetVerticesDirty();
- for (unsigned i = 0; i < e->XFloor.attached.Size(); i++) e->XFloor.attached[i]->SetVerticesDirty();
- }
-
- void SetPlaneTexZ(int pos, fixed_t val, bool dirtify = false) // This mainly gets used by init code. The only place where it must set the vertex to dirty is the interpolation code.
- {
- planes[pos].TexZ = val;
- if (dirtify) SetAllVerticesDirty();
- }
-
- void ChangePlaneTexZ(int pos, fixed_t val)
- {
- planes[pos].TexZ += val;
- SetAllVerticesDirty();
- }
-
- static inline short ClampLight(int level)
- {
- return (short)clamp(level, SHRT_MIN, SHRT_MAX);
- }
-
- void ChangeLightLevel(int newval)
- {
- lightlevel = ClampLight(lightlevel + newval);
- }
-
- void SetLightLevel(int newval)
- {
- lightlevel = ClampLight(newval);
- }
-
- int GetLightLevel() const
- {
- return lightlevel;
- }
-
- secplane_t &GetSecPlane(int pos)
- {
- return pos == floor? floorplane:ceilingplane;
- }
-
- bool isSecret() const
- {
- return !!(Flags & SECF_SECRET);
- }
-
- bool wasSecret() const
- {
- return !!(Flags & SECF_WASSECRET);
- }
-
- void ClearSecret()
- {
- Flags &= ~SECF_SECRET;
- }
-
- void ClearSpecial()
- {
- // clears all variables that originate from 'special'. Used for sector type transferring thinkers
- special = 0;
- damageamount = 0;
- damageinterval = 0;
- damagetype = NAME_None;
- leakydamage = 0;
- Flags &= ~SECF_SPECIALFLAGS;
- }
-
- bool PortalBlocksView(int plane)
- {
- if (SkyBoxes[plane] == NULL) return true;
- if (SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return false;
- return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
- }
-
- bool PortalBlocksSight(int plane)
- {
- if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
- return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
- }
-
- bool PortalBlocksMovement(int plane)
- {
- if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
- return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
- }
-
- bool PortalBlocksSound(int plane)
- {
- if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
- return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
- }
-
- // These may only be called if the portal has been validated
- fixedvec2 FloorDisplacement()
- {
- return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup);
- }
-
- fixedvec2 CeilingDisplacement()
- {
- return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup);
- }
-
- int GetTerrain(int pos) const;
-
- void TransferSpecial(sector_t *model);
- void GetSpecial(secspecial_t *spec);
- void SetSpecial(const secspecial_t *spec);
- bool PlaneMoving(int pos);
-
- // Portal-aware height calculation
- fixed_t HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL);
- fixed_t LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL);
-
- fixed_t HighestCeilingAt(AActor *a, sector_t **resultsec = NULL)
- {
- return HighestCeilingAt(a->X(), a->Y(), resultsec);
- }
-
- fixed_t LowestFloorAt(AActor *a, sector_t **resultsec = NULL)
- {
- return LowestFloorAt(a->X(), a->Y(), resultsec);
- }
-
- fixed_t NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL);
- fixed_t NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, fixed_t steph = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL);
-
- fixed_t NextHighestCeilingAt(AActor *a, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL)
- {
- return NextHighestCeilingAt(a->X(), a->Y(), z, flags, resultsec, resultffloor);
- }
-
- fixed_t NextLowestFloorAt(AActor *a, fixed_t z, int flags, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL)
- {
- return NextLowestFloorAt(a->X(), a->Y(), z, flags, a->MaxStepHeight, resultsec, resultffloor);
- }
-
- // Member variables
- fixed_t CenterFloor () const { return floorplane.ZatPoint (centerspot); }
- fixed_t CenterCeiling () const { return ceilingplane.ZatPoint (centerspot); }
-
- // [RH] store floor and ceiling planes instead of heights
- secplane_t floorplane, ceilingplane;
-
- // [RH] give floor and ceiling even more properties
- FDynamicColormap *ColorMap; // [RH] Per-sector colormap
-
-
- TObjPtr SoundTarget;
-
- short special;
- short lightlevel;
- short seqType; // this sector's sound sequence
-
- int sky;
- FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this.
-
- fixedvec2 centerspot; // origin for any sounds played by the sector
- int validcount; // if == validcount, already checked
- AActor* thinglist; // list of mobjs in sector
-
- // killough 8/28/98: friction is a sector property, not an mobj property.
- // these fields used to be in AActor, but presented performance problems
- // when processed as mobj properties. Fix is to make them sector properties.
- fixed_t friction, movefactor;
-
- int terrainnum[2];
-
- // thinker_t for reversable actions
- TObjPtr floordata; // jff 2/22/98 make thinkers on
- TObjPtr ceilingdata; // floors, ceilings, lighting,
- TObjPtr lightingdata; // independent of one another
-
- enum
- {
- CeilingMove,
- FloorMove,
- CeilingScroll,
- FloorScroll
- };
- TObjPtr interpolations[4];
-
- BYTE soundtraversed; // 0 = untraversed, 1,2 = sndlines -1
- // jff 2/26/98 lockout machinery for stairbuilding
- SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally
- SWORD prevsec; // -1 or number of sector for previous step
- SWORD nextsec; // -1 or number of next step sector
-
- short linecount;
- struct line_t **lines; // [linecount] size
-
- // killough 3/7/98: support flat heights drawn at another sector's heights
- sector_t *heightsec; // other sector, or NULL if no other sector
-
- DWORD bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps
- // [RH] these can also be blend values if
- // the alpha mask is non-zero
-
- // list of mobjs that are at least partially in the sector
- // thinglist is a subset of touching_thinglist
- struct msecnode_t *touching_thinglist; // phares 3/14/98
-
- float gravity; // [RH] Sector gravity (1.0 is normal)
- FNameNoInit damagetype; // [RH] Means-of-death for applied damage
- int damageamount; // [RH] Damage to do while standing on floor
- short damageinterval; // Interval for damage application
- short leakydamage; // chance of leaking through radiation suit
-
- WORD ZoneNumber; // [RH] Zone this sector belongs to
- WORD MoreFlags; // [RH] Internal sector flags
- DWORD Flags; // Sector flags
-
- // [RH] Action specials for sectors. Like Skull Tag, but more
- // flexible in a Bloody way. SecActTarget forms a list of actors
- // joined by their tracer fields. When a potential sector action
- // occurs, SecActTarget's TriggerAction method is called.
- TObjPtr SecActTarget;
-
- // [RH] The sky box to render for this sector. NULL means use a
- // regular sky.
- TObjPtr SkyBoxes[2];
- int PortalGroup;
-
- int sectornum; // for comparing sector copies
-
- extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat.
-
- // GL only stuff starts here
- float reflect[2];
-
- bool transdoor; // For transparent door hacks
- fixed_t transdoorheight; // for transparent door hacks
- int subsectorcount; // list of subsectors
- subsector_t ** subsectors;
- FPortal * portals[2]; // floor and ceiling portals
- FLightNode * lighthead;
-
- enum
- {
- vbo_fakefloor = floor+2,
- vbo_fakeceiling = ceiling+2,
- };
-
- int vboindex[4]; // VBO indices of the 4 planes this sector uses during rendering
- fixed_t vboheight[2]; // Last calculated height for the 2 planes of this actual sector
- int vbocount[2]; // Total count of vertices belonging to this sector's planes
-
- float GetReflect(int pos) { return gl_plane_reflection_i? reflect[pos] : 0; }
- bool VBOHeightcheck(int pos) const { return vboheight[pos] == GetPlaneTexZ(pos); }
-
- enum
- {
- INVALIDATE_PLANES = 1,
- INVALIDATE_OTHER = 2
- };
-
-};
-
-FArchive &operator<< (FArchive &arc, sector_t::splane &p);
-
-
-struct ReverbContainer;
-struct zone_t
-{
- ReverbContainer *Environment;
-};
-
-
-//
-// The SideDef.
-//
-
-class DBaseDecal;
-
-enum
-{
- WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative
- WALLF_NOAUTODECALS = 2, // Do not attach impact decals to this wall
- WALLF_NOFAKECONTRAST = 4, // Don't do fake contrast for this wall in side_t::GetLightLevel
- WALLF_SMOOTHLIGHTING = 8, // Similar to autocontrast but applies to all angles.
- WALLF_CLIP_MIDTEX = 16, // Like the line counterpart, but only for this side.
- WALLF_WRAP_MIDTEX = 32, // Like the line counterpart, but only for this side.
- WALLF_POLYOBJ = 64, // This wall belongs to a polyobject.
- WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog.
-};
-
-struct side_t
-{
- enum ETexpart
- {
- top=0,
- mid=1,
- bottom=2
- };
- struct part
- {
- fixed_t xoffset;
- fixed_t yoffset;
- fixed_t xscale;
- fixed_t yscale;
- FTextureID texture;
- TObjPtr interpolation;
- //int Light;
- };
-
- sector_t* sector; // Sector the SideDef is facing.
- DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall
- part textures[3];
- line_t *linedef;
- //DWORD linenum;
- DWORD LeftSide, RightSide; // [RH] Group walls into loops
- WORD TexelLength;
- SWORD Light;
- BYTE Flags;
- int Index; // needed to access custom UDMF fields which are stored in loading order.
-
- int GetLightLevel (bool foggy, int baselight, bool noabsolute=false, int *pfakecontrast_usedbygzdoom=NULL) const;
-
- void SetLight(SWORD l)
- {
- Light = l;
- }
-
- FTextureID GetTexture(int which) const
- {
- return textures[which].texture;
- }
- void SetTexture(int which, FTextureID tex)
- {
- textures[which].texture = tex;
- }
-
- void SetTextureXOffset(int which, fixed_t offset)
- {
- textures[which].xoffset = offset;
- }
- void SetTextureXOffset(fixed_t offset)
- {
- textures[top].xoffset =
- textures[mid].xoffset =
- textures[bottom].xoffset = offset;
- }
- fixed_t GetTextureXOffset(int which) const
- {
- return textures[which].xoffset;
- }
- void AddTextureXOffset(int which, fixed_t delta)
- {
- textures[which].xoffset += delta;
- }
-
- void SetTextureYOffset(int which, fixed_t offset)
- {
- textures[which].yoffset = offset;
- }
- void SetTextureYOffset(fixed_t offset)
- {
- textures[top].yoffset =
- textures[mid].yoffset =
- textures[bottom].yoffset = offset;
- }
- fixed_t GetTextureYOffset(int which) const
- {
- return textures[which].yoffset;
- }
- void AddTextureYOffset(int which, fixed_t delta)
- {
- textures[which].yoffset += delta;
- }
-
- void SetTextureXScale(int which, fixed_t scale)
- {
- textures[which].xscale = scale == 0 ? FRACUNIT : scale;
- }
- void SetTextureXScale(fixed_t scale)
- {
- textures[top].xscale = textures[mid].xscale = textures[bottom].xscale = scale == 0 ? FRACUNIT : scale;
- }
- fixed_t GetTextureXScale(int which) const
- {
- return textures[which].xscale;
- }
- void MultiplyTextureXScale(int which, fixed_t delta)
- {
- textures[which].xscale = FixedMul(textures[which].xscale, delta);
- }
-
-
- void SetTextureYScale(int which, fixed_t scale)
- {
- textures[which].yscale = scale == 0 ? FRACUNIT : scale;
- }
- void SetTextureYScale(fixed_t scale)
- {
- textures[top].yscale = textures[mid].yscale = textures[bottom].yscale = scale == 0 ? FRACUNIT : scale;
- }
- fixed_t GetTextureYScale(int which) const
- {
- return textures[which].yscale;
- }
- void MultiplyTextureYScale(int which, fixed_t delta)
- {
- textures[which].yscale = FixedMul(textures[which].yscale, delta);
- }
-
- DInterpolation *SetInterpolation(int position);
- void StopInterpolation(int position);
-
- vertex_t *V1() const;
- vertex_t *V2() const;
-
- //For GL
- FLightNode * lighthead; // all blended lights that may affect this wall
-
- seg_t **segs; // all segs belonging to this sidedef in ascending order. Used for precise rendering
- int numsegs;
-
-};
-
-FArchive &operator<< (FArchive &arc, side_t::part &p);
-
-struct line_t
-{
- vertex_t *v1, *v2; // vertices, from v1 to v2
- fixed_t dx, dy; // precalculated v2 - v1 for side checking
- DWORD flags;
- DWORD activation; // activation type
- int special;
- fixed_t Alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque)
- int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width)
- side_t *sidedef[2];
- fixed_t bbox[4]; // bounding box, for the extent of the LineDef.
- sector_t *frontsector, *backsector;
- int validcount; // if == validcount, already checked
- int locknumber; // [Dusk] lock number for special
- unsigned portalindex;
- TObjPtr skybox;
-
- FLinePortal *getPortal() const
- {
- return portalindex >= linePortals.Size() ? (FLinePortal*)NULL : &linePortals[portalindex];
- }
-
- // returns true if the portal is crossable by actors
- bool isLinePortal() const
- {
- return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE);
- }
-
- // returns true if the portal needs to be handled by the renderer
- bool isVisualPortal() const
- {
- return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE);
- }
-
- line_t *getPortalDestination() const
- {
- return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination;
- }
-
- int getPortalAlignment() const
- {
- return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign;
- }
-};
-
-// phares 3/14/98
-//
-// Sector list node showing all sectors an object appears in.
-//
-// There are two threads that flow through these nodes. The first thread
-// starts at touching_thinglist in a sector_t and flows through the m_snext
-// links to find all mobjs that are entirely or partially in the sector.
-// The second thread starts at touching_sectorlist in a AActor and flows
-// through the m_tnext links to find all sectors a thing touches. This is
-// useful when applying friction or push effects to sectors. These effects
-// can be done as thinkers that act upon all objects touching their sectors.
-// As an mobj moves through the world, these nodes are created and
-// destroyed, with the links changed appropriately.
-//
-// For the links, NULL means top or end of list.
-
-struct msecnode_t
-{
- sector_t *m_sector; // a sector containing this object
- AActor *m_thing; // this object
- struct msecnode_t *m_tprev; // prev msecnode_t for this thing
- struct msecnode_t *m_tnext; // next msecnode_t for this thing
- struct msecnode_t *m_sprev; // prev msecnode_t for this sector
- struct msecnode_t *m_snext; // next msecnode_t for this sector
- bool visited; // killough 4/4/98, 4/7/98: used in search algorithms
-};
-
-struct FPolyNode;
-struct FMiniBSP;
-
-//
-// The LineSeg.
-//
-struct seg_t
-{
- vertex_t* v1;
- vertex_t* v2;
-
- side_t* sidedef;
- line_t* linedef;
-
- // Sector references. Could be retrieved from linedef, too.
- sector_t* frontsector;
- sector_t* backsector; // NULL for one-sided lines
-
- seg_t* PartnerSeg;
- subsector_t* Subsector;
-
- float sidefrac; // relative position of seg's ending vertex on owning sidedef
-};
-
-struct glsegextra_t
-{
- DWORD PartnerSeg;
- subsector_t *Subsector;
-};
-
-extern seg_t *segs;
-
-
-//
-// A SubSector.
-// References a Sector.
-// Basically, this is a list of LineSegs indicating the visible walls that
-// define (all or some) sides of a convex BSP leaf.
-//
-
-enum
-{
- SSECF_DEGENERATE = 1,
- SSECF_DRAWN = 2,
- SSECF_POLYORG = 4,
-};
-
-struct FPortalCoverage
-{
- DWORD * subsectors;
- int sscount;
-};
-
-struct subsector_t
-{
- sector_t *sector;
- FPolyNode *polys;
- FMiniBSP *BSP;
- seg_t *firstline;
- sector_t *render_sector;
- DWORD numlines;
- int flags;
-
- void BuildPolyBSP();
- // subsector related GL data
- FLightNode * lighthead; // Light nodes (blended and additive)
- int validcount;
- short mapsection;
- char hacked; // 1: is part of a render hack
- // 2: has one-sided walls
- FPortalCoverage portalcoverage[2];
-};
-
-
-
-
-//
-// BSP node.
-//
-struct node_t
-{
- // Partition line.
- fixed_t x;
- fixed_t y;
- fixed_t dx;
- fixed_t dy;
- fixed_t bbox[2][4]; // Bounding box for each child.
- float len;
- union
- {
- void *children[2]; // If bit 0 is set, it's a subsector.
- int intchildren[2]; // Used by nodebuilder.
- };
-};
-
-
-// An entire BSP tree.
-
-struct FMiniBSP
-{
- bool bDirty;
-
- TArray Nodes;
- TArray Segs;
- TArray Subsectors;
- TArray Verts;
-};
-
-
-
-//
-// OTHER TYPES
-//
-
-typedef BYTE lighttable_t; // This could be wider for >8 bit display.
-
-// This encapsulates the fields of vissprite_t that can be altered by AlterWeaponSprite
-struct visstyle_t
-{
- lighttable_t *colormap;
- fixed_t alpha;
- FRenderStyle RenderStyle;
-};
-
-
-//----------------------------------------------------------------------------------
-//
-// The playsim can use different nodes than the renderer so this is
-// not the same as R_PointInSubsector
-//
-//----------------------------------------------------------------------------------
-subsector_t *P_PointInSubsector(fixed_t x, fixed_t y);
-inline sector_t *P_PointInSector(fixed_t x, fixed_t y)
-{
- return P_PointInSubsector(x, y)->sector;
-}
-
-inline fixedvec3 AActor::PosRelative(const AActor *other) const
-{
- return __pos + Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup);
-}
-
-inline fixedvec3 AActor::PosRelative(sector_t *sec) const
-{
- return __pos + Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup);
-}
-
-inline fixedvec3 AActor::PosRelative(line_t *line) const
-{
- return __pos + Displacements.getOffset(Sector->PortalGroup, line->frontsector->PortalGroup);
-}
-
-inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL)
-{
- return pos + Displacements.getOffset(refsec->PortalGroup, line->frontsector->PortalGroup);
-}
-
-inline void AActor::ClearInterpolation()
-{
- PrevX = X();
- PrevY = Y();
- PrevZ = Z();
- PrevAngle = angle;
- if (Sector) PrevPortalGroup = Sector->PortalGroup;
- else PrevPortalGroup = 0;
-}
-
-
-#endif
+// 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.
+//
+// DESCRIPTION:
+// Refresh/rendering module, shared data struct definitions.
+//
+//-----------------------------------------------------------------------------
+
+
+#ifndef __R_DEFS_H__
+#define __R_DEFS_H__
+
+#include "doomdef.h"
+#include "templates.h"
+#include "memarena.h"
+
+// Some more or less basic data types
+// we depend on.
+#include "m_fixed.h"
+
+// We rely on the thinker data struct
+// to handle sound origins in sectors.
+// SECTORS do store MObjs anyway.
+#include "actor.h"
+struct FLightNode;
+struct FGLSection;
+struct seg_t;
+
+#include "dthinker.h"
+
+#define MAXWIDTH 5760
+#define MAXHEIGHT 3600
+
+const WORD NO_INDEX = 0xffffu;
+const DWORD NO_SIDE = 0xffffffffu;
+
+// Silhouette, needed for clipping Segs (mainly)
+// and sprites representing things.
+enum
+{
+ SIL_NONE,
+ SIL_BOTTOM,
+ SIL_TOP,
+ SIL_BOTH
+};
+
+extern size_t MaxDrawSegs;
+struct FDisplacement;
+
+
+enum
+{
+ SKYBOX_ANCHOR = -1,
+ SKYBOX_SKYVIEWPOINT = 0, // a regular skybox
+ SKYBOX_STACKEDSECTORTHING, // stacked sectors with the thing method
+ SKYBOX_PORTAL, // stacked sectors with Sector_SetPortal
+ SKYBOX_LINKEDPORTAL, // linked portal (interactive)
+ SKYBOX_PLANE, // EE-style plane portal (not implemented in SW renderer)
+ SKYBOX_HORIZON, // EE-style horizon portal (not implemented in SW renderer)
+};
+
+
+//
+// INTERNAL MAP TYPES
+// used by play and refresh
+//
+
+//
+// Your plain vanilla vertex.
+// Note: transformed values not buffered locally,
+// like some DOOM-alikes ("wt", "WebView") did.
+//
+enum
+{
+ VERTEXFLAG_ZCeilingEnabled = 0x01,
+ VERTEXFLAG_ZFloorEnabled = 0x02
+};
+struct vertexdata_t
+{
+ fixed_t zCeiling, zFloor;
+ DWORD flags;
+};
+struct vertex_t
+{
+ fixed_t x, y;
+
+ float fx, fy; // Floating point coordinates of this vertex (excluding polyoblect translation!)
+ angle_t viewangle; // precalculated angle for clipping
+ int angletime; // recalculation time for view angle
+ bool dirty; // something has changed and needs to be recalculated
+ int numheights;
+ int numsectors;
+ sector_t ** sectors;
+ float * heightlist;
+
+ vertex_t()
+ {
+ x = y = 0;
+ fx = fy = 0;
+ angletime = 0;
+ viewangle = 0;
+ dirty = true;
+ numheights = numsectors = 0;
+ sectors = NULL;
+ heightlist = NULL;
+ }
+
+ bool operator== (const vertex_t &other)
+ {
+ return x == other.x && y == other.y;
+ }
+
+ bool operator!= (const vertex_t &other)
+ {
+ return x != other.x || y != other.y;
+ }
+
+ void clear()
+ {
+ x = y = 0;
+ }
+
+ angle_t GetClipAngle();
+};
+
+// Forward of LineDefs, for Sectors.
+struct line_t;
+
+class player_t;
+class FScanner;
+class FBitmap;
+struct FCopyInfo;
+class DInterpolation;
+class FArchive;
+
+enum
+{
+ UDMF_Line,
+ UDMF_Side,
+ UDMF_Sector,
+ UDMF_Thing
+};
+
+
+struct FUDMFKey
+{
+ enum
+ {
+ UDMF_Int,
+ UDMF_Float,
+ UDMF_String
+ };
+
+ FName Key;
+ int Type;
+ int IntVal;
+ double FloatVal;
+ FString StringVal;
+
+ FUDMFKey()
+ {
+ }
+
+ FUDMFKey& operator =(int val)
+ {
+ Type = UDMF_Int;
+ IntVal = val;
+ FloatVal = val;
+ StringVal = "";
+ return *this;
+ }
+
+ FUDMFKey& operator =(double val)
+ {
+ Type = UDMF_Float;
+ IntVal = int(val);
+ FloatVal = val;
+ StringVal = "";
+ return *this;
+ }
+
+ FUDMFKey& operator =(const FString &val)
+ {
+ Type = UDMF_String;
+ IntVal = strtol(val.GetChars(), NULL, 0);
+ FloatVal = strtod(val.GetChars(), NULL);
+ StringVal = val;
+ return *this;
+ }
+
+};
+
+class FUDMFKeys : public TArray
+{
+public:
+ void Sort();
+ FUDMFKey *Find(FName key);
+};
+
+//
+// The SECTORS record, at runtime.
+// Stores things/mobjs.
+//
+class DSectorEffect;
+struct sector_t;
+struct line_t;
+struct FRemapTable;
+
+enum
+{
+ SECSPAC_Enter = 1, // Trigger when player enters
+ SECSPAC_Exit = 2, // Trigger when player exits
+ SECSPAC_HitFloor = 4, // Trigger when player hits floor
+ SECSPAC_HitCeiling = 8, // Trigger when player hits ceiling
+ SECSPAC_Use = 16, // Trigger when player uses
+ SECSPAC_UseWall = 32, // Trigger when player uses a wall
+ SECSPAC_EyesDive = 64, // Trigger when player eyes go below fake floor
+ SECSPAC_EyesSurface = 128, // Trigger when player eyes go above fake floor
+ SECSPAC_EyesBelowC = 256, // Trigger when player eyes go below fake ceiling
+ SECSPAC_EyesAboveC = 512, // Trigger when player eyes go above fake ceiling
+ SECSPAC_HitFakeFloor= 1024, // Trigger when player hits fake floor
+};
+
+class ASectorAction : public AActor
+{
+ DECLARE_CLASS (ASectorAction, AActor)
+public:
+ ASectorAction (bool activatedByUse = false);
+ void Destroy ();
+ void BeginPlay ();
+ void Activate (AActor *source);
+ void Deactivate (AActor *source);
+ bool TriggerAction(AActor *triggerer, int activationType);
+ bool CanTrigger (AActor *triggerer) const;
+ bool IsActivatedByUse() const;
+protected:
+ virtual bool DoTriggerAction(AActor *triggerer, int activationType);
+ bool CheckTrigger(AActor *triggerer) const;
+private:
+ bool ActivatedByUse;
+};
+
+class ASkyViewpoint;
+
+struct secplane_t
+{
+ // the plane is defined as a*x + b*y + c*z + d = 0
+ // ic is 1/c, for faster Z calculations
+
+ fixed_t a, b, c, d, ic;
+
+ // Returns < 0 : behind; == 0 : on; > 0 : in front
+ int PointOnSide (fixed_t x, fixed_t y, fixed_t z) const
+ {
+ return TMulScale16(a,x, b,y, c,z) + d;
+ }
+
+ // Returns the value of z at (0,0) This is used by the 3D floor code which does not handle slopes
+ fixed_t Zat0 () const
+ {
+ return ic < 0 ? d : -d;
+ }
+
+ fixed_t ZatPoint(const fixedvec2 &spot) const
+ {
+ return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y));
+ }
+
+ fixed_t ZatPoint(const fixedvec3 &spot) const
+ {
+ return FixedMul(ic, -d - DMulScale16(a, spot.x, b, spot.y));
+ }
+
+ // Returns the value of z at (x,y)
+ fixed_t ZatPoint (fixed_t x, fixed_t y) const
+ {
+ return FixedMul (ic, -d - DMulScale16 (a, x, b, y));
+ }
+
+ // Returns the value of z at (x,y) as a double
+ double ZatPoint (double x, double y) const
+ {
+ return (d + a*x + b*y) * ic / (-65536.0 * 65536.0);
+ }
+
+ // Returns the value of z at vertex v
+ fixed_t ZatPoint (const vertex_t *v) const
+ {
+ return FixedMul (ic, -d - DMulScale16 (a, v->x, b, v->y));
+ }
+
+ fixed_t ZatPoint (const AActor *ac) const
+ {
+ return FixedMul (ic, -d - DMulScale16 (a, ac->X(), b, ac->Y()));
+ }
+
+ // Returns the value of z at (x,y) if d is equal to dist
+ fixed_t ZatPointDist (fixed_t x, fixed_t y, fixed_t dist) const
+ {
+ return FixedMul (ic, -dist - DMulScale16 (a, x, b, y));
+ }
+
+ // Returns the value of z at vertex v if d is equal to dist
+ fixed_t ZatPointDist (const vertex_t *v, fixed_t dist)
+ {
+ return FixedMul (ic, -dist - DMulScale16 (a, v->x, b, v->y));
+ }
+
+ // Flips the plane's vertical orientiation, so that if it pointed up,
+ // it will point down, and vice versa.
+ void FlipVert ()
+ {
+ a = -a;
+ b = -b;
+ c = -c;
+ d = -d;
+ ic = -ic;
+ }
+
+ // Returns true if 2 planes are the same
+ bool operator== (const secplane_t &other) const
+ {
+ return a == other.a && b == other.b && c == other.c && d == other.d;
+ }
+
+ // Returns true if 2 planes are different
+ bool operator!= (const secplane_t &other) const
+ {
+ return a != other.a || b != other.b || c != other.c || d != other.d;
+ }
+
+ // Moves a plane up/down by hdiff units
+ void ChangeHeight (fixed_t hdiff)
+ {
+ d = d - FixedMul (hdiff, c);
+ }
+
+ // Moves a plane up/down by hdiff units
+ fixed_t GetChangedHeight (fixed_t hdiff)
+ {
+ return d - FixedMul (hdiff, c);
+ }
+
+ // Returns how much this plane's height would change if d were set to oldd
+ fixed_t HeightDiff (fixed_t oldd) const
+ {
+ return FixedMul (oldd - d, ic);
+ }
+
+ // Returns how much this plane's height would change if d were set to oldd
+ fixed_t HeightDiff (fixed_t oldd, fixed_t newd) const
+ {
+ return FixedMul (oldd - newd, ic);
+ }
+
+ fixed_t PointToDist (fixed_t x, fixed_t y, fixed_t z) const
+ {
+ return -TMulScale16 (a, x, y, b, z, c);
+ }
+
+ fixed_t PointToDist(fixedvec2 xy, fixed_t z) const
+ {
+ return -TMulScale16(a, xy.x, xy.y, b, z, c);
+ }
+
+ fixed_t PointToDist (const vertex_t *v, fixed_t z) const
+ {
+ return -TMulScale16 (a, v->x, b, v->y, z, c);
+ }
+
+ void SetAtHeight(fixed_t height, int ceiling)
+ {
+ a = b = 0;
+ if (ceiling)
+ {
+ c = ic = -FRACUNIT;
+ d = height;
+ }
+ else
+ {
+ c = ic = FRACUNIT;
+ d = -height;
+ }
+ }
+
+ bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const;
+
+};
+
+FArchive &operator<< (FArchive &arc, secplane_t &plane);
+
+
+#include "p_3dfloors.h"
+struct subsector_t;
+struct sector_t;
+struct side_t;
+extern bool gl_plane_reflection_i;
+struct FPortal;
+
+// Ceiling/floor flags
+enum
+{
+ PLANEF_ABSLIGHTING = 1, // floor/ceiling light is absolute, not relative
+ PLANEF_BLOCKED = 2, // can not be moved anymore.
+ PLANEF_ADDITIVE = 4, // rendered additive
+
+ // linked portal stuff
+ PLANEF_NORENDER = 8,
+ PLANEF_NOPASS = 16,
+ PLANEF_BLOCKSOUND = 32,
+ PLANEF_DISABLED = 64,
+ PLANEF_OBSTRUCTED = 128, // if the portal plane is beyond the sector's floor or ceiling.
+};
+
+// Internal sector flags
+enum
+{
+ SECF_FAKEFLOORONLY = 2, // when used as heightsec in R_FakeFlat, only copies floor
+ SECF_CLIPFAKEPLANES = 4, // as a heightsec, clip planes to target sector's planes
+ SECF_NOFAKELIGHT = 8, // heightsec does not change lighting
+ SECF_IGNOREHEIGHTSEC= 16, // heightsec is only for triggering sector actions
+ SECF_UNDERWATER = 32, // sector is underwater
+ SECF_FORCEDUNDERWATER= 64, // sector is forced to be underwater
+ SECF_UNDERWATERMASK = 32+64,
+ SECF_DRAWN = 128, // sector has been drawn at least once
+ SECF_HIDDEN = 256, // Do not draw on textured automap
+ SECF_NOFLOORSKYBOX = 512, // force use of regular sky
+ SECF_NOCEILINGSKYBOX = 1024, // force use of regular sky (do not separate from NOFLOORSKYBOX!!!)
+};
+
+enum
+{
+ SECF_SILENT = 1, // actors in sector make no noise
+ SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector
+ SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast.
+ SECF_NORESPAWN = 8, // players can not respawn in this sector
+ SECF_FRICTION = 16, // sector has friction enabled
+ SECF_PUSH = 32, // pushers enabled
+ SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.)
+ SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage
+ SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode
+ SECF_ENDLEVEL = 512, // ends level when health goes below 10
+ SECF_HAZARD = 1024, // Change to Strife's delayed damage handling.
+
+ SECF_WASSECRET = 1 << 30, // a secret that was discovered
+ SECF_SECRET = 1 << 31, // a secret sector
+
+ SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD,
+ SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags
+ SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers
+};
+
+enum
+{
+ PL_SKYFLAT = 0x40000000
+};
+
+struct FDynamicColormap;
+
+
+struct FLinkedSector
+{
+ sector_t *Sector;
+ int Type;
+};
+
+
+// this substructure contains a few sector properties that are stored in dynamic arrays
+// These must not be copied by R_FakeFlat etc. or bad things will happen.
+struct extsector_t
+{
+ // Boom sector transfer information
+ struct fakefloor
+ {
+ TArray Sectors;
+ } FakeFloor;
+
+ // 3DMIDTEX information
+ struct midtex
+ {
+ struct plane
+ {
+ TArray AttachedSectors; // all sectors containing 3dMidtex lines attached to this sector
+ TArray AttachedLines; // all 3dMidtex lines attached to this sector
+ } Floor, Ceiling;
+ } Midtex;
+
+ // Linked sector information
+ struct linked
+ {
+ struct plane
+ {
+ TArray Sectors;
+ } Floor, Ceiling;
+ } Linked;
+
+ // 3D floors
+ struct xfloor
+ {
+ TDeletingArray ffloors; // 3D floors in this sector
+ TArray lightlist; // 3D light list
+ TArray attached; // 3D floors attached to this sector
+ } XFloor;
+
+ TArray vertices;
+
+ void Serialize(FArchive &arc);
+};
+
+struct FTransform
+{
+ // killough 3/7/98: floor and ceiling texture offsets
+ fixed_t xoffs, yoffs;
+
+ // [RH] floor and ceiling texture scales
+ fixed_t xscale, yscale;
+
+ // [RH] floor and ceiling texture rotation
+ angle_t angle;
+
+ // base values
+ fixed_t base_angle, base_yoffs;
+};
+
+struct secspecial_t
+{
+ FNameNoInit damagetype; // [RH] Means-of-death for applied damage
+ int damageamount; // [RH] Damage to do while standing on floor
+ short special;
+ short damageinterval; // Interval for damage application
+ short leakydamage; // chance of leaking through radiation suit
+ int Flags;
+
+ secspecial_t()
+ {
+ Clear();
+ }
+
+ void Clear()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+FArchive &operator<< (FArchive &arc, secspecial_t &p);
+
+struct sector_t
+{
+ // Member functions
+ bool IsLinked(sector_t *other, bool ceiling) const;
+ fixed_t FindLowestFloorSurrounding (vertex_t **v) const;
+ fixed_t FindHighestFloorSurrounding (vertex_t **v) const;
+ fixed_t FindNextHighestFloor (vertex_t **v) const;
+ fixed_t FindNextLowestFloor (vertex_t **v) const;
+ fixed_t FindLowestCeilingSurrounding (vertex_t **v) const; // jff 2/04/98
+ fixed_t FindHighestCeilingSurrounding (vertex_t **v) const; // jff 2/04/98
+ fixed_t FindNextLowestCeiling (vertex_t **v) const; // jff 2/04/98
+ fixed_t FindNextHighestCeiling (vertex_t **v) const; // jff 2/04/98
+ fixed_t FindShortestTextureAround () const; // jff 2/04/98
+ fixed_t FindShortestUpperAround () const; // jff 2/04/98
+ sector_t *FindModelFloorSector (fixed_t floordestheight) const; // jff 2/04/98
+ sector_t *FindModelCeilingSector (fixed_t floordestheight) const; // jff 2/04/98
+ int FindMinSurroundingLight (int max) const;
+ sector_t *NextSpecialSector (int type, sector_t *prev) const; // [RH]
+ fixed_t FindLowestCeilingPoint (vertex_t **v) const;
+ fixed_t FindHighestFloorPoint (vertex_t **v) const;
+ void AdjustFloorClip () const;
+ void SetColor(int r, int g, int b, int desat);
+ void SetFade(int r, int g, int b);
+ void ClosestPoint(fixed_t x, fixed_t y, fixed_t &ox, fixed_t &oy) const;
+ int GetFloorLight () const;
+ int GetCeilingLight () const;
+ sector_t *GetHeightSec() const;
+
+ DInterpolation *SetInterpolation(int position, bool attach);
+
+ ASkyViewpoint *GetSkyBox(int which);
+ void CheckPortalPlane(int plane);
+
+ enum
+ {
+ floor,
+ ceiling
+ };
+
+ struct splane
+ {
+ FTransform xform;
+ int Flags;
+ int Light;
+ fixed_t alpha;
+ FTextureID Texture;
+ fixed_t TexZ;
+ };
+
+
+ splane planes[2];
+
+ void SetXOffset(int pos, fixed_t o)
+ {
+ planes[pos].xform.xoffs = o;
+ }
+
+ void AddXOffset(int pos, fixed_t o)
+ {
+ planes[pos].xform.xoffs += o;
+ }
+
+ fixed_t GetXOffset(int pos) const
+ {
+ return planes[pos].xform.xoffs;
+ }
+
+ void SetYOffset(int pos, fixed_t o)
+ {
+ planes[pos].xform.yoffs = o;
+ }
+
+ void AddYOffset(int pos, fixed_t o)
+ {
+ planes[pos].xform.yoffs += o;
+ }
+
+ fixed_t GetYOffset(int pos, bool addbase = true) const
+ {
+ if (!addbase)
+ {
+ return planes[pos].xform.yoffs;
+ }
+ else
+ {
+ return planes[pos].xform.yoffs + planes[pos].xform.base_yoffs;
+ }
+ }
+
+ void SetXScale(int pos, fixed_t o)
+ {
+ planes[pos].xform.xscale = o;
+ }
+
+ fixed_t GetXScale(int pos) const
+ {
+ return planes[pos].xform.xscale;
+ }
+
+ void SetYScale(int pos, fixed_t o)
+ {
+ planes[pos].xform.yscale = o;
+ }
+
+ fixed_t GetYScale(int pos) const
+ {
+ return planes[pos].xform.yscale;
+ }
+
+ void SetAngle(int pos, angle_t o)
+ {
+ planes[pos].xform.angle = o;
+ }
+
+ angle_t GetAngle(int pos, bool addbase = true) const
+ {
+ if (!addbase)
+ {
+ return planes[pos].xform.angle;
+ }
+ else
+ {
+ return planes[pos].xform.angle + planes[pos].xform.base_angle;
+ }
+ }
+
+ void SetBase(int pos, fixed_t y, angle_t o)
+ {
+ planes[pos].xform.base_yoffs = y;
+ planes[pos].xform.base_angle = o;
+ }
+
+ void SetAlpha(int pos, fixed_t o)
+ {
+ planes[pos].alpha = o;
+ }
+
+ fixed_t GetAlpha(int pos) const
+ {
+ return planes[pos].alpha;
+ }
+
+ int GetFlags(int pos) const
+ {
+ return planes[pos].Flags;
+ }
+
+ void ChangeFlags(int pos, int And, int Or)
+ {
+ planes[pos].Flags &= ~And;
+ planes[pos].Flags |= Or;
+ }
+
+ int GetPlaneLight(int pos) const
+ {
+ return planes[pos].Light;
+ }
+
+ void SetPlaneLight(int pos, int level)
+ {
+ planes[pos].Light = level;
+ }
+
+ FTextureID GetTexture(int pos) const
+ {
+ return planes[pos].Texture;
+ }
+
+ void SetTexture(int pos, FTextureID tex, bool floorclip = true)
+ {
+ FTextureID old = planes[pos].Texture;
+ planes[pos].Texture = tex;
+ if (floorclip && pos == floor && tex != old) AdjustFloorClip();
+ }
+
+ fixed_t GetPlaneTexZ(int pos) const
+ {
+ return planes[pos].TexZ;
+ }
+
+ void SetVerticesDirty()
+ {
+ for (unsigned i = 0; i < e->vertices.Size(); i++) e->vertices[i]->dirty = true;
+ }
+
+ void SetAllVerticesDirty()
+ {
+ SetVerticesDirty();
+ for (unsigned i = 0; i < e->FakeFloor.Sectors.Size(); i++) e->FakeFloor.Sectors[i]->SetVerticesDirty();
+ for (unsigned i = 0; i < e->XFloor.attached.Size(); i++) e->XFloor.attached[i]->SetVerticesDirty();
+ }
+
+ void SetPlaneTexZ(int pos, fixed_t val, bool dirtify = false) // This mainly gets used by init code. The only place where it must set the vertex to dirty is the interpolation code.
+ {
+ planes[pos].TexZ = val;
+ if (dirtify) SetAllVerticesDirty();
+ }
+
+ void ChangePlaneTexZ(int pos, fixed_t val)
+ {
+ planes[pos].TexZ += val;
+ SetAllVerticesDirty();
+ }
+
+ static inline short ClampLight(int level)
+ {
+ return (short)clamp(level, SHRT_MIN, SHRT_MAX);
+ }
+
+ void ChangeLightLevel(int newval)
+ {
+ lightlevel = ClampLight(lightlevel + newval);
+ }
+
+ void SetLightLevel(int newval)
+ {
+ lightlevel = ClampLight(newval);
+ }
+
+ int GetLightLevel() const
+ {
+ return lightlevel;
+ }
+
+ secplane_t &GetSecPlane(int pos)
+ {
+ return pos == floor? floorplane:ceilingplane;
+ }
+
+ bool isSecret() const
+ {
+ return !!(Flags & SECF_SECRET);
+ }
+
+ bool wasSecret() const
+ {
+ return !!(Flags & SECF_WASSECRET);
+ }
+
+ void ClearSecret()
+ {
+ Flags &= ~SECF_SECRET;
+ }
+
+ void ClearSpecial()
+ {
+ // clears all variables that originate from 'special'. Used for sector type transferring thinkers
+ special = 0;
+ damageamount = 0;
+ damageinterval = 0;
+ damagetype = NAME_None;
+ leakydamage = 0;
+ Flags &= ~SECF_SPECIALFLAGS;
+ }
+
+ bool PortalBlocksView(int plane)
+ {
+ if (SkyBoxes[plane] == NULL) return true;
+ if (SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return false;
+ return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
+ }
+
+ bool PortalBlocksSight(int plane)
+ {
+ if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
+ return !!(planes[plane].Flags & (PLANEF_NORENDER | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
+ }
+
+ bool PortalBlocksMovement(int plane)
+ {
+ if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
+ return !!(planes[plane].Flags & (PLANEF_NOPASS | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
+ }
+
+ bool PortalBlocksSound(int plane)
+ {
+ if (SkyBoxes[plane] == NULL || SkyBoxes[plane]->special1 != SKYBOX_LINKEDPORTAL) return true;
+ return !!(planes[plane].Flags & (PLANEF_BLOCKSOUND | PLANEF_DISABLED | PLANEF_OBSTRUCTED));
+ }
+
+ // These may only be called if the portal has been validated
+ fixedvec2 FloorDisplacement()
+ {
+ return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::floor]->Sector->PortalGroup);
+ }
+
+ fixedvec2 CeilingDisplacement()
+ {
+ return Displacements.getOffset(PortalGroup, SkyBoxes[sector_t::ceiling]->Sector->PortalGroup);
+ }
+
+ int GetTerrain(int pos) const;
+
+ void TransferSpecial(sector_t *model);
+ void GetSpecial(secspecial_t *spec);
+ void SetSpecial(const secspecial_t *spec);
+ bool PlaneMoving(int pos);
+
+ // Portal-aware height calculation
+ fixed_t HighestCeilingAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL);
+ fixed_t LowestFloorAt(fixed_t x, fixed_t y, sector_t **resultsec = NULL);
+
+ fixed_t HighestCeilingAt(AActor *a, sector_t **resultsec = NULL)
+ {
+ return HighestCeilingAt(a->X(), a->Y(), resultsec);
+ }
+
+ fixed_t LowestFloorAt(AActor *a, sector_t **resultsec = NULL)
+ {
+ return LowestFloorAt(a->X(), a->Y(), resultsec);
+ }
+
+ fixed_t NextHighestCeilingAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL);
+ fixed_t NextLowestFloorAt(fixed_t x, fixed_t y, fixed_t z, int flags = 0, fixed_t steph = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL);
+
+ fixed_t NextHighestCeilingAt(AActor *a, fixed_t z, int flags = 0, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL)
+ {
+ return NextHighestCeilingAt(a->X(), a->Y(), z, flags, resultsec, resultffloor);
+ }
+
+ fixed_t NextLowestFloorAt(AActor *a, fixed_t z, int flags, sector_t **resultsec = NULL, F3DFloor **resultffloor = NULL)
+ {
+ return NextLowestFloorAt(a->X(), a->Y(), z, flags, a->MaxStepHeight, resultsec, resultffloor);
+ }
+
+ // Member variables
+ fixed_t CenterFloor () const { return floorplane.ZatPoint (centerspot); }
+ fixed_t CenterCeiling () const { return ceilingplane.ZatPoint (centerspot); }
+
+ // [RH] store floor and ceiling planes instead of heights
+ secplane_t floorplane, ceilingplane;
+
+ // [RH] give floor and ceiling even more properties
+ FDynamicColormap *ColorMap; // [RH] Per-sector colormap
+
+
+ TObjPtr SoundTarget;
+
+ short special;
+ short lightlevel;
+ short seqType; // this sector's sound sequence
+
+ int sky;
+ FNameNoInit SeqName; // Sound sequence name. Setting seqType non-negative will override this.
+
+ fixedvec2 centerspot; // origin for any sounds played by the sector
+ int validcount; // if == validcount, already checked
+ AActor* thinglist; // list of mobjs in sector
+
+ // killough 8/28/98: friction is a sector property, not an mobj property.
+ // these fields used to be in AActor, but presented performance problems
+ // when processed as mobj properties. Fix is to make them sector properties.
+ fixed_t friction, movefactor;
+
+ int terrainnum[2];
+
+ // thinker_t for reversable actions
+ TObjPtr floordata; // jff 2/22/98 make thinkers on
+ TObjPtr ceilingdata; // floors, ceilings, lighting,
+ TObjPtr lightingdata; // independent of one another
+
+ enum
+ {
+ CeilingMove,
+ FloorMove,
+ CeilingScroll,
+ FloorScroll
+ };
+ TObjPtr interpolations[4];
+
+ BYTE soundtraversed; // 0 = untraversed, 1,2 = sndlines -1
+ // jff 2/26/98 lockout machinery for stairbuilding
+ SBYTE stairlock; // -2 on first locked -1 after thinker done 0 normally
+ SWORD prevsec; // -1 or number of sector for previous step
+ SWORD nextsec; // -1 or number of next step sector
+
+ short linecount;
+ struct line_t **lines; // [linecount] size
+
+ // killough 3/7/98: support flat heights drawn at another sector's heights
+ sector_t *heightsec; // other sector, or NULL if no other sector
+
+ DWORD bottommap, midmap, topmap; // killough 4/4/98: dynamic colormaps
+ // [RH] these can also be blend values if
+ // the alpha mask is non-zero
+
+ // list of mobjs that are at least partially in the sector
+ // thinglist is a subset of touching_thinglist
+ struct msecnode_t *touching_thinglist; // phares 3/14/98
+
+ float gravity; // [RH] Sector gravity (1.0 is normal)
+ FNameNoInit damagetype; // [RH] Means-of-death for applied damage
+ int damageamount; // [RH] Damage to do while standing on floor
+ short damageinterval; // Interval for damage application
+ short leakydamage; // chance of leaking through radiation suit
+
+ WORD ZoneNumber; // [RH] Zone this sector belongs to
+ WORD MoreFlags; // [RH] Internal sector flags
+ DWORD Flags; // Sector flags
+
+ // [RH] Action specials for sectors. Like Skull Tag, but more
+ // flexible in a Bloody way. SecActTarget forms a list of actors
+ // joined by their tracer fields. When a potential sector action
+ // occurs, SecActTarget's TriggerAction method is called.
+ TObjPtr SecActTarget;
+
+ // [RH] The sky box to render for this sector. NULL means use a
+ // regular sky.
+ TObjPtr SkyBoxes[2];
+ int PortalGroup;
+
+ int sectornum; // for comparing sector copies
+
+ extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat.
+
+ // GL only stuff starts here
+ float reflect[2];
+
+ bool transdoor; // For transparent door hacks
+ fixed_t transdoorheight; // for transparent door hacks
+ int subsectorcount; // list of subsectors
+ subsector_t ** subsectors;
+ FPortal * portals[2]; // floor and ceiling portals
+ FLightNode * lighthead;
+
+ enum
+ {
+ vbo_fakefloor = floor+2,
+ vbo_fakeceiling = ceiling+2,
+ };
+
+ int vboindex[4]; // VBO indices of the 4 planes this sector uses during rendering
+ fixed_t vboheight[2]; // Last calculated height for the 2 planes of this actual sector
+ int vbocount[2]; // Total count of vertices belonging to this sector's planes
+
+ float GetReflect(int pos) { return gl_plane_reflection_i? reflect[pos] : 0; }
+ bool VBOHeightcheck(int pos) const { return vboheight[pos] == GetPlaneTexZ(pos); }
+
+ enum
+ {
+ INVALIDATE_PLANES = 1,
+ INVALIDATE_OTHER = 2
+ };
+
+};
+
+FArchive &operator<< (FArchive &arc, sector_t::splane &p);
+
+
+struct ReverbContainer;
+struct zone_t
+{
+ ReverbContainer *Environment;
+};
+
+
+//
+// The SideDef.
+//
+
+class DBaseDecal;
+
+enum
+{
+ WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative
+ WALLF_NOAUTODECALS = 2, // Do not attach impact decals to this wall
+ WALLF_NOFAKECONTRAST = 4, // Don't do fake contrast for this wall in side_t::GetLightLevel
+ WALLF_SMOOTHLIGHTING = 8, // Similar to autocontrast but applies to all angles.
+ WALLF_CLIP_MIDTEX = 16, // Like the line counterpart, but only for this side.
+ WALLF_WRAP_MIDTEX = 32, // Like the line counterpart, but only for this side.
+ WALLF_POLYOBJ = 64, // This wall belongs to a polyobject.
+ WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog.
+};
+
+struct side_t
+{
+ enum ETexpart
+ {
+ top=0,
+ mid=1,
+ bottom=2
+ };
+ struct part
+ {
+ fixed_t xoffset;
+ fixed_t yoffset;
+ fixed_t xscale;
+ fixed_t yscale;
+ FTextureID texture;
+ TObjPtr interpolation;
+ //int Light;
+ };
+
+ sector_t* sector; // Sector the SideDef is facing.
+ DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall
+ part textures[3];
+ line_t *linedef;
+ //DWORD linenum;
+ DWORD LeftSide, RightSide; // [RH] Group walls into loops
+ WORD TexelLength;
+ SWORD Light;
+ BYTE Flags;
+ int Index; // needed to access custom UDMF fields which are stored in loading order.
+
+ int GetLightLevel (bool foggy, int baselight, bool is3dlight=false, int *pfakecontrast_usedbygzdoom=NULL) const;
+
+ void SetLight(SWORD l)
+ {
+ Light = l;
+ }
+
+ FTextureID GetTexture(int which) const
+ {
+ return textures[which].texture;
+ }
+ void SetTexture(int which, FTextureID tex)
+ {
+ textures[which].texture = tex;
+ }
+
+ void SetTextureXOffset(int which, fixed_t offset)
+ {
+ textures[which].xoffset = offset;
+ }
+ void SetTextureXOffset(fixed_t offset)
+ {
+ textures[top].xoffset =
+ textures[mid].xoffset =
+ textures[bottom].xoffset = offset;
+ }
+ fixed_t GetTextureXOffset(int which) const
+ {
+ return textures[which].xoffset;
+ }
+ void AddTextureXOffset(int which, fixed_t delta)
+ {
+ textures[which].xoffset += delta;
+ }
+
+ void SetTextureYOffset(int which, fixed_t offset)
+ {
+ textures[which].yoffset = offset;
+ }
+ void SetTextureYOffset(fixed_t offset)
+ {
+ textures[top].yoffset =
+ textures[mid].yoffset =
+ textures[bottom].yoffset = offset;
+ }
+ fixed_t GetTextureYOffset(int which) const
+ {
+ return textures[which].yoffset;
+ }
+ void AddTextureYOffset(int which, fixed_t delta)
+ {
+ textures[which].yoffset += delta;
+ }
+
+ void SetTextureXScale(int which, fixed_t scale)
+ {
+ textures[which].xscale = scale == 0 ? FRACUNIT : scale;
+ }
+ void SetTextureXScale(fixed_t scale)
+ {
+ textures[top].xscale = textures[mid].xscale = textures[bottom].xscale = scale == 0 ? FRACUNIT : scale;
+ }
+ fixed_t GetTextureXScale(int which) const
+ {
+ return textures[which].xscale;
+ }
+ void MultiplyTextureXScale(int which, fixed_t delta)
+ {
+ textures[which].xscale = FixedMul(textures[which].xscale, delta);
+ }
+
+
+ void SetTextureYScale(int which, fixed_t scale)
+ {
+ textures[which].yscale = scale == 0 ? FRACUNIT : scale;
+ }
+ void SetTextureYScale(fixed_t scale)
+ {
+ textures[top].yscale = textures[mid].yscale = textures[bottom].yscale = scale == 0 ? FRACUNIT : scale;
+ }
+ fixed_t GetTextureYScale(int which) const
+ {
+ return textures[which].yscale;
+ }
+ void MultiplyTextureYScale(int which, fixed_t delta)
+ {
+ textures[which].yscale = FixedMul(textures[which].yscale, delta);
+ }
+
+ DInterpolation *SetInterpolation(int position);
+ void StopInterpolation(int position);
+
+ vertex_t *V1() const;
+ vertex_t *V2() const;
+
+ //For GL
+ FLightNode * lighthead; // all blended lights that may affect this wall
+
+ seg_t **segs; // all segs belonging to this sidedef in ascending order. Used for precise rendering
+ int numsegs;
+
+};
+
+FArchive &operator<< (FArchive &arc, side_t::part &p);
+
+struct line_t
+{
+ vertex_t *v1, *v2; // vertices, from v1 to v2
+ fixed_t dx, dy; // precalculated v2 - v1 for side checking
+ DWORD flags;
+ DWORD activation; // activation type
+ int special;
+ fixed_t Alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque)
+ int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width)
+ side_t *sidedef[2];
+ fixed_t bbox[4]; // bounding box, for the extent of the LineDef.
+ sector_t *frontsector, *backsector;
+ int validcount; // if == validcount, already checked
+ int locknumber; // [Dusk] lock number for special
+ unsigned portalindex;
+ TObjPtr skybox;
+
+ FLinePortal *getPortal() const
+ {
+ return portalindex >= linePortals.Size() ? (FLinePortal*)NULL : &linePortals[portalindex];
+ }
+
+ // returns true if the portal is crossable by actors
+ bool isLinePortal() const
+ {
+ return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_PASSABLE);
+ }
+
+ // returns true if the portal needs to be handled by the renderer
+ bool isVisualPortal() const
+ {
+ return portalindex >= linePortals.Size() ? false : !!(linePortals[portalindex].mFlags & PORTF_VISIBLE);
+ }
+
+ line_t *getPortalDestination() const
+ {
+ return portalindex >= linePortals.Size() ? (line_t*)NULL : linePortals[portalindex].mDestination;
+ }
+
+ int getPortalAlignment() const
+ {
+ return portalindex >= linePortals.Size() ? 0 : linePortals[portalindex].mAlign;
+ }
+};
+
+// phares 3/14/98
+//
+// Sector list node showing all sectors an object appears in.
+//
+// There are two threads that flow through these nodes. The first thread
+// starts at touching_thinglist in a sector_t and flows through the m_snext
+// links to find all mobjs that are entirely or partially in the sector.
+// The second thread starts at touching_sectorlist in a AActor and flows
+// through the m_tnext links to find all sectors a thing touches. This is
+// useful when applying friction or push effects to sectors. These effects
+// can be done as thinkers that act upon all objects touching their sectors.
+// As an mobj moves through the world, these nodes are created and
+// destroyed, with the links changed appropriately.
+//
+// For the links, NULL means top or end of list.
+
+struct msecnode_t
+{
+ sector_t *m_sector; // a sector containing this object
+ AActor *m_thing; // this object
+ struct msecnode_t *m_tprev; // prev msecnode_t for this thing
+ struct msecnode_t *m_tnext; // next msecnode_t for this thing
+ struct msecnode_t *m_sprev; // prev msecnode_t for this sector
+ struct msecnode_t *m_snext; // next msecnode_t for this sector
+ bool visited; // killough 4/4/98, 4/7/98: used in search algorithms
+};
+
+struct FPolyNode;
+struct FMiniBSP;
+
+//
+// The LineSeg.
+//
+struct seg_t
+{
+ vertex_t* v1;
+ vertex_t* v2;
+
+ side_t* sidedef;
+ line_t* linedef;
+
+ // Sector references. Could be retrieved from linedef, too.
+ sector_t* frontsector;
+ sector_t* backsector; // NULL for one-sided lines
+
+ seg_t* PartnerSeg;
+ subsector_t* Subsector;
+
+ float sidefrac; // relative position of seg's ending vertex on owning sidedef
+};
+
+struct glsegextra_t
+{
+ DWORD PartnerSeg;
+ subsector_t *Subsector;
+};
+
+extern seg_t *segs;
+
+
+//
+// A SubSector.
+// References a Sector.
+// Basically, this is a list of LineSegs indicating the visible walls that
+// define (all or some) sides of a convex BSP leaf.
+//
+
+enum
+{
+ SSECF_DEGENERATE = 1,
+ SSECF_DRAWN = 2,
+ SSECF_POLYORG = 4,
+};
+
+struct FPortalCoverage
+{
+ DWORD * subsectors;
+ int sscount;
+};
+
+struct subsector_t
+{
+ sector_t *sector;
+ FPolyNode *polys;
+ FMiniBSP *BSP;
+ seg_t *firstline;
+ sector_t *render_sector;
+ DWORD numlines;
+ int flags;
+
+ void BuildPolyBSP();
+ // subsector related GL data
+ FLightNode * lighthead; // Light nodes (blended and additive)
+ int validcount;
+ short mapsection;
+ char hacked; // 1: is part of a render hack
+ // 2: has one-sided walls
+ FPortalCoverage portalcoverage[2];
+};
+
+
+
+
+//
+// BSP node.
+//
+struct node_t
+{
+ // Partition line.
+ fixed_t x;
+ fixed_t y;
+ fixed_t dx;
+ fixed_t dy;
+ fixed_t bbox[2][4]; // Bounding box for each child.
+ float len;
+ union
+ {
+ void *children[2]; // If bit 0 is set, it's a subsector.
+ int intchildren[2]; // Used by nodebuilder.
+ };
+};
+
+
+// An entire BSP tree.
+
+struct FMiniBSP
+{
+ bool bDirty;
+
+ TArray Nodes;
+ TArray Segs;
+ TArray Subsectors;
+ TArray Verts;
+};
+
+
+
+//
+// OTHER TYPES
+//
+
+typedef BYTE lighttable_t; // This could be wider for >8 bit display.
+
+// This encapsulates the fields of vissprite_t that can be altered by AlterWeaponSprite
+struct visstyle_t
+{
+ lighttable_t *colormap;
+ fixed_t alpha;
+ FRenderStyle RenderStyle;
+};
+
+
+//----------------------------------------------------------------------------------
+//
+// The playsim can use different nodes than the renderer so this is
+// not the same as R_PointInSubsector
+//
+//----------------------------------------------------------------------------------
+subsector_t *P_PointInSubsector(fixed_t x, fixed_t y);
+inline sector_t *P_PointInSector(fixed_t x, fixed_t y)
+{
+ return P_PointInSubsector(x, y)->sector;
+}
+
+inline fixedvec3 AActor::PosRelative(const AActor *other) const
+{
+ return __pos + Displacements.getOffset(Sector->PortalGroup, other->Sector->PortalGroup);
+}
+
+inline fixedvec3 AActor::PosRelative(sector_t *sec) const
+{
+ return __pos + Displacements.getOffset(Sector->PortalGroup, sec->PortalGroup);
+}
+
+inline fixedvec3 AActor::PosRelative(line_t *line) const
+{
+ return __pos + Displacements.getOffset(Sector->PortalGroup, line->frontsector->PortalGroup);
+}
+
+inline fixedvec3 PosRelative(const fixedvec3 &pos, line_t *line, sector_t *refsec = NULL)
+{
+ return pos + Displacements.getOffset(refsec->PortalGroup, line->frontsector->PortalGroup);
+}
+
+inline void AActor::ClearInterpolation()
+{
+ PrevX = X();
+ PrevY = Y();
+ PrevZ = Z();
+ PrevAngle = angle;
+ if (Sector) PrevPortalGroup = Sector->PortalGroup;
+ else PrevPortalGroup = 0;
+}
+
+
+#endif
diff --git a/src/r_segs.cpp b/src/r_segs.cpp
index ae38b3978..0448cf6aa 100644
--- a/src/r_segs.cpp
+++ b/src/r_segs.cpp
@@ -272,17 +272,17 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
if (fixedlightlev < 0)
{
+ if (!(fake3D & FAKE3D_CLIPTOP))
+ {
+ sclipTop = sec->ceilingplane.ZatPoint(viewx, viewy);
+ }
for (i = frontsector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
{
- if (!(fake3D & FAKE3D_CLIPTOP))
- {
- sclipTop = sec->ceilingplane.ZatPoint(viewx, viewy);
- }
- if (sclipTop <= frontsector->e->XFloor.lightlist[i].plane.ZatPoint(viewx, viewy))
+ if (sclipTop <= frontsector->e->XFloor.lightlist[i].plane.Zat0())
{
lightlist_t *lit = &frontsector->e->XFloor.lightlist[i];
basecolormap = lit->extra_colormap;
- wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource == NULL) + r_actualextralight);
+ wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != NULL) + r_actualextralight);
break;
}
}
diff --git a/src/r_things.cpp b/src/r_things.cpp
index 1fb4c845b..21fd1605b 100644
--- a/src/r_things.cpp
+++ b/src/r_things.cpp
@@ -324,18 +324,19 @@ nextpost:
// [ZZ]
// R_ClipSpriteColumnWithPortals
//
-static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprite_t* spr)
-{
- // [ZZ] 10.01.2016: don't clip sprites from the root of a skybox.
- if (CurrentPortalInSkybox)
- return false;
+static TArray portaldrawsegs;
+
+static inline void R_CollectPortals()
+{
+ // This function collects all drawsegs that may be of interest to R_ClipSpriteColumnWithPortals
+ // Having that function over the entire list of drawsegs can break down performance quite drastically.
+ // This is doing the costly stuff only once so that R_ClipSpriteColumnWithPortals can
+ // a) exit early if no relevant info is found and
+ // b) skip most of the collected drawsegs which have no portal attached.
+ portaldrawsegs.Clear();
for (drawseg_t* seg = ds_p; seg-- > firstdrawseg; ) // copied code from killough below
{
- // ignore segs from other portals
- if (seg->CurrentPortalUniq != CurrentPortalUniq)
- continue;
-
// I don't know what makes this happen (some old top-down portal code or possibly skybox code? something adds null lines...)
// crashes at the first frame of the first map of Action2.wad
if (!seg->curline) continue;
@@ -352,8 +353,28 @@ static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprit
if (seg->curline->sidedef != line->sidedef[0])
continue;
+ portaldrawsegs.Push(seg);
+ }
+}
+
+static inline bool R_ClipSpriteColumnWithPortals(fixed_t x, fixed_t y, vissprite_t* spr)
+{
+ // [ZZ] 10.01.2016: don't clip sprites from the root of a skybox.
+ if (CurrentPortalInSkybox)
+ return false;
+
+ for(drawseg_t *seg : portaldrawsegs)
+ {
+ // ignore segs from other portals
+ if (seg->CurrentPortalUniq != CurrentPortalUniq)
+ continue;
+
+ // (all checks that are already done in R_CollectPortals have been removed for performance reasons.)
+
+ line_t* line = seg->curline->linedef;
+
// don't clip if the sprite is in front of the portal
- if (!P_PointOnLineSide(x, y, line))
+ if (!P_PointOnLineSidePrecise(x, y, line))
continue;
// now if current column is covered by this drawseg, we clip it away
@@ -364,6 +385,7 @@ static inline bool R_ClipSpriteColumnWithPortals (fixed_t x, fixed_t y, vissprit
return false;
}
+
//
// R_DrawVisSprite
// mfloorclip and mceilingclip should also be set.
@@ -2332,6 +2354,7 @@ void R_DrawHeightPlanes(fixed_t height); // kg3D - fake planes
void R_DrawMasked (void)
{
+ R_CollectPortals();
R_SortVisSprites (DrewAVoxel ? sv_compare2d : sv_compare, firstvissprite - vissprites);
if (height_top == NULL)
diff --git a/src/resourcefiles/file_directory.cpp b/src/resourcefiles/file_directory.cpp
index 8b85425f1..068ea508a 100644
--- a/src/resourcefiles/file_directory.cpp
+++ b/src/resourcefiles/file_directory.cpp
@@ -302,8 +302,13 @@ void FDirectory::AddEntry(const char *fullpath, int size)
// Store the full path here so that we can access the file later, even if it is from a filter directory.
lump_p->mFullPath = fullpath;
+
+ // [mxd] Convert name to lowercase
+ FString name = fullpath + strlen(Filename);
+ name.ToLower();
+
// The lump's name is only the part relative to the main directory
- lump_p->LumpNameSetup(fullpath + strlen(Filename));
+ lump_p->LumpNameSetup(name);
lump_p->LumpSize = size;
lump_p->Owner = this;
lump_p->Flags = 0;
diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp
index ec876da15..c1724c2c5 100644
--- a/src/thingdef/thingdef_codeptr.cpp
+++ b/src/thingdef/thingdef_codeptr.cpp
@@ -960,7 +960,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfCloser)
else
{
// Does the player aim at something that can be shot?
- P_BulletSlope(self, &target);
+ FTranslatedLineTarget t;
+ P_BulletSlope(self, &t, ALF_PORTALRESTRICT);
+ target = t.linetarget;
}
return DoJumpIfCloser(target, VM_ARGS_NAMES);
}
@@ -1637,7 +1639,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile)
player_t *player = self->player;
AWeapon *weapon = player->ReadyWeapon;
- AActor *linetarget;
+ FTranslatedLineTarget t;
// Only use ammo if called from a weapon
if (useammo && ACTION_CALL_FROM_WEAPON() && weapon)
@@ -1659,7 +1661,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile)
// Temporarily adjusts the pitch
fixed_t saved_player_pitch = self->pitch;
self->pitch -= pitch;
- AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &linetarget, NULL, false, (flags & FPF_NOAUTOAIM) != 0);
+ AActor * misl=P_SpawnPlayerMissile (self, x, y, z, ti, shootangle, &t, NULL, false, (flags & FPF_NOAUTOAIM) != 0);
self->pitch = saved_player_pitch;
// automatic handling of seeker missiles
@@ -1667,8 +1669,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile)
{
if (flags & FPF_TRANSFERTRANSLATION)
misl->Translation = self->Translation;
- if (linetarget && (misl->flags2 & MF2_SEEKERMISSILE))
- misl->tracer = linetarget;
+ if (t.linetarget && !t.unlinked && (misl->flags2 & MF2_SEEKERMISSILE))
+ misl->tracer = t.linetarget;
if (!(flags & FPF_AIMATANGLE))
{
// This original implementation is to aim straight ahead and then offset
@@ -1727,7 +1729,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
angle_t angle;
int pitch;
- AActor * linetarget;
+ FTranslatedLineTarget t;
int actualdamage;
if (!norandom)
@@ -1736,10 +1738,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
angle = self->angle + (pr_cwpunch.Random2() << 18);
if (range == 0)
range = MELEERANGE;
- pitch = P_AimLineAttack (self, angle, range, &linetarget);
+ pitch = P_AimLineAttack (self, angle, range, &t);
// only use ammo when actually hitting something!
- if ((flags & CPF_USEAMMO) && linetarget && weapon && ACTION_CALL_FROM_WEAPON())
+ if ((flags & CPF_USEAMMO) && t.linetarget && weapon && ACTION_CALL_FROM_WEAPON())
{
if (!weapon->DepleteAmmo(weapon->bAltFire, true))
return 0; // out of ammo
@@ -1749,15 +1751,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
pufftype = PClass::FindActor(NAME_BulletPuff);
int puffFlags = LAF_ISMELEEATTACK | ((flags & CPF_NORANDOMPUFFZ) ? LAF_NORANDOMPUFFZ : 0);
- P_LineAttack (self, angle, range, pitch, damage, NAME_Melee, pufftype, puffFlags, &linetarget, &actualdamage);
+ P_LineAttack (self, angle, range, pitch, damage, NAME_Melee, pufftype, puffFlags, &t, &actualdamage);
- if (!linetarget)
+ if (!t.linetarget)
{
if (MissSound) S_Sound(self, CHAN_WEAPON, MissSound, 1, ATTN_NORM);
}
else
{
- if (lifesteal && !(linetarget->flags5 & MF5_DONTDRAIN))
+ if (lifesteal && !(t.linetarget->flags5 & MF5_DONTDRAIN))
{
if (flags & CPF_STEALARMOR)
{
@@ -1794,11 +1796,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
if (!(flags & CPF_NOTURN))
{
// turn to face target
- self->angle = self->AngleTo(linetarget);
+ self->angle = t.SourceAngleToTarget();
}
if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED;
- if (flags & CPF_DAGGER) P_DaggerAlert (self, linetarget);
+ if (flags & CPF_DAGGER) P_DaggerAlert (self, t.linetarget);
}
return 0;
}
@@ -1900,7 +1902,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
if (range == 0) range = 8192*FRACUNIT;
if (sparsity == 0) sparsity = 1;
- AActor *linetarget;
+ FTranslatedLineTarget t;
fixedvec3 savedpos = self->Pos();
angle_t saved_angle = self->angle;
@@ -1923,8 +1925,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
{
self->angle = self->AngleTo(self->target);
}
- self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, aim ? self->target : NULL);
- if (linetarget == NULL && aim)
+ self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &t, ANGLE_1*60, 0, aim ? self->target : NULL);
+ if (t.linetarget == NULL && aim)
{
// We probably won't hit the target, but aim at it anyway so we don't look stupid.
fixedvec2 pos = self->Vec2To(self->target);
@@ -3929,6 +3931,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
angle_t an;
AActor *target, *viewport;
+ FTranslatedLineTarget t;
bool doCheckSight;
@@ -3964,12 +3967,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS)
else
{
// Does the player aim at something that can be shot?
- P_AimLineAttack(self, self->angle, MISSILERANGE, &target, (flags & JLOSF_NOAUTOAIM) ? ANGLE_1/2 : 0);
+ P_AimLineAttack(self, self->angle, MISSILERANGE, &t, (flags & JLOSF_NOAUTOAIM) ? ANGLE_1/2 : 0, ALF_PORTALRESTRICT);
- if (!target)
+ if (!t.linetarget)
{
ACTION_RETURN_STATE(NULL);
}
+ target = t.linetarget;
switch (flags & (JLOSF_TARGETLOS|JLOSF_FLIPFOV))
{
@@ -5570,10 +5574,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusGive)
}
else
{
- FBlockThingsIterator it(FBoundingBox(self->X(), self->Y(), distance));
- while ((thing = it.Next()))
+ FPortalGroupArray check(FPortalGroupArray::PGA_Full3d);
+ fixed_t mid = self->Z() + self->height / 2;
+ FMultiBlockThingsIterator it(check, self->X(), self->Y(), mid-distance, mid+distance, distance);
+ FMultiBlockThingsIterator::CheckResult cres;
+
+ while ((it.Next(&cres)))
{
- given += DoRadiusGive(self, thing, item, amount, distance, flags, filter, species, mindist);
+ given += DoRadiusGive(self, cres.thing, item, amount, distance, flags, filter, species, mindist);
}
}
ACTION_RETURN_INT(given);
diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h
index daa824264..3ae20a83d 100644
--- a/src/thingdef/thingdef_exp.h
+++ b/src/thingdef/thingdef_exp.h
@@ -84,7 +84,7 @@ struct FCompileContext
struct ExpVal
{
- ExpValType Type;
+ PType *Type;
union
{
int Int;
@@ -94,13 +94,13 @@ struct ExpVal
ExpVal()
{
- Type = VAL_Int;
+ Type = TypeSInt32;
Int = 0;
}
~ExpVal()
{
- if (Type == VAL_String)
+ if (Type == TypeString)
{
((FString *)&pointer)->~FString();
}
@@ -108,14 +108,14 @@ struct ExpVal
ExpVal(const FString &str)
{
- Type = VAL_String;
+ Type = TypeString;
::new(&pointer) FString(str);
}
ExpVal(const ExpVal &o)
{
Type = o.Type;
- if (o.Type == VAL_String)
+ if (o.Type == TypeString)
{
::new(&pointer) FString(*(FString *)&o.pointer);
}
@@ -127,12 +127,12 @@ struct ExpVal
ExpVal &operator=(const ExpVal &o)
{
- if (Type == VAL_String)
+ if (Type == TypeString)
{
((FString *)&pointer)->~FString();
}
Type = o.Type;
- if (o.Type == VAL_String)
+ if (o.Type == TypeString)
{
::new(&pointer) FString(*(FString *)&o.pointer);
}
@@ -145,27 +145,30 @@ struct ExpVal
int GetInt() const
{
- return Type == VAL_Int? Int : Type == VAL_Float? int(Float) : 0;
+ int regtype = Type->GetRegType();
+ return regtype == REGT_INT ? Int : regtype == REGT_FLOAT ? int(Float) : 0;
}
double GetFloat() const
{
- return Type == VAL_Int? double(Int) : Type == VAL_Float? Float : 0;
+ int regtype = Type->GetRegType();
+ return regtype == REGT_INT ? double(Int) : regtype == REGT_FLOAT ? Float : 0;
}
const FString GetString() const
{
- return Type == VAL_String ? *(FString *)&pointer : Type == VAL_Name ? FString(FName(ENamedName(Int)).GetChars()) : "";
+ return Type == TypeString ? *(FString *)&pointer : Type == TypeName ? FString(FName(ENamedName(Int)).GetChars()) : "";
}
bool GetBool() const
{
- return (Type == VAL_Int || Type == VAL_Sound) ? !!Int : Type == VAL_Float? Float!=0. : false;
+ int regtype = Type->GetRegType();
+ return regtype == REGT_INT ? !!Int : regtype == REGT_FLOAT ? Float!=0. : false;
}
FName GetName() const
{
- return Type == VAL_Name? ENamedName(Int) : NAME_None;
+ return Type == TypeName ? ENamedName(Int) : NAME_None;
}
};
@@ -195,7 +198,7 @@ protected:
{
isresolved = false;
ScriptPosition = pos;
- ValueType = VAL_Unresolved;
+ ValueType = NULL;
}
public:
virtual ~FxExpression() {}
@@ -205,26 +208,17 @@ public:
virtual bool isConstant() const;
virtual void RequestAddress();
virtual VMFunction *GetDirectFunction();
+ bool IsNumeric() const { return ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT; }
+ bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; }
virtual ExpEmit Emit(VMFunctionBuilder *build);
FScriptPosition ScriptPosition;
- FExpressionType ValueType;
+ PType *ValueType;
bool isresolved;
};
-class FxParameter : public FxExpression
-{
- FxExpression *Operand;
-
-public:
- FxParameter(FxExpression*);
- ~FxParameter();
- FxExpression *Resolve(FCompileContext&);
- ExpEmit Emit(VMFunctionBuilder *build);
-};
-
//==========================================================================
//
// FxIdentifier
@@ -288,35 +282,35 @@ class FxConstant : public FxExpression
public:
FxConstant(int val, const FScriptPosition &pos) : FxExpression(pos)
{
- ValueType = value.Type = VAL_Int;
+ ValueType = value.Type = TypeSInt32;
value.Int = val;
isresolved = true;
}
FxConstant(double val, const FScriptPosition &pos) : FxExpression(pos)
{
- ValueType = value.Type = VAL_Float;
+ ValueType = value.Type = TypeFloat64;
value.Float = val;
isresolved = true;
}
FxConstant(FSoundID val, const FScriptPosition &pos) : FxExpression(pos)
{
- ValueType = value.Type = VAL_Sound;
+ ValueType = value.Type = TypeSound;
value.Int = val;
isresolved = true;
}
FxConstant(FName val, const FScriptPosition &pos) : FxExpression(pos)
{
- ValueType = value.Type = VAL_Name;
+ ValueType = value.Type = TypeName;
value.Int = val;
isresolved = true;
}
FxConstant(const FString &str, const FScriptPosition &pos) : FxExpression(pos)
{
- ValueType = VAL_String;
+ ValueType = TypeString;
value = ExpVal(str);
isresolved = true;
}
@@ -327,19 +321,19 @@ public:
ValueType = cv.Type;
isresolved = true;
}
-
- FxConstant(const PClass *val, const FScriptPosition &pos) : FxExpression(pos)
+
+ FxConstant(PClass *val, const FScriptPosition &pos) : FxExpression(pos)
{
value.pointer = (void*)val;
ValueType = val;
- value.Type = VAL_Class;
+ value.Type = NewClassPointer(RUNTIME_CLASS(AActor));
isresolved = true;
}
FxConstant(FState *state, const FScriptPosition &pos) : FxExpression(pos)
{
value.pointer = state;
- ValueType = value.Type = VAL_State;
+ ValueType = value.Type = TypeState;
isresolved = true;
}
@@ -864,6 +858,7 @@ public:
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
ExpEmit Emit(VMFunctionBuilder *build, bool tailcall);
+ bool CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®);
unsigned GetArgCount() const { return ArgList == NULL ? 0 : ArgList->Size(); }
VMFunction *GetVMFunction() const { return Function->Variants[0].Implementation; }
bool IsDirectFunction();
diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp
index b5b35a770..5eb77aa80 100644
--- a/src/thingdef/thingdef_expression.cpp
+++ b/src/thingdef/thingdef_expression.cpp
@@ -189,25 +189,20 @@ FxExpression *FxExpression::ResolveAsBoolean(FCompileContext &ctx)
FxExpression *x = Resolve(ctx);
if (x != NULL)
{
- switch (x->ValueType.Type)
+ if (x->ValueType->GetRegType() == REGT_INT)
+ {
+ x->ValueType = TypeSInt32;
+ }
+ else if (x->ValueType == TypeState)
{
- case VAL_Int:
- case VAL_Sound:
- case VAL_Color:
- case VAL_Name:
- x->ValueType = VAL_Int;
- break;
-
- case VAL_State:
x = new FxCastStateToBool(x);
x = x->Resolve(ctx);
- break;
-
- default:
+ }
+ else
+ {
ScriptPosition.Message(MSG_ERROR, "Not an integral type");
delete this;
return NULL;
- break;
}
}
return x;
@@ -230,85 +225,25 @@ void FxExpression::RequestAddress()
//
//==========================================================================
-FxParameter::FxParameter(FxExpression *operand)
-: FxExpression(operand->ScriptPosition)
+static void EmitParameter(VMFunctionBuilder *build, FxExpression *operand, const FScriptPosition &pos)
{
- Operand = operand;
- ValueType = operand->ValueType;
-}
+ ExpEmit where = operand->Emit(build);
-//==========================================================================
-//
-//
-//
-//==========================================================================
-
-FxParameter::~FxParameter()
-{
- SAFE_DELETE(Operand);
-}
-
-//==========================================================================
-//
-//
-//
-//==========================================================================
-
-FxExpression *FxParameter::Resolve(FCompileContext& ctx)
-{
- CHECKRESOLVED();
- SAFE_RESOLVE(Operand, ctx);
- ValueType = Operand->ValueType;
- return this;
-}
-
-ExpEmit FxParameter::Emit(VMFunctionBuilder *build)
-{
- if (Operand->isConstant())
+ if (where.RegType == REGT_NIL)
{
- ExpVal val = static_cast(Operand)->GetValue();
- if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color)
- {
- build->EmitParamInt(val.Int);
- }
- else if (val.Type == VAL_Float)
- {
- build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val.Float));
- }
- else if (val.Type == VAL_Class || val.Type == VAL_Object)
- {
- build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_OBJECT));
- }
- else if (val.Type == VAL_State)
- {
- build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_STATE));
- }
- else if (val.Type == VAL_String)
- {
- build->Emit(OP_PARAM, 0, REGT_STRING | REGT_KONST, build->GetConstantString(val.GetString()));
- }
- else
- {
- build->Emit(OP_PARAM, 0, REGT_NIL, 0);
- ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant");
- }
+ pos.Message(MSG_ERROR, "Attempted to pass a non-value");
+ build->Emit(OP_PARAM, 0, where.RegType, where.RegNum);
}
else
{
- ExpEmit where = Operand->Emit(build);
-
- if (where.RegType == REGT_NIL)
+ int regtype = where.RegType;
+ if (where.Konst)
{
- ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value");
- build->Emit(OP_PARAM, 0, where.RegType, where.RegNum);
- }
- else
- {
- build->Emit(OP_PARAM, 0, where.RegType, where.RegNum);
- where.Free(build);
+ regtype |= REGT_KONST;
}
+ build->Emit(OP_PARAM, 0, regtype, where.RegNum);
+ where.Free(build);
}
- return ExpEmit();
}
//==========================================================================
@@ -350,35 +285,36 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
ExpEmit out;
out.Konst = true;
- if (value.Type == VAL_Int || value.Type == VAL_Sound || value.Type == VAL_Name || value.Type == VAL_Color)
+ int regtype = value.Type->GetRegType();
+ out.RegType = regtype;
+ if (regtype == REGT_INT)
{
- out.RegType = REGT_INT;
out.RegNum = build->GetConstantInt(value.Int);
}
- else if (value.Type == VAL_Float)
+ else if (regtype == REGT_FLOAT)
{
- out.RegType = REGT_FLOAT;
out.RegNum = build->GetConstantFloat(value.Float);
}
- else if (value.Type == VAL_Class || value.Type == VAL_Object)
+ else if (regtype == REGT_POINTER)
{
- out.RegType = REGT_POINTER;
- out.RegNum = build->GetConstantAddress(value.pointer, ATAG_OBJECT);
+ VM_ATAG tag = ATAG_GENERIC;
+ if (value.Type == TypeState)
+ {
+ tag = ATAG_STATE;
+ }
+ else if (value.Type->GetLoadOp() == OP_LO)
+ {
+ tag = ATAG_OBJECT;
+ }
+ out.RegNum = build->GetConstantAddress(value.pointer, tag);
}
- else if (value.Type == VAL_State)
+ else if (regtype == REGT_STRING)
{
- out.RegType = REGT_POINTER;
- out.RegNum = build->GetConstantAddress(value.pointer, ATAG_STATE);
- }
- else if (value.Type == VAL_String)
- {
- out.RegType = REGT_STRING;
out.RegNum = build->GetConstantString(value.GetString());
}
else
{
ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant");
- out.RegType = REGT_NIL;
out.RegNum = 0;
}
return out;
@@ -394,7 +330,7 @@ FxIntCast::FxIntCast(FxExpression *x)
: FxExpression(x->ScriptPosition)
{
basex=x;
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
}
//==========================================================================
@@ -419,14 +355,14 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
SAFE_RESOLVE(basex, ctx);
- if (basex->ValueType == VAL_Int)
+ if (basex->ValueType->GetRegType() == REGT_INT)
{
FxExpression *x = basex;
basex = NULL;
delete this;
return x;
}
- else if (basex->ValueType == VAL_Float)
+ else if (basex->ValueType->GetRegType() == REGT_FLOAT)
{
if (basex->isConstant())
{
@@ -455,7 +391,7 @@ ExpEmit FxIntCast::Emit(VMFunctionBuilder *build)
{
ExpEmit from = basex->Emit(build);
assert(!from.Konst);
- assert(basex->ValueType == VAL_Float);
+ assert(basex->ValueType->GetRegType() == REGT_FLOAT);
from.Free(build);
ExpEmit to(build, REGT_INT);
build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_F2I);
@@ -472,7 +408,7 @@ FxFloatCast::FxFloatCast(FxExpression *x)
: FxExpression(x->ScriptPosition)
{
basex=x;
- ValueType = VAL_Float;
+ ValueType = TypeFloat64;
}
//==========================================================================
@@ -497,14 +433,14 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
SAFE_RESOLVE(basex, ctx);
- if (basex->ValueType == VAL_Float)
+ if (basex->ValueType->GetRegType() == REGT_FLOAT)
{
FxExpression *x = basex;
basex = NULL;
delete this;
return x;
}
- else if (basex->ValueType == VAL_Int)
+ else if (basex->ValueType->GetRegType() == REGT_INT)
{
if (basex->isConstant())
{
@@ -533,7 +469,7 @@ ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build)
{
ExpEmit from = basex->Emit(build);
assert(!from.Konst);
- assert(basex->ValueType == VAL_Int);
+ assert(basex->ValueType->GetRegType() == REGT_INT);
from.Free(build);
ExpEmit to(build, REGT_FLOAT);
build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_I2F);
@@ -550,7 +486,7 @@ FxCastStateToBool::FxCastStateToBool(FxExpression *x)
: FxExpression(x->ScriptPosition)
{
basex = x;
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
}
//==========================================================================
@@ -575,7 +511,7 @@ FxExpression *FxCastStateToBool::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
SAFE_RESOLVE(basex, ctx);
- assert(basex->ValueType == VAL_State);
+ assert(basex->ValueType == TypeState);
assert(!basex->isConstant() && "We shouldn't be able to generate a constant state ref");
return this;
}
@@ -635,7 +571,7 @@ FxExpression *FxPlusSign::Resolve(FCompileContext& ctx)
CHECKRESOLVED();
SAFE_RESOLVE(Operand, ctx);
- if (Operand->ValueType.isNumeric())
+ if (Operand->IsNumeric())
{
FxExpression *e = Operand;
Operand = NULL;
@@ -689,12 +625,12 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx)
CHECKRESOLVED();
SAFE_RESOLVE(Operand, ctx);
- if (Operand->ValueType.isNumeric())
+ if (Operand->IsNumeric())
{
if (Operand->isConstant())
{
ExpVal val = static_cast(Operand)->GetValue();
- FxExpression *e = val.Type == VAL_Int?
+ FxExpression *e = val.Type->GetRegType() == REGT_INT ?
new FxConstant(-val.Int, ScriptPosition) :
new FxConstant(-val.Float, ScriptPosition);
delete this;
@@ -719,17 +655,17 @@ FxExpression *FxMinusSign::Resolve(FCompileContext& ctx)
ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build)
{
- assert(ValueType.Type == Operand->ValueType.Type);
+ assert(ValueType == Operand->ValueType);
ExpEmit from = Operand->Emit(build);
assert(from.Konst == 0);
// Do it in-place.
- if (ValueType == VAL_Int)
+ if (ValueType->GetRegType() == REGT_INT)
{
build->Emit(OP_NEG, from.RegNum, from.RegNum, 0);
}
else
{
- assert(ValueType == VAL_Float);
+ assert(ValueType->GetRegType() == REGT_FLOAT);
build->Emit(OP_FLOP, from.RegNum, from.RegNum, FLOP_NEG);
}
return from;
@@ -769,7 +705,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
CHECKRESOLVED();
SAFE_RESOLVE(Operand, ctx);
- if (Operand->ValueType == VAL_Float /* lax */)
+ if (Operand->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{
// DECORATE allows floats here so cast them to int.
Operand = new FxIntCast(Operand);
@@ -781,7 +717,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
}
}
- if (Operand->ValueType != VAL_Int)
+ if (Operand->ValueType->GetRegType() != REGT_INT)
{
ScriptPosition.Message(MSG_ERROR, "Integer type expected");
delete this;
@@ -795,7 +731,7 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
delete this;
return e;
}
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
return this;
}
@@ -807,8 +743,8 @@ FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build)
{
- assert(ValueType.Type == Operand->ValueType.Type);
- assert(ValueType == VAL_Int);
+ assert(ValueType == Operand->ValueType);
+ assert(ValueType == TypeSInt32);
ExpEmit from = Operand->Emit(build);
assert(from.Konst == 0);
// Do it in-place.
@@ -858,7 +794,7 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
return NULL;
}
- if (Operand->ValueType.isNumeric() || Operand->ValueType.isPointer())
+ if (Operand->IsNumeric() || Operand->IsPointer())
{
if (Operand->isConstant())
{
@@ -874,7 +810,7 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
delete this;
return NULL;
}
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
return this;
}
@@ -956,25 +892,21 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
return false;
}
- if (left->ValueType == VAL_Int && right->ValueType == VAL_Int)
+ if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT)
{
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
}
- else if (left->ValueType.isNumeric() && right->ValueType.isNumeric())
+ else if (left->IsNumeric() && right->IsNumeric())
{
- ValueType = VAL_Float;
+ ValueType = TypeFloat64;
}
- else if (left->ValueType == VAL_Object && right->ValueType == VAL_Object)
+ else if (left->ValueType->GetRegType() == REGT_POINTER && left->ValueType == right->ValueType)
{
- ValueType = VAL_Object;
- }
- else if (left->ValueType == VAL_Class && right->ValueType == VAL_Class)
- {
- ValueType = VAL_Class;
+ ValueType = left->ValueType;
}
else
{
- ValueType = VAL_Unknown;
+ ValueType = TypeVoid;
}
if (castnumeric)
@@ -986,11 +918,11 @@ bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
void FxBinary::Promote(FCompileContext &ctx)
{
- if (left->ValueType == VAL_Float && right->ValueType == VAL_Int)
+ if (left->ValueType->GetRegType() == REGT_FLOAT && right->ValueType->GetRegType() == REGT_INT)
{
right = (new FxFloatCast(right))->Resolve(ctx);
}
- else if (left->ValueType == VAL_Int && right->ValueType == VAL_Float)
+ else if (left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_FLOAT)
{
left = (new FxFloatCast(left))->Resolve(ctx);
}
@@ -1018,7 +950,7 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx)
CHECKRESOLVED();
if (!ResolveLR(ctx, true)) return NULL;
- if (!ValueType.isNumeric())
+ if (!IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
@@ -1026,7 +958,7 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx)
}
else if (left->isConstant() && right->isConstant())
{
- if (ValueType == VAL_Float)
+ if (ValueType->GetRegType() == REGT_FLOAT)
{
double v;
double v1 = static_cast(left)->GetValue().GetFloat();
@@ -1079,7 +1011,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
assert(!op1.Konst);
op1.Free(build);
op2.Free(build);
- if (ValueType == VAL_Float)
+ if (ValueType->GetRegType() == REGT_FLOAT)
{
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
ExpEmit to(build, REGT_FLOAT);
@@ -1088,7 +1020,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
}
else
{
- assert(ValueType == VAL_Int);
+ assert(ValueType->GetRegType() == REGT_INT);
assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT);
ExpEmit to(build, REGT_INT);
build->Emit(op2.Konst ? OP_ADD_RK : OP_ADD_RR, to.RegNum, op1.RegNum, op2.RegNum);
@@ -1101,7 +1033,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
assert(!op1.Konst || !op2.Konst);
op1.Free(build);
op2.Free(build);
- if (ValueType == VAL_Float)
+ if (ValueType->GetRegType() == REGT_FLOAT)
{
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
ExpEmit to(build, REGT_FLOAT);
@@ -1111,7 +1043,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
}
else
{
- assert(ValueType == VAL_Int);
+ assert(ValueType->GetRegType() == REGT_INT);
assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT);
ExpEmit to(build, REGT_INT);
build->Emit(op1.Konst ? OP_SUB_KR : op2.Konst ? OP_SUB_RK : OP_SUB_RR,
@@ -1144,7 +1076,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx)
if (!ResolveLR(ctx, true)) return NULL;
- if (!ValueType.isNumeric())
+ if (!IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
@@ -1152,7 +1084,7 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx)
}
else if (left->isConstant() && right->isConstant())
{
- if (ValueType == VAL_Float)
+ if (ValueType->GetRegType() == REGT_FLOAT)
{
double v;
double v1 = static_cast(left)->GetValue().GetFloat();
@@ -1222,7 +1154,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build)
assert(!op1.Konst);
op1.Free(build);
op2.Free(build);
- if (ValueType == VAL_Float)
+ if (ValueType->GetRegType() == REGT_FLOAT)
{
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
ExpEmit to(build, REGT_FLOAT);
@@ -1231,7 +1163,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build)
}
else
{
- assert(ValueType == VAL_Int);
+ assert(ValueType->GetRegType() == REGT_INT);
assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT);
ExpEmit to(build, REGT_INT);
build->Emit(op2.Konst ? OP_MUL_RK : OP_MUL_RR, to.RegNum, op1.RegNum, op2.RegNum);
@@ -1245,7 +1177,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build)
assert(Operator == '%' || Operator == '/');
op1.Free(build);
op2.Free(build);
- if (ValueType == VAL_Float)
+ if (ValueType->GetRegType() == REGT_FLOAT)
{
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
ExpEmit to(build, REGT_FLOAT);
@@ -1256,7 +1188,7 @@ ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build)
}
else
{
- assert(ValueType == VAL_Int);
+ assert(ValueType->GetRegType() == REGT_INT);
assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT);
ExpEmit to(build, REGT_INT);
build->Emit(Operator == '/' ? (op1.Konst ? OP_DIV_KR : op2.Konst ? OP_DIV_RK : OP_DIV_RR)
@@ -1289,7 +1221,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
CHECKRESOLVED();
if (!ResolveLR(ctx, true)) return NULL;
- if (!ValueType.isNumeric())
+ if (!IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
@@ -1299,7 +1231,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
{
int v;
- if (ValueType == VAL_Float)
+ if (ValueType->GetRegType() == REGT_FLOAT)
{
double v1 = static_cast(left)->GetValue().GetFloat();
double v2 = static_cast(right)->GetValue().GetFloat();
@@ -1322,7 +1254,7 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
return e;
}
Promote(ctx);
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
return this;
}
@@ -1410,28 +1342,18 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
return NULL;
}
- if (!ValueType.isNumeric() && !ValueType.isPointer())
+ if (!IsNumeric() && !IsPointer())
{
- if (left->ValueType.Type == right->ValueType.Type)
- {
- // compare other types?
- if (left->ValueType == VAL_Sound || left->ValueType == VAL_Color || left->ValueType == VAL_Name)
- {
- left->ValueType = right->ValueType = VAL_Int;
- goto cont;
- }
- }
-
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
return NULL;
}
-cont:
+
if (left->isConstant() && right->isConstant())
{
int v;
- if (ValueType == VAL_Float)
+ if (ValueType->GetRegType() == REGT_FLOAT)
{
double v1 = static_cast(left)->GetValue().GetFloat();
double v2 = static_cast(right)->GetValue().GetFloat();
@@ -1448,7 +1370,7 @@ cont:
return e;
}
Promote(ctx);
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
return this;
}
@@ -1505,7 +1427,7 @@ ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build)
FxBinaryInt::FxBinaryInt(int o, FxExpression *l, FxExpression *r)
: FxBinary(o, l, r)
{
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
}
//==========================================================================
@@ -1519,15 +1441,15 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx)
CHECKRESOLVED();
if (!ResolveLR(ctx, false)) return NULL;
- if (ValueType == VAL_Float /* lax */)
+ if (ValueType->GetRegType() == REGT_FLOAT /* lax */)
{
// For DECORATE which allows floats here.
- if (left->ValueType != VAL_Int)
+ if (left->ValueType->GetRegType() != REGT_INT)
{
left = new FxIntCast(left);
left = left->Resolve(ctx);
}
- if (right->ValueType != VAL_Int)
+ if (right->ValueType->GetRegType() != REGT_INT)
{
right = new FxIntCast(right);
right = right->Resolve(ctx);
@@ -1537,10 +1459,10 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx)
delete this;
return NULL;
}
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
}
- if (ValueType != VAL_Int)
+ if (ValueType->GetRegType() != REGT_INT)
{
ScriptPosition.Message(MSG_ERROR, "Integer type expected");
delete this;
@@ -1573,8 +1495,8 @@ FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx)
ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build)
{
- assert(left->ValueType == VAL_Int);
- assert(right->ValueType == VAL_Int);
+ assert(left->ValueType->GetRegType() == REGT_INT);
+ assert(right->ValueType->GetRegType() == REGT_INT);
static const VM_UBYTE InstrMap[][4] =
{
{ OP_SLL_RR, OP_SLL_KR, OP_SLL_RI }, // TK_LShift
@@ -1656,7 +1578,7 @@ FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r)
Operator=o;
left=l;
right=r;
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
}
//==========================================================================
@@ -1753,11 +1675,11 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
return x;
}
}
- if (left->ValueType != VAL_Int && left->ValueType != VAL_Sound)
+ if (left->ValueType->GetRegType() != REGT_INT)
{
left = new FxIntCast(left);
}
- if (right->ValueType != VAL_Int && right->ValueType != VAL_Sound)
+ if (right->ValueType->GetRegType() != REGT_INT)
{
right = new FxIntCast(right);
}
@@ -1775,7 +1697,7 @@ ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build)
// This is not the "right" way to do these, but it works for now.
// (Problem: No information sharing is done between nodes to reduce the
// code size if you have something like a1 && a2 && a3 && ... && an.)
- assert(left->ValueType == VAL_Int && right->ValueType == VAL_Int);
+ assert(left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT);
ExpEmit op1 = left->Emit(build);
assert(!op1.Konst);
int zero = build->GetConstantInt(0);
@@ -1865,10 +1787,10 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx)
RESOLVE(falsex, ctx);
ABORT(condition && truex && falsex);
- if (truex->ValueType == VAL_Int && falsex->ValueType == VAL_Int)
- ValueType = VAL_Int;
- else if (truex->ValueType.isNumeric() && falsex->ValueType.isNumeric())
- ValueType = VAL_Float;
+ if (truex->ValueType->GetRegType() == REGT_INT && falsex->ValueType->GetRegType() == REGT_INT)
+ ValueType = TypeSInt32;
+ else if (truex->IsNumeric() && falsex->IsNumeric())
+ ValueType = TypeFloat64;
//else if (truex->ValueType != falsex->ValueType)
if (condition->isConstant())
@@ -1883,14 +1805,14 @@ FxExpression *FxConditional::Resolve(FCompileContext& ctx)
return e;
}
- if (ValueType == VAL_Float)
+ if (ValueType->GetRegType() == REGT_FLOAT)
{
- if (truex->ValueType != VAL_Float)
+ if (truex->ValueType->GetRegType() != REGT_FLOAT)
{
truex = new FxFloatCast(truex);
RESOLVE(truex, ctx);
}
- if (falsex->ValueType != VAL_Float)
+ if (falsex->ValueType->GetRegType() != REGT_FLOAT)
{
falsex = new FxFloatCast(falsex);
RESOLVE(falsex, ctx);
@@ -1921,7 +1843,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
size_t patchspot = build->Emit(OP_JMP, 0);
// Evaluate true expression.
- if (truex->isConstant() && truex->ValueType == VAL_Int)
+ if (truex->isConstant() && truex->ValueType->GetRegType() == REGT_INT)
{
out = ExpEmit(build, REGT_INT);
build->EmitLoadInt(out.RegNum, static_cast(truex)->GetValue().GetInt());
@@ -1945,7 +1867,7 @@ ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
// Evaluate false expression.
build->BackpatchToHere(patchspot);
- if (falsex->isConstant() && falsex->ValueType == VAL_Int)
+ if (falsex->isConstant() && falsex->ValueType->GetRegType() == REGT_INT)
{
build->EmitLoadInt(out.RegNum, static_cast(falsex)->GetValue().GetInt());
}
@@ -2013,7 +1935,7 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx)
SAFE_RESOLVE(val, ctx);
- if (!val->ValueType.isNumeric())
+ if (!val->IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
@@ -2022,13 +1944,13 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx)
else if (val->isConstant())
{
ExpVal value = static_cast(val)->GetValue();
- switch (value.Type)
+ switch (value.Type->GetRegType())
{
- case VAL_Int:
+ case REGT_INT:
value.Int = abs(value.Int);
break;
- case VAL_Float:
+ case REGT_FLOAT:
value.Float = fabs(value.Float);
break;
@@ -2079,7 +2001,6 @@ FxMinMax::FxMinMax(TArray &expr, FName type, const FScriptPositio
assert(expr.Size() > 0);
assert(type == NAME_Min || type == NAME_Max);
- ValueType = VAL_Unknown;
choices.Resize(expr.Size());
for (unsigned i = 0; i < expr.Size(); ++i)
{
@@ -2106,11 +2027,11 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx)
RESOLVE(choices[i], ctx);
ABORT(choices[i]);
- if (choices[i]->ValueType == VAL_Float)
+ if (choices[i]->ValueType->GetRegType() == REGT_FLOAT)
{
floatcount++;
}
- else if (choices[i]->ValueType == VAL_Int)
+ else if (choices[i]->ValueType->GetRegType() == REGT_INT)
{
intcount++;
}
@@ -2123,12 +2044,12 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx)
}
if (floatcount != 0)
{
- ValueType = VAL_Float;
+ ValueType = TypeFloat64;
if (intcount != 0)
{ // There are some ints that need to be cast to floats
for (i = 0; i < choices.Size(); ++i)
{
- if (choices[i]->ValueType == VAL_Int)
+ if (choices[i]->ValueType->GetRegType() == REGT_INT)
{
choices[i] = new FxFloatCast(choices[i]);
RESOLVE(choices[i], ctx);
@@ -2139,7 +2060,7 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx)
}
else
{
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
}
// If at least two arguments are constants, they can be solved now.
@@ -2161,10 +2082,10 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx)
else
{
ExpVal value = static_cast(choices[j])->GetValue();
- assert(value.Type == ValueType.Type);
+ assert(value.Type == ValueType);
if (Type == NAME_Min)
{
- if (value.Type == VAL_Float)
+ if (value.Type->GetRegType() == REGT_FLOAT)
{
if (value.Float < best.Float)
{
@@ -2181,7 +2102,7 @@ FxExpression *FxMinMax::Resolve(FCompileContext &ctx)
}
else
{
- if (value.Type == VAL_Float)
+ if (value.Type->GetRegType() == REGT_FLOAT)
{
if (value.Float > best.Float)
{
@@ -2245,12 +2166,12 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build)
if (Type == NAME_Min)
{
- opcode = ValueType.Type == VAL_Float ? OP_LEF_RR : OP_LE_RR;
+ opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_LEF_RR : OP_LE_RR;
opA = 1;
}
else
{
- opcode = ValueType.Type == VAL_Float ? OP_LTF_RR : OP_LT_RR;
+ opcode = ValueType->GetRegType() == REGT_FLOAT ? OP_LTF_RR : OP_LT_RR;
opA = 0;
}
@@ -2259,7 +2180,7 @@ ExpEmit FxMinMax::Emit(VMFunctionBuilder *build)
// Get first value into a register. This will also be the result register.
if (choices[0]->isConstant())
{
- bestreg = ExpEmit(build, ValueType.Type == VAL_Float ? REGT_FLOAT : REGT_INT);
+ bestreg = ExpEmit(build, ValueType->GetRegType());
EmitLoad(build, bestreg, static_cast(choices[0])->GetValue());
}
else
@@ -2297,12 +2218,12 @@ FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScrip
{
if (mi != NULL && ma != NULL)
{
- min = new FxParameter(new FxIntCast(mi));
- max = new FxParameter(new FxIntCast(ma));
+ min = new FxIntCast(mi);
+ max = new FxIntCast(ma);
}
else min = max = NULL;
rng = r;
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
}
//==========================================================================
@@ -2331,8 +2252,8 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx)
RESOLVE(min, ctx);
RESOLVE(max, ctx);
ABORT(min && max);
- assert(min->ValueType == ValueType.Type);
- assert(max->ValueType == ValueType.Type);
+ assert(min->ValueType == ValueType);
+ assert(max->ValueType == ValueType);
}
return this;
};
@@ -2382,8 +2303,8 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
if (min != NULL && max != NULL)
{
- min->Emit(build);
- max->Emit(build);
+ EmitParameter(build, min, ScriptPosition);
+ EmitParameter(build, max, ScriptPosition);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1);
}
else
@@ -2418,7 +2339,14 @@ FxRandomPick::FxRandomPick(FRandom *r, TArray &expr, bool floaty,
}
rng = r;
- ValueType = floaty ? VAL_Float : VAL_Int;
+ if (floaty)
+ {
+ ValueType = TypeFloat64;
+ }
+ else
+ {
+ ValueType = TypeSInt32;
+ }
}
//==========================================================================
@@ -2444,7 +2372,7 @@ FxExpression *FxRandomPick::Resolve(FCompileContext &ctx)
{
RESOLVE(choices[index], ctx);
ABORT(choices[index]);
- assert(choices[index]->ValueType == ValueType.Type);
+ assert(choices[index]->ValueType == ValueType);
}
return this;
};
@@ -2498,7 +2426,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
// For floating point results, we need to get a new register, since we can't
// reuse the integer one used to store the random result.
- if (ValueType == VAL_Float)
+ if (ValueType->GetRegType() == REGT_FLOAT)
{
resultreg = ExpEmit(build, REGT_FLOAT);
resultreg.Free(build);
@@ -2528,7 +2456,7 @@ ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build)
// was expected. Copy it to the one we wanted.
resultreg.Reuse(build); // This is really just for the assert in Reuse()
- build->Emit(ValueType == VAL_Int ? OP_MOVE : OP_MOVEF, resultreg.RegNum, casereg.RegNum, 0);
+ build->Emit(ValueType->GetRegType() == REGT_INT ? OP_MOVE : OP_MOVEF, resultreg.RegNum, casereg.RegNum, 0);
resultreg.Free(build);
}
// Free this register so the remaining cases can use it.
@@ -2562,10 +2490,10 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri
{
if (mi != NULL && ma != NULL)
{
- min = new FxParameter(new FxFloatCast(mi));
- max = new FxParameter(new FxFloatCast(ma));
+ min = new FxFloatCast(mi);
+ max = new FxFloatCast(ma);
}
- ValueType = VAL_Float;
+ ValueType = TypeFloat64;
}
//==========================================================================
@@ -2611,8 +2539,8 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build)
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
if (min != NULL && max != NULL)
{
- min->Emit(build);
- max->Emit(build);
+ EmitParameter(build, min, ScriptPosition);
+ EmitParameter(build, max, ScriptPosition);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1);
}
else
@@ -2636,8 +2564,7 @@ FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos)
rng = r;
if (m) mask = new FxIntCast(m);
else mask = new FxConstant(-1, pos);
- mask = new FxParameter(mask);
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
}
//==========================================================================
@@ -2681,7 +2608,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build)
callfunc = ((PSymbolVMFunction *)sym)->Function;
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
- mask->Emit(build);
+ EmitParameter(build, mask, ScriptPosition);
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
ExpEmit out(build, REGT_INT);
build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum);
@@ -2814,7 +2741,7 @@ FxExpression *FxSelf::Resolve(FCompileContext& ctx)
return NULL;
}
ValueType = ctx.cls;
- ValueType.Type = VAL_Object;
+ ValueType = NewPointer(RUNTIME_CLASS(DObject));
return this;
}
@@ -2853,7 +2780,7 @@ FxDamage::FxDamage(const FScriptPosition &pos)
FxExpression *FxDamage::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
return this;
}
@@ -2940,41 +2867,14 @@ FxExpression *FxClassMember::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
SAFE_RESOLVE(classx, ctx);
- if (classx->ValueType != VAL_Object && classx->ValueType != VAL_Class)
+ PPointer *ptrtype = dyn_cast(classx->ValueType);
+ if (ptrtype == NULL || !ptrtype->IsKindOf(RUNTIME_CLASS(DObject)))
{
ScriptPosition.Message(MSG_ERROR, "Member variable requires a class or object");
delete this;
return NULL;
}
- PType *type = membervar->Type;
- PArray *arraytype = dyn_cast(type);
-
- if (arraytype != NULL)
- {
- type = arraytype->ElementType;
- }
- if (type->IsKindOf(RUNTIME_CLASS(PPointer)))
- {
- ValueType = VAL_Object;
- }
- else if (type->IsKindOf(RUNTIME_CLASS(PInt)))
- {
- ValueType = VAL_Int;
- }
- else if (type->IsKindOf(RUNTIME_CLASS(PFloat)))
- {
- ValueType = VAL_Float;
- }
- else
- {
- ScriptPosition.Message(MSG_ERROR, "Invalid type for member variable %s", membervar->SymbolName.GetChars());
- delete this;
- return NULL;
- }
- if (arraytype != NULL)
- {
- ValueType.MakeArray(arraytype->ElementCount);
- }
+ ValueType = membervar->Type;
return this;
}
@@ -3067,7 +2967,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
SAFE_RESOLVE(Array,ctx);
SAFE_RESOLVE(index,ctx);
- if (index->ValueType == VAL_Float /* lax */)
+ if (index->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{
// DECORATE allows floats here so cast them to int.
index = new FxIntCast(index);
@@ -3078,22 +2978,23 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
return NULL;
}
}
- if (index->ValueType != VAL_Int)
+ if (index->ValueType->GetRegType() != REGT_INT)
{
ScriptPosition.Message(MSG_ERROR, "Array index must be integer");
delete this;
return NULL;
}
- if (Array->ValueType != VAL_Array)
+ PArray *arraytype = dyn_cast(Array->ValueType);
+ if (arraytype == NULL)
{
ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays.");
delete this;
return NULL;
}
- ValueType = Array->ValueType.GetBaseType();
- if (ValueType != VAL_Int)
+ ValueType = arraytype->ElementType;
+ if (ValueType->GetRegType() != REGT_INT)
{
// int arrays only for now
ScriptPosition.Message(MSG_ERROR, "Only integer arrays are supported.");
@@ -3122,8 +3023,8 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
}
if (index->isConstant())
{
- int indexval = static_cast(index)->GetValue().GetInt();
- if (indexval < 0 || indexval >= Array->ValueType.size)
+ unsigned indexval = static_cast(index)->GetValue().GetInt();
+ if (indexval >= static_cast(Array->ValueType)->ElementCount)
{
I_Error("Array index out of bounds");
}
@@ -3134,7 +3035,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
{
ExpEmit indexv(index->Emit(build));
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, 2);
- build->Emit(OP_BOUND, indexv.RegNum, Array->ValueType.size);
+ build->Emit(OP_BOUND, indexv.RegNum, static_cast(Array->ValueType)->ElementCount);
build->Emit(OP_LW_R, dest.RegNum, start.RegNum, indexv.RegNum);
indexv.Free(build);
}
@@ -3275,21 +3176,21 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
if (ArgList != NULL)
{
- for(unsigned i = 0; i < ArgList->Size(); i++)
+ for (unsigned i = 0; i < ArgList->Size(); i++)
{
(*ArgList)[i] = (*ArgList)[i]->Resolve(ctx);
if ((*ArgList)[i] == NULL) failed = true;
if (Special < 0 && i == 0)
{
- if ((*ArgList)[i]->ValueType != VAL_Name)
+ if ((*ArgList)[i]->ValueType != TypeName)
{
ScriptPosition.Message(MSG_ERROR, "Name expected for parameter %d", i);
failed = true;
}
}
- else if ((*ArgList)[i]->ValueType != VAL_Int)
+ else if ((*ArgList)[i]->ValueType->GetRegType() != REGT_INT)
{
- if ((*ArgList)[i]->ValueType == VAL_Float /* lax */)
+ if ((*ArgList)[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{
(*ArgList)[i] = new FxIntCast((*ArgList)[i]);
}
@@ -3306,7 +3207,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
return NULL;
}
}
- ValueType = VAL_Int;
+ ValueType = TypeSInt32;
return this;
}
@@ -3347,13 +3248,13 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
FxExpression *argex = (*ArgList)[i];
if (Special < 0 && i == 0)
{
- assert(argex->ValueType == VAL_Name);
+ assert(argex->ValueType == TypeName);
assert(argex->isConstant());
build->EmitParamInt(-static_cast(argex)->GetValue().GetName());
}
else
{
- assert(argex->ValueType == VAL_Int);
+ assert(argex->ValueType->GetRegType() == REGT_INT);
if (argex->isConstant())
{
build->EmitParamInt(static_cast(argex)->GetValue().GetInt());
@@ -3432,17 +3333,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
TArray &rets = Function->Variants[0].Implementation->Proto->ReturnTypes;
if (rets.Size() > 0)
{
- // If more types are added to ParseNativeFunction(), add them here too.
- if (rets[0] == TypeSInt32) ValueType = VAL_Int;
- else if (rets[0] == TypeFloat64) ValueType = VAL_Float;
- else if (rets[0] == TypeAngle) ValueType = VAL_Angle;
- else if (rets[0] == TypeFixed) ValueType = VAL_Fixed;
- else if (rets[0] == TypeState) ValueType = VAL_State;
- else
- {
- ValueType = VAL_Int;
- assert(0 && "Unhandled return type in FxVMFunctionCall::Resolve");
- }
+ ValueType = rets[0];
}
return this;
}
@@ -3465,6 +3356,14 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
assert(build->Registers[REGT_POINTER].GetMostUsed() >= 3);
int count = GetArgCount();
+ if (count == 1)
+ {
+ ExpEmit reg;
+ if (CheckEmitCast(build, tailcall, reg))
+ {
+ return reg;
+ }
+ }
// Emit code to pass implied parameters
if (Function->Flags & VARF_Method)
{
@@ -3482,7 +3381,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
{
for (unsigned i = 0; i < ArgList->Size(); ++i)
{
- (*ArgList)[i]->Emit(build);
+ EmitParameter(build, (*ArgList)[i], ScriptPosition);
}
}
// Get a constant register for this function
@@ -3508,6 +3407,47 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build, bool tailcall)
}
}
+//==========================================================================
+//
+// If calling one of the casting kludge functions, don't bother calling the
+// function; just use the parameter directly. Returns true if this was a
+// kludge function, false otherwise.
+//
+//==========================================================================
+
+bool FxVMFunctionCall::CheckEmitCast(VMFunctionBuilder *build, bool returnit, ExpEmit ®)
+{
+ FName funcname = Function->SymbolName;
+ if (funcname == NAME___decorate_internal_int__ ||
+ funcname == NAME___decorate_internal_bool__ ||
+ funcname == NAME___decorate_internal_state__)
+ {
+ FxExpression *arg = (*ArgList)[0];
+ if (returnit)
+ {
+ if (arg->isConstant() &&
+ (funcname == NAME___decorate_internal_int__ ||
+ funcname == NAME___decorate_internal_bool__))
+ { // Use immediate version for integers in range
+ build->EmitRetInt(0, true, static_cast(arg)->GetValue().Int);
+ }
+ else
+ {
+ ExpEmit where = arg->Emit(build);
+ build->Emit(OP_RET, RET_FINAL, where.RegType | (where.Konst ? REGT_KONST : 0), where.RegNum);
+ where.Free(build);
+ }
+ reg = ExpEmit();
+ }
+ else
+ {
+ reg = arg->Emit(build);
+ }
+ return true;
+ }
+ return false;
+}
+
//==========================================================================
//
//
@@ -3518,7 +3458,7 @@ FxFlopFunctionCall::FxFlopFunctionCall(size_t index, FArgumentList *args, const
: FxExpression(pos)
{
assert(index < countof(FxFlops) && "FLOP index out of range");
- Index = index;
+ Index = (int)index;
ArgList = args;
}
@@ -3551,7 +3491,7 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx)
return NULL;
}
- if (!(*ArgList)[0]->ValueType.isNumeric())
+ if (!(*ArgList)[0]->IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter");
delete this;
@@ -3565,11 +3505,11 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx)
delete this;
return x;
}
- if ((*ArgList)[0]->ValueType == VAL_Int)
+ if ((*ArgList)[0]->ValueType->GetRegType() == REGT_INT)
{
(*ArgList)[0] = new FxFloatCast((*ArgList)[0]);
}
- ValueType = VAL_Float;
+ ValueType = TypeFloat64;
return this;
}
@@ -3682,7 +3622,7 @@ FxExpression *FxIfStatement::Resolve(FCompileContext &ctx)
WhenFalse = WhenFalse->Resolve(ctx);
ABORT(WhenFalse);
}
- ValueType = VAL_Unknown;
+ ValueType = TypeVoid;
if (Condition->isConstant())
{
@@ -3834,7 +3774,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
SAFE_RESOLVE(basex, ctx);
- if (basex->ValueType != VAL_Name)
+ if (basex->ValueType != TypeName)
{
ScriptPosition.Message(MSG_ERROR, "Cannot convert to class type");
delete this;
@@ -3904,7 +3844,7 @@ int DecoNameToClass(VMFrameStack *stack, VMValue *param, int numparam, VMReturn
ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
{
- if (basex->ValueType != VAL_Name)
+ if (basex->ValueType != TypeName)
{
return ExpEmit(build->GetConstantAddress(NULL, ATAG_OBJECT), REGT_POINTER, true);
}
@@ -4035,7 +3975,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
}
names.Delete(0);
names.ShrinkToFit();
- ValueType = VAL_State;
+ ValueType = TypeState;
return this;
}
@@ -4133,7 +4073,7 @@ FxDamageValue::FxDamageValue(FxExpression *v, bool calc)
: FxExpression(v->ScriptPosition)
{
val = v;
- ValueType = VAL_Unknown;
+ ValueType = TypeVoid;
Calculated = calc;
MyFunction = NULL;
@@ -4154,7 +4094,7 @@ FxExpression *FxDamageValue::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
SAFE_RESOLVE(val, ctx)
- if (!val->ValueType.isNumeric())
+ if (!val->IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp
index daff4a99b..105bf237f 100644
--- a/src/thingdef/thingdef_parse.cpp
+++ b/src/thingdef/thingdef_parse.cpp
@@ -127,7 +127,7 @@ FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool c
v = MAKEARGB(1, RPART(c), GPART(c), BPART(c));
}
ExpVal val;
- val.Type = VAL_Color;
+ val.Type = TypeColor;
val.Int = v;
x = new FxConstant(val, sc);
}
diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp
index 50b03eb27..702758eb7 100644
--- a/src/thingdef/thingdef_states.cpp
+++ b/src/thingdef/thingdef_states.cpp
@@ -77,7 +77,7 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag)
if (special > 0 && min_args >= 0)
{
FArgumentList *args = new FArgumentList;
- args->Push(new FxParameter(new FxConstant(special, sc)));
+ args->Push(new FxConstant(special, sc));
i = 0;
// Make this consistent with all other parameter parsing
@@ -85,7 +85,7 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag)
{
while (i < 5)
{
- args->Push(new FxParameter(new FxIntCast(ParseExpression(sc, bag.Info))));
+ args->Push(new FxIntCast(ParseExpression(sc, bag.Info)));
i++;
if (!sc.CheckToken (',')) break;
}
@@ -441,6 +441,45 @@ static PPrototype *ReturnCheck(PPrototype *proto1, PPrototype *proto2, FScanner
//
//==========================================================================
+static FxExpression *ParseIf(FScanner &sc, FState state, FString statestring, Baggage &bag,
+ PPrototype *&retproto, bool &lastwasret)
+{
+ FxExpression *add, *cond;
+ FxExpression *true_part, *false_part = NULL;
+ PPrototype *true_proto, *false_proto = NULL;
+ bool true_ret, false_ret = false;
+ sc.MustGetStringName("(");
+ cond = ParseExpression(sc, bag.Info);
+ sc.MustGetStringName(")");
+ sc.MustGetStringName("{"); // braces are mandatory
+ true_part = ParseActions(sc, state, statestring, bag, true_proto, true_ret);
+ sc.MustGetString();
+ if (sc.Compare("else"))
+ {
+ if (sc.CheckString("if"))
+ {
+ false_part = ParseIf(sc, state, statestring, bag, false_proto, false_ret);
+ }
+ else
+ {
+ sc.MustGetStringName("{"); // braces are still mandatory
+ false_part = ParseActions(sc, state, statestring, bag, false_proto, false_ret);
+ sc.MustGetString();
+ }
+ }
+ add = new FxIfStatement(cond, true_part, false_part, sc);
+ retproto = ReturnCheck(retproto, true_proto, sc);
+ retproto = ReturnCheck(retproto, false_proto, sc);
+ // If one side does not end with a return, we don't consider the if statement
+ // to end with a return. If the else case is missing, it can never be considered
+ // as ending with a return.
+ if (true_ret && false_ret)
+ {
+ lastwasret = true;
+ }
+ return add;
+}
+
FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Baggage &bag,
PPrototype *&retproto, bool &endswithret)
{
@@ -467,32 +506,7 @@ FxExpression *ParseActions(FScanner &sc, FState state, FString statestring, Bagg
lastwasret = false;
if (sc.Compare("if"))
{ // Hangle an if statement
- FxExpression *cond;
- FxExpression *true_part, *false_part = NULL;
- PPrototype *true_proto, *false_proto = NULL;
- bool true_ret, false_ret = false;
- sc.MustGetStringName("(");
- cond = ParseExpression(sc, bag.Info);
- sc.MustGetStringName(")");
- sc.MustGetStringName("{"); // braces are mandatory
- true_part = ParseActions(sc, state, statestring, bag, true_proto, true_ret);
- sc.MustGetString();
- if (sc.Compare("else"))
- {
- sc.MustGetStringName("{"); // braces are still mandatory
- false_part = ParseActions(sc, state, statestring, bag, false_proto, false_ret);
- sc.MustGetString();
- }
- add = new FxIfStatement(cond, true_part, false_part, sc);
- proto = ReturnCheck(proto, true_proto, sc);
- proto = ReturnCheck(proto, false_proto, sc);
- // If one side does not end with a return, we don't consider the if statement
- // to end with a return. If the else case is missing, it can never be considered
- // as ending with a return.
- if (true_ret && false_ret)
- {
- lastwasret = true;
- }
+ add = ParseIf(sc, state, statestring, bag, proto, lastwasret);
}
else if (sc.Compare("return"))
{ // Handle a return statement
@@ -569,7 +583,7 @@ FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, B
}
return call;
}
- sc.ScriptError("Invalid state parameter %s\n", sc.String);
+ sc.ScriptError("Invalid parameter '%s'\n", sc.String);
return NULL;
}
@@ -647,7 +661,7 @@ void ParseFunctionParameters(FScanner &sc, PClassActor *cls, TArray 0)
diff --git a/src/thingdef/thingdef_type.h b/src/thingdef/thingdef_type.h
deleted file mode 100644
index 1707a8939..000000000
--- a/src/thingdef/thingdef_type.h
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef THINGDEF_TYPE_H
-#define THINGDEF_TYPE_H
-//==========================================================================
-//
-//
-//
-//==========================================================================
-
-enum ExpValType
-{
- VAL_Unresolved, // type not yet known
- VAL_Int, // integer number
- VAL_Float, // floating point number
- VAL_Unknown, // nothing
- VAL_Array, // Array (very limited right now)
- VAL_Object, // Object reference
- VAL_Class, // Class reference
- VAL_Sound, // Sound identifier. Internally it's an int.
- VAL_Name, // A Name
- VAL_String, // A string
- VAL_Color, // A color
- VAL_State, // A State pointer
-
- // only used for accessing external variables to ensure proper conversion
- VAL_Fixed,
- VAL_Angle,
- VAL_Bool,
-};
-
-struct FExpressionType
-{
- BYTE Type;
- BYTE BaseType;
- WORD size; // for arrays;
- const PClass *ClassType;
-
- FExpressionType &operator=(int typeval)
- {
- Type = typeval;
- BaseType = 0;
- size = 0;
- ClassType = NULL;
- return *this;
- }
-
- FExpressionType &operator=(const PClass *cls)
- {
- Type = VAL_Class;
- BaseType = 0;
- size = 0;
- ClassType = cls;
- return *this;
- }
-
- bool operator==(int typeval) const
- {
- return Type == typeval;
- }
-
- bool operator!=(int typeval) const
- {
- return Type != typeval;
- }
-
- bool isNumeric() const
- {
- return Type == VAL_Float || Type == VAL_Int;
- }
-
- bool isPointer() const
- {
- return Type == VAL_Object || Type == VAL_Class;
- }
-
- FExpressionType GetBaseType() const
- {
- FExpressionType ret = *this;
- ret.Type = BaseType;
- ret.BaseType = 0;
- ret.size = 0;
- return ret;
- }
-
-
- // currently only used for args[].
- // Needs to be done differently for a generic implementation!
- void MakeArray(int siz)
- {
- BaseType = Type;
- Type = VAL_Array;
- size = siz;
- }
-
-};
-
-#endif
diff --git a/src/win32/i_crash.cpp b/src/win32/i_crash.cpp
index 0735e3553..70d10fa30 100644
--- a/src/win32/i_crash.cpp
+++ b/src/win32/i_crash.cpp
@@ -45,7 +45,13 @@
#include
#endif
#ifndef __GNUC__
+#if _MSC_VER
+#pragma warning(disable:4091) // this silences a warning for a bogus definition in the Windows 8.1 SDK.
+#endif
#include
+#if _MSC_VER
+#pragma warning(default:4091)
+#endif
#endif
#include
#include
diff --git a/src/win32/zdoom.RES b/src/win32/zdoom.RES
deleted file mode 100644
index 55d9e7549..000000000
Binary files a/src/win32/zdoom.RES and /dev/null differ
diff --git a/src/zscript/vm.h b/src/zscript/vm.h
index f92906fd2..5b37aa47c 100644
--- a/src/zscript/vm.h
+++ b/src/zscript/vm.h
@@ -900,7 +900,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a;
#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a;
#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
-#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base)));
+#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
// For optional paramaters. These have dangling elses for you to fill in the default assignment. e.g.:
// PARAM_INT_OPT(0,myint) { myint = 55; }
@@ -918,7 +918,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else
#define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else
#define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else
-#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x != NULL && x->IsDescendantOf(RUNTIME_CLASS(base))); } else
+#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); } else
// The above, but with an automatically increasing position index.
#define PARAM_PROLOGUE int paramnum = -1;
diff --git a/tools/fixrtext/fixrtext.vcproj b/tools/fixrtext/fixrtext.vcproj
deleted file mode 100644
index 33bfde6f0..000000000
--- a/tools/fixrtext/fixrtext.vcproj
+++ /dev/null
@@ -1,182 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/lemon/lemon.vcproj b/tools/lemon/lemon.vcproj
deleted file mode 100644
index d3205b967..000000000
--- a/tools/lemon/lemon.vcproj
+++ /dev/null
@@ -1,431 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/re2c/re2c.vcproj b/tools/re2c/re2c.vcproj
deleted file mode 100644
index 81d8c4941..000000000
--- a/tools/re2c/re2c.vcproj
+++ /dev/null
@@ -1,845 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/updaterevision/updaterevision.vcproj b/tools/updaterevision/updaterevision.vcproj
deleted file mode 100644
index 17675b681..000000000
--- a/tools/updaterevision/updaterevision.vcproj
+++ /dev/null
@@ -1,376 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/zipdir/zipdir.vcproj b/tools/zipdir/zipdir.vcproj
deleted file mode 100644
index e279e551c..000000000
--- a/tools/zipdir/zipdir.vcproj
+++ /dev/null
@@ -1,356 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt
index c3de91e30..19e4d4f6d 100644
--- a/wadsrc/static/xlat/eternity.txt
+++ b/wadsrc/static/xlat/eternity.txt
@@ -1,216 +1,217 @@
-#include "xlat/doom.txt"
-
-// xlat file for Eternity levels.
-// Many specials are unsupported, especially portal stuff.
-// Some unsupported linedefs wouldn't be hard to add to ZDoom,
-// or are already there but implemented differently. Others are
-// practically impossible, or aren't worth the effort.
-
-define Unsupported (0)
-
-enum
-{
- Init_EDSector = 253,
- Init_EDLine = 254
-}
-
-// The tag for such a line is actually a key to find, in an ExtraData lump
-// indicated for the current level by the EMAPINFO lump, what line special
-// to actually use. This is how parameterized linedefs are used by Eternity
-// in the Doom format.
-
-270 = 0, Static_Init(tag, Init_EDLine) // "ExtraDataSpecial"
-
-// These two are standard MBF specials, no need to redefine them, they're in xlat/doom.txt
-// 271 = 0, Static_Init (tag, Init_TransferSky, 0)
-// 272 = 0, Static_Init (tag, Init_TransferSky, 1)
-
-// Small script starters. Small is considered deprecated now anyway.
-273 = 0, Unsupported() // "WR_StartScript_1S"
-274 = 0, Unsupported() // "W1_StartScript"
-275 = 0, Unsupported() // "W1_StartScript_1S"
-276 = 0, Unsupported() // "SR_StartScript"
-277 = 0, Unsupported() // "S1_StartScript"
-278 = 0, Unsupported() // "GR_StartScript"
-279 = 0, Unsupported() // "G1_StartScript"
-280 = 0, Unsupported() // "WR_StartScript"
-
-// 3D mid-textures
-281 = 0, Sector_Attach3DMidtex(tag, 0, 0) // "3DMidTex_MoveWithFloor"
-282 = 0, Sector_Attach3DMidtex(tag, 0, 1) // "3DMidTex_MoveWithCeiling"
-
-// Plane portals are not supported in ZDoom, though they probably wouldn't be too hard to implement.
-283 = 0, Sector_SetPortal(tag,3, 1, 0, 0) // "Portal_PlaneCeiling"
-284 = 0, Sector_SetPortal(tag,3, 0, 0, 0) // "Portal_PlaneFloor"
-285 = 0, Sector_SetPortal(tag,3, 2, 0, 0) // "Portal_PlaneFloorCeiling"
-286 = 0, Sector_SetPortal(tag,4, 1, 0, 0) // "Portal_HorizonCeiling"
-287 = 0, Sector_SetPortal(tag,4, 0, 0, 0) // "Portal_HorizonFloor"
-288 = 0, Sector_SetPortal(tag,4, 2, 0, 0) // "Portal_HorizonFloorCeiling"
-289 = 0, Sector_SetPortal(0, 5, 0, tag) // "Portal_LineTransfer"
-
-// Skybox portals
-290 = 0, Sector_SetPortal(tag, 2, 1, 1, 0) // "Portal_SkyboxCeiling"
-291 = 0, Sector_SetPortal(tag, 2, 0, 1, 0) // "Portal_SkyboxFloor"
-292 = 0, Sector_SetPortal(tag, 2, 2, 1, 0) // "Portal_SkyboxFloorCeiling"
-
-// Sector specials
-293 = 0, Sector_SetWind(tag, 0, 0, 1) // "TransferHereticWind"
-294 = 0, Sector_SetCurrent(tag, 0, 0, 1) // "TransferHereticCurrent"
-
-// Anchored portals -- Sector_SetPortal needs to allow to set both floor and ceiling, though.
-295 = 0, Sector_SetPortal(tag, 0, 1, 1, 0) // "Portal_AnchoredCeiling"
-296 = 0, Sector_SetPortal(tag, 0, 0, 1, 0) // "Portal_AnchoredFloor"
-297 = 0, Sector_SetPortal(tag, 0, 2, 1, 0) // "Portal_AnchoredFloorCeiling"
-298 = 0, Sector_SetPortal(tag, 0, 1, 0, 0) // "Portal_AnchorLine"
-299 = 0, Sector_SetPortal(tag, 0, 0, 0, 0) // "Portal_AnchorLineFloor"
-
-// Parameterized linedefs
-// They are never used directly in Doom-format maps. Instead, it passes through ExtraData and 270.
-// Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF.
-// The translation here is for the odd Extradata that specifies them as numbers.
-300 = 0, Door_Raise(0)
-301 = 0, Door_Open(0)
-302 = 0, Door_Close(0)
-303 = 0, Door_CloseWaitOpen(0)
-304 = 0, Door_WaitRaise(0)
-305 = 0, Door_WaitClose(0)
-306 = 0, Floor_RaiseToHighest(0)
-307 = 0, Floor_LowerToHighestEE(0)
-308 = 0, Floor_RaiseToLowest(0)
-309 = 0, Floor_LowerToLowest(0)
-310 = 0, Floor_RaiseToNearest(0)
-311 = 0, Floor_LowerToNearest(0)
-312 = 0, Floor_RaiseToLowestCeiling(0)
-313 = 0, Floor_LowerToLowestCeiling(0)
-314 = 0, Floor_RaiseToCeiling(0)
-315 = 0, Floor_RaiseByTexture(0)
-316 = 0, Floor_LowerByTexture(0)
-317 = 0, Floor_RaiseByValue(0)
-318 = 0, Floor_LowerByValue(0)
-319 = 0, Floor_MoveToValue(0)
-320 = 0, Floor_RaiseInstant(0)
-321 = 0, Floor_LowerInstant(0)
-322 = 0, Floor_ToCeilingInstant(0)
-323 = 0, Ceiling_RaiseToHighest(0)
-324 = 0, Ceiling_ToHighestInstant(0)
-325 = 0, Ceiling_RaiseToNearest(0)
-326 = 0, Ceiling_LowerToNearest(0)
-327 = 0, Ceiling_RaiseToLowest(0)
-328 = 0, Ceiling_LowerToLowest(0)
-329 = 0, Ceiling_RaiseToHighestFloor(0)
-330 = 0, Ceiling_LowerToHighestFloor(0)
-331 = 0, Ceiling_ToFloorInstant(0)
-332 = 0, Ceiling_LowerToFloor(0)
-333 = 0, Ceiling_RaiseByTexture(0)
-334 = 0, Ceiling_LowerByTexture(0)
-335 = 0, Ceiling_RaiseByValue(0)
-336 = 0, Ceiling_LowerByValue(0)
-337 = 0, Ceiling_MoveToValue(0)
-338 = 0, Ceiling_RaiseInstant(0)
-339 = 0, Ceiling_LowerInstant(0)
-340 = 0, Stairs_BuildUpDoom(0)
-341 = 0, Stairs_BuildDownDoom(0)
-342 = 0, Stairs_BuildUpDoomSync(0)
-343 = 0, Stairs_BuildDownDoomSync(0)
-
-// Two-way portals are not supported yet either
-344 = 0, Unsupported() // "Portal_TwowayCeiling"
-345 = 0, Unsupported() // "Portal_TwowayFloor"
-346 = 0, Unsupported() // "Portal_TwowayAnchorLine"
-347 = 0, Unsupported() // "Portal_TwowayAnchorLineFloor"
-
-// More parameterized linedefs
-348 = 0, Polyobj_StartLine(0)
-349 = 0, Polyobj_ExplicitLine(0)
-350 = 0, Polyobj_DoorSlide(0)
-351 = 0, Polyobj_DoorSwing(0)
-352 = 0, Polyobj_Move(0)
-353 = 0, Polyobj_OR_Move(0)
-354 = 0, Polyobj_RotateRight(0)
-355 = 0, Polyobj_OR_RotateRight(0)
-356 = 0, Polyobj_RotateLeft(0)
-357 = 0, Polyobj_OR_RotateLeft(0)
-
-// Eternity's linked portals, vertical link version (floor-to-ceiling)
-358 = 0, Sector_SetPortal(tag, 6, 1, 1, 0) // "Portal_AnchoredCeiling"
-359 = 0, Sector_SetPortal(tag, 6, 0, 1, 0) // "Portal_AnchoredFloor"
-360 = 0, Sector_SetPortal(tag, 6, 1, 0, 0) // "Portal_AnchorLine"
-361 = 0, Sector_SetPortal(tag, 6, 0, 0, 0) // "Portal_AnchorLineFloor"
-
-// Even more parameterized linedefs
-362 = 0, Pillar_Build(0)
-363 = 0, Pillar_BuildAndCrush(0)
-364 = 0, Pillar_Open(0)
-365 = 0, ACS_Execute(0)
-366 = 0, ACS_Suspend(0)
-367 = 0, ACS_Terminate(0)
-368 = 0, Light_RaiseByValue(0)
-369 = 0, Light_LowerByValue(0)
-370 = 0, Light_ChangeToValue(0)
-371 = 0, Light_Fade(0)
-372 = 0, Light_Glow(0)
-373 = 0, Light_Flicker(0)
-374 = 0, Light_Strobe(0)
-375 = 0, Radius_Quake(0)
-
-// Eternity's linked portals, horizontal link version (wall-to-wall)
-376 = 0, Line_SetPortal(0, tag, 4) // "Portal_LinkedLineToLine"
-377 = 0, Line_SetPortal(1, tag, 4) // "Portal_LinkedLineToLineAnchor"
-
-// The famous Hexen linedef
-378 = 0, Line_SetIdentification(0)
-
-// Attached sectors == linked sectors; However, the implementation in Eternity
-// is based on front sectors of tagged lines, not on sector tags. So instead
-// of Sector_SetLink, we pass through Static_Init to translate those.
-379 = 0, Static_Init(tag, 3, 1) // "Attach_SetCeilingControl"
-380 = 0, Static_Init(tag, 3, 0) // "Attach_SetFloorControl"
-381 = 0, Static_Init(0, 3, 0, 1) // "Attach_FloorToControl"
-382 = 0, Static_Init(0, 3, 1, 2) // "Attach_CeilingToControl"
-383 = 0, Static_Init(0, 3, 0, 5) // "Attach_MirrorFloorToControl"
-384 = 0, Static_Init(0, 3, 0, 10) // "Attach_MirrorCeilingToControl"
-
-// Attach tagged portal to front sector
-385 = 0, Sector_SetPortal(0, 1, 3, tag) // "Apply_PortalToFrontsector"
-
-// Slopes!
-386 = 0, Plane_Align (1, 0) // "Slope_FrontsectorFloor"
-387 = 0, Plane_Align (0, 1) // "Slope_FrontsectorCeiling"
-388 = 0, Plane_Align (1, 1) // "Slope_FrontsectorFloorAndCeiling"
-389 = 0, Plane_Align (2, 0) // "Slope_BacksectorFloor"
-390 = 0, Plane_Align (0, 2) // "Slope_BacksectorCeiling"
-391 = 0, Plane_Align (2, 2) // "Slope_BacksectorFloorAndCeiling"
-392 = 0, Plane_Align (2, 1) // "Slope_BackFloorAndFrontCeiling"
-393 = 0, Plane_Align (1, 2) // "Slope_BackCeilingAndFrontFloor"
-394 = 0, Plane_Copy (tag, 0) // "Slope_FrontFloorToTaggedSlope"
-395 = 0, Plane_Copy (0, tag) // "Slope_FrontCeilingToTaggedSlope"
-396 = 0, Plane_Copy(tag, tag)// "Slope_FrontFloorAndCeilingToTaggedSlope"
-
-// Last parameterized linedefs
-397 = 0, Floor_Waggle(0)
-398 = 0, Thing_Spawn(0)
-399 = 0, Thing_SpawnNoFog(0)
-400 = 0, Teleport_EndGame(0)
-
-401 = 0, Static_Init(tag, Init_EDSector)
-
-402 = 0, Thing_Projectile(0)
-403 = 0, Thing_ProjectileGravity(0)
-404 = 0, Thing_Activate(0)
-405 = 0, Thing_Deactivate(0)
-410 = 0, Plat_PerpetualRaise(0)
-411 = 0, Plat_Stop(0)
-412 = 0, Plat_DownWaitUpStay(0)
-413 = 0, Plat_DownByValue(0)
-414 = 0, Plat_UpWaitDownStay(0)
-415 = 0, Plat_UpByValue(0)
-416 = 0, Floor_LowerToHighest(0)
-420 = 0, ACS_ExecuteWithResult(0)
-421 = 0, Thing_ChangeTID(0)
-422 = 0, Thing_Raise(0)
-423 = 0, Thing_Stop(0)
-424 = 0, ThrustThing(0)
-425 = 0, ThrustThingZ(0)
-426 = 0, DamageThing(0)
-427 = 0, Thing_Damage(0)
-428 = 0, Thing_Destroy(0)
+#include "xlat/doom.txt"
+
+// xlat file for Eternity levels.
+// Many specials are unsupported, especially portal stuff.
+// Some unsupported linedefs wouldn't be hard to add to ZDoom,
+// or are already there but implemented differently. Others are
+// practically impossible, or aren't worth the effort.
+
+define Unsupported (0)
+
+enum
+{
+ Init_EDSector = 253,
+ Init_EDLine = 254
+}
+
+// The tag for such a line is actually a key to find, in an ExtraData lump
+// indicated for the current level by the EMAPINFO lump, what line special
+// to actually use. This is how parameterized linedefs are used by Eternity
+// in the Doom format.
+
+270 = 0, Static_Init(tag, Init_EDLine) // "ExtraDataSpecial"
+
+// These two are standard MBF specials, no need to redefine them, they're in xlat/doom.txt
+// 271 = 0, Static_Init (tag, Init_TransferSky, 0)
+// 272 = 0, Static_Init (tag, Init_TransferSky, 1)
+
+273 = WALK|REP|FIRSTSIDE, ACS_Execute(tag)
+274 = WALK, ACS_Execute(tag)
+275 = WALK|FIRSTSIDE, ACS_Execute(tag)
+276 = USE|REP, ACS_Execute(tag)
+277 = USE, ACS_Execute(tag)
+278 = SHOOT|REP, ACS_Execute(tag)
+279 = SHOOT, ACS_Execute(tag)
+280 = WALK|REP, ACS_Execute(tag)
+
+// 3D mid-textures
+281 = 0, Sector_Attach3DMidtex(tag, 0, 0) // "3DMidTex_MoveWithFloor"
+282 = 0, Sector_Attach3DMidtex(tag, 0, 1) // "3DMidTex_MoveWithCeiling"
+
+// Plane portals are not supported in ZDoom, though they probably wouldn't be too hard to implement.
+283 = 0, Sector_SetPortal(tag,3, 1, 0, 0) // "Portal_PlaneCeiling"
+284 = 0, Sector_SetPortal(tag,3, 0, 0, 0) // "Portal_PlaneFloor"
+285 = 0, Sector_SetPortal(tag,3, 2, 0, 0) // "Portal_PlaneFloorCeiling"
+286 = 0, Sector_SetPortal(tag,4, 1, 0, 0) // "Portal_HorizonCeiling"
+287 = 0, Sector_SetPortal(tag,4, 0, 0, 0) // "Portal_HorizonFloor"
+288 = 0, Sector_SetPortal(tag,4, 2, 0, 0) // "Portal_HorizonFloorCeiling"
+289 = 0, Sector_SetPortal(0, 5, 0, tag) // "Portal_LineTransfer"
+
+// Skybox portals
+290 = 0, Sector_SetPortal(tag, 2, 1, 1, 0) // "Portal_SkyboxCeiling"
+291 = 0, Sector_SetPortal(tag, 2, 0, 1, 0) // "Portal_SkyboxFloor"
+292 = 0, Sector_SetPortal(tag, 2, 2, 1, 0) // "Portal_SkyboxFloorCeiling"
+
+// Sector specials
+293 = 0, Sector_SetWind(tag, 0, 0, 1) // "TransferHereticWind"
+294 = 0, Sector_SetCurrent(tag, 0, 0, 1) // "TransferHereticCurrent"
+
+// Anchored portals -- Sector_SetPortal needs to allow to set both floor and ceiling, though.
+295 = 0, Sector_SetPortal(tag, 0, 1, 1, 0) // "Portal_AnchoredCeiling"
+296 = 0, Sector_SetPortal(tag, 0, 0, 1, 0) // "Portal_AnchoredFloor"
+297 = 0, Sector_SetPortal(tag, 0, 2, 1, 0) // "Portal_AnchoredFloorCeiling"
+298 = 0, Sector_SetPortal(tag, 0, 1, 0, 0) // "Portal_AnchorLine"
+299 = 0, Sector_SetPortal(tag, 0, 0, 0, 0) // "Portal_AnchorLineFloor"
+
+// Parameterized linedefs
+// They are never used directly in Doom-format maps. Instead, it passes through ExtraData and 270.
+// Hexen format is incomplete; and Quasar wants to use ZDoom-compatible special values for UDMF.
+// The translation here is for the odd Extradata that specifies them as numbers.
+300 = 0, Door_Raise(0)
+301 = 0, Door_Open(0)
+302 = 0, Door_Close(0)
+303 = 0, Door_CloseWaitOpen(0)
+304 = 0, Door_WaitRaise(0)
+305 = 0, Door_WaitClose(0)
+306 = 0, Floor_RaiseToHighest(0)
+307 = 0, Floor_LowerToHighestEE(0)
+308 = 0, Floor_RaiseToLowest(0)
+309 = 0, Floor_LowerToLowest(0)
+310 = 0, Floor_RaiseToNearest(0)
+311 = 0, Floor_LowerToNearest(0)
+312 = 0, Floor_RaiseToLowestCeiling(0)
+313 = 0, Floor_LowerToLowestCeiling(0)
+314 = 0, Floor_RaiseToCeiling(0)
+315 = 0, Floor_RaiseByTexture(0)
+316 = 0, Floor_LowerByTexture(0)
+317 = 0, Floor_RaiseByValue(0)
+318 = 0, Floor_LowerByValue(0)
+319 = 0, Floor_MoveToValue(0)
+320 = 0, Floor_RaiseInstant(0)
+321 = 0, Floor_LowerInstant(0)
+322 = 0, Floor_ToCeilingInstant(0)
+323 = 0, Ceiling_RaiseToHighest(0)
+324 = 0, Ceiling_ToHighestInstant(0)
+325 = 0, Ceiling_RaiseToNearest(0)
+326 = 0, Ceiling_LowerToNearest(0)
+327 = 0, Ceiling_RaiseToLowest(0)
+328 = 0, Ceiling_LowerToLowest(0)
+329 = 0, Ceiling_RaiseToHighestFloor(0)
+330 = 0, Ceiling_LowerToHighestFloor(0)
+331 = 0, Ceiling_ToFloorInstant(0)
+332 = 0, Ceiling_LowerToFloor(0)
+333 = 0, Ceiling_RaiseByTexture(0)
+334 = 0, Ceiling_LowerByTexture(0)
+335 = 0, Ceiling_RaiseByValue(0)
+336 = 0, Ceiling_LowerByValue(0)
+337 = 0, Ceiling_MoveToValue(0)
+338 = 0, Ceiling_RaiseInstant(0)
+339 = 0, Ceiling_LowerInstant(0)
+340 = 0, Stairs_BuildUpDoom(0)
+341 = 0, Stairs_BuildDownDoom(0)
+342 = 0, Stairs_BuildUpDoomSync(0)
+343 = 0, Stairs_BuildDownDoomSync(0)
+
+// Two-way portals are not supported yet either
+344 = 0, Unsupported() // "Portal_TwowayCeiling"
+345 = 0, Unsupported() // "Portal_TwowayFloor"
+346 = 0, Unsupported() // "Portal_TwowayAnchorLine"
+347 = 0, Unsupported() // "Portal_TwowayAnchorLineFloor"
+
+// More parameterized linedefs
+348 = 0, Polyobj_StartLine(0)
+349 = 0, Polyobj_ExplicitLine(0)
+350 = 0, Polyobj_DoorSlide(0)
+351 = 0, Polyobj_DoorSwing(0)
+352 = 0, Polyobj_Move(0)
+353 = 0, Polyobj_OR_Move(0)
+354 = 0, Polyobj_RotateRight(0)
+355 = 0, Polyobj_OR_RotateRight(0)
+356 = 0, Polyobj_RotateLeft(0)
+357 = 0, Polyobj_OR_RotateLeft(0)
+
+// Eternity's linked portals, vertical link version (floor-to-ceiling)
+358 = 0, Sector_SetPortal(tag, 6, 1, 1, 0) // "Portal_AnchoredCeiling"
+359 = 0, Sector_SetPortal(tag, 6, 0, 1, 0) // "Portal_AnchoredFloor"
+360 = 0, Sector_SetPortal(tag, 6, 1, 0, 0) // "Portal_AnchorLine"
+361 = 0, Sector_SetPortal(tag, 6, 0, 0, 0) // "Portal_AnchorLineFloor"
+
+// Even more parameterized linedefs
+362 = 0, Pillar_Build(0)
+363 = 0, Pillar_BuildAndCrush(0)
+364 = 0, Pillar_Open(0)
+365 = 0, ACS_Execute(0)
+366 = 0, ACS_Suspend(0)
+367 = 0, ACS_Terminate(0)
+368 = 0, Light_RaiseByValue(0)
+369 = 0, Light_LowerByValue(0)
+370 = 0, Light_ChangeToValue(0)
+371 = 0, Light_Fade(0)
+372 = 0, Light_Glow(0)
+373 = 0, Light_Flicker(0)
+374 = 0, Light_Strobe(0)
+375 = 0, Radius_Quake(0)
+
+// Eternity's linked portals, horizontal link version (wall-to-wall)
+376 = 0, Line_SetPortal(0, tag, 4) // "Portal_LinkedLineToLine"
+377 = 0, Line_SetPortal(1, tag, 4) // "Portal_LinkedLineToLineAnchor"
+
+// The famous Hexen linedef
+378 = 0, Line_SetIdentification(0)
+
+// Attached sectors == linked sectors; However, the implementation in Eternity
+// is based on front sectors of tagged lines, not on sector tags. So instead
+// of Sector_SetLink, we pass through Static_Init to translate those.
+379 = 0, Static_Init(tag, 3, 1) // "Attach_SetCeilingControl"
+380 = 0, Static_Init(tag, 3, 0) // "Attach_SetFloorControl"
+381 = 0, Static_Init(0, 3, 0, 1) // "Attach_FloorToControl"
+382 = 0, Static_Init(0, 3, 1, 2) // "Attach_CeilingToControl"
+383 = 0, Static_Init(0, 3, 0, 5) // "Attach_MirrorFloorToControl"
+384 = 0, Static_Init(0, 3, 0, 10) // "Attach_MirrorCeilingToControl"
+
+// Attach tagged portal to front sector
+385 = 0, Sector_SetPortal(0, 1, 3, tag) // "Apply_PortalToFrontsector"
+
+// Slopes!
+386 = 0, Plane_Align (1, 0) // "Slope_FrontsectorFloor"
+387 = 0, Plane_Align (0, 1) // "Slope_FrontsectorCeiling"
+388 = 0, Plane_Align (1, 1) // "Slope_FrontsectorFloorAndCeiling"
+389 = 0, Plane_Align (2, 0) // "Slope_BacksectorFloor"
+390 = 0, Plane_Align (0, 2) // "Slope_BacksectorCeiling"
+391 = 0, Plane_Align (2, 2) // "Slope_BacksectorFloorAndCeiling"
+392 = 0, Plane_Align (2, 1) // "Slope_BackFloorAndFrontCeiling"
+393 = 0, Plane_Align (1, 2) // "Slope_BackCeilingAndFrontFloor"
+394 = 0, Plane_Copy (tag, 0) // "Slope_FrontFloorToTaggedSlope"
+395 = 0, Plane_Copy (0, tag) // "Slope_FrontCeilingToTaggedSlope"
+396 = 0, Plane_Copy(tag, tag)// "Slope_FrontFloorAndCeilingToTaggedSlope"
+
+// Last parameterized linedefs
+397 = 0, Floor_Waggle(0)
+398 = 0, Thing_Spawn(0)
+399 = 0, Thing_SpawnNoFog(0)
+400 = 0, Teleport_EndGame(0)
+
+401 = 0, Static_Init(tag, Init_EDSector)
+
+402 = 0, Thing_Projectile(0)
+403 = 0, Thing_ProjectileGravity(0)
+404 = 0, Thing_Activate(0)
+405 = 0, Thing_Deactivate(0)
+410 = 0, Plat_PerpetualRaise(0)
+411 = 0, Plat_Stop(0)
+412 = 0, Plat_DownWaitUpStay(0)
+413 = 0, Plat_DownByValue(0)
+414 = 0, Plat_UpWaitDownStay(0)
+415 = 0, Plat_UpByValue(0)
+416 = 0, Floor_LowerToHighest(0)
+420 = 0, ACS_ExecuteWithResult(0)
+421 = 0, Thing_ChangeTID(0)
+422 = 0, Thing_Raise(0)
+423 = 0, Thing_Stop(0)
+424 = 0, ThrustThing(0)
+425 = 0, ThrustThingZ(0)
+426 = 0, DamageThing(0)
+427 = 0, Thing_Damage(0)
+428 = 0, Thing_Destroy(0)
+429 = 0, Door_LockedRaise(0)
+430 = 0, ACS_LockedExecute(0)
diff --git a/wadsrc/wadsrc.vcproj b/wadsrc/wadsrc.vcproj
deleted file mode 100644
index f5d63706b..000000000
--- a/wadsrc/wadsrc.vcproj
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/zdoom.sln b/zdoom.sln
deleted file mode 100644
index 11dc1b075..000000000
--- a/zdoom.sln
+++ /dev/null
@@ -1,177 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual Studio 2005
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zdoom", "zdoom.vcproj", "{8049475B-5C87-46F9-9358-635218A4EF18}"
- ProjectSection(ProjectDependencies) = postProject
- {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96} = {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}
- {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63} = {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}
- {6077B7D6-349F-4077-B552-3BC302EF5859} = {6077B7D6-349F-4077-B552-3BC302EF5859}
- {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E} = {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}
- {0F80ACBF-460E-44F0-B28E-B3272D1774A7} = {0F80ACBF-460E-44F0-B28E-B3272D1774A7}
- {DA47396F-60C1-4BDE-A977-7F7DE461CF77} = {DA47396F-60C1-4BDE-A977-7F7DE461CF77}
- {1D179D4B-F008-431B-8C72-111F8372584F} = {1D179D4B-F008-431B-8C72-111F8372584F}
- {B68E0ABF-B627-48A3-A92F-D8F827A75054} = {B68E0ABF-B627-48A3-A92F-D8F827A75054}
- {8997289F-10BF-4678-8BAA-3BB509C84953} = {8997289F-10BF-4678-8BAA-3BB509C84953}
- {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466} = {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}
- {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4} = {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}
- {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F} = {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcproj", "{F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lemon", "tools\lemon\lemon.vcproj", "{0F80ACBF-460E-44F0-B28E-B3272D1774A7}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "re2c", "tools\re2c\re2c.vcproj", "{667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wadsrc", "wadsrc\wadsrc.vcproj", "{1D179D4B-F008-431B-8C72-111F8372584F}"
- ProjectSection(ProjectDependencies) = postProject
- {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3} = {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "updaterevision", "tools\updaterevision\updaterevision.vcproj", "{6077B7D6-349F-4077-B552-3BC302EF5859}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpeg-6b", "jpeg-6b\jpeg-6b.vcproj", "{AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fixrtext", "tools\fixrtext\fixrtext.vcproj", "{DA47396F-60C1-4BDE-A977-7F7DE461CF77}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dumb_static", "dumb\vc6\dumb_static\dumb_static.vcproj", "{8997289F-10BF-4678-8BAA-3BB509C84953}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gdtoa", "gdtoa\gdtoa.vcproj", "{B68E0ABF-B627-48A3-A92F-D8F827A75054}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zipdir", "tools\zipdir\zipdir.vcproj", "{24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}"
- ProjectSection(ProjectDependencies) = postProject
- {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4} = {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}
- {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63} = {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}
- {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F} = {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lzmalib", "lzma\lzmalib.vcproj", "{6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "bzip2\bzip2.vcproj", "{A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "game-music-emu", "game-music-emu\game-music-emu.vcproj", "{9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Debug|x64 = Debug|x64
- Release|Win32 = Release|Win32
- Release|x64 = Release|x64
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {8049475B-5C87-46F9-9358-635218A4EF18}.Debug|Win32.ActiveCfg = Debug|Win32
- {8049475B-5C87-46F9-9358-635218A4EF18}.Debug|Win32.Build.0 = Debug|Win32
- {8049475B-5C87-46F9-9358-635218A4EF18}.Debug|x64.ActiveCfg = Debug|x64
- {8049475B-5C87-46F9-9358-635218A4EF18}.Debug|x64.Build.0 = Debug|x64
- {8049475B-5C87-46F9-9358-635218A4EF18}.Release|Win32.ActiveCfg = Release|Win32
- {8049475B-5C87-46F9-9358-635218A4EF18}.Release|Win32.Build.0 = Release|Win32
- {8049475B-5C87-46F9-9358-635218A4EF18}.Release|x64.ActiveCfg = Release|x64
- {8049475B-5C87-46F9-9358-635218A4EF18}.Release|x64.Build.0 = Release|x64
- {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Debug|Win32.ActiveCfg = Debug|Win32
- {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Debug|Win32.Build.0 = Debug|Win32
- {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Debug|x64.ActiveCfg = Debug|x64
- {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Debug|x64.Build.0 = Debug|x64
- {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Release|Win32.ActiveCfg = Release|Win32
- {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Release|Win32.Build.0 = Release|Win32
- {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Release|x64.ActiveCfg = Release|x64
- {F9D9E7D4-E1A2-4866-9E85-B1B14137EE63}.Release|x64.Build.0 = Release|x64
- {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Debug|Win32.ActiveCfg = Debug|Win32
- {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Debug|Win32.Build.0 = Debug|Win32
- {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Debug|x64.ActiveCfg = Release|Win32
- {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Debug|x64.Build.0 = Release|Win32
- {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Release|Win32.ActiveCfg = Release|Win32
- {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Release|Win32.Build.0 = Release|Win32
- {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Release|x64.ActiveCfg = Release|Win32
- {0F80ACBF-460E-44F0-B28E-B3272D1774A7}.Release|x64.Build.0 = Release|Win32
- {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Debug|Win32.ActiveCfg = Debug|Win32
- {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Debug|Win32.Build.0 = Debug|Win32
- {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Debug|x64.ActiveCfg = Release|Win32
- {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Debug|x64.Build.0 = Release|Win32
- {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Release|Win32.ActiveCfg = Release|Win32
- {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Release|Win32.Build.0 = Release|Win32
- {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Release|x64.ActiveCfg = Release|Win32
- {667D2EE7-C357-49E2-9BAB-0A4A45F0F76E}.Release|x64.Build.0 = Release|Win32
- {1D179D4B-F008-431B-8C72-111F8372584F}.Debug|Win32.ActiveCfg = Debug|Win32
- {1D179D4B-F008-431B-8C72-111F8372584F}.Debug|Win32.Build.0 = Debug|Win32
- {1D179D4B-F008-431B-8C72-111F8372584F}.Debug|x64.ActiveCfg = Release|Win32
- {1D179D4B-F008-431B-8C72-111F8372584F}.Debug|x64.Build.0 = Release|Win32
- {1D179D4B-F008-431B-8C72-111F8372584F}.Release|Win32.ActiveCfg = Release|Win32
- {1D179D4B-F008-431B-8C72-111F8372584F}.Release|Win32.Build.0 = Release|Win32
- {1D179D4B-F008-431B-8C72-111F8372584F}.Release|x64.ActiveCfg = Release|Win32
- {1D179D4B-F008-431B-8C72-111F8372584F}.Release|x64.Build.0 = Release|Win32
- {6077B7D6-349F-4077-B552-3BC302EF5859}.Debug|Win32.ActiveCfg = Debug|Win32
- {6077B7D6-349F-4077-B552-3BC302EF5859}.Debug|Win32.Build.0 = Debug|Win32
- {6077B7D6-349F-4077-B552-3BC302EF5859}.Debug|x64.ActiveCfg = Debug|x64
- {6077B7D6-349F-4077-B552-3BC302EF5859}.Debug|x64.Build.0 = Debug|x64
- {6077B7D6-349F-4077-B552-3BC302EF5859}.Release|Win32.ActiveCfg = Release|Win32
- {6077B7D6-349F-4077-B552-3BC302EF5859}.Release|Win32.Build.0 = Release|Win32
- {6077B7D6-349F-4077-B552-3BC302EF5859}.Release|x64.ActiveCfg = Release|x64
- {6077B7D6-349F-4077-B552-3BC302EF5859}.Release|x64.Build.0 = Release|x64
- {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Debug|Win32.ActiveCfg = Debug|Win32
- {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Debug|Win32.Build.0 = Debug|Win32
- {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Debug|x64.ActiveCfg = Debug|x64
- {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Debug|x64.Build.0 = Debug|x64
- {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Release|Win32.ActiveCfg = Release|Win32
- {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Release|Win32.Build.0 = Release|Win32
- {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Release|x64.ActiveCfg = Release|x64
- {AC3F5340-40CB-4C3A-8AA7-CB7158DB4466}.Release|x64.Build.0 = Release|x64
- {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Debug|Win32.ActiveCfg = Debug|Win32
- {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Debug|Win32.Build.0 = Debug|Win32
- {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Debug|x64.ActiveCfg = Debug|Win32
- {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Debug|x64.Build.0 = Debug|Win32
- {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Release|Win32.ActiveCfg = Release|Win32
- {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Release|Win32.Build.0 = Release|Win32
- {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Release|x64.ActiveCfg = Release|Win32
- {DA47396F-60C1-4BDE-A977-7F7DE461CF77}.Release|x64.Build.0 = Release|Win32
- {8997289F-10BF-4678-8BAA-3BB509C84953}.Debug|Win32.ActiveCfg = Debug|Win32
- {8997289F-10BF-4678-8BAA-3BB509C84953}.Debug|Win32.Build.0 = Debug|Win32
- {8997289F-10BF-4678-8BAA-3BB509C84953}.Debug|x64.ActiveCfg = Debug|x64
- {8997289F-10BF-4678-8BAA-3BB509C84953}.Debug|x64.Build.0 = Debug|x64
- {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|Win32.ActiveCfg = Release|Win32
- {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|Win32.Build.0 = Release|Win32
- {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|x64.ActiveCfg = Release|x64
- {8997289F-10BF-4678-8BAA-3BB509C84953}.Release|x64.Build.0 = Release|x64
- {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Debug|Win32.ActiveCfg = Debug|Win32
- {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Debug|Win32.Build.0 = Debug|Win32
- {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Debug|x64.ActiveCfg = Debug|x64
- {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Debug|x64.Build.0 = Debug|x64
- {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Release|Win32.ActiveCfg = Release|Win32
- {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Release|Win32.Build.0 = Release|Win32
- {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Release|x64.ActiveCfg = Release|x64
- {B68E0ABF-B627-48A3-A92F-D8F827A75054}.Release|x64.Build.0 = Release|x64
- {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Debug|Win32.ActiveCfg = Debug|Win32
- {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Debug|Win32.Build.0 = Debug|Win32
- {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Debug|x64.ActiveCfg = Debug|x64
- {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Debug|x64.Build.0 = Debug|x64
- {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Release|Win32.ActiveCfg = Release|Win32
- {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Release|Win32.Build.0 = Release|Win32
- {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Release|x64.ActiveCfg = Release|x64
- {24A19C02-F041-4AB0-A1A1-02E1E88EDBD3}.Release|x64.Build.0 = Release|x64
- {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Debug|Win32.ActiveCfg = Debug|Win32
- {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Debug|Win32.Build.0 = Debug|Win32
- {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Debug|x64.ActiveCfg = Debug|x64
- {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Debug|x64.Build.0 = Debug|x64
- {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Release|Win32.ActiveCfg = Release|Win32
- {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Release|Win32.Build.0 = Release|Win32
- {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Release|x64.ActiveCfg = Release|x64
- {6EB27E78-7C7A-4F08-8E19-957E8EB3A20F}.Release|x64.Build.0 = Release|x64
- {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Debug|Win32.ActiveCfg = Debug|Win32
- {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Debug|Win32.Build.0 = Debug|Win32
- {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Debug|x64.ActiveCfg = Debug|x64
- {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Debug|x64.Build.0 = Debug|x64
- {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Release|Win32.ActiveCfg = Release|Win32
- {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Release|Win32.Build.0 = Release|Win32
- {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Release|x64.ActiveCfg = Release|x64
- {A7DE5C73-D623-4118-A48A-BDFD1FAE97D4}.Release|x64.Build.0 = Release|x64
- {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Debug|Win32.ActiveCfg = Debug|Win32
- {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Debug|Win32.Build.0 = Debug|Win32
- {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Debug|x64.ActiveCfg = Release|x64
- {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Debug|x64.Build.0 = Release|x64
- {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Release|Win32.ActiveCfg = Release|Win32
- {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Release|Win32.Build.0 = Release|Win32
- {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Release|x64.ActiveCfg = Release|x64
- {9B465A9E-E5C7-4577-B559-3CA2F7AE7D96}.Release|x64.Build.0 = Release|x64
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/zdoom.vcproj b/zdoom.vcproj
deleted file mode 100644
index 3b98c29b1..000000000
--- a/zdoom.vcproj
+++ /dev/null
@@ -1,6970 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/zlib/zlib.vcproj b/zlib/zlib.vcproj
deleted file mode 100644
index 06d9ed48c..000000000
--- a/zlib/zlib.vcproj
+++ /dev/null
@@ -1,419 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-