- added a Boom (strict) compatibility mode.

- Restored some original Doom behavior that received complaints from users:
* reactivated the old sliding against diagonal walls code and compatibility optioned it with COMPATF_WALLRUN.
* re-added the original hitscan checking code using a cross-section of the actor instead of the bounding box, compatibility optioned with COMPATF_HITSCAN.


SVN r2340 (trunk)
This commit is contained in:
Christoph Oelckers 2010-05-28 11:15:05 +00:00
parent 9dfdf2ecdd
commit 8f881be0fb
6 changed files with 171 additions and 100 deletions

View file

@ -116,6 +116,7 @@ static FCompatOption Options[] =
{ "corpsegibs", COMPATF_CORPSEGIBS, 0 }, { "corpsegibs", COMPATF_CORPSEGIBS, 0 },
{ "noblockfriends", COMPATF_NOBLOCKFRIENDS, 0 }, { "noblockfriends", COMPATF_NOBLOCKFRIENDS, 0 },
{ "spritesort", COMPATF_SPRITESORT, 0 }, { "spritesort", COMPATF_SPRITESORT, 0 },
{ "hitscan", COMPATF_HITSCAN, 0 },
{ NULL, 0, 0 } { NULL, 0, 0 }
}; };

View file

@ -500,7 +500,8 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
case 2: // same as 1 but stricter (NO_PASSMOBJ and INVISIBILITY are also set) case 2: // same as 1 but stricter (NO_PASSMOBJ and INVISIBILITY are also set)
v = COMPATF_SHORTTEX|COMPATF_STAIRINDEX|COMPATF_USEBLOCKING|COMPATF_NODOORLIGHT|COMPATF_SPRITESORT| v = COMPATF_SHORTTEX|COMPATF_STAIRINDEX|COMPATF_USEBLOCKING|COMPATF_NODOORLIGHT|COMPATF_SPRITESORT|
COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_NO_PASSMOBJ|COMPATF_LIMITPAIN| COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_NO_PASSMOBJ|COMPATF_LIMITPAIN|
COMPATF_DEHHEALTH|COMPATF_INVISIBILITY|COMPATF_CROSSDROPOFF|COMPATF_CORPSEGIBS; COMPATF_DEHHEALTH|COMPATF_INVISIBILITY|COMPATF_CROSSDROPOFF|COMPATF_CORPSEGIBS|COMPATF_HITSCAN|
COMPATF_WALLRUN|COMPATF_NOTOSSDROPS;
break; break;
case 3: // Boom compat mode case 3: // Boom compat mode
@ -516,6 +517,11 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
COMPATF_MBFMONSTERMOVE|COMPATF_NOBLOCKFRIENDS; COMPATF_MBFMONSTERMOVE|COMPATF_NOBLOCKFRIENDS;
break; break;
case 6: // Boom with some added settings to reenable spme 'broken' behavior
v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP|COMPATF_NO_PASSMOBJ|
COMPATF_INVISIBILITY|COMPATF_CORPSEGIBS|COMPATF_HITSCAN|COMPATF_WALLRUN|COMPATF_NOTOSSDROPS;
break;
} }
compatflags = v; compatflags = v;
} }
@ -548,6 +554,7 @@ CVAR (Flag, compat_mbfmonstermove,compatflags, COMPATF_MBFMONSTERMOVE);
CVAR (Flag, compat_corpsegibs, compatflags, COMPATF_CORPSEGIBS); CVAR (Flag, compat_corpsegibs, compatflags, COMPATF_CORPSEGIBS);
CVAR (Flag, compat_noblockfriends,compatflags,COMPATF_NOBLOCKFRIENDS); CVAR (Flag, compat_noblockfriends,compatflags,COMPATF_NOBLOCKFRIENDS);
CVAR (Flag, compat_spritesort, compatflags,COMPATF_SPRITESORT); CVAR (Flag, compat_spritesort, compatflags,COMPATF_SPRITESORT);
CVAR (Flag, compat_hitscan, compatflags,COMPATF_HITSCAN);
//========================================================================== //==========================================================================
// //

