Merge pull request 'Refactor conga' (#146) from keepdancingbabies into blankart-dev

Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/146
This commit is contained in:
NepDisk 2025-10-01 16:29:48 +02:00
commit 200d5e6b08
6 changed files with 206 additions and 21 deletions

View file

@ -1654,6 +1654,7 @@ static const char *CON_LoadingStrings[LOADED_ALLDONE+1] =
"Init rendering daemon...", //LOADED_RINIT
"Init audio subsystem...", //LOADED_SINITSFXCHANNELS
"Cache HUD...", //LOADED_STINIT
"Test fixed-point arithmetic...", //LOADED_MATHINIT
"Init ACSVM...", //LOADED_ACSINIT
"Check game status...", //LOADED_DCHECKNETGAME
"Now starting..."

View file

@ -52,6 +52,7 @@ typedef enum
LOADED_RINIT,
LOADED_SINITSFXCHANNELS,
LOADED_STINIT,
LOADED_MATHINIT,
LOADED_ACSINIT,
LOADED_DCHECKNETGAME,
LOADED_ALLDONE = LOADED_DCHECKNETGAME,

View file

@ -1814,6 +1814,61 @@ void D_SRB2Main(void)
ST_Init();
CON_SetLoadingProgress(LOADED_STINIT);
CONS_Printf("FixedSqrt of 32767 fracunits: %d; FixedSqrt64: %d\n",
FixedSqrt(0x7FFF0000),
FixedSqrt64(0x7FFF0000));
if (FixedSqrt(0x7FFF0000) == FixedSqrt64(0x7FFF0000))
{
CONS_Printf("\x83" "32767: Test OK!" "\x80" "\n");
}
else
{
CONS_Printf("\x85" "32767: Test NG!" "\x80" "\n");
}
CONS_Printf("FixedSqrt of 4 fracunits: %d; FixedSqrt64: %d\n",
FixedSqrt(0x40000),
FixedSqrt64(0x40000));
if (FixedSqrt(0x40000) == FixedSqrt64(0x40000))
{
CONS_Printf("\x83" "4: Test OK!" "\x80" "\n");
}
else
{
CONS_Printf("\x85" "4: Test NG!" "\x80" "\n");
}
// You should probably generate the weird number with RANDOM.org
#define WEIRDNUMBER 3886284 /* 59.3 fracunits; this should approximate to around 7 */
CONS_Printf("FixedSqrt of 59.3 fracunits: %d; FixedSqrt64: %d\n",
FixedSqrt(WEIRDNUMBER),
FixedSqrt64(WEIRDNUMBER));
if (FixedSqrt(WEIRDNUMBER) == FixedSqrt64(WEIRDNUMBER))
{
CONS_Printf("\x83" "59.3: Test OK!" "\x80" "\n");
}
else
{
CONS_Printf("\x85" "59.3: Test NG!" "\x80" "\n");
}
#undef WEIRDNUMBER
CONS_Printf("FixedSqrt64 of 65535 fracunits: %d (not possible at 32-bit scale)\n",
FixedSqrt64(0xFFFFFFFF));
CONS_Printf("IntSqrt of 32767: %d; IntSqrt64: %d\n",
IntSqrt(0x7FFF),
IntSqrt64(0x7FFF));
CONS_Printf("IntSqrt of 4: %d; IntSqrt64: %d\n",
IntSqrt(4),
IntSqrt64(4));
CON_SetLoadingProgress(LOADED_MATHINIT);
CONS_Printf("ACS_Init(): Init Action Code Script VM.\n");
ACS_Init();
CON_SetLoadingProgress(LOADED_ACSINIT);

View file

@ -160,6 +160,58 @@ static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] =
#define ENDDIST (12*ACTIVEDISTVAR) // Distance when the game stops giving you bananas
// 1/21/2025: I hate tiptoeing around the integer limit.
// This is at a smaller scale.
static UINT32 K_Dist2D(INT32 x1, INT32 y1, INT32 x2, INT32 y2)
{
// d = √((x2 - x1)² + (y2 - y1)²)
INT32 xdiff, ydiff;
INT64 xprod, yprod;
xdiff = (x2 - x1);
ydiff = (y2 - y1);
xprod = ((INT64)xdiff * (INT64)xdiff);
yprod = ((INT64)ydiff * (INT64)ydiff);
return (UINT32)(IntSqrt64(xprod + yprod));
}
// Basic integer distancing, to quote myself:
// "Even if you did 256 units for 1 fracunit in distancing, it'd be a better result than trying to
// deal with overflows on a system that's already being pushed to the limit by needing 65536 units
// for precision. No seriously, I don't think anyone's losing sleep over "hmmmmm, 0.0000152 or
// 0.0039?????" when most 2D game engines only give a fuck about MAYBE 0.001"
static UINT32 K_IntDistance(fixed_t curx,
fixed_t cury,
fixed_t curz,
fixed_t destx,
fixed_t desty,
fixed_t destz)
{
return K_Dist2D(0,
curz / FRACUNIT,
K_Dist2D(curx / FRACUNIT, cury / FRACUNIT, destx / FRACUNIT, desty / FRACUNIT),
destz / FRACUNIT);
}
// This one uses map scaling instead, use in case of loss of depth on mobjscaled maps.
static UINT32 K_IntDistanceForMap(fixed_t curx,
fixed_t cury,
fixed_t curz,
fixed_t destx,
fixed_t desty,
fixed_t destz)
{
return K_Dist2D(0,
curz / mapobjectscale,
K_Dist2D(curx / mapobjectscale,
cury / mapobjectscale,
destx / mapobjectscale,
desty / mapobjectscale),
destz / mapobjectscale);
}
SINT8 K_ItemResultToType(SINT8 getitem)
{
if (getitem <= 0 || getitem >= NUMKARTRESULTS) // Sad (Fallback)
@ -839,10 +891,16 @@ INT32 K_GetRollingRouletteItem(player_t *player)
return translation[(player->itemroulette % roulette_size) / 3];
}
// Legacy odds are fickle and finicky, so we exaggerate distances
// to simulate parity with pathfind odds.
#define LEGACYODDSEXAGGERATE (2*FRACUNIT/3)
UINT32 K_CalculateInitalPDIS(const player_t *player, UINT8 pingame)
{
UINT8 i;
UINT32 pdis = 0;
// Hacky solution to the overflow problem: use 64-bit integers!
UINT64 pdis = 0;
if (!K_UsingLegacyCheckpoints())
{
@ -969,25 +1027,15 @@ UINT32 K_CalculateInitalPDIS(const player_t *player, UINT8 pingame)
secondPlayer = &players[secondIndex];
// Add the distance to the player behind you.
// Distances are divided by 4, then further divided by a fracunit
// to prevent overflow issues.
pdis += (P_AproxDistance(P_AproxDistance(
firstPlayer->mo->x/4 - secondPlayer->mo->x/4,
firstPlayer->mo->y/4 - secondPlayer->mo->y/4),
firstPlayer->mo->z/4 - secondPlayer->mo->z/4)
/ FRACUNIT);
// Scale it to mostly return to normalcy.
pdis = (pdis * 2);
// Again, but this time base it on playercount, same form as
// the following vanilla adjustment, but much weaker since it
// stacks with it
// MAXODDS should always match the number of players the game is designed
// around, so there shouldn't be any issues with basing this calc around that.
// Hacky solution to the overflow problem: use 64-bit integers!
pdis = (UINT32)(((UINT64)(100 + MAXODDS - min(pingame, 16)) * pdis) / 100);
// At a (relative to map) integer scale using basic distancing
// arithmetic; more accurate and less concern for overflows.
pdis += K_IntDistanceForMap(
secondPlayer->mo->x,
secondPlayer->mo->y,
secondPlayer->mo->z,
firstPlayer->mo->x,
firstPlayer->mo->y,
firstPlayer->mo->z);
// Advance to next index.
firstIndex = secondIndex;
@ -998,9 +1046,22 @@ UINT32 K_CalculateInitalPDIS(const player_t *player, UINT8 pingame)
}
}
return pdis;
// Exaggerate odds; don't you love the legacy system? :Trollic:
pdis = FixedMul64(pdis, LEGACYODDSEXAGGERATE);
// Clamp pdis to the highest 32-bit integer.
// This is a shitty solution for overflow prevention, but it's an overflow prevention
// nonethless.
if (pdis > UINT32_MAX)
{
pdis = UINT32_MAX;
}
return (UINT32)(pdis);
}
#undef LEGACYODDSEXAGGERATE
UINT32 K_CalculatePDIS(const player_t *player, UINT8 numPlayers, boolean *spbrush)
{
UINT32 pdis = 0;

View file

@ -61,6 +61,45 @@ fixed_t FixedSqrt(fixed_t x)
#endif
}
// Shitty 64-bit duplicate so certain distancing edgecases in k_odds die
INT64 FixedSqrt64(INT64 x)
{
#ifdef HAVE_SQRT
const float fx = FixedToFloat64(x);
float fr;
#ifdef HAVE_SQRTF
fr = sqrtf(fx);
#else
fr = (float)sqrt(fx);
#endif
return FloatToFixed64(fr);
#else
// The neglected art of Fixed Point arithmetic
// Jetro Lauha
// Seminar Presentation
// Assembly 2006, 3rd- 6th August 2006
// (Revised: September 13, 2006)
// URL: http://jet.ro/files/The_neglected_art_of_Fixed_Point_arithmetic_20060913.pdf
register UINT64 root, remHi, remLo, testDiv, count;
root = 0; /* Clear root */
remHi = 0; /* Clear high part of partial remainder */
remLo = x; /* Get argument into low part of partial remainder */
count = (31 + (FRACBITS >> 1)); /* Load loop counter */
do
{
remHi = (remHi << 2) | (remLo >> 62); remLo <<= 2; /* get 2 bits of arg */
root <<= 1; /* Get ready for the next bit in the root */
testDiv = (root << 1) + 1; /* Test radical */
if (remHi >= testDiv)
{
remHi -= testDiv;
root += 1;
}
} while (count-- != 0);
return root;
#endif
}
fixed_t FixedHypot(fixed_t x, fixed_t y)
{
// Moved the code from R_PointToDist2 to here,
@ -1122,6 +1161,11 @@ FUNCMATH FUNCINLINE static inline fixed_t FixedMulC(fixed_t a, fixed_t b)
return (fixed_t)((((INT64)a * b)) / FRACUNIT);
}
FUNCMATH FUNCINLINE static inline INT64 FixedMul64C(fixed_t a, fixed_t b)
{
return (INt64)((((INT64)a * b)) / FRACUNIT);
}
FUNCMATH FUNCINLINE static inline fixed_t FixedDivC2(fixed_t a, fixed_t b)
{
INT64 ret;

View file

@ -55,11 +55,21 @@ FUNCMATH FUNCINLINE static ATTRINLINE float FixedToFloat(fixed_t x)
return x / (float)FRACUNIT;
}
FUNCMATH FUNCINLINE static ATTRINLINE float FixedToFloat64(INT64 x)
{
return (float)x / (float)FRACUNIT;
}
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FloatToFixed(float f)
{
return (fixed_t)(f * FRACUNIT);
}
FUNCMATH FUNCINLINE static ATTRINLINE INT64 FloatToFixed64(float f)
{
return (INT64)(f * FRACUNIT);
}
// for backwards compat
#define FIXED_TO_FLOAT(x) FixedToFloat(x) // (((float)(x)) / ((float)FRACUNIT))
#define FLOAT_TO_FIXED(f) FloatToFixed(f) // (fixed_t)((f) * ((float)FRACUNIT))
@ -79,6 +89,13 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedMul(fixed_t a, fixed_t b)
return (fixed_t)(((UINT64)((INT64)a * b)) >> FRACBITS);
}
FUNCMATH FUNCINLINE static ATTRINLINE INT64 FixedMul64(INT64 a, INT64 b)
{
// Need to cast to unsigned before shifting to avoid undefined behaviour
// for negative integers
return (INT64)(((UINT64)(a * b)) >> FRACBITS);
}
/** \brief The FixedDiv2 function
\param a fixed_t number
@ -145,6 +162,12 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedPercentageFloat(float fpercen
*/
FUNCMATH fixed_t FixedSqrt(fixed_t x);
FUNCMATH INT64 FixedSqrt64(INT64 x);
// Theoretically, we can feed this any integer value and it'll output an
// accurate square root * 256.
#define IntSqrt(x) (INT32)(FixedSqrt(x) / 256)
#define IntSqrt64(x) (INT64)(FixedSqrt64(x) / 256)
/** \brief The FixedHypot function