mirror of
https://github.com/ZDoom/gzdoom-last-svn.git
synced 2025-06-02 18:21:02 +00:00
Update to ZDoom r898:
- Replaced P_PathTraverse with an FPathTraverse class, rewrote all code using P_PathTraverse and got rid of a lot of global variables in the process. - Simplified the use of the checkarray in FBlockThingsIterator: Since the entire game runs single threaded there is no need for multiple check arrays if recursive use occurs. Using the same array with a higher start index is sufficient if the size is reset after finishing using the iterator. April 9, 2008 (SBarInfo Update #17) - Fixed: SBarInfo tried to calculate scaled offsets on unscaled status bars. - Added: createpopup to SBarInfo. No we don't have custom popups yet. It only defines the transition effect. Currently none or slideinbottom. - Made the first argument of DrawMugShot optional (think of it as an overloaded function). The use of the first argument is deprecated due to the event of per player class faces. - More changes from DrawImage to screen->DrawTexture(). I guess I didn't get them all just yet. - Added the FCriticalSection class in critsec.h to make it easier to use critical sections in other places besides the OPL player. - Reimplemented snd_midiprecache, now for MIDI as well as MUS, and defaulting to false. git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@89 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
parent
700adbf82f
commit
b75a6dcea6
28 changed files with 1685 additions and 1262 deletions
|
@ -1791,6 +1791,10 @@
|
|||
RelativePath=".\src\win32\boing8.ico"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\win32\critsec.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\win32\cursor1.cur"
|
||||
>
|
||||
|
@ -2976,6 +2980,10 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\sdl\critsec.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\sdl\dikeys.h"
|
||||
>
|
||||
|
|
143
src/b_func.cpp
143
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<SBarInfoCommand> commands;
|
||||
|
@ -82,6 +112,7 @@ struct SBarInfo
|
|||
{
|
||||
TArray<FString> 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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ typedef struct
|
|||
WORD NumSecondaryChans;
|
||||
WORD NumInstruments;
|
||||
WORD Pad;
|
||||
// WORD UsedInstruments[NumInstruments];
|
||||
} MUSHeader;
|
||||
|
||||
bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile);
|
||||
|
|
|
@ -261,9 +261,9 @@ void OPLMIDIDevice::Stop()
|
|||
|
||||
int OPLMIDIDevice::StreamOutSync(MIDIHDR *header)
|
||||
{
|
||||
Serialize();
|
||||
ChipAccess.Enter();
|
||||
StreamOut(header);
|
||||
Unserialize();
|
||||
ChipAccess.Leave();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#define USE_WINDOWS_DWORD
|
||||
#else
|
||||
#include <SDL.h>
|
||||
#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
|
||||
|
|
|
@ -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<AActor *> BTChecked;
|
||||
|
||||
static TDeletingArray< BTChecked* > FreeBTChecked;
|
||||
|
||||
static TArray<AActor *> 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<AActor *> *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<intercept_t> 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);
|
||||
|
|
1055
src/p_map.cpp
1055
src/p_map.cpp
File diff suppressed because it is too large
Load diff
278
src/p_maputl.cpp
278
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<AActor *> 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<AActor *> *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<intercept_t> intercepts (128);
|
||||
//===========================================================================
|
||||
|
||||
divline_t trace;
|
||||
int ptflags;
|
||||
TArray<intercept_t> 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<AActor*> &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<AActor*> &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<AActor*> &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<AActor*> &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<AActor *> 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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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<intercept_t> intercepts;
|
||||
static TArray<intercept_t> intercepts (128);
|
||||
|
||||
class SightCheck
|
||||
{
|
||||
|
|
695
src/p_trace.cpp
695
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<F3DFloor*> &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;i<entersector->e->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 (bf<ff_top)
|
||||
{
|
||||
entersector->floorplane=*rover->top.plane;
|
||||
entersector->floorpic=*rover->top.texture;
|
||||
bf=ff_top;
|
||||
}
|
||||
}
|
||||
else if (hitz<ff_bottom)
|
||||
{
|
||||
//below
|
||||
if (bc>ff_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;i<entersector->e->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 (bf<ff_top)
|
||||
{
|
||||
entersector->floorplane=*rover->top.plane;
|
||||
entersector->floorpic=*rover->top.texture;
|
||||
bf=ff_top;
|
||||
}
|
||||
}
|
||||
else if (hitz<ff_bottom)
|
||||
{
|
||||
//below
|
||||
if (bc>ff_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 (hitz<ff_floor) // actor is hit below the current floor
|
||||
{
|
||||
Results->HitType=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 (hitz<ff_floor) // actor is hit below the current floor
|
||||
{
|
||||
Results->HitType=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);
|
||||
|
|
|
@ -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
|
||||
|
|
48
src/sdl/critsec.h
Normal file
48
src/sdl/critsec.h
Normal file
|
@ -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
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 : "");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
42
src/win32/critsec.h
Normal file
42
src/win32/critsec.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Wraps a Windows critical section object.
|
||||
|
||||
#ifndef CRITSEC_H
|
||||
#define CRITSEC_H
|
||||
|
||||
#ifndef _WINNT_
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#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
|
Loading…
Add table
Add a link
Reference in a new issue