View file

@ -325,6 +325,7 @@ enum
COMPATF_CORPSEGIBS = 1 << 25, // Crushed monsters are turned into gibs, rather than replaced by gibs. COMPATF_CORPSEGIBS = 1 << 25, // Crushed monsters are turned into gibs, rather than replaced by gibs.
COMPATF_NOBLOCKFRIENDS = 1 << 26, // Friendly monsters aren't blocked by monster-blocking lines. COMPATF_NOBLOCKFRIENDS = 1 << 26, // Friendly monsters aren't blocked by monster-blocking lines.
COMPATF_SPRITESORT = 1 << 27, // Invert sprite sorting order for sprites of equal distance COMPATF_SPRITESORT = 1 << 27, // Invert sprite sorting order for sprites of equal distance
COMPATF_HITSCAN = 1 << 28, // Hitscans use original blockmap anf hit check code.
}; };
// Emulate old bugs for select maps. These are not exposed by a cvar // Emulate old bugs for select maps. These are not exposed by a cvar

View file

@ -149,13 +149,14 @@ value_t OffOn[2] = {
{ 1.0, "Off" } { 1.0, "Off" }
}; };
value_t CompatModes[6] = { value_t CompatModes[] = {
{ 0.0, "Default" }, { 0.0, "Default" },
{ 1.0, "Doom" }, { 1.0, "Doom" },
{ 2.0, "Doom (strict)" }, { 2.0, "Doom (strict)" },
{ 3.0, "Boom" }, { 3.0, "Boom" },
{ 4.0, "ZDoom 2.0.63" }, { 6.0, "Boom (strict)" },
{ 5.0, "MBF" }, { 5.0, "MBF" },
{ 4.0, "ZDoom 2.0.63" },
}; };
menu_t *CurrentMenu; menu_t *CurrentMenu;
@ -1092,7 +1093,7 @@ static menu_t DMFlagsMenu =
*=======================================*/ *=======================================*/
static menuitem_t CompatibilityItems[] = { static menuitem_t CompatibilityItems[] = {
{ discrete, "Compatibility mode", {&compatmode}, {6.0}, {1.0}, {0.0}, {CompatModes} }, { discrete, "Compatibility mode", {&compatmode}, {7.0}, {1.0}, {0.0}, {CompatModes} },
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ bitflag, "Find shortest textures like Doom", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SHORTTEX} }, { bitflag, "Find shortest textures like Doom", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SHORTTEX} },
{ bitflag, "Use buggier stair building", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_STAIRINDEX} }, { bitflag, "Use buggier stair building", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_STAIRINDEX} },
@ -1122,6 +1123,7 @@ static menuitem_t CompatibilityItems[] = {
{ bitflag, "Crushed monsters can be resurrected", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_CORPSEGIBS} }, { bitflag, "Crushed monsters can be resurrected", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_CORPSEGIBS} },
{ bitflag, "Friendly monsters aren't blocked", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_NOBLOCKFRIENDS} }, { bitflag, "Friendly monsters aren't blocked", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_NOBLOCKFRIENDS} },
{ bitflag, "Invert sprite sorting", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SPRITESORT} }, { bitflag, "Invert sprite sorting", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SPRITESORT} },
{ bitflag, "Use Doom code for hitscan checks", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_HITSCAN} },
{ discrete, "Interpolate monster movement", {&nomonsterinterpolation}, {2.0}, {0.0}, {0.0}, {NoYes} }, { discrete, "Interpolate monster movement", {&nomonsterinterpolation}, {2.0}, {0.0}, {0.0}, {NoYes} },
}; };

View file

