diff --git a/gzdoom.vcproj b/gzdoom.vcproj
index 3f706099..91660078 100644
--- a/gzdoom.vcproj
+++ b/gzdoom.vcproj
@@ -1791,6 +1791,10 @@
RelativePath=".\src\win32\boing8.ico"
>
+
+
@@ -2976,6 +2980,10 @@
/>
+
+
diff --git a/src/b_func.cpp b/src/b_func.cpp
index 5970c15f..3e72ff43 100644
--- a/src/b_func.cpp
+++ b/src/b_func.cpp
@@ -25,98 +25,87 @@
static FRandom pr_botdofire ("BotDoFire");
-//Used with Reachable().
-static AActor *looker;
-static AActor *rtarget;
-static bool reachable;
-static fixed_t last_z;
-static sector_t *last_s;
-static fixed_t estimated_dist;
-static bool PTR_Reachable (intercept_t *in)
+//Checks TRUE reachability from
+//one looker to another. First mobj (looker) is looker.
+bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
{
- fixed_t hitx, hity;
- fixed_t frac;
- line_t *line;
- AActor *thing;
- fixed_t dist;
- sector_t *s;
+ if (looker == rtarget)
+ return false;
- frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST);
- dist = FixedMul (frac, MAX_TRAVERSE_DIST);
+ if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) -
+ rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y))
+ < looker->height) //Where rtarget is, looker can't be.
+ return false;
- hitx = trace.x + FixedMul (looker->momx, frac);
- hity = trace.y + FixedMul (looker->momy, frac);
+ sector_t *last_s = looker->Sector;
+ fixed_t last_z = last_s->floorplane.ZatPoint (looker->x, looker->y);
+ fixed_t estimated_dist = P_AproxDistance (looker->x - rtarget->x, looker->y - rtarget->y);
+ bool reachable = true;
- if (in->isaline)
+ FPathTraverse it(looker->x+looker->momx, looker->y+looker->momy, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS);
+ intercept_t *in;
+ while ((in = it.Next()))
{
- line = in->d.line;
+ fixed_t hitx, hity;
+ fixed_t frac;
+ line_t *line;
+ AActor *thing;
+ fixed_t dist;
+ sector_t *s;
- if (!(line->flags & ML_TWOSIDED) || (line->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING|ML_BLOCK_PLAYERS)))
- {
- return (reachable = false); //Cannot continue.
- }
- else
- {
- //Determine if going to use backsector/frontsector.
- s = (line->backsector == last_s) ? line->frontsector : line->backsector;
- fixed_t ceilingheight = s->ceilingplane.ZatPoint (hitx, hity);
- fixed_t floorheight = s->floorplane.ZatPoint (hitx, hity);
+ frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST);
+ dist = FixedMul (frac, MAX_TRAVERSE_DIST);
- if (!bglobal.IsDangerous (s) && //Any nukage/lava?
- (floorheight <= (last_z+MAXMOVEHEIGHT)
- && ((ceilingheight == floorheight && line->special)
- || (ceilingheight - floorheight) >= looker->height))) //Does it fit?
+ hitx = it.Trace().x + FixedMul (looker->momx, frac);
+ hity = it.Trace().y + FixedMul (looker->momy, frac);
+
+ if (in->isaline)
+ {
+ line = in->d.line;
+
+ if (!(line->flags & ML_TWOSIDED) || (line->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING|ML_BLOCK_PLAYERS)))
{
- last_z = floorheight;
- last_s = s;
- return true;
+ return false; //Cannot continue.
}
else
{
- return (reachable = false);
+ //Determine if going to use backsector/frontsector.
+ s = (line->backsector == last_s) ? line->frontsector : line->backsector;
+ fixed_t ceilingheight = s->ceilingplane.ZatPoint (hitx, hity);
+ fixed_t floorheight = s->floorplane.ZatPoint (hitx, hity);
+
+ if (!bglobal.IsDangerous (s) && //Any nukage/lava?
+ (floorheight <= (last_z+MAXMOVEHEIGHT)
+ && ((ceilingheight == floorheight && line->special)
+ || (ceilingheight - floorheight) >= looker->height))) //Does it fit?
+ {
+ last_z = floorheight;
+ last_s = s;
+ continue;
+ }
+ else
+ {
+ return false;
+ }
}
}
+
+ if (dist > estimated_dist)
+ {
+ return true;
+ }
+
+ thing = in->d.thing;
+ if (thing == looker) //Can't reach self in this case.
+ continue;
+ if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT)))
+ {
+ return true;
+ }
+
+ reachable = false;
}
-
- if (dist > estimated_dist)
- {
- reachable = true;
- return false; //Don't need to continue.
- }
-
- thing = in->d.thing;
- if (thing == looker) //Can't reach self in this case.
- return true;
- if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT)))
- {
- reachable = true;
- return false;
- }
-
- reachable = false;
- return true;
-}
-
-//Checks TRUE reachability from
-//one actor to another. First mobj (actor) is looker.
-bool FCajunMaster::Reachable (AActor *actor, AActor *target)
-{
- if (actor == target)
- return false;
-
- if ((target->Sector->ceilingplane.ZatPoint (target->x, target->y) -
- target->Sector->floorplane.ZatPoint (target->x, target->y))
- < actor->height) //Where target is, looker can't be.
- return false;
-
- looker = actor;
- rtarget = target;
- last_s = actor->Sector;
- last_z = last_s->floorplane.ZatPoint (actor->x, actor->y);
- reachable = true;
- estimated_dist = P_AproxDistance (actor->x - target->x, actor->y - target->y);
- P_PathTraverse (actor->x+actor->momx, actor->y+actor->momy, target->x, target->y, PT_ADDLINES|PT_ADDTHINGS, PTR_Reachable);
return reachable;
}
diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h
index 7d38c324..510da22b 100644
--- a/src/g_shared/sbarinfo.h
+++ b/src/g_shared/sbarinfo.h
@@ -40,6 +40,7 @@
#include "v_collection.h"
#define NUMHUDS 9
+#define NUMPOPUPS 3
class FBarTexture;
class FScanner;
@@ -47,6 +48,35 @@ class FScanner;
struct SBarInfoCommand; //we need to be able to use this before it is defined.
struct MugShotState;
+//Popups!
+enum PopupTransition
+{
+ TRANSITION_NONE,
+ TRANSITION_SLIDEINBOTTOM,
+};
+
+struct Popup
+{
+ PopupTransition transition;
+ bool opened;
+ bool moving;
+ int height;
+ int width;
+ int speed;
+ int x;
+ int y;
+
+ Popup();
+ void init();
+ void tick();
+ void open();
+ void close();
+ bool isDoneMoving();
+ int getXOffset();
+ int getYOffset();
+};
+
+//SBarInfo
struct SBarInfoBlock
{
TArray commands;
@@ -82,6 +112,7 @@ struct SBarInfo
{
TArray Images;
SBarInfoBlock huds[NUMHUDS];
+ Popup popups[NUMPOPUPS];
bool automapbar;
bool interpolateHealth;
bool interpolateArmor;
@@ -276,6 +307,7 @@ enum //Key words
SBARINFO_LOWERHEALTHCAP,
SBARINFO_STATUSBAR,
SBARINFO_MUGSHOT,
+ SBARINFO_CREATEPOPUP,
};
enum //Bar types
@@ -340,7 +372,7 @@ public:
void ShowPop(int popnum);
void SetMugShotState(const char* stateName, bool waitTillDone=false);
private:
- void doCommands(SBarInfoBlock &block);
+ void doCommands(SBarInfoBlock &block, int xOffset=0, int yOffset=0);
void DrawGraphic(FTexture* texture, int x, int y, int flags=0);
void DrawString(const char* str, int x, int y, EColorRange translation, int spacing=0);
void DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing=0, bool fillzeros=false);
@@ -366,6 +398,7 @@ private:
int mugshotHealth;
int chainWiggle;
int artiflash;
+ int pendingPopup;
int currentPopup;
unsigned int invBarOffset;
FBarShader shader_horz_normal;
diff --git a/src/g_shared/sbarinfo_display.cpp b/src/g_shared/sbarinfo_display.cpp
index 77cb7f7b..21a9da55 100644
--- a/src/g_shared/sbarinfo_display.cpp
+++ b/src/g_shared/sbarinfo_display.cpp
@@ -267,6 +267,8 @@ DSBarInfo::DSBarInfo () : DBaseStatusBar (SBarInfoScript->height),
chainWiggle = 0;
artiflash = 4;
currentState = NULL;
+ currentPopup = POP_None;
+ pendingPopup = POP_None;
}
DSBarInfo::~DSBarInfo ()
@@ -320,11 +322,11 @@ void DSBarInfo::Draw (EHudState state)
if(currentPopup != POP_None)
{
if(currentPopup == POP_Log)
- doCommands(SBarInfoScript->huds[STBAR_POPUPLOG]);
+ doCommands(SBarInfoScript->huds[STBAR_POPUPLOG], SBarInfoScript->popups[currentPopup].getXOffset(), SBarInfoScript->popups[currentPopup].getYOffset());
else if(currentPopup == POP_Keys)
- doCommands(SBarInfoScript->huds[STBAR_POPUPKEYS]);
+ doCommands(SBarInfoScript->huds[STBAR_POPUPKEYS], SBarInfoScript->popups[currentPopup].getXOffset(), SBarInfoScript->popups[currentPopup].getYOffset());
else if(currentPopup == POP_Status)
- doCommands(SBarInfoScript->huds[STBAR_POPUPSTATUS]);
+ doCommands(SBarInfoScript->huds[STBAR_POPUPSTATUS], SBarInfoScript->popups[currentPopup].getXOffset(), SBarInfoScript->popups[currentPopup].getYOffset());
}
}
@@ -410,6 +412,16 @@ void DSBarInfo::Tick ()
rampageTimer = 0;
}
mugshotHealth = CPlayer->health;
+ if(currentPopup != POP_None)
+ {
+ SBarInfoScript->popups[currentPopup].tick();
+ if(SBarInfoScript->popups[currentPopup].opened == false && SBarInfoScript->popups[currentPopup].isDoneMoving())
+ {
+ currentPopup = pendingPopup;
+ if(currentPopup != POP_None)
+ SBarInfoScript->popups[currentPopup].open();
+ }
+ }
}
void DSBarInfo::ReceivedWeapon (AWeapon *weapon)
@@ -426,9 +438,20 @@ void DSBarInfo::ShowPop(int popnum)
{
DBaseStatusBar::ShowPop(popnum);
if(popnum != currentPopup)
- currentPopup = popnum;
+ {
+ pendingPopup = popnum;
+ }
else
- currentPopup = POP_None;
+ pendingPopup = POP_None;
+ if(currentPopup != POP_None)
+ SBarInfoScript->popups[currentPopup].close();
+ else
+ {
+ currentPopup = pendingPopup;
+ pendingPopup = POP_None;
+ if(currentPopup != POP_None)
+ SBarInfoScript->popups[currentPopup].open();
+ }
}
//Public so it can be called by ACS
@@ -447,7 +470,7 @@ void DSBarInfo::SetMugShotState(const char* stateName, bool waitTillDone)
}
}
-void DSBarInfo::doCommands(SBarInfoBlock &block)
+void DSBarInfo::doCommands(SBarInfoBlock &block, int xOffset, int yOffset)
{
//prepare ammo counts
AAmmo *ammo1, *ammo2;
@@ -467,6 +490,8 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
for(unsigned int i = 0;i < block.commands.Size();i++)
{
SBarInfoCommand& cmd = block.commands[i];
+ cmd.x += xOffset;
+ cmd.y += yOffset;
switch(cmd.type) //read and execute all the commands
{
case SBARINFO_DRAWSWITCHABLEIMAGE: //draw the alt image if we don't have the item else this is like a normal drawimage
@@ -712,7 +737,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
}
else if((cmd.flags & DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY))
{
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
break;
case SBARINFO_DRAWINVENTORYBAR:
@@ -1063,7 +1088,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
((cmd.flags & GAMETYPE_COOPERATIVE) && multiplayer && !deathmatch) ||
((cmd.flags & GAMETYPE_TEAMGAME) && teamplay))
{
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
break;
case SBARINFO_PLAYERCLASS:
@@ -1072,14 +1097,14 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
int spawnClass = CPlayer->cls->ClassIndex;
if(cmd.special == spawnClass || cmd.special2 == spawnClass || cmd.special3 == spawnClass)
{
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
break;
}
case SBARINFO_ASPECTRATIO:
if(CheckRatio(screen->GetWidth(), screen->GetHeight()) == cmd.value)
{
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
break;
case SBARINFO_ISSELECTED:
@@ -1090,16 +1115,16 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
if(weapon2 != NULL)
{
if((cmd.flags & SBARINFOEVENT_NOT) && (weapon1 != CPlayer->ReadyWeapon->GetSpecies() && weapon2 != CPlayer->ReadyWeapon->GetSpecies()))
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
else if(!(cmd.flags & SBARINFOEVENT_NOT) && (weapon1 == CPlayer->ReadyWeapon->GetSpecies() || weapon2 == CPlayer->ReadyWeapon->GetSpecies()))
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
else
{
if(!(cmd.flags & SBARINFOEVENT_NOT) && weapon1 == CPlayer->ReadyWeapon->GetSpecies())
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
else if((cmd.flags & SBARINFOEVENT_NOT) && weapon1 != CPlayer->ReadyWeapon->GetSpecies())
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
}
break;
@@ -1115,7 +1140,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
bool usesammo2 = (AmmoType2 != NULL);
if(!(cmd.flags & SBARINFOEVENT_NOT) && !usesammo1 && !usesammo2) //if the weapon doesn't use ammo don't go though the trouble.
{
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
break;
}
//Or means only 1 ammo type needs to match and means both need to match.
@@ -1126,11 +1151,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
if(((cmd.flags & SBARINFOEVENT_OR) && (match1 || match2)) || ((cmd.flags & SBARINFOEVENT_AND) && (match1 && match2)))
{
if(!(cmd.flags & SBARINFOEVENT_NOT))
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
else if(cmd.flags & SBARINFOEVENT_NOT)
{
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
}
else //Every thing here could probably be one long if statement but then it would be more confusing.
@@ -1138,11 +1163,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
if((usesammo1 && (AmmoType1 == IfAmmo1)) || (usesammo2 && (AmmoType2 == IfAmmo1)))
{
if(!(cmd.flags & SBARINFOEVENT_NOT))
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
else if(cmd.flags & SBARINFOEVENT_NOT)
{
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
}
}
@@ -1154,24 +1179,26 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
if(cmd.flags & SBARINFOEVENT_AND)
{
if((item1 != NULL && item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
else if((item1 == NULL || item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
else if(cmd.flags & SBARINFOEVENT_OR)
{
if((item1 != NULL || item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
else if((item1 == NULL && item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
}
else if((item1 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
else if((item1 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
- doCommands(cmd.subBlock);
+ doCommands(cmd.subBlock, xOffset, yOffset);
break;
}
}
+ cmd.x -= xOffset;
+ cmd.y -= yOffset;
}
}
@@ -1191,7 +1218,8 @@ void DSBarInfo::DrawGraphic(FTexture* texture, int x, int y, int flags)
y += ST_Y;
int w = texture->GetScaledWidth();
int h = texture->GetScaledHeight() + y;
- screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
+ if(Scaled)
+ screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
h -= y;
if((flags & DRAWIMAGE_TRANSLATABLE))
{
@@ -1238,7 +1266,8 @@ void DSBarInfo::DrawString(const char* str, int x, int y, EColorRange translatio
int ry = y + ST_Y;
int rw = character->GetScaledWidth();
int rh = character->GetScaledHeight();
- screen->VirtualToRealCoordsInt(rx, ry, rw, rh, 320, 200, true);
+ if(Scaled)
+ screen->VirtualToRealCoordsInt(rx, ry, rw, rh, 320, 200, true);
screen->DrawTexture(character, rx, ry,
DTA_DestWidth, rw,
DTA_DestHeight, rh,
@@ -1297,7 +1326,8 @@ void DSBarInfo::DrawFace(FString &defaultFace, int accuracy, bool xdth, bool ani
y += ST_Y;
int w = face->GetScaledWidth();
int h = face->GetScaledHeight();
- screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
+ if(Scaled)
+ screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
screen->DrawTexture(face, x, y,
DTA_DestWidth, w,
DTA_DestHeight, h,
@@ -1492,10 +1522,10 @@ void DSBarInfo::DrawGem(FTexture* chain, FTexture* gem, int value, int x, int y,
int offset = (int) (((double) (chainWidth-padleft-padright)/100)*value);
if(chain != NULL)
{
- DrawImage(chain, x+(offset%chainsize), y);
+ DrawGraphic(chain, x+(offset%chainsize), y);
}
if(gem != NULL)
- DrawImage(gem, x+padleft+offset, y, translate ? getTranslation() : NULL);
+ DrawGraphic(gem, x+padleft+offset, y, translate ? DRAWIMAGE_TRANSLATABLE : 0);
}
FRemapTable* DSBarInfo::getTranslation()
diff --git a/src/g_shared/sbarinfo_parser.cpp b/src/g_shared/sbarinfo_parser.cpp
index fb87786c..fb683e6b 100644
--- a/src/g_shared/sbarinfo_parser.cpp
+++ b/src/g_shared/sbarinfo_parser.cpp
@@ -60,6 +60,7 @@ static const char *SBarInfoTopLevel[] =
"lowerhealthcap",
"statusbar",
"mugshot",
+ "createpopup",
NULL
};
@@ -305,6 +306,43 @@ void SBarInfo::ParseSBarInfo(int lump)
MugShotStates.Push(state);
break;
}
+ case SBARINFO_CREATEPOPUP:
+ {
+ int pop = 0;
+ sc.MustGetToken(TK_Identifier);
+ if(sc.Compare("keys"))
+ pop = 0;
+ else if(sc.Compare("log"))
+ pop = 1;
+ else if(sc.Compare("status"))
+ pop = 2;
+ else
+ sc.ScriptError("Unkown popup: '%s'", sc.String);
+ Popup &popup = popups[pop];
+ sc.MustGetToken(',');
+ sc.MustGetToken(TK_IntConst);
+ popup.width = sc.Number;
+ sc.MustGetToken(',');
+ sc.MustGetToken(TK_IntConst);
+ popup.height = sc.Number;
+ sc.MustGetToken(',');
+ if(!sc.CheckToken(TK_None))
+ {
+ sc.MustGetToken(TK_Identifier);
+ if(sc.Compare("slideinbottom"))
+ {
+ popup.transition = TRANSITION_SLIDEINBOTTOM;
+ sc.MustGetToken(',');
+ sc.MustGetToken(TK_IntConst);
+ popup.speed = sc.Number;
+ }
+ else
+ sc.ScriptError("Unkown transition type: '%s'", sc.String);
+ }
+ popup.init();
+ sc.MustGetToken(';');
+ break;
+ }
}
}
}
@@ -553,9 +591,11 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
sc.MustGetToken(';');
break;
case SBARINFO_DRAWMUGSHOT:
- sc.MustGetToken(TK_StringConst);
- cmd.setString(sc, sc.String, 0, 3, true);
- sc.MustGetToken(',');
+ if(sc.CheckToken(TK_StringConst))
+ {
+ cmd.setString(sc, sc.String, 0, 3, true);
+ sc.MustGetToken(',');
+ }
sc.MustGetToken(TK_IntConst); //accuracy
if(sc.Number < 1 || sc.Number > 9)
sc.ScriptError("Expected a number between 1 and 9, got %d instead.", sc.Number);
@@ -1237,6 +1277,88 @@ const MugShotState *FindMugShotState(FString state)
return NULL;
}
+//Popup
+Popup::Popup()
+{
+ transition = TRANSITION_NONE;
+ height = 320;
+ width = 200;
+ speed = 0;
+ x = 320;
+ y = 200;
+ opened = false;
+ moving = false;
+}
+
+void Popup::init()
+{
+ x = width;
+ y = height;
+ if(transition == TRANSITION_SLIDEINBOTTOM)
+ {
+ x = 0;
+ }
+}
+
+void Popup::tick()
+{
+ if(transition == TRANSITION_SLIDEINBOTTOM)
+ {
+ if(moving)
+ {
+ if(opened)
+ y -= clamp(height + (y - height), 1, speed);
+ else
+ y += clamp(height - y, 1, speed);
+ }
+ if(y != 0 && y != height)
+ moving = true;
+ else
+ moving = false;
+ }
+ else
+ {
+ moving = false;
+ if(opened)
+ {
+ y = 0;
+ x = 0;
+ }
+ else
+ {
+ y = height;
+ x = width;
+ }
+ }
+}
+
+bool Popup::isDoneMoving()
+{
+ return !moving;
+}
+
+int Popup::getXOffset()
+{
+ return x;
+}
+
+int Popup::getYOffset()
+{
+ return y;
+}
+
+void Popup::open()
+{
+ opened = true;
+ moving = true;
+}
+
+void Popup::close()
+{
+ opened = false;
+ moving = true;
+}
+
//Used to allow replacements of states
int FindMugShotStateIndex(FName state)
{
diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp
index 7db13ed7..e8ad2b91 100644
--- a/src/gameconfigfile.cpp
+++ b/src/gameconfigfile.cpp
@@ -70,6 +70,8 @@ EXTERN_CVAR (Bool, snd_pitched)
EXTERN_CVAR (Color, am_wallcolor)
EXTERN_CVAR (Color, am_fdwallcolor)
EXTERN_CVAR (Color, am_cdwallcolor)
+EXTERN_CVAR (Float, spc_amp)
+EXTERN_CVAR (Bool, snd_midiprecache)
FString WeaponSection;
@@ -297,14 +299,15 @@ void FGameConfigFile::DoGlobalSetup ()
}
if (last < 206)
{ // spc_amp is now a float, not an int.
- FBaseCVar *amp = FindCVar ("spc_amp", NULL);
- if (amp != NULL)
+ if (spc_amp > 16)
{
- UCVarValue val = amp->GetGenericRep(CVAR_Float);
- val.Float /= 16.f;
- amp->SetGenericRep(val, CVAR_Float);
+ spc_amp = spc_amp / 16.f;
}
}
+ if (last < 207)
+ { // Now that snd_midiprecache works again, you probably don't want it on.
+ snd_midiprecache = false;
+ }
}
}
}
diff --git a/src/m_bbox.cpp b/src/m_bbox.cpp
index 3a938ab1..d13f790e 100644
--- a/src/m_bbox.cpp
+++ b/src/m_bbox.cpp
@@ -40,12 +40,59 @@ void FBoundingBox::AddToBox (fixed_t x, fixed_t y)
m_Box[BOXTOP] = y;
}
+//==========================================================================
+//
+// FBoundingBox :: BoxOnLineSide
+//
+// Considers the line to be infinite
+// Returns side 0 or 1, -1 if box crosses the line.
+//
+//==========================================================================
+
int FBoundingBox::BoxOnLineSide (const line_t *ld) const
{
- return P_BoxOnLineSide(m_Box, ld);
+ int p1;
+ int p2;
+
+ switch (ld->slopetype)
+ {
+ case ST_HORIZONTAL:
+ p1 = m_Box[BOXTOP] > ld->v1->y;
+ p2 = m_Box[BOXBOTTOM] > ld->v1->y;
+ if (ld->dx < 0)
+ {
+ p1 ^= 1;
+ p2 ^= 1;
+ }
+ break;
+
+ case ST_VERTICAL:
+ p1 = m_Box[BOXRIGHT] < ld->v1->x;
+ p2 = m_Box[BOXLEFT] < ld->v1->x;
+ if (ld->dy < 0)
+ {
+ p1 ^= 1;
+ p2 ^= 1;
+ }
+ break;
+
+ case ST_POSITIVE:
+ p1 = P_PointOnLineSide (m_Box[BOXLEFT], m_Box[BOXTOP], ld);
+ p2 = P_PointOnLineSide (m_Box[BOXRIGHT], m_Box[BOXBOTTOM], ld);
+ break;
+
+ case ST_NEGATIVE:
+ default: // Just to assure GCC that p1 and p2 really do get initialized
+ p1 = P_PointOnLineSide (m_Box[BOXRIGHT], m_Box[BOXTOP], ld);
+ p2 = P_PointOnLineSide (m_Box[BOXLEFT], m_Box[BOXBOTTOM], ld);
+ break;
+ }
+
+ return (p1 == p2) ? p1 : -1;
}
+
diff --git a/src/mus2midi.h b/src/mus2midi.h
index e36da678..79b41007 100644
--- a/src/mus2midi.h
+++ b/src/mus2midi.h
@@ -71,6 +71,7 @@ typedef struct
WORD NumSecondaryChans;
WORD NumInstruments;
WORD Pad;
+ // WORD UsedInstruments[NumInstruments];
} MUSHeader;
bool ProduceMIDI (const BYTE *musBuf, TArray &outFile);
diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp
index 10b8ff00..bfab365c 100644
--- a/src/oplsynth/music_opl_mididevice.cpp
+++ b/src/oplsynth/music_opl_mididevice.cpp
@@ -261,9 +261,9 @@ void OPLMIDIDevice::Stop()
int OPLMIDIDevice::StreamOutSync(MIDIHDR *header)
{
- Serialize();
+ ChipAccess.Enter();
StreamOut(header);
- Unserialize();
+ ChipAccess.Leave();
return 0;
}
diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp
index f8201e03..2e0c5e90 100644
--- a/src/oplsynth/opl_mus_player.cpp
+++ b/src/oplsynth/opl_mus_player.cpp
@@ -28,59 +28,22 @@ OPLmusicBlock::OPLmusicBlock()
TwoChips = !opl_onechip;
Looping = false;
io = NULL;
-#ifdef _WIN32
- InitializeCriticalSection (&ChipAccess);
-#else
- ChipAccess = SDL_CreateMutex ();
- if (ChipAccess == NULL)
- {
- return;
- }
-#endif
io = new OPLio;
}
OPLmusicBlock::~OPLmusicBlock()
{
BlockForStats = NULL;
-#ifdef _WIN32
- DeleteCriticalSection (&ChipAccess);
-#else
- if (ChipAccess != NULL)
- {
- SDL_DestroyMutex (ChipAccess);
- ChipAccess = NULL;
- }
-#endif
delete io;
}
-void OPLmusicBlock::Serialize()
-{
-#ifdef _WIN32
- EnterCriticalSection (&ChipAccess);
-#else
- if (SDL_mutexP (ChipAccess) != 0)
- return;
-#endif
-}
-
-void OPLmusicBlock::Unserialize()
-{
-#ifdef _WIN32
- LeaveCriticalSection (&ChipAccess);
-#else
- SDL_mutexV (ChipAccess);
-#endif
-}
-
void OPLmusicBlock::ResetChips ()
{
TwoChips = !opl_onechip;
- Serialize();
+ ChipAccess.Enter();
io->OPLdeinit ();
io->OPLinit (TwoChips + 1);
- Unserialize();
+ ChipAccess.Leave();
}
void OPLmusicBlock::Restart()
@@ -237,7 +200,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
samples1 = samples;
memset(buff, 0, numbytes);
- Serialize();
+ ChipAccess.Enter();
while (numsamples > 0)
{
double ticky = NextTickIn;
@@ -294,7 +257,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
}
}
}
- Unserialize();
+ ChipAccess.Leave();
return res;
}
diff --git a/src/oplsynth/opl_mus_player.h b/src/oplsynth/opl_mus_player.h
index d20e0a96..0540ecb1 100644
--- a/src/oplsynth/opl_mus_player.h
+++ b/src/oplsynth/opl_mus_player.h
@@ -1,11 +1,4 @@
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include
-#define USE_WINDOWS_DWORD
-#else
-#include
-#endif
-
+#include "critsec.h"
#include "muslib.h"
#include "files.h"
@@ -23,19 +16,12 @@ public:
protected:
virtual int PlayTick() = 0;
- void Serialize();
- void Unserialize();
-
double NextTickIn;
double SamplesPerTick;
bool TwoChips;
bool Looping;
-#ifdef _WIN32
- CRITICAL_SECTION ChipAccess;
-#else
- SDL_mutex *ChipAccess;
-#endif
+ FCriticalSection ChipAccess;
};
class OPLmusicFile : public OPLmusicBlock
diff --git a/src/p_local.h b/src/p_local.h
index be538e24..f097f7c3 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -61,7 +61,6 @@
#define BASETHRESHOLD 100
-
//
// P_PSPR
//
@@ -161,6 +160,7 @@ typedef struct
{
fixed_t frac; // along trace line
bool isaline;
+ bool done;
union {
AActor *thing;
line_t *line;
@@ -216,7 +216,6 @@ inline void P_MakeDivline (const line_t *li, divline_t *dl)
}
fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1);
-int P_BoxOnLineSide (const fixed_t *tmbox, const line_t *ld);
struct FLineOpening
{
@@ -256,10 +255,7 @@ public:
class FBlockThingsIterator
{
- typedef TArray BTChecked;
-
- static TDeletingArray< BTChecked* > FreeBTChecked;
-
+ static TArray CheckArray;
int minx, maxx;
int miny, maxy;
@@ -267,21 +263,24 @@ class FBlockThingsIterator
int curx, cury;
bool dontfreecheck;
- BTChecked *checkarray;
+ int checkindex;
FBlockNode *block;
- BTChecked *GetCheckArray();
- void FreeCheckArray();
void StartBlock(int x, int y);
+ // The following 3 functions are only for use in the path traverser
+ // and therefore declared private.
+ static int GetCheckIndex();
+ static void SetCheckIndex(int newvalue);
+ FBlockThingsIterator(int x, int y, int checkindex);
+
+ friend class FPathTraverse;
+
public:
- FBlockThingsIterator(int minx, int miny, int maxx, int maxy, TArray *check = NULL);
+ FBlockThingsIterator(int minx, int miny, int maxx, int maxy);
FBlockThingsIterator(const FBoundingBox &box);
- ~FBlockThingsIterator()
- {
- if (!dontfreecheck) FreeCheckArray();
- }
+ ~FBlockThingsIterator();
AActor *Next();
void Reset() { StartBlock(minx, miny); }
};
@@ -294,20 +293,31 @@ public:
AActor *Next();
};
+class FPathTraverse
+{
+ static TArray intercepts;
+
+ divline_t trace;
+ unsigned int intercept_index;
+ unsigned int intercept_count;
+ fixed_t maxfrac;
+ unsigned int count;
+
+ void AddLineIntercepts(int bx, int by);
+ void AddThingIntercepts(int bx, int by, int checkindex);
+public:
+
+ intercept_t *Next();
+
+ FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags);
+ ~FPathTraverse();
+ const divline_t &Trace() const { return trace; }
+};
+
+
#define PT_ADDLINES 1
#define PT_ADDTHINGS 2
-extern divline_t trace;
-
-bool
-P_PathTraverse
-( fixed_t x1,
- fixed_t y1,
- fixed_t x2,
- fixed_t y2,
- int flags,
- bool (*trav) (intercept_t *));
-
AActor *P_BlockmapSearch (AActor *origin, int distance, AActor *(*func)(AActor *, int));
AActor *P_RoughMonsterSearch (AActor *mo, int distance);
@@ -386,9 +396,7 @@ bool P_CheckMissileSpawn (AActor *missile);
void P_PlaySpawnSound(AActor *missile, AActor *spawner);
// [RH] Position the chasecam
-void P_AimCamera (AActor *t1);
-extern fixed_t CameraX, CameraY, CameraZ;
-extern sector_t *CameraSector;
+void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec);
// [RH] Means of death
void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, FName damageType, bool hurtSelf, bool dodamage=true);
@@ -434,9 +442,7 @@ extern FBlockNode** blocklinks; // for thing chains
// P_INTER
//
void P_TouchSpecialThing (AActor *special, AActor *toucher);
-
void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0);
-
bool P_GiveBody (AActor *actor, int num);
void P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison);
void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound);
diff --git a/src/p_map.cpp b/src/p_map.cpp
index a313b650..4e40df89 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -60,16 +60,13 @@
#define WATER_SINK_SPEED (FRACUNIT/2)
#define WATER_JUMP_SPEED (FRACUNIT*7/2)
-#define USE_PUZZLE_ITEM_SPECIAL 129
-
-
CVAR (Bool, cl_bloodsplats, true, CVAR_ARCHIVE)
CVAR (Int, sv_smartaim, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
static void CheckForPushSpecial (line_t *line, int side, AActor *mobj);
static void SpawnShootDecal (AActor *t1, const FTraceResults &trace);
static void SpawnDeepSplash (AActor *t1, const FTraceResults &trace, AActor *puff,
- fixed_t vx, fixed_t vy, fixed_t vz);
+ fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz);
static FRandom pr_tracebleed ("TraceBleed");
static FRandom pr_checkthing ("CheckThing");
@@ -1714,18 +1711,28 @@ bool P_TryMove (AActor *thing, fixed_t x, fixed_t y,
// SLIDE MOVE
// Allows the player to slide along any angled walls.
//
-fixed_t bestslidefrac;
-fixed_t secondslidefrac;
+struct FSlide
+{
+ fixed_t bestslidefrac;
+ fixed_t secondslidefrac;
-line_t* bestslideline;
-line_t* secondslideline;
+ line_t* bestslideline;
+ line_t* secondslideline;
-AActor* slidemo;
+ AActor* slidemo;
-fixed_t tmxmove;
-fixed_t tmymove;
+ fixed_t tmxmove;
+ fixed_t tmymove;
+
+ void HitSlideLine(line_t *ld);
+ void SlideTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy);
+ void SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps);
+
+ // The bouncing code uses the same data structure
+ bool BounceTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy);
+ bool BounceWall (AActor *mo);
+};
-extern bool onground;
//
@@ -1734,7 +1741,7 @@ extern bool onground;
// so that the next move will slide along the wall.
// If the floor is icy, then you can bounce off a wall. // phares
//
-void P_HitSlideLine (line_t* ld)
+void FSlide::HitSlideLine (line_t* ld)
{
int side;
@@ -1870,79 +1877,89 @@ void P_HitSlideLine (line_t* ld)
//
// PTR_SlideTraverse
//
-bool PTR_SlideTraverse (intercept_t* in)
+void FSlide::SlideTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy)
{
- line_t* li;
-
- if (!in->isaline)
- I_Error ("PTR_SlideTraverse: not a line?");
-
- li = in->d.line;
-
- if ( !(li->flags & ML_TWOSIDED) )
+ FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES);
+ intercept_t *in;
+
+ while ((in = it.Next()))
{
- if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
+ line_t* li;
+
+ if (!in->isaline)
{
- // don't hit the back side
- return true;
+ // should never happen
+ Printf ("PTR_SlideTraverse: not a line?");
+ continue;
}
- goto isblocking;
- }
- if (li->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING))
- {
- goto isblocking;
- }
- if (li->flags & ML_BLOCK_PLAYERS && slidemo->player != NULL)
- {
- goto isblocking;
- }
- if (li->flags & ML_BLOCKMONSTERS && !(slidemo->flags3 & MF3_NOBLOCKMONST))
- {
- goto isblocking;
- }
-
- FLineOpening open;
- // set openrange, opentop, openbottom
- P_LineOpening (open, slidemo, li, trace.x + FixedMul (trace.dx, in->frac),
- trace.y + FixedMul (trace.dy, in->frac));
-
- if (open.range < slidemo->height)
- goto isblocking; // doesn't fit
-
- if (open.top - slidemo->z < slidemo->height)
- goto isblocking; // mobj is too high
-
- if (open.bottom - slidemo->z > slidemo->MaxStepHeight)
- {
- goto isblocking; // too big a step up
- }
- else if (slidemo->z < open.bottom)
- { // [RH] Check to make sure there's nothing in the way for the step up
- fixed_t savedz = slidemo->z;
- slidemo->z = open.bottom;
- bool good = P_TestMobjZ (slidemo);
- slidemo->z = savedz;
- if (!good)
+
+ li = in->d.line;
+
+ if ( !(li->flags & ML_TWOSIDED) || !li->backsector )
+ {
+ if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
+ {
+ // don't hit the back side
+ continue;
+ }
+ goto isblocking;
+ }
+ if (li->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING))
+ {
+ goto isblocking;
+ }
+ if (li->flags & ML_BLOCK_PLAYERS && slidemo->player != NULL)
+ {
+ goto isblocking;
+ }
+ if (li->flags & ML_BLOCKMONSTERS && !(slidemo->flags3 & MF3_NOBLOCKMONST))
{
goto isblocking;
}
- }
- // this line doesn't block movement
- return true;
+ FLineOpening open;
+ // set openrange, opentop, openbottom
+ P_LineOpening (open, slidemo, li, it.Trace().x + FixedMul (it.Trace().dx, in->frac),
+ it.Trace().y + FixedMul (it.Trace().dy, in->frac));
- // the line does block movement,
- // see if it is closer than best so far
- isblocking:
- if (in->frac < bestslidefrac)
- {
- secondslidefrac = bestslidefrac;
- secondslideline = bestslideline;
- bestslidefrac = in->frac;
- bestslideline = li;
+ if (open.range < slidemo->height)
+ goto isblocking; // doesn't fit
+
+ if (open.top - slidemo->z < slidemo->height)
+ goto isblocking; // mobj is too high
+
+ if (open.bottom - slidemo->z > slidemo->MaxStepHeight)
+ {
+ goto isblocking; // too big a step up
+ }
+ else if (slidemo->z < open.bottom)
+ { // [RH] Check to make sure there's nothing in the way for the step up
+ fixed_t savedz = slidemo->z;
+ slidemo->z = open.bottom;
+ bool good = P_TestMobjZ (slidemo);
+ slidemo->z = savedz;
+ if (!good)
+ {
+ goto isblocking;
+ }
+ }
+
+ // this line doesn't block movement
+ continue;
+
+ // the line does block movement,
+ // see if it is closer than best so far
+ isblocking:
+ if (in->frac < bestslidefrac)
+ {
+ secondslidefrac = bestslidefrac;
+ secondslideline = bestslideline;
+ bestslidefrac = in->frac;
+ bestslideline = li;
+ }
+
+ return; // stop
}
-
- return false; // stop
}
@@ -1956,7 +1973,7 @@ bool PTR_SlideTraverse (intercept_t* in)
//
// This is a kludgy mess.
//
-void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps)
+void FSlide::SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps)
{
fixed_t leadx, leady;
fixed_t trailx, traily;
@@ -1965,8 +1982,8 @@ void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps)
const secplane_t * walkplane;
int hitcount;
- slidemo = mo;
hitcount = 3;
+ slidemo = mo;
if (mo->player && mo->reactiontime > 0)
return; // player coming right out of a teleporter.
@@ -2000,10 +2017,10 @@ void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps)
bestslidefrac = FRACUNIT+1;
- P_PathTraverse (leadx, leady, leadx+tryx, leady+tryy, PT_ADDLINES, PTR_SlideTraverse);
- P_PathTraverse (trailx, leady, trailx+tryx, leady+tryy, PT_ADDLINES, PTR_SlideTraverse);
- P_PathTraverse (leadx, traily, leadx+tryx, traily+tryy, PT_ADDLINES, PTR_SlideTraverse);
-
+ SlideTraverse (leadx, leady, leadx+tryx, leady+tryy);
+ SlideTraverse (trailx, leady, trailx+tryx, leady+tryy);
+ SlideTraverse (leadx, traily, leadx+tryx, traily+tryy);
+
// move up to the wall
if (bestslidefrac == FRACUNIT+1)
{
@@ -2043,7 +2060,7 @@ void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps)
tryx = tmxmove = FixedMul (tryx, bestslidefrac);
tryy = tmymove = FixedMul (tryy, bestslidefrac);
- P_HitSlideLine (bestslideline); // clip the moves
+ HitSlideLine (bestslideline); // clip the moves
mo->momx = tmxmove * numsteps;
mo->momy = tmymove * numsteps;
@@ -2066,6 +2083,12 @@ void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps)
}
}
+void P_SlideMove (AActor *mo, fixed_t tryx, fixed_t tryy, int numsteps)
+{
+ FSlide slide;
+ slide.SlideMove(mo, tryx, tryy, numsteps);
+}
+
//============================================================================
//
// P_CheckSlopeWalk
@@ -2204,51 +2227,62 @@ const secplane_t * P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymo
//
//============================================================================
-bool PTR_BounceTraverse (intercept_t *in)
+bool FSlide::BounceTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy)
{
- line_t *li;
+ FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES);
+ intercept_t *in;
- if (!in->isaline)
- I_Error ("PTR_BounceTraverse: not a line?");
-
- li = in->d.line;
- assert(((size_t)li - (size_t)lines) % sizeof(line_t) == 0);
- if (li->flags & ML_BLOCKEVERYTHING)
+ while ((in = it.Next()))
{
- goto bounceblocking;
+
+ line_t *li;
+
+ if (!in->isaline)
+ {
+ Printf ("PTR_BounceTraverse: not a line?");
+ continue;
+ }
+
+ li = in->d.line;
+ assert(((size_t)li - (size_t)lines) % sizeof(line_t) == 0);
+ if (li->flags & ML_BLOCKEVERYTHING)
+ {
+ goto bounceblocking;
+ }
+ if (!(li->flags&ML_TWOSIDED) || !li->backsector)
+ {
+ if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
+ continue; // don't hit the back side
+ goto bounceblocking;
+ }
+
+ FLineOpening open;
+
+ P_LineOpening (open, slidemo, li, it.Trace().x + FixedMul (it.Trace().dx, in->frac),
+ it.Trace().y + FixedMul (it.Trace().dy, in->frac)); // set openrange, opentop, openbottom
+ if (open.range < slidemo->height)
+ goto bounceblocking; // doesn't fit
+
+ if (open.top - slidemo->z < slidemo->height)
+ goto bounceblocking; // mobj is too high
+
+ if (open.bottom > slidemo->z)
+ goto bounceblocking; // mobj is too low
+
+ continue; // this line doesn't block movement
+
+ // the line does block movement, see if it is closer than best so far
+ bounceblocking:
+ if (in->frac < bestslidefrac)
+ {
+ secondslidefrac = bestslidefrac;
+ secondslideline = bestslideline;
+ bestslidefrac = in->frac;
+ bestslideline = li;
+ }
+ return false; // stop
}
- if (!(li->flags&ML_TWOSIDED))
- {
- if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
- return true; // don't hit the back side
- goto bounceblocking;
- }
-
- FLineOpening open;
-
- P_LineOpening (open, slidemo, li, trace.x + FixedMul (trace.dx, in->frac),
- trace.y + FixedMul (trace.dy, in->frac)); // set openrange, opentop, openbottom
- if (open.range < slidemo->height)
- goto bounceblocking; // doesn't fit
-
- if (open.top - slidemo->z < slidemo->height)
- goto bounceblocking; // mobj is too high
-
- if (open.bottom > slidemo->z)
- goto bounceblocking; // mobj is too low
-
- return true; // this line doesn't block movement
-
-// the line does block movement, see if it is closer than best so far
-bounceblocking:
- if (in->frac < bestslidefrac)
- {
- secondslidefrac = bestslidefrac;
- secondslideline = bestslideline;
- bestslidefrac = in->frac;
- bestslideline = li;
- }
- return false; // stop
+ return true;
}
//============================================================================
@@ -2257,7 +2291,7 @@ bounceblocking:
//
//============================================================================
-bool P_BounceWall (AActor *mo)
+bool FSlide::BounceWall (AActor *mo)
{
fixed_t leadx, leady;
int side;
@@ -2292,8 +2326,7 @@ bool P_BounceWall (AActor *mo)
}
bestslidefrac = FRACUNIT+1;
bestslideline = mo->BlockingLine;
- if (P_PathTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy,
- PT_ADDLINES, PTR_BounceTraverse) && mo->BlockingLine == NULL)
+ if (BounceTraverse(leadx, leady, leadx+mo->momx, leady+mo->momy) && mo->BlockingLine == NULL)
{ // Could not find a wall, so bounce off the floor/ceiling instead.
fixed_t floordist = mo->z - mo->floorz;
fixed_t ceildist = mo->ceilingz - mo->z;
@@ -2340,15 +2373,11 @@ bool P_BounceWall (AActor *mo)
movelen = P_AproxDistance (mo->momx, mo->momy);
movelen = (movelen * 192) >> 8; // friction
- fixed_t box[4];
- box[BOXTOP] = mo->y + mo->radius;
- box[BOXBOTTOM] = mo->y - mo->radius;
- box[BOXLEFT] = mo->x - mo->radius;
- box[BOXRIGHT] = mo->x + mo->radius;
- if (P_BoxOnLineSide (box, line) == -1)
+ FBoundingBox box(mo->x, mo->y, mo->radius);
+ if (box.BoxOnLineSide (line) == -1)
{
mo->SetOrigin (mo->x + FixedMul(mo->radius,
- finecosine[deltaangle]), mo->y + FixedMul(mo->radius, finesine[deltaangle]), mo->z);;
+ finecosine[deltaangle]), mo->y + FixedMul(mo->radius, finesine[deltaangle]), mo->z);
}
if (movelen < FRACUNIT)
{
@@ -2359,6 +2388,13 @@ bool P_BounceWall (AActor *mo)
return true;
}
+bool P_BounceWall (AActor *mo)
+{
+ FSlide slide;
+ return slide.BounceWall(mo);
+}
+
+
//============================================================================
//
@@ -2366,14 +2402,13 @@ bool P_BounceWall (AActor *mo)
//
//============================================================================
AActor* linetarget; // who got hit (or NULL)
-AActor* shootthing;
-fixed_t shootz; // Height if not aiming up or down
-fixed_t attackrange;
-fixed_t aimpitch;
struct aim_t
{
-
+ fixed_t aimpitch;
+ fixed_t attackrange;
+ fixed_t shootz; // Height if not aiming up or down
+ AActor* shootthing;
fixed_t toppitch, bottompitch;
AActor * thing_friend, * thing_other;
@@ -2385,6 +2420,9 @@ struct aim_t
bool crossedffloors;
+ void AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy);
+ bool AimTraverse3DFloors(const divline_t &trace, intercept_t * in);
+
};
aim_t aim;
@@ -2394,7 +2432,7 @@ aim_t aim;
// AimTraverse3DFloors
//
//============================================================================
-bool P_AimTraverse3DFloors(intercept_t * in)
+bool aim_t::AimTraverse3DFloors(const divline_t &trace, intercept_t * in)
{
sector_t * nextsector;
secplane_t * nexttopplane, * nextbottomplane;
@@ -2426,7 +2464,7 @@ bool P_AimTraverse3DFloors(intercept_t * in)
for(unsigned k=0;ke->XFloor.ffloors.Size();k++)
{
- aim.crossedffloors=true;
+ crossedffloors=true;
rover=s->e->XFloor.ffloors[k];
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
@@ -2438,26 +2476,26 @@ bool P_AimTraverse3DFloors(intercept_t * in)
highpitch = -(int)R_PointToAngle2 (0, shootz, dist, ff_top);
lowpitch = -(int)R_PointToAngle2 (0, shootz, dist, ff_bottom);
- if (highpitch<=aim.toppitch)
+ if (highpitch<=toppitch)
{
// blocks completely
- if (lowpitch>=aim.bottompitch) return false;
+ if (lowpitch>=bottompitch) return false;
// blocks upper edge of view
- if (lowpitch>aim.toppitch)
+ if (lowpitch>toppitch)
{
- aim.toppitch=lowpitch;
+ toppitch=lowpitch;
if (frontflag!=i-1)
{
nexttopplane=rover->bottom.plane;
}
}
}
- else if (lowpitch>=aim.bottompitch)
+ else if (lowpitch>=bottompitch)
{
// blocks lower edge of view
- if (highpitchtop.plane;
@@ -2468,28 +2506,28 @@ bool P_AimTraverse3DFloors(intercept_t * in)
if (frontflag==i-1)
{
- if (s==aim.lastsector)
+ if (s==lastsector)
{
// upper slope intersects with this 3d-floor
- if (rover->bottom.plane==aim.lastceilingplane && lowpitch > aim.toppitch)
+ if (rover->bottom.plane==lastceilingplane && lowpitch > toppitch)
{
- aim.toppitch=lowpitch;
+ toppitch=lowpitch;
}
// lower slope intersects with this 3d-floor
- if (rover->top.plane==aim.lastfloorplane && highpitch < aim.bottompitch)
+ if (rover->top.plane==lastfloorplane && highpitch < bottompitch)
{
- aim.bottompitch=highpitch;
+ bottompitch=highpitch;
}
}
}
- if (aim.toppitch >= aim.bottompitch) return false; // stop
+ if (toppitch >= bottompitch) return false; // stop
}
}
}
- aim.lastsector=nextsector;
- aim.lastceilingplane=nexttopplane;
- aim.lastfloorplane=nextbottomplane;
+ lastsector=nextsector;
+ lastceilingplane=nexttopplane;
+ lastfloorplane=nextbottomplane;
return true;
}
@@ -2500,170 +2538,173 @@ bool P_AimTraverse3DFloors(intercept_t * in)
//
//============================================================================
-bool PTR_AimTraverse (intercept_t* in)
+void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy)
{
- fixed_t & toppitch=aim.toppitch;
- fixed_t & bottompitch=aim.bottompitch;
+ FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES|PT_ADDTHINGS);
+ intercept_t *in;
- line_t* li;
- AActor* th;
- fixed_t pitch;
- fixed_t thingtoppitch;
- fixed_t thingbottompitch;
- fixed_t dist;
- int thingpitch;
-
- if (in->isaline)
+ while ((in = it.Next()))
{
- li = in->d.line;
+ line_t* li;
+ AActor* th;
+ fixed_t pitch;
+ fixed_t thingtoppitch;
+ fixed_t thingbottompitch;
+ fixed_t dist;
+ int thingpitch;
- if ( !(li->flags & ML_TWOSIDED) || (li->flags & ML_BLOCKEVERYTHING) )
- return false; // stop
+ if (in->isaline)
+ {
+ li = in->d.line;
- // Crosses a two sided line.
- // A two sided line will restrict the possible target ranges.
- FLineOpening open;
- P_LineOpening (open, NULL, li, trace.x + FixedMul (trace.dx, in->frac),
- trace.y + FixedMul (trace.dy, in->frac));
+ if ( !(li->flags & ML_TWOSIDED) || (li->flags & ML_BLOCKEVERYTHING) )
+ return; // stop
- if (open.bottom >= open.top)
- return false; // stop
+ // Crosses a two sided line.
+ // A two sided line will restrict the possible target ranges.
+ FLineOpening open;
+ P_LineOpening (open, NULL, li, it.Trace().x + FixedMul (it.Trace().dx, in->frac),
+ it.Trace().y + FixedMul (it.Trace().dy, in->frac));
+ if (open.bottom >= open.top)
+ return; // stop
+
+ dist = FixedMul (attackrange, in->frac);
+
+ pitch = -(int)R_PointToAngle2 (0, shootz, dist, open.bottom);
+ if (pitch < bottompitch)
+ bottompitch = pitch;
+
+ pitch = -(int)R_PointToAngle2 (0, shootz, dist, open.top);
+ if (pitch > toppitch)
+ toppitch = pitch;
+
+ if (toppitch >= bottompitch)
+ return; // stop
+
+ if (!AimTraverse3DFloors(it.Trace(), in)) return;
+ continue;
+ }
+
+ // shoot a thing
+ th = in->d.thing;
+ if (th == shootthing)
+ continue; // can't shoot self
+
+ if (!(th->flags&MF_SHOOTABLE))
+ continue; // corpse or something
+
+ // check for physical attacks on a ghost
+ if ((th->flags3 & MF3_GHOST) &&
+ shootthing->player && // [RH] Be sure shootthing is a player
+ shootthing->player->ReadyWeapon &&
+ (shootthing->player->ReadyWeapon->flags2 & MF2_THRUGHOST))
+ {
+ continue;
+ }
+
dist = FixedMul (attackrange, in->frac);
- pitch = -(int)R_PointToAngle2 (0, shootz, dist, open.bottom);
- if (pitch < bottompitch)
- bottompitch = pitch;
+ // we must do one last check whether the trace has crossed a 3D floor
+ if (lastsector==th->Sector && th->Sector->e->XFloor.ffloors.Size())
+ {
+ if (lastceilingplane)
+ {
+ fixed_t ff_top=lastceilingplane->ZatPoint(th->x, th->y);
+ fixed_t pitch = -(int)R_PointToAngle2 (0, shootz, dist, ff_top);
+ // upper slope intersects with this 3d-floor
+ if (pitch > toppitch)
+ {
+ toppitch=pitch;
+ }
+ }
+ if (lastfloorplane)
+ {
+ fixed_t ff_bottom=lastfloorplane->ZatPoint(th->x, th->y);
+ fixed_t pitch = -(int)R_PointToAngle2 (0, shootz, dist, ff_bottom);
+ // lower slope intersects with this 3d-floor
+ if (pitch < bottompitch)
+ {
+ bottompitch=pitch;
+ }
+ }
+ }
- pitch = -(int)R_PointToAngle2 (0, shootz, dist, open.top);
- if (pitch > toppitch)
- toppitch = pitch;
+ // check angles to see if the thing can be aimed at
- if (toppitch >= bottompitch)
- return false; // stop
-
- return P_AimTraverse3DFloors(in);
- }
+ thingtoppitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z + th->height);
- // shoot a thing
- th = in->d.thing;
- if (th == shootthing)
- return true; // can't shoot self
+ if (thingtoppitch > bottompitch)
+ continue; // shot over the thing
- if (!(th->flags&MF_SHOOTABLE))
- return true; // corpse or something
+ thingbottompitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z);
- // check for physical attacks on a ghost
- if ((th->flags3 & MF3_GHOST) &&
- shootthing->player && // [RH] Be sure shootthing is a player
- shootthing->player->ReadyWeapon &&
- (shootthing->player->ReadyWeapon->flags2 & MF2_THRUGHOST))
- {
- return true;
- }
+ if (thingbottompitch < toppitch)
+ continue; // shot under the thing
- dist = FixedMul (attackrange, in->frac);
-
- // we must do one last check whether the trace has crossed a 3D floor
- if (aim.lastsector==th->Sector && th->Sector->e->XFloor.ffloors.Size())
- {
- if (aim.lastceilingplane)
+ if (crossedffloors)
{
- fixed_t ff_top=aim.lastceilingplane->ZatPoint(th->x, th->y);
- fixed_t pitch = -(int)R_PointToAngle2 (0, shootz, dist, ff_top);
- // upper slope intersects with this 3d-floor
- if (pitch > toppitch)
+ // if 3D floors were in the way do an extra visibility check for safety
+ if (!P_CheckSight(shootthing, th, 1))
{
- toppitch=pitch;
+ // the thing can't be seen so we can safely exclude its range from our aiming field
+ if (thingtoppitchtoppitch) toppitch=thingbottompitch;
+ }
+ else if (thingbottompitch>bottompitch)
+ {
+ if (thingtoppitchZatPoint(th->x, th->y);
- fixed_t pitch = -(int)R_PointToAngle2 (0, shootz, dist, ff_bottom);
- // lower slope intersects with this 3d-floor
- if (pitch < bottompitch)
- {
- bottompitch=pitch;
- }
- }
- }
+ // this thing can be hit!
+ if (thingtoppitch < toppitch)
+ thingtoppitch = toppitch;
- // check angles to see if the thing can be aimed at
-
- thingtoppitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z + th->height);
-
- if (thingtoppitch > bottompitch)
- return true; // shot over the thing
-
- thingbottompitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z);
-
- if (thingbottompitch < toppitch)
- return true; // shot under the thing
+ if (thingbottompitch > bottompitch)
+ thingbottompitch = bottompitch;
- if (aim.crossedffloors)
- {
- // if 3D floors were in the way do an extra visibility check for safety
- if (!P_CheckSight(shootthing, th, 1))
- {
- // the thing can't be seen so we can safely exclude its range from our aiming field
- if (thingtoppitchtoppitch) toppitch=thingbottompitch;
- }
- else if (thingbottompitch>bottompitch)
- {
- if (thingtoppitch bottompitch)
- thingbottompitch = bottompitch;
-
- thingpitch = thingtoppitch/2 + thingbottompitch/2;
-
- if (sv_smartaim && !aim.notsmart)
- {
- // try to be a little smarter about what to aim at!
- // In particular avoid autoaiming at friends amd barrels.
- if (th->IsFriend(shootthing))
+ if (sv_smartaim && !notsmart)
{
- if (sv_smartaim < 2)
+ // try to be a little smarter about what to aim at!
+ // In particular avoid autoaiming at friends amd barrels.
+ if (th->IsFriend(shootthing))
{
- // friends don't aim at friends (except players), at least not first
- aim.thing_friend=th;
- aim.pitch_friend=thingpitch;
+ if (sv_smartaim < 2)
+ {
+ // friends don't aim at friends (except players), at least not first
+ thing_friend=th;
+ pitch_friend=thingpitch;
+ }
}
- }
- else if (!(th->flags3&MF3_ISMONSTER) )
- {
- if (sv_smartaim < 3)
+ else if (!(th->flags3&MF3_ISMONSTER) )
{
- // don't autoaim at barrels and other shootable stuff unless no monsters have been found
- aim.thing_other=th;
- aim.pitch_other=thingpitch;
+ if (sv_smartaim < 3)
+ {
+ // don't autoaim at barrels and other shootable stuff unless no monsters have been found
+ thing_other=th;
+ pitch_other=thingpitch;
+ }
+ }
+ else
+ {
+ linetarget=th;
+ aimpitch=thingpitch;
+ return;
}
}
else
{
linetarget=th;
aimpitch=thingpitch;
- return false;
+ return;
}
}
- else
- {
- linetarget=th;
- aimpitch=thingpitch;
- return false;
- }
- return true;
}
//============================================================================
@@ -2675,20 +2716,21 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vr
{
fixed_t x2;
fixed_t y2;
+ aim_t aim;
angle >>= ANGLETOFINESHIFT;
- shootthing = t1;
+ aim.shootthing = t1;
x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
- shootz = t1->z + (t1->height>>1) - t1->floorclip;
+ aim.shootz = t1->z + (t1->height>>1) - t1->floorclip;
if (t1->player != NULL)
{
- shootz += FixedMul (t1->player->mo->AttackZOffset, t1->player->crouchfactor);
+ aim.shootz += FixedMul (t1->player->mo->AttackZOffset, t1->player->crouchfactor);
}
else
{
- shootz += 8*FRACUNIT;
+ aim.shootz += 8*FRACUNIT;
}
// can't shoot outside view angles
@@ -2711,14 +2753,14 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vr
aim.bottompitch = t1->pitch + vrange;
aim.notsmart = forcenosmart;
- attackrange = distance;
+ aim.attackrange = distance;
linetarget = NULL;
// for smart aiming
aim.thing_friend=aim.thing_other=NULL;
// Information for tracking crossed 3D floors
- aimpitch=t1->pitch;
+ aim.aimpitch=t1->pitch;
aim.crossedffloors=t1->Sector->e->XFloor.ffloors.Size()!=0;
aim.lastsector=t1->Sector;
aim.lastfloorplane=aim.lastceilingplane=NULL;
@@ -2735,22 +2777,22 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vr
if (bottomz<=t1->z) aim.lastfloorplane=rover->top.plane;
}
- P_PathTraverse (t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse);
+ aim.AimTraverse (t1->x, t1->y, x2, y2);
if (!linetarget)
{
if (aim.thing_other)
{
linetarget=aim.thing_other;
- aimpitch=aim.pitch_other;
+ aim.aimpitch=aim.pitch_other;
}
else if (aim.thing_friend)
{
linetarget=aim.thing_friend;
- aimpitch=aim.pitch_friend;
+ aim.aimpitch=aim.pitch_friend;
}
}
- return linetarget ? aimpitch : t1->pitch;
+ return linetarget ? aim.aimpitch : t1->pitch;
}
@@ -2826,8 +2868,6 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
{
shootz += 8*FRACUNIT;
}
- attackrange = distance;
- aimpitch = pitch;
hitGhosts = (t1->player != NULL &&
t1->player->ReadyWeapon != NULL &&
@@ -2977,7 +3017,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance,
puff = P_SpawnPuff (pufftype, hitx, hity, hitz, angle - ANG180, 2, flags|PF_HITTHING|PF_TEMPORARY);
killPuff = true;
}
- SpawnDeepSplash (t1, trace, puff, vx, vy, vz);
+ SpawnDeepSplash (t1, trace, puff, vx, vy, vz, shootz);
}
}
if (killPuff && puff != NULL)
@@ -3165,6 +3205,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color
fixed_t x1, y1;
FVector3 start, end;
FTraceResults trace;
+ fixed_t shootz;
pitch = (angle_t)(-source->pitch) >> ANGLETOFINESHIFT;
angle = source->angle >> ANGLETOFINESHIFT;
@@ -3243,7 +3284,7 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color
AActor *thepuff = Spawn ("BulletPuff", 0, 0, 0, ALLOW_REPLACE);
if (thepuff != NULL)
{
- SpawnDeepSplash (source, trace, thepuff, vx, vy, vz);
+ SpawnDeepSplash (source, trace, thepuff, vx, vy, vz, shootz);
thepuff->Destroy ();
}
}
@@ -3286,10 +3327,8 @@ void P_RailAttack (AActor *source, int damage, int offset, int color1, int color
//
CVAR (Float, chase_height, -8.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Float, chase_dist, 90.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
-fixed_t CameraX, CameraY, CameraZ;
-sector_t *CameraSector;
-void P_AimCamera (AActor *t1)
+void P_AimCamera (AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &CameraZ, sector_t *&CameraSector)
{
fixed_t distance = (fixed_t)(chase_dist * FRACUNIT);
angle_t angle = (t1->angle - ANG180) >> ANGLETOFINESHIFT;
@@ -3326,123 +3365,130 @@ void P_AimCamera (AActor *t1)
//
// USE LINES
//
-AActor *usething;
-bool foundline;
-bool PTR_UseTraverse (intercept_t *in)
+bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline)
{
- // [RH] Check for things to talk with or use a puzzle item on
- if (!in->isaline)
- {
- if (usething==in->d.thing) return true;
- // Check thing
+ FPathTraverse it(usething->x, usething->y, endx, endy, PT_ADDLINES|PT_ADDTHINGS);
+ intercept_t *in;
- // Check for puzzle item use or USESPECIAL flag
- if (in->d.thing->flags5 & MF5_USESPECIAL || in->d.thing->special == USE_PUZZLE_ITEM_SPECIAL)
- {
- if (LineSpecials[in->d.thing->special] (NULL, usething, false,
- in->d.thing->args[0], in->d.thing->args[1], in->d.thing->args[2],
- in->d.thing->args[3], in->d.thing->args[4]))
- return false;
- }
- // Dead things can't talk.
- if (in->d.thing->health <= 0)
- {
- return true;
- }
- // Fighting things don't talk either.
- if (in->d.thing->flags4 & MF4_INCOMBAT)
- {
- return true;
- }
- if (in->d.thing->Conversation != NULL)
- {
- // Give the NPC a chance to play a brief animation
- in->d.thing->ConversationAnimation (0);
- P_StartConversation (in->d.thing, usething, true, true);
- return false;
- }
- return true;
- }
-
- FLineOpening open;
- // [RH] The range passed to P_PathTraverse was doubled so that it could
- // find things up to 128 units away (for Strife), but it should still reject
- // lines further than 64 units away.
- if (in->frac > FRACUNIT/2)
+ while ((in = it.Next()))
{
- // don't pass usething here. It will not do what might be expected!
- P_LineOpening (open, NULL, in->d.line, trace.x + FixedMul (trace.dx, in->frac),
- trace.y + FixedMul (trace.dy, in->frac));
- return open.range>0;
- }
-
- if (in->d.line->special == 0 || (GET_SPAC(in->d.line->flags) != SPAC_USETHROUGH &&
- GET_SPAC(in->d.line->flags) != SPAC_USE))
- {
-blocked:
- if (in->d.line->flags & ML_BLOCKEVERYTHING)
+ // [RH] Check for things to talk with or use a puzzle item on
+ if (!in->isaline)
{
- open.range = 0;
+ if (usething==in->d.thing) continue;
+ // Check thing
+
+ // Check for puzzle item use or USESPECIAL flag
+ if (in->d.thing->flags5 & MF5_USESPECIAL || in->d.thing->special == UsePuzzleItem)
+ {
+ if (LineSpecials[in->d.thing->special] (NULL, usething, false,
+ in->d.thing->args[0], in->d.thing->args[1], in->d.thing->args[2],
+ in->d.thing->args[3], in->d.thing->args[4]))
+ return true;
+ }
+ // Dead things can't talk.
+ if (in->d.thing->health <= 0)
+ {
+ continue;
+ }
+ // Fighting things don't talk either.
+ if (in->d.thing->flags4 & MF4_INCOMBAT)
+ {
+ continue;
+ }
+ if (in->d.thing->Conversation != NULL)
+ {
+ // Give the NPC a chance to play a brief animation
+ in->d.thing->ConversationAnimation (0);
+ P_StartConversation (in->d.thing, usething, true, true);
+ return true;
+ }
+ continue;
+ }
+
+ FLineOpening open;
+ // [RH] The range passed to P_PathTraverse was doubled so that it could
+ // find things up to 128 units away (for Strife), but it should still reject
+ // lines further than 64 units away.
+ if (in->frac > FRACUNIT/2)
+ {
+ // don't pass usething here. It will not do what might be expected!
+ P_LineOpening (open, NULL, in->d.line, it.Trace().x + FixedMul (it.Trace().dx, in->frac),
+ it.Trace().y + FixedMul (it.Trace().dy, in->frac));
+ if (open.range <= 0) return false;
+ else continue;
+ }
+ if (in->d.line->special == 0 || (GET_SPAC(in->d.line->flags) != SPAC_USETHROUGH &&
+ GET_SPAC(in->d.line->flags) != SPAC_USE))
+ {
+ blocked:
+ if (in->d.line->flags & ML_BLOCKEVERYTHING)
+ {
+ open.range = 0;
+ }
+ else
+ {
+ P_LineOpening (open, NULL, in->d.line, it.Trace().x + FixedMul (it.Trace().dx, in->frac),
+ it.Trace().y + FixedMul (it.Trace().dy, in->frac));
+ }
+ if (open.range <= 0 ||
+ (in->d.line->special != 0 && (i_compatflags & COMPATF_USEBLOCKING)))
+ {
+ // [RH] Give sector a chance to intercept the use
+
+ sector_t * sec;
+
+ sec = usething->Sector;
+
+ if (sec->SecActTarget && sec->SecActTarget->TriggerAction (usething, SECSPAC_Use))
+ {
+ return true;
+ }
+
+ sec = P_PointOnLineSide(usething->x, usething->y, in->d.line) == 0?
+ in->d.line->frontsector : in->d.line->backsector;
+
+ if (sec != NULL && sec->SecActTarget &&
+ sec->SecActTarget->TriggerAction (usething, SECSPAC_UseWall))
+ {
+ return true;
+ }
+
+ if (usething->player)
+ {
+ S_Sound (usething, CHAN_VOICE, "*usefail", 1, ATTN_IDLE);
+ }
+ return true; // can't use through a wall
+ }
+ foundline = true;
+ continue; // not a special line, but keep checking
+ }
+
+ if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
+ // [RH] continue traversal for two-sided lines
+ //return in->d.line->backsector != NULL; // don't use back side
+ goto blocked; // do a proper check for back sides of triggers
+
+ P_ActivateLine (in->d.line, usething, 0, SPAC_USE);
+
+ //WAS can't use more than one special line in a row
+ //jff 3/21/98 NOW multiple use allowed with enabling line flag
+ //[RH] And now I've changed it again. If the line is of type
+ // SPAC_USE, then it eats the use. Everything else passes
+ // it through, including SPAC_USETHROUGH.
+ if (i_compatflags & COMPATF_USEBLOCKING)
+ {
+ if (GET_SPAC(in->d.line->flags) == SPAC_USETHROUGH) continue;
+ else return true;
}
else
{
- P_LineOpening (open, NULL, in->d.line, trace.x + FixedMul (trace.dx, in->frac),
- trace.y + FixedMul (trace.dy, in->frac));
+ if (GET_SPAC(in->d.line->flags) != SPAC_USE) continue;
+ else return true;
}
- if (open.range <= 0 ||
- (in->d.line->special != 0 && (i_compatflags & COMPATF_USEBLOCKING)))
- {
- // [RH] Give sector a chance to intercept the use
-
- sector_t * sec;
-
- sec = usething->Sector;
-
- if (sec->SecActTarget && sec->SecActTarget->TriggerAction (usething, SECSPAC_Use))
- {
- return false;
- }
-
- sec = P_PointOnLineSide(usething->x, usething->y, in->d.line) == 0?
- in->d.line->frontsector : in->d.line->backsector;
-
- if (sec != NULL && sec->SecActTarget &&
- sec->SecActTarget->TriggerAction (usething, SECSPAC_UseWall))
- {
- return false;
- }
-
- if (usething->player)
- {
- S_Sound (usething, CHAN_VOICE, "*usefail", 1, ATTN_IDLE);
- }
- return false; // can't use through a wall
- }
- foundline = true;
- return true; // not a special line, but keep checking
- }
-
- if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
- // [RH] continue traversal for two-sided lines
- //return in->d.line->backsector != NULL; // don't use back side
- goto blocked; // do a proper check for back sides of triggers
-
- P_ActivateLine (in->d.line, usething, 0, SPAC_USE);
-
- //WAS can't use more than one special line in a row
- //jff 3/21/98 NOW multiple use allowed with enabling line flag
- //[RH] And now I've changed it again. If the line is of type
- // SPAC_USE, then it eats the use. Everything else passes
- // it through, including SPAC_USETHROUGH.
- if (i_compatflags & COMPATF_USEBLOCKING)
- {
- return GET_SPAC(in->d.line->flags) == SPAC_USETHROUGH;
- }
- else
- {
- return GET_SPAC(in->d.line->flags) != SPAC_USE;
}
+ return false;
}
// Returns false if a "oof" sound should be made because of a blocking
@@ -3455,19 +3501,27 @@ blocked:
// by Lee Killough
//
-bool PTR_NoWayTraverse (intercept_t *in)
+bool P_NoWayTraverse (AActor *usething, fixed_t endx, fixed_t endy)
{
- line_t *ld = in->d.line;
- FLineOpening open;
+ FPathTraverse it(usething->x, usething->y, endx, endy, PT_ADDLINES);
+ intercept_t *in;
- // [GrafZahl] de-obfuscated. Was I the only one who was unable to makes sense out of
- // this convoluted mess?
- if (ld->special) return true;
- if (ld->flags&(ML_BLOCKING|ML_BLOCKEVERYTHING|ML_BLOCK_PLAYERS)) return false;
- P_LineOpening(open, NULL, ld, trace.x+FixedMul(trace.dx, in->frac),trace.y+FixedMul(trace.dy, in->frac));
- return open.range >0 &&
- open.bottom <= usething->z + usething->MaxStepHeight &&
- open.top >= usething->z + usething->height;
+ while ((in = it.Next()))
+ {
+ line_t *ld = in->d.line;
+ FLineOpening open;
+
+ // [GrafZahl] de-obfuscated. Was I the only one who was unable to makes sense out of
+ // this convoluted mess?
+ if (ld->special) continue;
+ 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));
+ if (open.range <= 0 ||
+ open.bottom > usething->z + usething->MaxStepHeight ||
+ open.top < usething->z + usething->height) return true;
+ }
+ return false;
}
/*
@@ -3482,16 +3536,14 @@ bool PTR_NoWayTraverse (intercept_t *in)
void P_UseLines (player_t *player)
{
angle_t angle;
- fixed_t x1, y1, x2, y2;
+ fixed_t x2, y2;
+ bool foundline;
- usething = player->mo;
foundline = false;
angle = player->mo->angle >> ANGLETOFINESHIFT;
- x1 = player->mo->x;
- y1 = player->mo->y;
- x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle]*2;
- y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle]*2;
+ x2 = player->mo->x + (USERANGE>>FRACBITS)*finecosine[angle]*2;
+ y2 = player->mo->y + (USERANGE>>FRACBITS)*finesine[angle]*2;
// old code:
//
@@ -3499,80 +3551,19 @@ void P_UseLines (player_t *player)
//
// This added test makes the "oof" sound work on 2s lines -- killough:
- if (P_PathTraverse (x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_UseTraverse))
+ if (!P_UseTraverse (player->mo, x2, y2, foundline))
{ // [RH] Give sector a chance to eat the use
- sector_t *sec = usething->Sector;
+ sector_t *sec = player->mo->Sector;
int spac = SECSPAC_Use;
- if (foundline)
- spac |= SECSPAC_UseWall;
- if ((!sec->SecActTarget ||
- !sec->SecActTarget->TriggerAction (usething, spac)) &&
- !P_PathTraverse (x1, y1, x2, y2, PT_ADDLINES, PTR_NoWayTraverse))
+ if (foundline) spac |= SECSPAC_UseWall;
+ if ((!sec->SecActTarget || !sec->SecActTarget->TriggerAction (player->mo, spac)) &&
+ P_NoWayTraverse (player->mo, x2, y2))
{
- S_Sound (usething, CHAN_VOICE, "*usefail", 1, ATTN_IDLE);
+ S_Sound (player->mo, CHAN_VOICE, "*usefail", 1, ATTN_IDLE);
}
}
}
-//==========================================================================
-//
-// PTR_PuzzleItemTraverse
-//
-//==========================================================================
-
-static AActor *PuzzleItemUser;
-static int PuzzleItemType;
-static bool PuzzleActivated;
-
-bool PTR_PuzzleItemTraverse (intercept_t *in)
-{
- AActor *mobj;
- FLineOpening open;
-
- if (in->isaline)
- { // Check line
- if (in->d.line->special != USE_PUZZLE_ITEM_SPECIAL)
- {
- P_LineOpening (open, NULL, in->d.line, trace.x + FixedMul (trace.dx, in->frac),
- trace.y + FixedMul (trace.dy, in->frac));
- if (open.range <= 0)
- {
- return false; // can't use through a wall
- }
- return true; // Continue searching
- }
- if (P_PointOnLineSide (PuzzleItemUser->x, PuzzleItemUser->y,
- in->d.line) == 1)
- { // Don't use back sides
- return false;
- }
- if (PuzzleItemType != in->d.line->args[0])
- { // Item type doesn't match
- return false;
- }
- P_StartScript (PuzzleItemUser, in->d.line, in->d.line->args[1], NULL, 0,
- in->d.line->args[2], in->d.line->args[3], in->d.line->args[4], true, false);
- in->d.line->special = 0;
- PuzzleActivated = true;
- return false; // Stop searching
- }
- // Check thing
- mobj = in->d.thing;
- if (mobj->special != USE_PUZZLE_ITEM_SPECIAL)
- { // Wrong special
- return true;
- }
- if (PuzzleItemType != mobj->args[0])
- { // Item type doesn't match
- return true;
- }
- P_StartScript (PuzzleItemUser, NULL, mobj->args[1], NULL, 0,
- mobj->args[2], mobj->args[3], mobj->args[4], true, false);
- mobj->special = 0;
- PuzzleActivated = true;
- return false; // Stop searching
-}
-
//==========================================================================
//
// P_UsePuzzleItem
@@ -3581,36 +3572,72 @@ bool PTR_PuzzleItemTraverse (intercept_t *in)
//
//==========================================================================
-bool P_UsePuzzleItem (AActor *actor, int itemType)
+bool P_UsePuzzleItem (AActor *PuzzleItemUser, int PuzzleItemType)
{
int angle;
fixed_t x1, y1, x2, y2;
- PuzzleItemType = itemType;
- PuzzleItemUser = actor;
- PuzzleActivated = false;
- angle = actor->angle>>ANGLETOFINESHIFT;
- x1 = actor->x;
- y1 = actor->y;
+ angle = PuzzleItemUser->angle>>ANGLETOFINESHIFT;
+ x1 = PuzzleItemUser->x;
+ y1 = PuzzleItemUser->y;
x2 = x1+(USERANGE>>FRACBITS)*finecosine[angle];
y2 = y1+(USERANGE>>FRACBITS)*finesine[angle];
- P_PathTraverse (x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS,
- PTR_PuzzleItemTraverse);
- return PuzzleActivated;
+
+ FPathTraverse it(x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS);
+ intercept_t *in;
+
+ while ((in = it.Next()))
+ {
+ AActor *mobj;
+ FLineOpening open;
+
+ if (in->isaline)
+ { // Check line
+ if (in->d.line->special != UsePuzzleItem)
+ {
+ P_LineOpening (open, NULL, in->d.line, it.Trace().x + FixedMul (it.Trace().dx, in->frac),
+ it.Trace().y + FixedMul (it.Trace().dy, in->frac));
+ if (open.range <= 0)
+ {
+ return false; // can't use through a wall
+ }
+ continue;
+ }
+ if (P_PointOnLineSide (PuzzleItemUser->x, PuzzleItemUser->y, in->d.line) == 1)
+ { // Don't use back sides
+ return false;
+ }
+ if (PuzzleItemType != in->d.line->args[0])
+ { // Item type doesn't match
+ return false;
+ }
+ P_StartScript (PuzzleItemUser, in->d.line, in->d.line->args[1], NULL, 0,
+ in->d.line->args[2], in->d.line->args[3], in->d.line->args[4], true, false);
+ in->d.line->special = 0;
+ return true;
+ }
+ // Check thing
+ mobj = in->d.thing;
+ if (mobj->special != UsePuzzleItem)
+ { // Wrong special
+ continue;
+ }
+ if (PuzzleItemType != mobj->args[0])
+ { // Item type doesn't match
+ continue;
+ }
+ P_StartScript (PuzzleItemUser, NULL, mobj->args[1], NULL, 0,
+ mobj->args[2], mobj->args[3], mobj->args[4], true, false);
+ mobj->special = 0;
+ return true;
+ }
+ return false;
}
//
// RADIUS ATTACK
//
-//=============================================================================
-//
-// PIT_RadiusAttack
-//
-// "bombsource" is the creature that caused the explosion at "bombspot".
-// [RH] Now it knows about vertical distances and can thrust things vertically.
-//=============================================================================
-
// [RH] Damage scale to apply to thing that shot the missile.
static float selfthrustscale;
@@ -4737,7 +4764,7 @@ void SpawnShootDecal (AActor *t1, const FTraceResults &trace)
}
static void SpawnDeepSplash (AActor *t1, const FTraceResults &trace, AActor *puff,
- fixed_t vx, fixed_t vy, fixed_t vz)
+ fixed_t vx, fixed_t vy, fixed_t vz, fixed_t shootz)
{
if (!trace.CrossedWater->heightsec) return;
diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp
index d4a73488..81c7ba02 100644
--- a/src/p_maputl.cpp
+++ b/src/p_maputl.cpp
@@ -59,57 +59,6 @@ fixed_t P_AproxDistance (fixed_t dx, fixed_t dy)
return (dx < dy) ? dx+dy-(dx>>1) : dx+dy-(dy>>1);
}
-//==========================================================================
-//
-// P_BoxOnLineSide
-//
-// Considers the line to be infinite
-// Returns side 0 or 1, -1 if box crosses the line.
-//
-//==========================================================================
-
-int P_BoxOnLineSide (const fixed_t *tmbox, const line_t *ld)
-{
- int p1;
- int p2;
-
- switch (ld->slopetype)
- {
- case ST_HORIZONTAL:
- p1 = tmbox[BOXTOP] > ld->v1->y;
- p2 = tmbox[BOXBOTTOM] > ld->v1->y;
- if (ld->dx < 0)
- {
- p1 ^= 1;
- p2 ^= 1;
- }
- break;
-
- case ST_VERTICAL:
- p1 = tmbox[BOXRIGHT] < ld->v1->x;
- p2 = tmbox[BOXLEFT] < ld->v1->x;
- if (ld->dy < 0)
- {
- p1 ^= 1;
- p2 ^= 1;
- }
- break;
-
- case ST_POSITIVE:
- p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
- p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
- break;
-
- case ST_NEGATIVE:
- default: // Just to assure GCC that p1 and p2 really do get initialized
- p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
- p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
- break;
- }
-
- return (p1 == p2) ? p1 : -1;
-}
-
//==========================================================================
//
// P_InterceptVector
@@ -270,6 +219,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
// THING POSITION SETTING
//
+//==========================================================================
//
// P_UnsetThingPosition
// Unlinks a thing from block map and sectors.
@@ -277,6 +227,8 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
// lookups maintaining lists of things inside
// these structures need to be updated.
//
+//==========================================================================
+
void AActor::UnlinkFromWorld ()
{
sector_list = NULL;
@@ -332,11 +284,14 @@ void AActor::UnlinkFromWorld ()
}
+//==========================================================================
//
// P_SetThingPosition
// Links a thing into both a block and a subsector based on it's x y.
// Sets thing->sector properly
//
+//==========================================================================
+
void AActor::LinkToWorld (bool buggy)
{
// link into subsector
@@ -440,12 +395,15 @@ void AActor::LinkToWorld (sector_t *sec)
}
}
+//==========================================================================
//
// [RH] LinkToWorldForMapThing
//
// Emulate buggy PointOnLineSide and fix actors that lie on
// lines to compensate for some IWAD maps.
//
+//==========================================================================
+
static int R_PointOnSideSlow (fixed_t x, fixed_t y, node_t *node)
{
// [RH] This might have been faster than two multiplies and an
@@ -549,7 +507,6 @@ sector_t *AActor::LinkToWorldForMapThing ()
}
}
-#if 1
// Not inside the line's bounding box
if (x + radius <= ldef->bbox[BOXLEFT]
|| x - radius >= ldef->bbox[BOXRIGHT]
@@ -593,39 +550,6 @@ sector_t *AActor::LinkToWorldForMapThing ()
y += FixedMul(distance, finesine[finean]);
return P_PointInSector (x, y);
}
-#else
- if (DMulScale32 (y - ldef->v1->y, ldef->dx, ldef->v1->x - x, ldef->dy) == 0)
- {
- // It touches the infinite line; now make sure it touches the linedef
- SQWORD num, den;
-
- den = (SQWORD)ldef->dx*ldef->dx + (SQWORD)ldef->dy*ldef->dy;
- if (den != 0)
- {
- num = (SQWORD)(x-ldef->v1->x)*ldef->dx+(SQWORD)(y-ldef->v1->y)*ldef->dy;
- if (num >= 0 && num <= den)
- {
- DPrintf ("%s at (%d,%d) lies directly on %s line %d\n",
- this->GetClass()->TypeName.GetChars(), x>>FRACBITS, y>>FRACBITS,
- ldef->dx == 0? "vertical" : ldef->dy == 0? "horizontal" : "diagonal",
- ldef-lines);
- angle_t finean = R_PointToAngle2 (0, 0, ldef->dx, ldef->dy);
- if (ldef->backsector != NULL && ldef->backsector == ssec->sector)
- {
- finean += ANGLE_90;
- }
- else
- {
- finean -= ANGLE_90;
- }
- finean >>= ANGLETOFINESHIFT;
- x += finecosine[finean]) >> 2;
- y += finesine[finean]) >> 2;
- break;
- }
- }
- }
-#endif
}
}
}
@@ -815,34 +739,20 @@ line_t *FBlockLinesIterator::Next()
//===========================================================================
//
-// FBlockThingsIterator :: GetCheckArray
+// FBlockThingsIterator :: CheckArray
//
//===========================================================================
-TDeletingArray< FBlockThingsIterator::BTChecked* > FBlockThingsIterator::FreeBTChecked;
+TArray FBlockThingsIterator::CheckArray(32);
-FBlockThingsIterator::BTChecked *FBlockThingsIterator::GetCheckArray()
+int FBlockThingsIterator::GetCheckIndex()
{
- dontfreecheck = false;
- if (FreeBTChecked.Size() != 0)
- {
- BTChecked *ret;
- FreeBTChecked.Pop(ret);
- ret->Clear();
- return ret;
- }
- return new BTChecked();
+ return CheckArray.Size();
}
-//===========================================================================
-//
-// FBlockThingsIterator :: FreeCheckArray
-//
-//===========================================================================
-
-void FBlockThingsIterator::FreeCheckArray()
+void FBlockThingsIterator::SetCheckIndex(int newvalue)
{
- FreeBTChecked.Push(checkarray);
+ CheckArray.Resize(newvalue);
}
//===========================================================================
@@ -851,17 +761,19 @@ void FBlockThingsIterator::FreeCheckArray()
//
//===========================================================================
-FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int _maxy, TArray *Check)
+FBlockThingsIterator::FBlockThingsIterator(int x, int y, int check)
{
- if (Check != NULL)
- {
- checkarray = Check;
- dontfreecheck = true;
- }
- else
- {
- checkarray = GetCheckArray();
- }
+ checkindex = check;
+ dontfreecheck = true;
+ minx = maxx = x;
+ miny = maxy = y;
+ Reset();
+}
+
+FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int _maxy)
+{
+ checkindex = CheckArray.Size();
+ dontfreecheck = false;
minx = _minx;
maxx = _maxx;
miny = _miny;
@@ -871,7 +783,8 @@ FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int
FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box)
{
- checkarray = GetCheckArray();
+ checkindex = CheckArray.Size();
+ dontfreecheck = false;
maxy = (box.Top() - bmaporgy) >> MAPBLOCKSHIFT;
miny = (box.Bottom() - bmaporgy) >> MAPBLOCKSHIFT;
maxx = (box.Right() - bmaporgx) >> MAPBLOCKSHIFT;
@@ -879,6 +792,17 @@ FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box)
Reset();
}
+//===========================================================================
+//
+// FBlockThingsIterator :: FreeCheckArray
+//
+//===========================================================================
+
+FBlockThingsIterator::~FBlockThingsIterator()
+{
+ if (!dontfreecheck) CheckArray.Resize(checkindex);
+}
+
//===========================================================================
//
// FBlockThingsIterator :: StartBlock
@@ -917,16 +841,16 @@ AActor *FBlockThingsIterator::Next()
block = block->NextActor;
// Don't recheck things that were already checked
- for (i = (int)checkarray->Size() - 1; i >= 0; --i)
+ for (i = (int)CheckArray.Size() - 1; i >= checkindex; --i)
{
- if ((*checkarray)[i] == me)
+ if (CheckArray[i] == me)
{
break;
}
}
- if (i < 0)
+ if (i < checkindex)
{
- checkarray->Push (me);
+ CheckArray.Push (me);
return me;
}
}
@@ -974,16 +898,18 @@ AActor *FRadiusThingsIterator::Next()
}
+//===========================================================================
//
-// INTERCEPT ROUTINES
+// FPathTraverse :: Intercepts
//
-TArray intercepts (128);
+//===========================================================================
-divline_t trace;
-int ptflags;
+TArray FPathTraverse::intercepts(128);
+
+//===========================================================================
//
-// PIT_AddLineIntercepts.
+// FPathTraverse :: AddLineIntercepts.
// Looks for lines in the given block
// that intercept the given trace
// to add to the intercepts list.
@@ -991,7 +917,9 @@ int ptflags;
// A line is crossed if its endpoints
// are on opposite sides of the trace.
//
-void P_AddLineIntercepts(int bx, int by)
+//===========================================================================
+
+void FPathTraverse::AddLineIntercepts(int bx, int by)
{
FBlockLinesIterator it(bx, by, bx, by, true);
line_t *ld;
@@ -1030,18 +958,22 @@ void P_AddLineIntercepts(int bx, int by)
newintercept.frac = frac;
newintercept.isaline = true;
+ newintercept.done = false;
newintercept.d.line = ld;
intercepts.Push (newintercept);
}
}
+//===========================================================================
//
-// PIT_AddThingIntercepts
+// FPathTraverse :: AddThingIntercepts
//
-void P_AddThingIntercepts (int bx, int by, TArray &checkbt)
+//===========================================================================
+
+void FPathTraverse::AddThingIntercepts (int bx, int by, int checkindex)
{
- FBlockThingsIterator it(bx, by, bx, by, &checkbt);
+ FBlockThingsIterator it(bx, by, checkindex);
AActor *thing;
while ((thing = it.Next()))
@@ -1106,6 +1038,7 @@ void P_AddThingIntercepts (int bx, int by, TArray &checkbt)
intercept_t newintercept;
newintercept.frac = frac;
newintercept.isaline = false;
+ newintercept.done = false;
newintercept.d.thing = thing;
intercepts.Push (newintercept);
continue;
@@ -1120,6 +1053,7 @@ void P_AddThingIntercepts (int bx, int by, TArray &checkbt)
intercept_t newintercept;
newintercept.frac = 0;
newintercept.isaline = false;
+ newintercept.done = false;
newintercept.d.thing = thing;
intercepts.Push (newintercept);
}
@@ -1127,60 +1061,41 @@ void P_AddThingIntercepts (int bx, int by, TArray &checkbt)
}
+//===========================================================================
//
-// P_TraverseIntercepts
-// Returns true if the traverser function returns true
-// for all lines.
+// FPathTraverse :: Next
//
-bool P_TraverseIntercepts (traverser_t func, fixed_t maxfrac)
+//===========================================================================
+
+intercept_t *FPathTraverse::Next()
{
- unsigned int count;
- fixed_t dist;
- unsigned int scanpos;
- intercept_t *scan;
intercept_t *in = NULL;
- count = intercepts.Size ();
-
- while (count--)
+ fixed_t dist = FIXED_MAX;
+ for (unsigned scanpos = intercept_index; scanpos < intercepts.Size (); scanpos++)
{
- dist = FIXED_MAX;
- for (scanpos = 0; scanpos < intercepts.Size (); scanpos++)
+ intercept_t *scan = &intercepts[scanpos];
+ if (scan->frac < dist && !scan->done)
{
- scan = &intercepts[scanpos];
- if (scan->frac < dist)
- {
- dist = scan->frac;
- in = scan;
- }
+ dist = scan->frac;
+ in = scan;
}
-
- if (dist > maxfrac || in == NULL)
- return true; // checked everything in range
-
- if (!func (in))
- return false; // don't bother going farther
-
- in->frac = FIXED_MAX;
}
-
- return true; // everything was traversed
+
+ if (dist > maxfrac || in == NULL) return NULL; // checked everything in range
+ in->done = true;
+ return in;
}
-
-
-
+//===========================================================================
//
-// P_PathTraverse
+// FPathTraverse
// Traces a line from x1,y1 to x2,y2,
-// calling the traverser function for each.
-// Returns true if the traverser function returns true
-// for all lines.
//
-bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, bool (*trav) (intercept_t *))
-{
- static TArray pathbt;
+//===========================================================================
+FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags)
+{
fixed_t xt1;
fixed_t yt1;
fixed_t xt2;
@@ -1203,8 +1118,7 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags,
int count;
validcount++;
- intercepts.Clear ();
- pathbt.Clear ();
+ intercept_index = intercepts.Size();
if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
x1 += FRACUNIT; // don't side exactly on a line
@@ -1295,16 +1209,18 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags,
mapx = xt1;
mapy = yt1;
+ // we want to use one list of checked actors for the entire operation
+ int BTI_CheckIndex = FBlockThingsIterator::GetCheckIndex();
for (count = 0 ; count < 100 ; count++)
{
if (flags & PT_ADDLINES)
{
- P_AddLineIntercepts(mapx, mapy);
+ AddLineIntercepts(mapx, mapy);
}
if (flags & PT_ADDTHINGS)
{
- P_AddThingIntercepts(mapx, mapy, pathbt);
+ AddThingIntercepts(mapx, mapy, BTI_CheckIndex);
}
if (mapx == xt2 && mapy == yt2)
@@ -1336,14 +1252,14 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags,
// be checked.
if (flags & PT_ADDLINES)
{
- P_AddLineIntercepts(mapx + mapxstep, mapy);
- P_AddLineIntercepts(mapx, mapy + mapystep);
+ AddLineIntercepts(mapx + mapxstep, mapy);
+ AddLineIntercepts(mapx, mapy + mapystep);
}
if (flags & PT_ADDTHINGS)
{
- P_AddThingIntercepts(mapx + mapxstep, mapy, pathbt);
- P_AddThingIntercepts(mapx, mapy + mapystep, pathbt);
+ AddThingIntercepts(mapx + mapxstep, mapy, BTI_CheckIndex);
+ AddThingIntercepts(mapx, mapy + mapystep, BTI_CheckIndex);
}
xintercept += xstep;
yintercept += ystep;
@@ -1352,10 +1268,16 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags,
break;
}
}
- // go through the sorted list
- return P_TraverseIntercepts ( trav, FRACUNIT );
+ FBlockThingsIterator::SetCheckIndex(BTI_CheckIndex);
+ maxfrac = FRACUNIT;
}
+FPathTraverse::~FPathTraverse()
+{
+ intercepts.Resize(intercept_index);
+}
+
+
//===========================================================================
//
// P_RoughMonsterSearch
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 117eef13..06094b3b 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -80,7 +80,6 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj);
extern cycle_t BotSupportCycles;
extern cycle_t BotWTG;
-extern fixed_t attackrange;
EXTERN_CVAR (Bool, r_drawfuzz);
EXTERN_CVAR (Int, cl_rockettrails)
diff --git a/src/p_sight.cpp b/src/p_sight.cpp
index 4f41bfe5..23960c7f 100644
--- a/src/p_sight.cpp
+++ b/src/p_sight.cpp
@@ -43,8 +43,7 @@ static int sightcounts[6];
static cycle_t SightCycles;
static cycle_t MaxSightCycles;
-// we might as well use the global intercepts array instead of creating a new one
-extern TArray intercepts;
+static TArray intercepts (128);
class SightCheck
{
diff --git a/src/p_trace.cpp b/src/p_trace.cpp
index 609307ee..30d21670 100644
--- a/src/p_trace.cpp
+++ b/src/p_trace.cpp
@@ -36,70 +36,73 @@
#include "p_local.h"
#include "i_system.h"
-static fixed_t StartZ;
-static fixed_t Vx, Vy, Vz;
-static DWORD ActorMask, WallMask;
-static AActor *IgnoreThis;
-static FTraceResults *Results;
-static sector_t *CurSector;
-static fixed_t MaxDist;
-static fixed_t EnterDist;
-static bool (*TraceCallback)(FTraceResults &res);
-static DWORD TraceFlags;
+struct FTraceInfo
+{
+ fixed_t StartX, StartY, StartZ;
+ fixed_t Vx, Vy, Vz;
+ DWORD ActorMask, WallMask;
+ AActor *IgnoreThis;
+ FTraceResults *Results;
+ sector_t *CurSector;
+ fixed_t MaxDist;
+ fixed_t EnterDist;
+ bool (*TraceCallback)(FTraceResults &res);
+ DWORD TraceFlags;
-// These are required for 3D-floor checking
-// to create a fake sector with a floor
-// or ceiling plane coming from a 3D-floor
-static sector_t DummySector[2];
-static int sectorsel;
+ // These are required for 3D-floor checking
+ // to create a fake sector with a floor
+ // or ceiling plane coming from a 3D-floor
+ sector_t DummySector[2];
+ int sectorsel;
+
+ bool TraceTraverse (int ptflags);
+ bool CheckSectorPlane (const sector_t *sector, bool checkFloor);
+};
-static bool PTR_TraceIterator (intercept_t *);
-static bool CheckSectorPlane (const sector_t *sector, bool checkFloor, divline_t & trace);
static bool EditTraceResult (DWORD flags, FTraceResults &res);
+
bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
fixed_t vx, fixed_t vy, fixed_t vz, fixed_t maxDist,
DWORD actorMask, DWORD wallMask, AActor *ignore,
FTraceResults &res,
DWORD flags, bool (*callback)(FTraceResults &res))
{
- // Under extreme circumstances ADecal::DoTrace can call this from inside a linespecial call!
- static bool recursion;
- if (recursion) return false;
- recursion=true;
-
int ptflags;
+ FTraceInfo inf;
ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS : PT_ADDLINES;
- StartZ = z;
- Vx = vx;
- Vy = vy;
- Vz = vz;
- ActorMask = actorMask;
- WallMask = wallMask;
- IgnoreThis = ignore;
- CurSector = sector;
- MaxDist = maxDist;
- EnterDist = 0;
- TraceCallback = callback;
- TraceFlags = flags;
+ inf.StartX = x;
+ inf.StartY = y;
+ inf.StartZ = z;
+ inf.Vx = vx;
+ inf.Vy = vy;
+ inf.Vz = vz;
+ inf.ActorMask = actorMask;
+ inf.WallMask = wallMask;
+ inf.IgnoreThis = ignore;
+ inf.CurSector = sector;
+ inf.MaxDist = maxDist;
+ inf.EnterDist = 0;
+ inf.TraceCallback = callback;
+ inf.TraceFlags = flags;
res.CrossedWater = NULL;
- Results = &res;
+ inf.Results = &res;
res.HitType = TRACE_HitNone;
// Do a 3D floor check in the starting sector
res.ffloor=NULL;
- sectorsel=0;
+ inf.sectorsel=0;
TDeletingArray &ff = sector->e->XFloor.ffloors;
if (ff.Size())
{
- memcpy(&DummySector[0],sector,sizeof(sector_t));
- CurSector=sector=&DummySector[0];
- sectorsel=1;
+ memcpy(&inf.DummySector[0],sector,sizeof(sector_t));
+ inf.CurSector=sector=&inf.DummySector[0];
+ inf.sectorsel=1;
fixed_t bf = sector->floorplane.ZatPoint (x, y);
fixed_t bc = sector->ceilingplane.ZatPoint (x, y);
@@ -141,11 +144,11 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
if (xd>SQWORD(32767)*FRACUNIT)
{
- maxDist=FixedDiv(FIXED_MAX-x,vx);
+ maxDist = inf.MaxDist=FixedDiv(FIXED_MAX-x,vx);
}
else if (xd<-SQWORD(32767)*FRACUNIT)
{
- maxDist=FixedDiv(FIXED_MIN-x,vx);
+ maxDist = inf.MaxDist=FixedDiv(FIXED_MIN-x,vx);
}
@@ -153,40 +156,34 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
if (yd>SQWORD(32767)*FRACUNIT)
{
- maxDist=FixedDiv(FIXED_MAX-y,vy);
+ maxDist = inf.MaxDist=FixedDiv(FIXED_MAX-y,vy);
}
else if (yd<-SQWORD(32767)*FRACUNIT)
{
- maxDist=FixedDiv(FIXED_MIN-y,vy);
+ maxDist = inf.MaxDist=FixedDiv(FIXED_MIN-y,vy);
}
// recalculate the trace's end points for robustness
- if (P_PathTraverse (x, y, x + FixedMul (vx, maxDist), y + FixedMul (vy, maxDist),
- ptflags, PTR_TraceIterator))
+ if (inf.TraceTraverse (ptflags))
{ // check for intersection with floor/ceiling
- res.Sector = CurSector;
- divline_t trace;
+ res.Sector = inf.CurSector;
- trace.x=x;
- trace.y=y;
-
- if (CheckSectorPlane (CurSector, true, trace))
+ if (inf.CheckSectorPlane (inf.CurSector, true))
{
res.HitType = TRACE_HitFloor;
if (res.CrossedWater == NULL &&
- CurSector->heightsec != NULL &&
- CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z)
+ inf.CurSector->heightsec != NULL &&
+ inf.CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z)
{
- res.CrossedWater = CurSector;
+ res.CrossedWater = inf.CurSector;
}
}
- else if (CheckSectorPlane (CurSector, false, trace))
+ else if (inf.CheckSectorPlane (inf.CurSector, false))
{
res.HitType = TRACE_HitCeiling;
}
}
- recursion=false;
if (res.HitType != TRACE_HitNone)
{
if (flags)
@@ -210,339 +207,343 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
}
}
-static bool PTR_TraceIterator (intercept_t *in)
+bool FTraceInfo::TraceTraverse (int ptflags)
{
- fixed_t hitx, hity, hitz;
- fixed_t dist;
+ FPathTraverse it(StartX, StartY, StartX + FixedMul (Vx, MaxDist), StartY + FixedMul (Vy, MaxDist), ptflags);
+ intercept_t *in;
- if (in->isaline)
+ while ((in = it.Next()))
{
- int lineside;
- sector_t *entersector;
+ fixed_t hitx, hity, hitz;
+ fixed_t dist;
- dist = FixedMul (MaxDist, in->frac);
- hitx = trace.x + FixedMul (Vx, dist);
- hity = trace.y + FixedMul (Vy, dist);
- hitz = StartZ + FixedMul (Vz, dist);
-
- fixed_t ff, fc, bf = 0, bc = 0;
-
- // CurSector may be a copy so we must compare the sector number, not the index!
- if (in->d.line->frontsector->sectornum == CurSector->sectornum)
+ if (in->isaline)
{
- lineside = 0;
- }
- else if (in->d.line->backsector && in->d.line->backsector->sectornum == CurSector->sectornum)
- {
- lineside = 1;
- }
- else
- { // Dammit. Why does Doom have to allow non-closed sectors?
- if (in->d.line->backsector == NULL)
+ int lineside;
+ sector_t *entersector;
+
+ dist = FixedMul (MaxDist, in->frac);
+ hitx = StartX + FixedMul (Vx, dist);
+ hity = StartY + FixedMul (Vy, dist);
+ hitz = StartZ + FixedMul (Vz, dist);
+
+ fixed_t ff, fc, bf = 0, bc = 0;
+
+ // CurSector may be a copy so we must compare the sector number, not the index!
+ if (in->d.line->frontsector->sectornum == CurSector->sectornum)
{
lineside = 0;
- CurSector = in->d.line->frontsector;
+ }
+ else if (in->d.line->backsector && in->d.line->backsector->sectornum == CurSector->sectornum)
+ {
+ lineside = 1;
}
else
- {
- lineside = P_PointOnLineSide (trace.x, trace.y, in->d.line);
- CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector;
- }
- }
-
- if (!(in->d.line->flags & ML_TWOSIDED))
- {
- entersector = NULL;
- }
- else
- {
- entersector = (lineside == 0) ? in->d.line->backsector : in->d.line->frontsector;
-
- // For backwards compatibility: Ignore lines with the same sector on both sides.
- // This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15 need it.
- if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector)
- {
- return true;
- }
- }
-
- ff = CurSector->floorplane.ZatPoint (hitx, hity);
- fc = CurSector->ceilingplane.ZatPoint (hitx, hity);
-
- if (entersector != NULL)
- {
- bf = entersector->floorplane.ZatPoint (hitx, hity);
- bc = entersector->ceilingplane.ZatPoint (hitx, hity);
- }
-
- if (Results->CrossedWater == NULL &&
- CurSector->heightsec &&
- !(CurSector->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
- //CurSector->heightsec->waterzone &&
- hitz <= CurSector->heightsec->floorplane.ZatPoint (hitx, hity))
- {
- // hit crossed a water plane
- Results->CrossedWater = CurSector;
- }
-
- if (hitz <= ff)
- { // hit floor in front of wall
- Results->HitType = TRACE_HitFloor;
- }
- else if (hitz >= fc)
- { // hit ceiling in front of wall
- Results->HitType = TRACE_HitCeiling;
- }
- else if (entersector == NULL ||
- hitz <= bf || hitz >= bc ||
- in->d.line->flags & WallMask)
- { // hit the wall
-
- Results->HitType = TRACE_HitWall;
- Results->Tier =
- entersector == NULL ? TIER_Middle :
- hitz <= bf ? TIER_Lower :
- hitz >= bc ? TIER_Upper : TIER_Middle;
- if (TraceFlags & TRACE_Impact)
- {
- P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
- }
- }
- else
- { // made it past the wall
- // check for 3D floors first
- if (entersector->e->XFloor.ffloors.Size())
- {
- memcpy(&DummySector[sectorsel],entersector,sizeof(sector_t));
- entersector=&DummySector[sectorsel];
- sectorsel^=1;
-
- for(unsigned int i=0;ie->XFloor.ffloors.Size();i++)
+ { // Dammit. Why does Doom have to allow non-closed sectors?
+ if (in->d.line->backsector == NULL)
{
- F3DFloor * rover=entersector->e->XFloor.ffloors[i];
-
- if (rover->flags&FF_SOLID && rover->flags&FF_EXISTS)
- {
- fixed_t ff_bottom=rover->bottom.plane->ZatPoint(hitx, hity);
- fixed_t ff_top=rover->top.plane->ZatPoint(hitx, hity);
-
- // clip to the part of the sector we are in
- if (hitz>ff_top)
- {
- // above
- if (bffloorplane=*rover->top.plane;
- entersector->floorpic=*rover->top.texture;
- bf=ff_top;
- }
- }
- else if (hitzff_bottom)
- {
- entersector->ceilingplane=*rover->bottom.plane;
- entersector->ceilingpic=*rover->bottom.texture;
- bc=ff_bottom;
- }
- }
- else
- {
- //hit the edge - equivalent to hitting the wall
- Results->HitType = TRACE_HitWall;
- Results->Tier = TIER_FFloor;
- Results->ffloor = rover;
- if ((TraceFlags & TRACE_Impact) && in->d.line->special)
- {
- P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
- }
- goto cont;
- }
- }
- }
- }
-
-
-
- Results->HitType = TRACE_HitNone;
- if (TraceFlags & TRACE_PCross)
- {
- P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCROSS);
- }
- if (TraceFlags & TRACE_Impact)
- { // This is incorrect for "impact", but Hexen did this, so
- // we need to as well, for compatibility
- P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
- }
- }
-cont:
-
- if (Results->HitType != TRACE_HitNone)
- {
- // We hit something, so figure out where exactly
- Results->Sector = CurSector;
-
- if (Results->HitType != TRACE_HitWall &&
- !CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor, trace))
- { // trace is parallel to the plane (or right on it)
- if (entersector == NULL)
- {
- Results->HitType = TRACE_HitWall;
- Results->Tier = TIER_Middle;
+ lineside = 0;
+ CurSector = in->d.line->frontsector;
}
else
{
- if (hitz <= bf || hitz >= bc)
+ lineside = P_PointOnLineSide (StartX, StartY, in->d.line);
+ CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector;
+ }
+ }
+
+ if (!(in->d.line->flags & ML_TWOSIDED))
+ {
+ entersector = NULL;
+ }
+ else
+ {
+ entersector = (lineside == 0) ? in->d.line->backsector : in->d.line->frontsector;
+
+ // For backwards compatibility: Ignore lines with the same sector on both sides.
+ // This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15 need it.
+ if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector)
+ {
+ continue;
+ }
+ }
+
+ ff = CurSector->floorplane.ZatPoint (hitx, hity);
+ fc = CurSector->ceilingplane.ZatPoint (hitx, hity);
+
+ if (entersector != NULL)
+ {
+ bf = entersector->floorplane.ZatPoint (hitx, hity);
+ bc = entersector->ceilingplane.ZatPoint (hitx, hity);
+ }
+
+ if (Results->CrossedWater == NULL &&
+ CurSector->heightsec &&
+ !(CurSector->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
+ //CurSector->heightsec->waterzone &&
+ hitz <= CurSector->heightsec->floorplane.ZatPoint (hitx, hity))
+ {
+ // hit crossed a water plane
+ Results->CrossedWater = CurSector;
+ }
+
+ if (hitz <= ff)
+ { // hit floor in front of wall
+ Results->HitType = TRACE_HitFloor;
+ }
+ else if (hitz >= fc)
+ { // hit ceiling in front of wall
+ Results->HitType = TRACE_HitCeiling;
+ }
+ else if (entersector == NULL ||
+ hitz <= bf || hitz >= bc ||
+ in->d.line->flags & WallMask)
+ { // hit the wall
+ Results->HitType = TRACE_HitWall;
+ Results->Tier =
+ entersector == NULL ? TIER_Middle :
+ hitz <= bf ? TIER_Lower :
+ hitz >= bc ? TIER_Upper : TIER_Middle;
+ if (TraceFlags & TRACE_Impact)
+ {
+ P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
+ }
+ }
+ else
+ { // made it past the wall
+ // check for 3D floors first
+ if (entersector->e->XFloor.ffloors.Size())
+ {
+ memcpy(&DummySector[sectorsel],entersector,sizeof(sector_t));
+ entersector=&DummySector[sectorsel];
+ sectorsel^=1;
+
+ for(unsigned int i=0;ie->XFloor.ffloors.Size();i++)
+ {
+ F3DFloor * rover=entersector->e->XFloor.ffloors[i];
+
+ if (rover->flags&FF_SOLID && rover->flags&FF_EXISTS)
+ {
+ fixed_t ff_bottom=rover->bottom.plane->ZatPoint(hitx, hity);
+ fixed_t ff_top=rover->top.plane->ZatPoint(hitx, hity);
+
+ // clip to the part of the sector we are in
+ if (hitz>ff_top)
+ {
+ // above
+ if (bffloorplane=*rover->top.plane;
+ entersector->floorpic=*rover->top.texture;
+ bf=ff_top;
+ }
+ }
+ else if (hitzff_bottom)
+ {
+ entersector->ceilingplane=*rover->bottom.plane;
+ entersector->ceilingpic=*rover->bottom.texture;
+ bc=ff_bottom;
+ }
+ }
+ else
+ {
+ //hit the edge - equivalent to hitting the wall
+ Results->HitType = TRACE_HitWall;
+ Results->Tier = TIER_FFloor;
+ Results->ffloor = rover;
+ if ((TraceFlags & TRACE_Impact) && in->d.line->special)
+ {
+ P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
+ }
+ goto cont;
+ }
+ }
+ }
+ }
+
+
+
+ Results->HitType = TRACE_HitNone;
+ if (TraceFlags & TRACE_PCross)
+ {
+ P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCROSS);
+ }
+ if (TraceFlags & TRACE_Impact)
+ { // This is incorrect for "impact", but Hexen did this, so
+ // we need to as well, for compatibility
+ P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
+ }
+ }
+cont:
+
+ if (Results->HitType != TRACE_HitNone)
+ {
+ // We hit something, so figure out where exactly
+ Results->Sector = CurSector;
+
+ if (Results->HitType != TRACE_HitWall &&
+ !CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor))
+ { // trace is parallel to the plane (or right on it)
+ if (entersector == NULL)
{
Results->HitType = TRACE_HitWall;
- Results->Tier =
- hitz <= bf ? TIER_Lower :
- hitz >= bc ? TIER_Upper : TIER_Middle;
+ Results->Tier = TIER_Middle;
}
else
{
- Results->HitType = TRACE_HitNone;
+ if (hitz <= bf || hitz >= bc)
+ {
+ Results->HitType = TRACE_HitWall;
+ Results->Tier =
+ hitz <= bf ? TIER_Lower :
+ hitz >= bc ? TIER_Upper : TIER_Middle;
+ }
+ else
+ {
+ Results->HitType = TRACE_HitNone;
+ }
+ }
+ if (Results->HitType == TRACE_HitWall && TraceFlags & TRACE_Impact)
+ {
+ P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
}
}
- if (Results->HitType == TRACE_HitWall && TraceFlags & TRACE_Impact)
+
+ if (Results->HitType == TRACE_HitWall)
{
- P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
+ Results->X = hitx;
+ Results->Y = hity;
+ Results->Z = hitz;
+ Results->Distance = dist;
+ Results->Fraction = in->frac;
+ Results->Line = in->d.line;
+ Results->Side = lineside;
}
}
- if (Results->HitType == TRACE_HitWall)
+ if (Results->HitType == TRACE_HitNone)
{
- Results->X = hitx;
- Results->Y = hity;
- Results->Z = hitz;
- Results->Distance = dist;
- Results->Fraction = in->frac;
- Results->Line = in->d.line;
- Results->Side = lineside;
+ CurSector = entersector;
+ EnterDist = dist;
+ continue;
+ }
+
+ if (TraceCallback != NULL)
+ {
+ if (!TraceCallback (*Results)) return false;
+ }
+ else
+ {
+ return false;
}
}
- if (Results->HitType == TRACE_HitNone)
+ // Encountered an actor
+ if (!(in->d.thing->flags & ActorMask) ||
+ in->d.thing == IgnoreThis)
{
- CurSector = entersector;
- EnterDist = dist;
- return true;
+ continue;
}
- if (TraceCallback != NULL)
- {
- return TraceCallback (*Results);
- }
- else
- {
- return false;
- }
- }
-
- // Encountered an actor
- if (!(in->d.thing->flags & ActorMask) ||
- in->d.thing == IgnoreThis)
- {
- return true;
- }
-
- dist = FixedMul (MaxDist, in->frac);
- hitx = trace.x + FixedMul (Vx, dist);
- hity = trace.y + FixedMul (Vy, dist);
- hitz = StartZ + FixedMul (Vz, dist);
-
- if (hitz > in->d.thing->z + in->d.thing->height)
- { // trace enters above actor
- if (Vz >= 0) return true; // Going up: can't hit
-
- // Does it hit the top of the actor?
- dist = FixedDiv(in->d.thing->z + in->d.thing->height - StartZ, Vz);
-
- if (dist > MaxDist) return true;
- in->frac = FixedDiv(dist, MaxDist);
-
- hitx = trace.x + FixedMul (Vx, dist);
- hity = trace.y + FixedMul (Vy, dist);
+ dist = FixedMul (MaxDist, in->frac);
+ hitx = StartX + FixedMul (Vx, dist);
+ hity = StartY + FixedMul (Vy, dist);
hitz = StartZ + FixedMul (Vz, dist);
- // calculated coordinate is outside the actor's bounding box
- if (abs(hitx - in->d.thing->x) > in->d.thing->radius ||
- abs(hity - in->d.thing->y) > in->d.thing->radius) return true;
- }
- else if (hitz < in->d.thing->z)
- { // trace enters below actor
- if (Vz <= 0) return true; // Going down: can't hit
-
- // Does it hit the bottom of the actor?
- dist = FixedDiv(in->d.thing->z - StartZ, Vz);
- if (dist > MaxDist) return true;
- in->frac = FixedDiv(dist, MaxDist);
+ if (hitz > in->d.thing->z + in->d.thing->height)
+ { // trace enters above actor
+ if (Vz >= 0) continue; // Going up: can't hit
+
+ // Does it hit the top of the actor?
+ dist = FixedDiv(in->d.thing->z + in->d.thing->height - StartZ, Vz);
- hitx = trace.x + FixedMul (Vx, dist);
- hity = trace.y + FixedMul (Vy, dist);
- hitz = StartZ + FixedMul (Vz, dist);
+ if (dist > MaxDist) continue;
+ in->frac = FixedDiv(dist, MaxDist);
- // calculated coordinate is outside the actor's bounding box
- if (abs(hitx - in->d.thing->x) > in->d.thing->radius ||
- abs(hity - in->d.thing->y) > in->d.thing->radius) return true;
- }
+ hitx = StartX + FixedMul (Vx, dist);
+ hity = StartY + FixedMul (Vy, dist);
+ hitz = StartZ + FixedMul (Vz, dist);
- // check for extrafloors first
- if (CurSector->e->XFloor.ffloors.Size())
- {
- fixed_t ff_floor=CurSector->floorplane.ZatPoint(hitx, hity);
- fixed_t ff_ceiling=CurSector->ceilingplane.ZatPoint(hitx, hity);
-
- if (hitz>ff_ceiling) // actor is hit above the current ceiling
- {
- Results->HitType=TRACE_HitCeiling;
+ // calculated coordinate is outside the actor's bounding box
+ if (abs(hitx - in->d.thing->x) > in->d.thing->radius ||
+ abs(hity - in->d.thing->y) > in->d.thing->radius) continue;
}
- else if (hitzHitType=TRACE_HitFloor;
- }
- else goto cont1;
+ else if (hitz < in->d.thing->z)
+ { // trace enters below actor
+ if (Vz <= 0) continue; // Going down: can't hit
+
+ // Does it hit the bottom of the actor?
+ dist = FixedDiv(in->d.thing->z - StartZ, Vz);
+ if (dist > MaxDist) continue;
+ in->frac = FixedDiv(dist, MaxDist);
- // the trace hit a 3D-floor before the thing.
- // Calculate an intersection and abort.
- Results->Sector = CurSector;
- if (!CheckSectorPlane(CurSector, Results->HitType==TRACE_HitFloor, trace))
- {
- Results->HitType=TRACE_HitNone;
- }
- if (TraceCallback != NULL)
- {
- return TraceCallback (*Results);
- }
- else
- {
- return false;
- }
- }
+ hitx = StartX + FixedMul (Vx, dist);
+ hity = StartY + FixedMul (Vy, dist);
+ hitz = StartZ + FixedMul (Vz, dist);
+ // calculated coordinate is outside the actor's bounding box
+ if (abs(hitx - in->d.thing->x) > in->d.thing->radius ||
+ abs(hity - in->d.thing->y) > in->d.thing->radius) continue;
+ }
+ // check for extrafloors first
+ if (CurSector->e->XFloor.ffloors.Size())
+ {
+ fixed_t ff_floor=CurSector->floorplane.ZatPoint(hitx, hity);
+ fixed_t ff_ceiling=CurSector->ceilingplane.ZatPoint(hitx, hity);
+
+ if (hitz>ff_ceiling) // actor is hit above the current ceiling
+ {
+ Results->HitType=TRACE_HitCeiling;
+ }
+ else if (hitzHitType=TRACE_HitFloor;
+ }
+ else goto cont1;
+
+ // the trace hit a 3D-floor before the thing.
+ // Calculate an intersection and abort.
+ Results->Sector = CurSector;
+ if (!CheckSectorPlane(CurSector, Results->HitType==TRACE_HitFloor))
+ {
+ Results->HitType=TRACE_HitNone;
+ }
+ if (TraceCallback != NULL)
+ {
+ return TraceCallback (*Results);
+ }
+ else
+ {
+ return false;
+ }
+ }
cont1:
- Results->HitType = TRACE_HitActor;
- Results->X = hitx;
- Results->Y = hity;
- Results->Z = hitz;
- Results->Distance = dist;
- Results->Fraction = in->frac;
- Results->Actor = in->d.thing;
+ Results->HitType = TRACE_HitActor;
+ Results->X = hitx;
+ Results->Y = hity;
+ Results->Z = hitz;
+ Results->Distance = dist;
+ Results->Fraction = in->frac;
+ Results->Actor = in->d.thing;
- if (TraceCallback != NULL)
- {
- return TraceCallback (*Results);
- }
- else
- {
- return false;
+ if (TraceCallback != NULL)
+ {
+ if (!TraceCallback (*Results)) return false;
+ }
+ else
+ {
+ return false;
+ }
}
+ return true;
}
-static bool CheckSectorPlane (const sector_t *sector, bool checkFloor, divline_t & trace)
+bool FTraceInfo::CheckSectorPlane (const sector_t *sector, bool checkFloor)
{
secplane_t plane;
@@ -559,16 +560,16 @@ static bool CheckSectorPlane (const sector_t *sector, bool checkFloor, divline_t
if (den != 0)
{
- fixed_t num = TMulScale16 (plane.a, trace.x,
- plane.b, trace.y,
+ fixed_t num = TMulScale16 (plane.a, StartX,
+ plane.b, StartY,
plane.c, StartZ) + plane.d;
fixed_t hitdist = FixedDiv (-num, den);
if (hitdist > EnterDist && hitdist < MaxDist)
{
- Results->X = trace.x + FixedMul (Vx, hitdist);
- Results->Y = trace.y + FixedMul (Vy, hitdist);
+ Results->X = StartX + FixedMul (Vx, hitdist);
+ Results->Y = StartY + FixedMul (Vy, hitdist);
Results->Z = StartZ + FixedMul (Vz, hitdist);
Results->Distance = hitdist;
Results->Fraction = FixedDiv (hitdist, MaxDist);
diff --git a/src/r_main.cpp b/src/r_main.cpp
index 0e0859fc..74e82eb5 100644
--- a/src/r_main.cpp
+++ b/src/r_main.cpp
@@ -1134,11 +1134,7 @@ void R_SetupFrame (AActor *actor)
camera->sprite != 0) // Sprite 0 is always TNT1
{
// [RH] Use chasecam view
- P_AimCamera (camera);
- iview->nviewx = CameraX;
- iview->nviewy = CameraY;
- iview->nviewz = CameraZ;
- viewsector = CameraSector;
+ P_AimCamera (camera, iview->nviewx, iview->nviewy, iview->nviewz, viewsector);
r_showviewer = true;
}
else
diff --git a/src/sdl/critsec.h b/src/sdl/critsec.h
new file mode 100644
index 00000000..daaf30f7
--- /dev/null
+++ b/src/sdl/critsec.h
@@ -0,0 +1,48 @@
+// Wraps an SDL mutex object. (A critical section is a Windows synchronization
+// object similar to a mutex but optimized for access by threads belonging to
+// only one process, hence the class name.)
+
+#ifndef CRITSEC_H
+#define CRITSEC_H
+
+#include "SDL.h"
+#include "SDL_thread.h"
+#include "i_system.h"
+
+class FCriticalSection
+{
+public:
+ FCriticalSection()
+ {
+ CritSec = SDL_CreateMutex();
+ if (CritSec == NULL)
+ {
+ I_FatalError("Failed to create a critical section mutex.");
+ }
+ }
+ ~FCriticalSection()
+ {
+ if (CritSec != NULL)
+ {
+ SDL_DestroyMutex(CritSec);
+ }
+ }
+ void Enter()
+ {
+ if (SDL_mutexP(CritSec) != 0)
+ {
+ I_FatalError("Failed entering a critical section.");
+ }
+ }
+ void Leave()
+ {
+ if (SDL_mutexV(CritSec) != 0)
+ {
+ I_FatalError("Failed to leave a critical section.");
+ }
+ }
+private:
+ SDL_mutex *CritSec;
+};
+
+#endif
diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h
index 58e31d6e..e807839e 100644
--- a/src/sound/i_musicinterns.h
+++ b/src/sound/i_musicinterns.h
@@ -112,6 +112,7 @@ public:
virtual bool FakeVolume() = 0;
virtual bool Pause(bool paused) = 0;
virtual bool NeedThreadedCallback() = 0;
+ virtual void PrecacheInstruments(const BYTE *instruments, int count);
};
// WinMM implementation of a MIDI output device -----------------------------
@@ -137,6 +138,7 @@ public:
bool FakeVolume();
bool NeedThreadedCallback();
bool Pause(bool paused);
+ void PrecacheInstruments(const BYTE *instruments, int count);
protected:
static void CALLBACK CallbackFunc(HMIDIOUT, UINT, DWORD_PTR, DWORD, DWORD);
@@ -236,6 +238,7 @@ protected:
virtual void DoInitialSetup() = 0;
virtual void DoRestart() = 0;
virtual bool CheckDone() = 0;
+ virtual void Precache() = 0;
virtual DWORD *MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) = 0;
enum
@@ -294,6 +297,7 @@ protected:
void DoInitialSetup();
void DoRestart();
bool CheckDone();
+ void Precache();
DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
MUSHeader *MusHeader;
@@ -319,6 +323,7 @@ protected:
void DoInitialSetup();
void DoRestart();
bool CheckDone();
+ void Precache();
DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
void AdvanceTracks(DWORD time);
diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp
index e85919a7..d7bc8f1f 100644
--- a/src/sound/music_midi_base.cpp
+++ b/src/sound/music_midi_base.cpp
@@ -12,8 +12,6 @@ static bool nummididevicesset;
#ifdef _WIN32
UINT mididevice;
-CVAR (Bool, snd_midiprecache, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
-
CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
UINT oldmididev = mididevice;
@@ -155,8 +153,9 @@ CCMD (snd_listmididevices)
MIDIOUTCAPS caps;
MMRESULT res;
- PrintMidiDevice (-2, "TiMidity++", 0, 0);
- PrintMidiDevice (-1, "FMOD", 0, 0);
+ PrintMidiDevice (-3, "Emulated OPL FM Synth", MOD_FMSYNTH, 0);
+ PrintMidiDevice (-2, "TiMidity++", 0, MOD_WAVETABLE | MOD_SWSYNTH);
+ PrintMidiDevice (-1, "FMOD", 0, MOD_WAVETABLE | MOD_SWSYNTH);
if (nummididevices != 0)
{
for (id = 0; id < nummididevices; ++id)
@@ -206,6 +205,7 @@ void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues)
CCMD (snd_listmididevices)
{
+ Printf("%s-3. Emulated OPL FM Synth\n", -3 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-1. FMOD\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : "");
}
diff --git a/src/sound/music_midi_midiout.cpp b/src/sound/music_midi_midiout.cpp
index 99b918f5..11c41f27 100644
--- a/src/sound/music_midi_midiout.cpp
+++ b/src/sound/music_midi_midiout.cpp
@@ -754,6 +754,96 @@ void MIDISong2::SetTempo(int new_tempo)
}
}
+//==========================================================================
+//
+// MIDISong2 :: Precache
+//
+// Scans each track for program change events on normal channels and note on
+// events on channel 10. Does not care about bank selects, since they're
+// unlikely to appear in a song aimed at Doom.
+//
+//==========================================================================
+
+void MIDISong2::Precache()
+{
+ int i, j;
+
+ // This array keeps track of instruments that are used. The first 128
+ // entries are for melodic instruments. The second 128 are for
+ // percussion.
+ BYTE found_instruments[256] = { 0, };
+
+ DoRestart();
+ for (i = 0; i < NumTracks; ++i)
+ {
+ TrackInfo *track = &Tracks[i];
+ BYTE running_status = 0;
+ BYTE ev, data1, data2, command, channel;
+ int len;
+
+ while (track->TrackP < track->MaxTrackP)
+ {
+ ev = track->TrackBegin[track->TrackP++];
+ command = ev & 0xF0;
+
+ if (command == MIDI_SYSEX || command == MIDI_SYSEXEND)
+ {
+ len = track->ReadVarLen();
+ track->TrackP += len;
+ }
+ else if (command == MIDI_META)
+ {
+ track->TrackP++;
+ len = track->ReadVarLen();
+ track->TrackP += len;
+ }
+ else if ((command & 0xF0) == 0xF0)
+ {
+ track->TrackP += CommonLengths[ev & 0xF];
+ }
+ else
+ {
+ if ((ev & 0x80) == 0)
+ { // Use running status.
+ data1 = ev;
+ ev = running_status;
+ }
+ else
+ { // Store new running status.
+ running_status = ev;
+ data1 = track->TrackBegin[track->TrackP++];
+ }
+ command = ev & 0x70;
+ channel = ev & 0x0F;
+ if (EventLengths[command >> 4] == 2)
+ {
+ data2 = track->TrackBegin[track->TrackP++];
+ }
+ if (channel != 9 && command == (MIDI_PRGMCHANGE & 0x70))
+ {
+ found_instruments[data1 & 127] = 1;
+ }
+ else if (channel == 9 && command == (MIDI_NOTEON & 0x70) && data2 != 0)
+ {
+ found_instruments[data1 | 128] = 1;
+ }
+ track->ReadVarLen(); // Skip delay.
+ }
+ }
+ }
+ DoRestart();
+
+ // Now pack everything into a contiguous region for the PrecacheInstruments call().
+ for (i = j = 0; i < 256; ++i)
+ {
+ if (found_instruments[i])
+ {
+ found_instruments[j++] = i;
+ }
+ }
+ MIDI->PrecacheInstruments(found_instruments, j);
+}
+
//==========================================================================
//
// MIDISong2 :: GetOPLDumper
diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp
index db78a7ad..c57ddfad 100644
--- a/src/sound/music_midistream.cpp
+++ b/src/sound/music_midistream.cpp
@@ -221,6 +221,7 @@ void MIDIStreamer::Play(bool looping)
}
CheckCaps();
+ Precache();
// Set time division and tempo.
if (0 != MIDI->SetTimeDiv(Division) ||
@@ -301,7 +302,8 @@ void MIDIStreamer::Play(bool looping)
// MIDIStreamer :: Pause
//
// "Pauses" the song by setting it to zero volume and filling subsequent
-// buffers with NOPs until the song is unpaused.
+// buffers with NOPs until the song is unpaused. A MIDI device that
+// supports real pauses will return true from its Pause() method.
//
//==========================================================================
@@ -711,3 +713,22 @@ MIDIDevice::MIDIDevice()
MIDIDevice::~MIDIDevice()
{
}
+
+//==========================================================================
+//
+// MIDIDevice :: PrecacheInstruments
+//
+// The MIDIStreamer calls this method between device open and the first
+// buffered stream with a list of instruments known to be used by the song.
+// If the device can benefit from preloading the instruments, it can do so
+// now.
+//
+// For each entry, bit 7 set indicates that the instrument is percussion and
+// the lower 7 bits contain the note number to use on MIDI channel 10,
+// otherwise it is melodic and the lower 7 bits are the program number.
+//
+//==========================================================================
+
+void MIDIDevice::PrecacheInstruments(const BYTE *instruments, int count)
+{
+}
diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp
index f7b875cf..651f154b 100644
--- a/src/sound/music_mus_midiout.cpp
+++ b/src/sound/music_mus_midiout.cpp
@@ -179,6 +179,34 @@ bool MUSSong2::CheckDone()
return MusP >= MaxMusP;
}
+//==========================================================================
+//
+// MUSSong2 :: Precache
+//
+// MUS songs contain information in their header for exactly this purpose.
+//
+//==========================================================================
+
+void MUSSong2::Precache()
+{
+ BYTE *work = (BYTE *)alloca(MusHeader->NumInstruments);
+ const WORD *used = (WORD *)MusHeader + sizeof(MUSHeader) / 2;
+ int i, j;
+
+ for (i = j = 0; i < MusHeader->NumInstruments; ++i)
+ {
+ if (used[i] < 128)
+ {
+ work[j++] = (BYTE)used[i];
+ }
+ else if (used[i] >= 135 && used[i] <= 181)
+ { // Percussions are 100-based, not 128-based, eh?
+ work[j++] = (used[i] - 100) | 0x80;
+ }
+ }
+ MIDI->PrecacheInstruments(&work[0], j);
+}
+
//==========================================================================
//
// MUSSong2 :: MakeEvents
diff --git a/src/sound/music_win_mididevice.cpp b/src/sound/music_win_mididevice.cpp
index 56080ec3..aa137a26 100644
--- a/src/sound/music_win_mididevice.cpp
+++ b/src/sound/music_win_mididevice.cpp
@@ -55,6 +55,8 @@
// PUBLIC DATA DEFINITIONS -------------------------------------------------
+CVAR (Bool, snd_midiprecache, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
+
// CODE --------------------------------------------------------------------
//==========================================================================
@@ -203,6 +205,61 @@ void WinMIDIDevice::Stop()
}
}
+//==========================================================================
+//
+// WinMIDIDevice :: PrecacheInstruments
+//
+// For each entry, bit 7 set indicates that the instrument is percussion and
+// the lower 7 bits contain the note number to use on MIDI channel 10,
+// otherwise it is melodic and the lower 7 bits are the program number.
+//
+// My old GUS PnP needed the instruments to be preloaded, or it would miss
+// some notes the first time through the song. I doubt any modern
+// hardware has this problem, but since I'd already written the code for
+// ZDoom 1.22 and below, I'm resurrecting it now for completeness, since I'm
+// using preloading for the internal Timidity.
+//
+//==========================================================================
+
+void WinMIDIDevice::PrecacheInstruments(const BYTE *instruments, int count)
+{
+ // Setting snd_midiprecache to false disables this precaching, since it
+ // does involve sleeping for more than a miniscule amount of time.
+ if (!snd_midiprecache)
+ {
+ return;
+ }
+ for (int i = 0, chan = 0; i < count; ++i)
+ {
+ if (instruments[i] & 0x80)
+ { // Percussion
+ midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_NOTEON | 9 | ((instruments[i] & 0x7f) << 8) | (1 << 16));
+ }
+ else
+ { // Melodic
+ midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_PRGMCHANGE | chan | (instruments[i] << 8));
+ midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_NOTEON | chan | (60 << 8) | (1 << 16));
+ if (++chan == 9)
+ { // Skip the percussion channel
+ chan = 10;
+ }
+ }
+ // Once we've got an instrument playing on each melodic channel, sleep to give
+ // the driver time to load the instruments. Also do this for the final batch
+ // of instruments.
+ if (chan == 16 || i == count - 1)
+ {
+ Sleep(250);
+ for (chan = 15; chan-- != 0; )
+ {
+ // Turn all notes off
+ midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_CTRLCHANGE | chan | (123 << 8));
+ }
+ // And now chan is back at 0, ready to start the cycle over.
+ }
+ }
+}
+
//==========================================================================
//
// WinMIDIDevice :: Pause
diff --git a/src/svnrevision.h b/src/svnrevision.h
index 8c980983..be0ef286 100644
--- a/src/svnrevision.h
+++ b/src/svnrevision.h
@@ -3,5 +3,5 @@
// This file was automatically generated by the
// updaterevision tool. Do not edit by hand.
-#define ZD_SVN_REVISION_STRING "894"
-#define ZD_SVN_REVISION_NUMBER 894
+#define ZD_SVN_REVISION_STRING "898"
+#define ZD_SVN_REVISION_NUMBER 898
diff --git a/src/version.h b/src/version.h
index 5aa1e017..846f8b85 100644
--- a/src/version.h
+++ b/src/version.h
@@ -56,12 +56,12 @@
// Version identifier for network games.
// Bump it every time you do a release unless you're certain you
// didn't change anything that will affect sync.
-#define NETGAMEVERSION 215
+#define NETGAMEVERSION 216
// Version stored in the ini's [LastRun] section.
// Bump it if you made some configuration change that you want to
// be able to migrate in FGameConfigFile::DoGlobalSetup().
-#define LASTRUNVERSION "206"
+#define LASTRUNVERSION "207"
// Protocol version used in demos.
// Bump it if you change existing DEM_ commands or add new ones.
diff --git a/src/win32/critsec.h b/src/win32/critsec.h
new file mode 100644
index 00000000..05d54f15
--- /dev/null
+++ b/src/win32/critsec.h
@@ -0,0 +1,42 @@
+// Wraps a Windows critical section object.
+
+#ifndef CRITSEC_H
+#define CRITSEC_H
+
+#ifndef _WINNT_
+#define WIN32_LEAN_AND_MEAN
+#include
+#define USE_WINDOWS_DWORD
+#endif
+
+class FCriticalSection
+{
+public:
+ FCriticalSection()
+ {
+ InitializeCriticalSection(&CritSec);
+ }
+ ~FCriticalSection()
+ {
+ DeleteCriticalSection(&CritSec);
+ }
+ void Enter()
+ {
+ EnterCriticalSection(&CritSec);
+ }
+ void Leave()
+ {
+ LeaveCriticalSection(&CritSec);
+ }
+#if 0
+ // SDL has no equivalent functionality, so better not use it on Windows.
+ bool TryEnter()
+ {
+ return TryEnterCriticalSection(&CritSec) != 0;
+ }
+#endif
+private:
+ CRITICAL_SECTION CritSec;
+};
+
+#endif