@ -2183,48 +2183,53 @@ void FSlide::HitSlideLine (line_t* ld)
} // ^ } // ^
else // | else // |
{ // phares { // phares
#if 0 // Doom's original algorithm here does not work well due to imprecisions of the sine table.
fixed_t newlen; // However, keep it active if the wallrunning compatibility flag is on
if (i_compatflags & COMPATF_WALLRUN)
if (deltaangle > ANG180)
deltaangle += ANG180;
// I_Error ("SlideLine: ang>ANG180");
lineangle >>= ANGLETOFINESHIFT;
deltaangle >>= ANGLETOFINESHIFT;
newlen = FixedMul (movelen, finecosine[deltaangle]);
tmxmove = FixedMul (newlen, finecosine[lineangle]);
tmymove = FixedMul (newlen, finesine[lineangle]);
#else
divline_t dll, dlv;
fixed_t inter1, inter2, inter3;
P_MakeDivline (ld, &dll);
dlv.x = slidemo->x;
dlv.y = slidemo->y;
dlv.dx = dll.dy;
dlv.dy = -dll.dx;
inter1 = P_InterceptVector(&dll, &dlv);
dlv.dx = tmxmove;
dlv.dy = tmymove;
inter2 = P_InterceptVector (&dll, &dlv);
inter3 = P_InterceptVector (&dlv, &dll);
if (inter3 != 0)
{ {
tmxmove = Scale (inter2-inter1, dll.dx, inter3); fixed_t newlen;
tmymove = Scale (inter2-inter1, dll.dy, inter3);
if (deltaangle > ANG180)
deltaangle += ANG180;
// I_Error ("SlideLine: ang>ANG180");
lineangle >>= ANGLETOFINESHIFT;
deltaangle >>= ANGLETOFINESHIFT;
newlen = FixedMul (movelen, finecosine[deltaangle]);
tmxmove = FixedMul (newlen, finecosine[lineangle]);
tmymove = FixedMul (newlen, finesine[lineangle]);
} }
else else
{ {
tmxmove = tmymove = 0; divline_t dll, dlv;
fixed_t inter1, inter2, inter3;
P_MakeDivline (ld, &dll);
dlv.x = slidemo->x;
dlv.y = slidemo->y;
dlv.dx = dll.dy;
dlv.dy = -dll.dx;
inter1 = P_InterceptVector(&dll, &dlv);
dlv.dx = tmxmove;
dlv.dy = tmymove;
inter2 = P_InterceptVector (&dll, &dlv);
inter3 = P_InterceptVector (&dlv, &dll);
if (inter3 != 0)
{
tmxmove = Scale (inter2-inter1, dll.dx, inter3);
tmymove = Scale (inter2-inter1, dll.dy, inter3);
}
else
{
tmxmove = tmymove = 0;
}
} }
#endif
} // phares } // phares
} }

View file

@ -970,81 +970,136 @@ void FPathTraverse::AddThingIntercepts (int bx, int by, FBlockThingsIterator &it
divline_t line; divline_t line;
int i; int i;
// [RH] Don't check a corner to corner crossection for hit.
// Instead, check against the actual bounding box.
// There's probably a smarter way to determine which two sides if (!(i_compatflags & COMPATF_HITSCAN))
// of the thing face the trace than by trying all four sides...
for (i = 0; i < 4; ++i)
{ {
switch (i) // [RH] Don't check a corner to corner crossection for hit.
// Instead, check against the actual bounding box (but not if compatibility optioned.)
// There's probably a smarter way to determine which two sides
// of the thing face the trace than by trying all four sides...
for (i = 0; i < 4; ++i)
{ {
case 0: // Top edge switch (i)
line.x = thing->x + thing->radius;
line.y = thing->y + thing->radius;
line.dx = -thing->radius * 2;
line.dy = 0;
break;
case 1: // Right edge
line.x = thing->x + thing->radius;
line.y = thing->y - thing->radius;
line.dx = 0;
line.dy = thing->radius * 2;
break;
case 2: // Bottom edge
line.x = thing->x - thing->radius;
line.y = thing->y - thing->radius;
line.dx = thing->radius * 2;
line.dy = 0;
break;
case 3: // Left edge
line.x = thing->x - thing->radius;
line.y = thing->y + thing->radius;
line.dx = 0;
line.dy = thing->radius * -2;
break;
}
// Check if this side is facing the trace origin
if (P_PointOnDivlineSide (trace.x, trace.y, &line) == 0)
{
numfronts++;
// If it is, see if the trace crosses it
if (P_PointOnDivlineSide (line.x, line.y, &trace) !=
P_PointOnDivlineSide (line.x + line.dx, line.y + line.dy, &trace))
{ {
// It's a hit case 0: // Top edge
fixed_t frac = P_InterceptVector (&trace, &line); line.x = thing->x + thing->radius;
if (frac < 0) line.y = thing->y + thing->radius;
{ // behind source line.dx = -thing->radius * 2;
line.dy = 0;
break;
case 1: // Right edge
line.x = thing->x + thing->radius;
line.y = thing->y - thing->radius;
line.dx = 0;
line.dy = thing->radius * 2;
break;
case 2: // Bottom edge
line.x = thing->x - thing->radius;
line.y = thing->y - thing->radius;
line.dx = thing->radius * 2;
line.dy = 0;
break;
case 3: // Left edge
line.x = thing->x - thing->radius;
line.y = thing->y + thing->radius;
line.dx = 0;
line.dy = thing->radius * -2;
break;
}
// Check if this side is facing the trace origin
if (P_PointOnDivlineSide (trace.x, trace.y, &line) == 0)
{
numfronts++;
// If it is, see if the trace crosses it
if (P_PointOnDivlineSide (line.x, line.y, &trace) !=
P_PointOnDivlineSide (line.x + line.dx, line.y + line.dy, &trace))
{
// It's a hit
fixed_t frac = P_InterceptVector (&trace, &line);
if (frac < 0)
{ // behind source
continue;
}
intercept_t newintercept;
newintercept.frac = frac;
newintercept.isaline = false;
newintercept.done = false;
newintercept.d.thing = thing;
intercepts.Push (newintercept);
continue; continue;
} }
}
}
// If none of the sides was facing the trace, then the trace
// must have started inside the box, so add it as an intercept.
if (numfronts == 0)
{
intercept_t newintercept;
newintercept.frac = 0;
newintercept.isaline = false;
newintercept.done = false;
newintercept.d.thing = thing;
intercepts.Push (newintercept);
}
}
else
{
// Old code for compatibility purposes
fixed_t x1, y1, x2, y2;
int s1, s2;
divline_t dl;
fixed_t frac;
bool tracepositive = (trace.dx ^ trace.dy)>0;
// check a corner to corner crossection for hit
if (tracepositive)
{
x1 = thing->x - thing->radius;
y1 = thing->y + thing->radius;
x2 = thing->x + thing->radius;
y2 = thing->y - thing->radius;
}
else
{
x1 = thing->x - thing->radius;
y1 = thing->y - thing->radius;
x2 = thing->x + thing->radius;
y2 = thing->y + thing->radius;
}
s1 = P_PointOnDivlineSide (x1, y1, &trace);
s2 = P_PointOnDivlineSide (x2, y2, &trace);
if (s1 != s2)
{
dl.x = x1;
dl.y = y1;
dl.dx = x2-x1;
dl.dy = y2-y1;
frac = P_InterceptVector (&trace, &dl);
if (frac >= 0)
{
intercept_t newintercept; intercept_t newintercept;
newintercept.frac = frac; newintercept.frac = frac;
newintercept.isaline = false; newintercept.isaline = false;
newintercept.done = false; newintercept.done = false;
newintercept.d.thing = thing; newintercept.d.thing = thing;
intercepts.Push (newintercept); intercepts.Push (newintercept);
continue;
} }
} }
} }
// If none of the sides was facing the trace, then the trace
// must have started inside the box, so add it as an intercept.
if (numfronts == 0)
{
intercept_t newintercept;
newintercept.frac = 0;
newintercept.isaline = false;
newintercept.done = false;
newintercept.d.thing = thing;
intercepts.Push (newintercept);
}
} }
} }