mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'master' into targets
This commit is contained in:
commit
b1ec5654bc
52 changed files with 7334 additions and 2203 deletions
|
|
@ -497,6 +497,9 @@ OBJS:=$(i_main_o) \
|
|||
$(OBJDIR)/k_collide.o\
|
||||
$(OBJDIR)/k_battle.o \
|
||||
$(OBJDIR)/k_pwrlv.o \
|
||||
$(OBJDIR)/k_waypoint.o\
|
||||
$(OBJDIR)/k_pathfind.o\
|
||||
$(OBJDIR)/k_bheap.o \
|
||||
$(OBJDIR)/m_aatree.o \
|
||||
$(OBJDIR)/m_anigif.o \
|
||||
$(OBJDIR)/m_argv.o \
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ UINT16 pingmeasurecount = 1;
|
|||
UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone.
|
||||
UINT32 playerpingtable[MAXPLAYERS]; //table of player latency values.
|
||||
tic_t servermaxping = 800; // server's max ping. Defaults to 800
|
||||
static tic_t lowest_lag;
|
||||
boolean server_lagless;
|
||||
SINT8 nodetoplayer[MAXNETNODES];
|
||||
SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
|
||||
SINT8 nodetoplayer3[MAXNETNODES]; // say the numplayer for this node if any (splitscreen == 2)
|
||||
|
|
@ -4965,6 +4967,9 @@ static void CL_SendClientCmd(void)
|
|||
size_t packetsize = 0;
|
||||
boolean mis = false;
|
||||
|
||||
if (lowest_lag && ( gametic % lowest_lag ))
|
||||
return;
|
||||
|
||||
netbuffer->packettype = PT_CLIENTCMD;
|
||||
|
||||
if (cl_packetmissed)
|
||||
|
|
@ -5433,16 +5438,65 @@ static tic_t gametime = 0;
|
|||
|
||||
static void UpdatePingTable(void)
|
||||
{
|
||||
tic_t fastest;
|
||||
tic_t lag;
|
||||
|
||||
INT32 i;
|
||||
|
||||
if (server)
|
||||
{
|
||||
if (netgame && !(gametime % 35)) // update once per second.
|
||||
PingUpdate();
|
||||
|
||||
fastest = 0;
|
||||
|
||||
// update node latency values so we can take an average later.
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i])
|
||||
realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i]));
|
||||
{
|
||||
if (playeringame[i] && playernode[i] > 0)
|
||||
{
|
||||
if (! server_lagless && playernode[i] > 0)
|
||||
{
|
||||
lag = GetLag(playernode[i]);
|
||||
realpingtable[i] += G_TicsToMilliseconds(lag);
|
||||
|
||||
if (! fastest || lag < fastest)
|
||||
fastest = lag;
|
||||
}
|
||||
else
|
||||
realpingtable[i] += G_TicsToMilliseconds(GetLag(playernode[i]));
|
||||
}
|
||||
}
|
||||
pingmeasurecount++;
|
||||
|
||||
if (server_lagless)
|
||||
lowest_lag = 0;
|
||||
else
|
||||
{
|
||||
lowest_lag = fastest;
|
||||
|
||||
if (fastest)
|
||||
lag = fastest;
|
||||
else
|
||||
lag = GetLag(0);
|
||||
|
||||
lag = ( realpingtable[0] + G_TicsToMilliseconds(lag) );
|
||||
|
||||
switch (playerpernode[0])
|
||||
{
|
||||
case 4:
|
||||
realpingtable[nodetoplayer4[0]] = lag;
|
||||
/*FALLTHRU*/
|
||||
case 3:
|
||||
realpingtable[nodetoplayer3[0]] = lag;
|
||||
/*FALLTHRU*/
|
||||
case 2:
|
||||
realpingtable[nodetoplayer2[0]] = lag;
|
||||
/*FALLTHRU*/
|
||||
case 1:
|
||||
realpingtable[nodetoplayer[0]] = lag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -543,6 +543,8 @@ extern UINT32 realpingtable[MAXPLAYERS];
|
|||
extern UINT32 playerpingtable[MAXPLAYERS];
|
||||
extern tic_t servermaxping;
|
||||
|
||||
extern boolean server_lagless;
|
||||
|
||||
extern consvar_t
|
||||
#ifdef VANILLAJOINNEXTROUND
|
||||
cv_joinnextround,
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ static void D_Display(void)
|
|||
}
|
||||
|
||||
if (demo.rewinding)
|
||||
V_DrawFadeScreen(TC_RAINBOW, (leveltime & 0x20) ? SKINCOLOR_PASTEL : SKINCOLOR_MOONSLAM);
|
||||
V_DrawFadeScreen(TC_RAINBOW, (leveltime & 0x20) ? SKINCOLOR_PASTEL : SKINCOLOR_MOONSET);
|
||||
|
||||
// vid size change is now finished if it was on...
|
||||
vid.recalc = 0;
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ static void TeamScramble_OnChange(void);
|
|||
static void NetTimeout_OnChange(void);
|
||||
static void JoinTimeout_OnChange(void);
|
||||
|
||||
static void Lagless_OnChange (void);
|
||||
|
||||
static void Ringslinger_OnChange(void);
|
||||
static void Gravity_OnChange(void);
|
||||
static void ForceSkin_OnChange(void);
|
||||
|
|
@ -386,6 +388,8 @@ consvar_t cv_kartdebugamount = {"kartdebugamount", "1", CV_NETVAR|CV_CHEAT|CV_NO
|
|||
consvar_t cv_kartdebugshrink = {"kartdebugshrink", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_kartdebugdistribution = {"kartdebugdistribution", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_kartdebughuddrop = {"kartdebughuddrop", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
static CV_PossibleValue_t kartdebugwaypoint_cons_t[] = {{0, "Off"}, {1, "Forwards"}, {2, "Backwards"}, {0, NULL}};
|
||||
consvar_t cv_kartdebugwaypoints = {"kartdebugwaypoints", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, kartdebugwaypoint_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
consvar_t cv_kartdebugcheckpoint = {"kartdebugcheckpoint", "Off", CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_kartdebugnodes = {"kartdebugnodes", "Off", CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
|
@ -448,6 +452,8 @@ consvar_t cv_jointimeout = {"jointimeout", "105", CV_CALL|CV_SAVE, nettimeout_co
|
|||
static CV_PossibleValue_t maxping_cons_t[] = {{0, "MIN"}, {1000, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_maxping = {"maxping", "800", CV_SAVE, maxping_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
consvar_t cv_lagless = {"lagless", "Off", CV_SAVE|CV_NETVAR|CV_CALL, CV_OnOff, Lagless_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
static CV_PossibleValue_t pingtimeout_cons_t[] = {{8, "MIN"}, {120, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_pingtimeout = {"pingtimeout", "10", CV_SAVE, pingtimeout_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
|
|
@ -455,6 +461,8 @@ consvar_t cv_pingtimeout = {"pingtimeout", "10", CV_SAVE, pingtimeout_cons_t, NU
|
|||
static CV_PossibleValue_t showping_cons_t[] = {{0, "Off"}, {1, "Always"}, {2, "Warning"}, {0, NULL}};
|
||||
consvar_t cv_showping = {"showping", "Always", CV_SAVE, showping_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
consvar_t cv_showviewpointtext = {"showviewpointtext", "On", CV_SAVE, CV_OnOff, 0, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
// Intermission time Tails 04-19-2002
|
||||
static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_inttime = {"inttime", "20", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
|
@ -712,8 +720,10 @@ void D_RegisterServerCommands(void)
|
|||
CV_RegisterVar(&cv_skipmapcheck);
|
||||
CV_RegisterVar(&cv_sleep);
|
||||
CV_RegisterVar(&cv_maxping);
|
||||
CV_RegisterVar(&cv_lagless);
|
||||
CV_RegisterVar(&cv_pingtimeout);
|
||||
CV_RegisterVar(&cv_showping);
|
||||
CV_RegisterVar(&cv_showviewpointtext);
|
||||
|
||||
#ifdef SEENAMES
|
||||
CV_RegisterVar(&cv_allowseenames);
|
||||
|
|
@ -1880,8 +1890,6 @@ void SendWeaponPref(void)
|
|||
buf[0] = 0;
|
||||
if (cv_flipcam.value)
|
||||
buf[0] |= 1;
|
||||
if (cv_analog.value)
|
||||
buf[0] |= 2;
|
||||
SendNetXCmd(XD_WEAPONPREF, buf, 1);
|
||||
}
|
||||
|
||||
|
|
@ -1892,8 +1900,6 @@ void SendWeaponPref2(void)
|
|||
buf[0] = 0;
|
||||
if (cv_flipcam2.value)
|
||||
buf[0] |= 1;
|
||||
if (cv_analog2.value)
|
||||
buf[0] |= 2;
|
||||
SendNetXCmd2(XD_WEAPONPREF, buf, 1);
|
||||
}
|
||||
|
||||
|
|
@ -1904,8 +1910,6 @@ void SendWeaponPref3(void)
|
|||
buf[0] = 0;
|
||||
if (cv_flipcam3.value)
|
||||
buf[0] |= 1;
|
||||
if (cv_analog3.value)
|
||||
buf[0] |= 2;
|
||||
SendNetXCmd3(XD_WEAPONPREF, buf, 1);
|
||||
}
|
||||
|
||||
|
|
@ -1916,8 +1920,6 @@ void SendWeaponPref4(void)
|
|||
buf[0] = 0;
|
||||
if (cv_flipcam4.value)
|
||||
buf[0] |= 1;
|
||||
if (cv_analog4.value)
|
||||
buf[0] |= 2;
|
||||
SendNetXCmd4(XD_WEAPONPREF, buf, 1);
|
||||
}
|
||||
|
||||
|
|
@ -1925,11 +1927,9 @@ static void Got_WeaponPref(UINT8 **cp,INT32 playernum)
|
|||
{
|
||||
UINT8 prefs = READUINT8(*cp);
|
||||
|
||||
players[playernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE);
|
||||
players[playernum].pflags &= ~(PF_FLIPCAM);
|
||||
if (prefs & 1)
|
||||
players[playernum].pflags |= PF_FLIPCAM;
|
||||
if (prefs & 2)
|
||||
players[playernum].pflags |= PF_ANALOGMODE;
|
||||
}
|
||||
|
||||
static void Got_PowerLevel(UINT8 **cp,INT32 playernum)
|
||||
|
|
@ -2851,13 +2851,15 @@ static void Got_Respawn(UINT8 **cp, INT32 playernum)
|
|||
return;
|
||||
}
|
||||
|
||||
// incase the above checks were modified to allow sending a respawn on these occasions:
|
||||
if (players[respawnplayer].mo && !P_IsObjectOnGround(players[respawnplayer].mo))
|
||||
return;
|
||||
|
||||
if (players[respawnplayer].mo)
|
||||
P_DamageMobj(players[respawnplayer].mo, NULL, NULL, 10000);
|
||||
demo_extradata[playernum] |= DXD_RESPAWN;
|
||||
{
|
||||
// incase the above checks were modified to allow sending a respawn on these occasions:
|
||||
if (!P_IsObjectOnGround(players[respawnplayer].mo))
|
||||
return;
|
||||
|
||||
K_DoIngameRespawn(&players[respawnplayer]);
|
||||
demo_extradata[playernum] |= DXD_RESPAWN;
|
||||
}
|
||||
}
|
||||
|
||||
/** Deals with an ::XD_RANDOMSEED message in a netgame.
|
||||
|
|
@ -4770,6 +4772,14 @@ static void JoinTimeout_OnChange(void)
|
|||
jointimeout = (tic_t)cv_jointimeout.value;
|
||||
}
|
||||
|
||||
static void
|
||||
Lagless_OnChange (void)
|
||||
{
|
||||
/* don't back out of dishonesty, or go lagless after playing honestly */
|
||||
if (cv_lagless.value && gamestate == GS_LEVEL)
|
||||
server_lagless = true;
|
||||
}
|
||||
|
||||
UINT32 timelimitintics = 0;
|
||||
|
||||
/** Deals with a timelimit change by printing the change to the console.
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ extern consvar_t cv_votetime;
|
|||
|
||||
extern consvar_t cv_kartdebugitem, cv_kartdebugamount, cv_kartdebugshrink, cv_kartdebugdistribution, cv_kartdebughuddrop;
|
||||
extern consvar_t cv_kartdebugcheckpoint, cv_kartdebugnodes, cv_kartdebugcolorize;
|
||||
extern consvar_t cv_kartdebugwaypoints;
|
||||
|
||||
extern consvar_t cv_itemfinder;
|
||||
|
||||
|
|
@ -144,8 +145,10 @@ extern consvar_t cv_ringslinger, cv_soundtest;
|
|||
extern consvar_t cv_specialrings, cv_powerstones, cv_matchboxes, cv_competitionboxes;
|
||||
|
||||
extern consvar_t cv_maxping;
|
||||
extern consvar_t cv_lagless;
|
||||
extern consvar_t cv_pingtimeout;
|
||||
extern consvar_t cv_showping;
|
||||
extern consvar_t cv_showviewpointtext;
|
||||
|
||||
extern consvar_t cv_skipmapcheck;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@
|
|||
// as commands per game tick.
|
||||
#include "d_ticcmd.h"
|
||||
|
||||
// the player struct stores a waypoint for racing
|
||||
#include "k_waypoint.h"
|
||||
|
||||
// Extra abilities/settings for skins (combinable stuff)
|
||||
typedef enum
|
||||
{
|
||||
|
|
@ -118,7 +121,7 @@ typedef enum
|
|||
|
||||
/*** misc ***/
|
||||
PF_FORCESTRAFE = 1<<29, // Turning inputs are translated into strafing inputs
|
||||
PF_ANALOGMODE = 1<<30, // Analog mode?
|
||||
PF_HITFINISHLINE = 1<<30, // Already hit the finish line this tic
|
||||
|
||||
// free: 1<<30 and 1<<31
|
||||
} pflags_t;
|
||||
|
|
@ -240,10 +243,6 @@ typedef enum
|
|||
k_position, // Used for Kart positions, mostly for deterministic stuff
|
||||
k_oldposition, // Used for taunting when you pass someone
|
||||
k_positiondelay, // Used for position number, so it can grow when passing/being passed
|
||||
k_prevcheck, // Previous checkpoint distance; for p_user.c (was "pw_pcd")
|
||||
k_nextcheck, // Next checkpoint distance; for p_user.c (was "pw_ncd")
|
||||
k_waypoint, // Waypoints.
|
||||
k_starpostwp, // Temporarily stores player waypoint for... some reason. Used when respawning and finishing.
|
||||
k_starpostflip, // the last starpost we hit requires flipping?
|
||||
k_respawn, // Timer for the DEZ laser respawn effect
|
||||
k_dropdash, // Charge up for respawn Drop Dash
|
||||
|
|
@ -331,6 +330,7 @@ typedef enum
|
|||
k_springstars, // Spawn stars around a player when they hit a spring
|
||||
k_springcolor, // Color of spring stars
|
||||
k_killfield, // How long have you been in the kill field, stay in too long and lose a bumper
|
||||
k_wrongway, // Display WRONG WAY on screen
|
||||
|
||||
NUMKARTSTUFF
|
||||
} kartstufftype_t;
|
||||
|
|
@ -436,6 +436,8 @@ typedef struct player_s
|
|||
angle_t frameangle; // for the player add the ability to have the sprite only face other angles
|
||||
INT16 lturn_max[MAXPREDICTTICS]; // What's the expected turn value for full-left for a number of frames back (to account for netgame latency)?
|
||||
INT16 rturn_max[MAXPREDICTTICS]; // Ditto but for full-right
|
||||
UINT32 distancetofinish;
|
||||
waypoint_t *nextwaypoint;
|
||||
|
||||
// Bit flags.
|
||||
// See pflags_t, above.
|
||||
|
|
|
|||
|
|
@ -1774,7 +1774,6 @@ static actionpointer_t actionpointers[] =
|
|||
{{A_GrenadeRing}, "A_GRENADERING"}, // SRB2kart
|
||||
{{A_SetSolidSteam}, "A_SETSOLIDSTEAM"},
|
||||
{{A_UnsetSolidSteam}, "A_UNSETSOLIDSTEAM"},
|
||||
{{A_SignPlayer}, "A_SIGNPLAYER"},
|
||||
{{A_OverlayThink}, "A_OVERLAYTHINK"},
|
||||
{{A_JetChase}, "A_JETCHASE"},
|
||||
{{A_JetbThink}, "A_JETBTHINK"},
|
||||
|
|
@ -4887,27 +4886,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_BUBBLES2",
|
||||
|
||||
// Level End Sign
|
||||
"S_SIGN1",
|
||||
"S_SIGN2",
|
||||
"S_SIGN3",
|
||||
"S_SIGN4",
|
||||
"S_SIGN5",
|
||||
"S_SIGN6",
|
||||
"S_SIGN7",
|
||||
"S_SIGN8",
|
||||
"S_SIGN9",
|
||||
"S_SIGN10",
|
||||
"S_SIGN11",
|
||||
"S_SIGN12",
|
||||
"S_SIGN13",
|
||||
"S_SIGN14",
|
||||
"S_SIGN15",
|
||||
"S_SIGN16",
|
||||
"S_SIGN17",
|
||||
"S_SIGN18",
|
||||
"S_SIGN19",
|
||||
"S_SIGN20",
|
||||
"S_SIGN_END",
|
||||
"S_SIGN_POLE",
|
||||
"S_SIGN_BACK",
|
||||
"S_SIGN_SIDE",
|
||||
"S_SIGN_FACE",
|
||||
|
||||
// Steam Riser
|
||||
"S_STEAM1",
|
||||
|
|
@ -5690,6 +5672,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_SNOW2",
|
||||
"S_SNOW3",
|
||||
|
||||
// Blizzard Snowball
|
||||
"S_BLIZZARDSNOW1",
|
||||
"S_BLIZZARDSNOW2",
|
||||
"S_BLIZZARDSNOW3",
|
||||
|
||||
// Water Splish
|
||||
"S_SPLISH1",
|
||||
"S_SPLISH2",
|
||||
|
|
@ -6360,6 +6347,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_DRIFTSPARK_B1",
|
||||
"S_DRIFTSPARK_C1",
|
||||
"S_DRIFTSPARK_C2",
|
||||
"S_DRIFTSPARK_D1",
|
||||
"S_DRIFTSPARK_D2",
|
||||
|
||||
// Brake drift sparks
|
||||
"S_BRAKEDRIFT",
|
||||
|
|
@ -6370,6 +6359,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_DRIFTDUST3",
|
||||
"S_DRIFTDUST4",
|
||||
|
||||
// Drift Sparkles
|
||||
"S_DRIFTWARNSPARK1",
|
||||
"S_DRIFTWARNSPARK2",
|
||||
"S_DRIFTWARNSPARK3",
|
||||
"S_DRIFTWARNSPARK4",
|
||||
|
||||
// Fast lines
|
||||
"S_FASTLINE1",
|
||||
"S_FASTLINE2",
|
||||
|
|
@ -6386,7 +6381,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_FASTDUST6",
|
||||
"S_FASTDUST7",
|
||||
|
||||
// Thunder Shield Burst
|
||||
// Drift boost effect
|
||||
"S_DRIFTEXPLODE1",
|
||||
"S_DRIFTEXPLODE2",
|
||||
"S_DRIFTEXPLODE3",
|
||||
"S_DRIFTEXPLODE4",
|
||||
|
||||
// Sneaker boost effect
|
||||
"S_BOOSTFLAME",
|
||||
|
|
@ -6661,6 +6660,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
|
||||
// DEZ respawn laser
|
||||
"S_DEZLASER",
|
||||
"S_DEZLASER_TRAIL1",
|
||||
"S_DEZLASER_TRAIL2",
|
||||
"S_DEZLASER_TRAIL3",
|
||||
"S_DEZLASER_TRAIL4",
|
||||
"S_DEZLASER_TRAIL5",
|
||||
|
||||
// Audience Members
|
||||
"S_RANDOMAUDIENCE",
|
||||
|
|
@ -6779,9 +6783,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
|
|||
"S_LAMPPOST",
|
||||
"S_MOSSYTREE",
|
||||
|
||||
"S_SHADOW",
|
||||
"S_WHITESHADOW",
|
||||
|
||||
"S_BUMP1",
|
||||
"S_BUMP2",
|
||||
"S_BUMP3",
|
||||
|
|
@ -7370,6 +7371,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
// Interactive Objects
|
||||
"MT_BUBBLES", // Bubble source
|
||||
"MT_SIGN", // Level end sign
|
||||
"MT_SIGN_PIECE",
|
||||
"MT_SPIKEBALL", // Spike Ball
|
||||
"MT_SPECIALSPIKEBALL",
|
||||
"MT_SPINFIRE",
|
||||
|
|
@ -7596,6 +7598,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
// Environmental Effects
|
||||
"MT_RAIN", // Rain
|
||||
"MT_SNOWFLAKE", // Snowflake
|
||||
"MT_BLIZZARDSNOW", // Blizzard Snowball
|
||||
"MT_SPLISH", // Water splish!
|
||||
"MT_SMOKE",
|
||||
"MT_SMALLBUBBLE", // small bubble
|
||||
|
|
@ -7755,6 +7758,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
|
||||
"MT_FASTLINE",
|
||||
"MT_FASTDUST",
|
||||
"MT_DRIFTEXPLODE",
|
||||
"MT_BOOSTFLAME",
|
||||
"MT_BOOSTSMOKE",
|
||||
"MT_SNEAKERTRAIL",
|
||||
|
|
@ -7856,8 +7860,6 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
|
|||
"MT_LAMPPOST",
|
||||
"MT_MOSSYTREE",
|
||||
|
||||
"MT_SHADOW",
|
||||
|
||||
"MT_BUMP",
|
||||
|
||||
"MT_FLINGENERGY",
|
||||
|
|
@ -8193,7 +8195,7 @@ static const char *const PLAYERFLAG_LIST[] = {
|
|||
|
||||
/*** misc ***/
|
||||
"FORCESTRAFE", // Translate turn inputs into strafe inputs
|
||||
"ANALOGMODE", // Analog mode?
|
||||
"HITFINISHLINE", // Already hit the finish line this tic
|
||||
|
||||
NULL // stop loop here.
|
||||
};
|
||||
|
|
@ -8252,7 +8254,7 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart.
|
|||
"SCARLET", // SKINCOLOR_SCARLET
|
||||
"KETCHUP", // SKINCOLOR_KETCHUP
|
||||
"DAWN", // SKINCOLOR_DAWN
|
||||
"SUNSET", // SKINCOLOR_SUNSET
|
||||
"SUNSLAM", // SKINCOLOR_SUNSLAM
|
||||
"CREAMSICLE", // SKINCOLOR_CREAMSICLE
|
||||
"ORANGE", // SKINCOLOR_ORANGE
|
||||
"ROSEWOOD", // SKINCOLOR_ROSEWOOD
|
||||
|
|
@ -8312,9 +8314,9 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart.
|
|||
"THISTLE", // SKINCOLOR_THISTLE
|
||||
"PURPLE", // SKINCOLOR_PURPLE
|
||||
"PASTEL", // SKINCOLOR_PASTEL
|
||||
"MOONSLAM", // SKINCOLOR_MOONSLAM
|
||||
"MOONSET", // SKINCOLOR_MOONSET
|
||||
"DUSK", // SKINCOLOR_DUSK
|
||||
"BUBBLEGUM", // SKINCOLOR_BUBBLEGUM
|
||||
"VIOLET", // SKINCOLOR_VIOLET
|
||||
"MAGENTA", // SKINCOLOR_MAGENTA
|
||||
"FUCHSIA", // SKINCOLOR_FUCHSIA
|
||||
"TOXIC", // SKINCOLOR_TOXIC
|
||||
|
|
@ -8430,10 +8432,6 @@ static const char *const KARTSTUFF_LIST[] = {
|
|||
"POSITION",
|
||||
"OLDPOSITION",
|
||||
"POSITIONDELAY",
|
||||
"PREVCHECK",
|
||||
"NEXTCHECK",
|
||||
"WAYPOINT",
|
||||
"STARPOSTWP",
|
||||
"STARPOSTFLIP",
|
||||
"RESPAWN",
|
||||
"DROPDASH",
|
||||
|
|
@ -8515,7 +8513,8 @@ static const char *const KARTSTUFF_LIST[] = {
|
|||
"TIREGREASE",
|
||||
"SPRINGSTARS",
|
||||
"SPRINGCOLOR",
|
||||
"KILLFIELD"
|
||||
"KILLFIELD",
|
||||
"WRONGWAY"
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
@ -8710,10 +8709,10 @@ struct {
|
|||
|
||||
// Precipitation
|
||||
{"PRECIP_NONE",PRECIP_NONE},
|
||||
{"PRECIP_STORM",PRECIP_STORM},
|
||||
{"PRECIP_SNOW",PRECIP_SNOW},
|
||||
{"PRECIP_RAIN",PRECIP_RAIN},
|
||||
{"PRECIP_BLANK",PRECIP_BLANK},
|
||||
{"PRECIP_SNOW",PRECIP_SNOW},
|
||||
{"PRECIP_BLIZZARD",PRECIP_BLIZZARD},
|
||||
{"PRECIP_STORM",PRECIP_STORM},
|
||||
{"PRECIP_STORM_NORAIN",PRECIP_STORM_NORAIN},
|
||||
{"PRECIP_STORM_NOSTRIKES",PRECIP_STORM_NOSTRIKES},
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ enum
|
|||
ML_BLOCKMAP, // LUT, motion clipping, walls/grid element
|
||||
};
|
||||
|
||||
// Extra flag for objects
|
||||
#define MTF_EXTRA 1
|
||||
|
||||
// Reverse gravity flag for objects.
|
||||
#define MTF_OBJECTFLIP 2
|
||||
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ typedef enum
|
|||
SKINCOLOR_SCARLET,
|
||||
SKINCOLOR_KETCHUP,
|
||||
SKINCOLOR_DAWN,
|
||||
SKINCOLOR_SUNSET,
|
||||
SKINCOLOR_SUNSLAM,
|
||||
SKINCOLOR_CREAMSICLE,
|
||||
SKINCOLOR_ORANGE,
|
||||
SKINCOLOR_ROSEWOOD,
|
||||
|
|
@ -340,9 +340,9 @@ typedef enum
|
|||
SKINCOLOR_THISTLE,
|
||||
SKINCOLOR_PURPLE,
|
||||
SKINCOLOR_PASTEL,
|
||||
SKINCOLOR_MOONSLAM,
|
||||
SKINCOLOR_MOONSET,
|
||||
SKINCOLOR_DUSK,
|
||||
SKINCOLOR_BUBBLEGUM,
|
||||
SKINCOLOR_VIOLET,
|
||||
SKINCOLOR_MAGENTA,
|
||||
SKINCOLOR_FUCHSIA,
|
||||
SKINCOLOR_TOXIC,
|
||||
|
|
|
|||
|
|
@ -41,18 +41,36 @@ extern UINT32 mapmusposition;
|
|||
|
||||
extern INT16 maptol;
|
||||
extern UINT8 globalweather;
|
||||
extern INT32 curWeather;
|
||||
extern UINT8 curWeather;
|
||||
extern INT32 cursaveslot;
|
||||
extern INT16 lastmapsaved;
|
||||
extern boolean gamecomplete;
|
||||
|
||||
#define PRECIP_NONE 0
|
||||
#define PRECIP_STORM 1
|
||||
#define PRECIP_SNOW 2
|
||||
#define PRECIP_RAIN 3
|
||||
#define PRECIP_BLANK 4
|
||||
#define PRECIP_STORM_NORAIN 5
|
||||
#define PRECIP_STORM_NOSTRIKES 6
|
||||
typedef enum
|
||||
{
|
||||
PRECIP_NONE = 0,
|
||||
PRECIP_RAIN,
|
||||
PRECIP_SNOW,
|
||||
PRECIP_BLIZZARD,
|
||||
PRECIP_STORM,
|
||||
PRECIP_STORM_NORAIN,
|
||||
PRECIP_STORM_NOSTRIKES,
|
||||
MAXPRECIP
|
||||
} preciptype_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PRECIPFX_THUNDER = 1,
|
||||
PRECIPFX_LIGHTNING = 1<<1
|
||||
} precipeffect_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mobjtype_t type;
|
||||
precipeffect_t effects;
|
||||
} precipprops_t;
|
||||
|
||||
extern precipprops_t precipprops[MAXPRECIP];
|
||||
|
||||
// Set if homebrew PWAD stuff has been added.
|
||||
extern boolean modifiedgame;
|
||||
|
|
|
|||
34
src/g_game.c
34
src/g_game.c
|
|
@ -84,8 +84,21 @@ UINT32 mapmusposition; // Position to jump to
|
|||
|
||||
INT16 gamemap = 1;
|
||||
INT16 maptol;
|
||||
|
||||
UINT8 globalweather = 0;
|
||||
INT32 curWeather = PRECIP_NONE;
|
||||
UINT8 curWeather = PRECIP_NONE;
|
||||
|
||||
precipprops_t precipprops[MAXPRECIP] =
|
||||
{
|
||||
{MT_NULL, 0}, // PRECIP_NONE
|
||||
{MT_RAIN, 0}, // PRECIP_RAIN
|
||||
{MT_SNOWFLAKE, 0}, // PRECIP_SNOW
|
||||
{MT_BLIZZARDSNOW, 0}, // PRECIP_BLIZZARD
|
||||
{MT_RAIN, PRECIPFX_THUNDER|PRECIPFX_LIGHTNING}, // PRECIP_STORM
|
||||
{MT_NULL, PRECIPFX_THUNDER|PRECIPFX_LIGHTNING}, // PRECIP_STORM_NORAIN
|
||||
{MT_RAIN, PRECIPFX_THUNDER} // PRECIP_STORM_NOSTRIKES
|
||||
};
|
||||
|
||||
INT32 cursaveslot = -1; // Auto-save 1p savegame slot
|
||||
INT16 lastmapsaved = 0; // Last map we auto-saved at
|
||||
boolean gamecomplete = false;
|
||||
|
|
@ -1779,6 +1792,8 @@ void G_DoLoadLevel(boolean resetplayer)
|
|||
|
||||
// clear hud messages remains (usually from game startup)
|
||||
CON_ClearHUD();
|
||||
|
||||
server_lagless = cv_lagless.value;
|
||||
}
|
||||
|
||||
static INT32 pausedelay = 0;
|
||||
|
|
@ -2559,7 +2574,6 @@ void G_PlayerReborn(INT32 player)
|
|||
SINT8 pity;
|
||||
|
||||
// SRB2kart
|
||||
INT32 starpostwp;
|
||||
INT32 itemtype;
|
||||
INT32 itemamount;
|
||||
INT32 itemroulette;
|
||||
|
|
@ -2581,7 +2595,7 @@ void G_PlayerReborn(INT32 player)
|
|||
jointime = players[player].jointime;
|
||||
splitscreenindex = players[player].splitscreenindex;
|
||||
spectator = players[player].spectator;
|
||||
pflags = (players[player].pflags & (PF_TIMEOVER|PF_FLIPCAM|PF_TAGIT|PF_TAGGED|PF_ANALOGMODE|PF_WANTSTOJOIN));
|
||||
pflags = (players[player].pflags & (PF_TIMEOVER|PF_FLIPCAM|PF_TAGIT|PF_TAGGED|PF_WANTSTOJOIN));
|
||||
|
||||
// As long as we're not in multiplayer, carry over cheatcodes from map to map
|
||||
if (!(netgame || multiplayer))
|
||||
|
|
@ -2623,12 +2637,9 @@ void G_PlayerReborn(INT32 player)
|
|||
rings = (G_BattleGametype() ? 0 : 5);
|
||||
comebackpoints = 0;
|
||||
wanted = 0;
|
||||
starpostwp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
starpostwp = players[player].kartstuff[k_starpostwp];
|
||||
|
||||
itemroulette = (players[player].kartstuff[k_itemroulette] > 0 ? 1 : 0);
|
||||
roulettetype = players[player].kartstuff[k_roulettetype];
|
||||
|
||||
|
|
@ -2695,7 +2706,6 @@ void G_PlayerReborn(INT32 player)
|
|||
p->pity = pity;
|
||||
|
||||
// SRB2kart
|
||||
p->kartstuff[k_starpostwp] = starpostwp; // TODO: get these out of kartstuff, it causes desync (Does it...?)
|
||||
p->kartstuff[k_itemroulette] = itemroulette;
|
||||
p->kartstuff[k_roulettetype] = roulettetype;
|
||||
p->kartstuff[k_itemtype] = itemtype;
|
||||
|
|
@ -3235,7 +3245,8 @@ void G_DoReborn(INT32 playernum)
|
|||
// respawn at the start
|
||||
mobj_t *oldmo = NULL;
|
||||
|
||||
if (player->starpostnum || ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) && player->laps)) // SRB2kart
|
||||
// Now only respawn at the start if you haven't crossed it at all
|
||||
if (player->laps) // SRB2kart
|
||||
starpost = true;
|
||||
|
||||
// first dissasociate the corpse
|
||||
|
|
@ -4925,7 +4936,10 @@ void G_ReadDemoExtraData(void)
|
|||
if (extradata & DXD_RESPAWN)
|
||||
{
|
||||
if (players[p].mo)
|
||||
P_DamageMobj(players[p].mo, NULL, NULL, 10000); // Is this how this should work..?
|
||||
{
|
||||
// Is this how this should work..?
|
||||
K_DoIngameRespawn(&players[p]);
|
||||
}
|
||||
}
|
||||
if (extradata & DXD_SKIN)
|
||||
{
|
||||
|
|
@ -6945,7 +6959,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
|
|||
(void)extrainfo_p;
|
||||
sprintf(pdemo->winnername, "transrights420");
|
||||
pdemo->winnerskin = 1;
|
||||
pdemo->winnercolor = SKINCOLOR_MOONSLAM;
|
||||
pdemo->winnercolor = SKINCOLOR_MOONSET;
|
||||
pdemo->winnertime = 6666;*/
|
||||
|
||||
// Read standings!
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "../st_stuff.h"
|
||||
#include "../i_system.h"
|
||||
#include "../m_cheat.h"
|
||||
#include "../r_things.h" // R_GetShadowZ
|
||||
#ifdef ESLOPE
|
||||
#include "../p_slopes.h"
|
||||
#endif
|
||||
|
|
@ -3563,6 +3564,9 @@ static void HWR_Subsector(size_t num)
|
|||
|
||||
sub->sector->extra_colormap = gr_frontsector->extra_colormap;
|
||||
|
||||
//R_PlaneLightOverride(gr_frontsector, false, &floorlightlevel);
|
||||
//R_PlaneLightOverride(gr_frontsector, true, &ceilinglightlevel);
|
||||
|
||||
// render floor ?
|
||||
#ifdef DOPLANES
|
||||
// yeah, easy backface cull! :)
|
||||
|
|
@ -4058,37 +4062,6 @@ static gr_vissprite_t *HWR_NewVisSprite(void)
|
|||
return HWR_GetVisSprite(gr_visspritecount++);
|
||||
}
|
||||
|
||||
// Finds a floor through which light does not pass.
|
||||
static fixed_t HWR_OpaqueFloorAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
|
||||
{
|
||||
const sector_t *sec = R_PointInSubsector(x, y)->sector;
|
||||
fixed_t floorz = sec->floorheight;
|
||||
|
||||
if (sec->ffloors)
|
||||
{
|
||||
ffloor_t *rover;
|
||||
fixed_t delta1, delta2;
|
||||
const fixed_t thingtop = z + height;
|
||||
|
||||
for (rover = sec->ffloors; rover; rover = rover->next)
|
||||
{
|
||||
if (!(rover->flags & FF_EXISTS)
|
||||
|| !(rover->flags & FF_RENDERPLANES)
|
||||
|| rover->flags & FF_TRANSLUCENT
|
||||
|| rover->flags & FF_FOG
|
||||
|| rover->flags & FF_INVERTPLANES)
|
||||
continue;
|
||||
|
||||
delta1 = z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
|
||||
delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
|
||||
if (*rover->topheight > floorz && abs(delta1) < abs(delta2))
|
||||
floorz = *rover->topheight;
|
||||
}
|
||||
}
|
||||
|
||||
return floorz;
|
||||
}
|
||||
|
||||
//
|
||||
// HWR_DoCulling
|
||||
// Hardware version of R_DoCulling
|
||||
|
|
@ -4129,185 +4102,116 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v
|
|||
return false;
|
||||
}
|
||||
|
||||
static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float this_scale)
|
||||
static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
|
||||
{
|
||||
FOutVector swallVerts[4];
|
||||
GLPatch_t *gpatch;
|
||||
FOutVector shadowVerts[4];
|
||||
FSurfaceInfo sSurf;
|
||||
fixed_t floorheight, mobjfloor;
|
||||
float offset = 0;
|
||||
float fscale; float fx; float fy; float offset;
|
||||
UINT8 lightlevel = 0;
|
||||
extracolormap_t *colormap = NULL;
|
||||
UINT8 i;
|
||||
|
||||
mobjfloor = HWR_OpaqueFloorAtPos(
|
||||
spr->mobj->x, spr->mobj->y,
|
||||
spr->mobj->z, spr->mobj->height);
|
||||
if (cv_shadowoffs.value)
|
||||
INT32 light;
|
||||
fixed_t scalemul;
|
||||
UINT16 alpha;
|
||||
fixed_t floordiff;
|
||||
fixed_t floorz;
|
||||
fixed_t slopez;
|
||||
pslope_t *floorslope;
|
||||
|
||||
floorz = R_GetShadowZ(thing, &floorslope);
|
||||
floordiff = abs(thing->z - floorz);
|
||||
|
||||
alpha = floordiff / (4*FRACUNIT) + 75;
|
||||
if (alpha >= 255) return;
|
||||
alpha = 255 - alpha;
|
||||
|
||||
if (thing->whiteshadow)
|
||||
{
|
||||
angle_t shadowdir;
|
||||
|
||||
// Set direction
|
||||
if (splitscreen && stplyr == &players[displayplayers[1]])
|
||||
shadowdir = localangle[1] + FixedAngle(cv_cam2_rotate.value);
|
||||
else if (splitscreen > 1 && stplyr == &players[displayplayers[2]])
|
||||
shadowdir = localangle[2] + FixedAngle(cv_cam3_rotate.value);
|
||||
else if (splitscreen > 2 && stplyr == &players[displayplayers[3]])
|
||||
shadowdir = localangle[3] + FixedAngle(cv_cam4_rotate.value);
|
||||
else
|
||||
shadowdir = localangle[0] + FixedAngle(cv_cam_rotate.value);
|
||||
|
||||
// Find floorheight
|
||||
floorheight = HWR_OpaqueFloorAtPos(
|
||||
spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - mobjfloor),
|
||||
spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - mobjfloor),
|
||||
spr->mobj->z, spr->mobj->height);
|
||||
|
||||
// The shadow is falling ABOVE it's mobj?
|
||||
// Don't draw it, then!
|
||||
if (spr->mobj->z < floorheight)
|
||||
return;
|
||||
else
|
||||
{
|
||||
fixed_t floorz;
|
||||
floorz = HWR_OpaqueFloorAtPos(
|
||||
spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - floorheight),
|
||||
spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - floorheight),
|
||||
spr->mobj->z, spr->mobj->height);
|
||||
// The shadow would be falling on a wall? Don't draw it, then.
|
||||
// Would draw midair otherwise.
|
||||
if (floorz < floorheight)
|
||||
return;
|
||||
}
|
||||
|
||||
floorheight = FixedInt(spr->mobj->z - floorheight);
|
||||
|
||||
offset = floorheight;
|
||||
gpatch = (GLPatch_t *)W_CachePatchName("LSHADOW", PU_CACHE);
|
||||
lightlevel = 255;
|
||||
}
|
||||
else
|
||||
floorheight = FixedInt(spr->mobj->z - mobjfloor);
|
||||
{
|
||||
gpatch = (GLPatch_t *)W_CachePatchName("DSHADOW", PU_CACHE);
|
||||
lightlevel = 0;
|
||||
}
|
||||
|
||||
if (!(gpatch && gpatch->mipmap.grInfo.format)) return;
|
||||
HWR_GetPatch(gpatch);
|
||||
|
||||
scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
|
||||
scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height);
|
||||
|
||||
fscale = FIXED_TO_FLOAT(scalemul);
|
||||
fx = FIXED_TO_FLOAT(thing->x);
|
||||
fy = FIXED_TO_FLOAT(thing->y);
|
||||
|
||||
// create the sprite billboard
|
||||
//
|
||||
// 3--2
|
||||
// | /|
|
||||
// |/ |
|
||||
// 0--1
|
||||
|
||||
// x1/x2 were already scaled in HWR_ProjectSprite
|
||||
// First match the normal sprite
|
||||
swallVerts[0].x = swallVerts[3].x = spr->x1;
|
||||
swallVerts[2].x = swallVerts[1].x = spr->x2;
|
||||
swallVerts[0].z = swallVerts[3].z = spr->z1;
|
||||
swallVerts[2].z = swallVerts[1].z = spr->z2;
|
||||
|
||||
if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f)
|
||||
{
|
||||
// Always a pixel above the floor, perfectly flat.
|
||||
swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset * this_scale - (floorheight+3);
|
||||
|
||||
// Now transform the TOP vertices along the floor in the direction of the camera
|
||||
swallVerts[3].x = spr->x1 + ((gpatch->height * this_scale) + offset) * gr_viewcos;
|
||||
swallVerts[2].x = spr->x2 + ((gpatch->height * this_scale) + offset) * gr_viewcos;
|
||||
swallVerts[3].z = spr->z1 + ((gpatch->height * this_scale) + offset) * gr_viewsin;
|
||||
swallVerts[2].z = spr->z2 + ((gpatch->height * this_scale) + offset) * gr_viewsin;
|
||||
}
|
||||
if (thing && fabsf(fscale - 1.0f) > 1.0E-36f)
|
||||
offset = (gpatch->height/2) * fscale;
|
||||
else
|
||||
{
|
||||
// Always a pixel above the floor, perfectly flat.
|
||||
swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset - (floorheight+3);
|
||||
offset = (float)(gpatch->height/2);
|
||||
|
||||
// Now transform the TOP vertices along the floor in the direction of the camera
|
||||
swallVerts[3].x = spr->x1 + (gpatch->height + offset) * gr_viewcos;
|
||||
swallVerts[2].x = spr->x2 + (gpatch->height + offset) * gr_viewcos;
|
||||
swallVerts[3].z = spr->z1 + (gpatch->height + offset) * gr_viewsin;
|
||||
swallVerts[2].z = spr->z2 + (gpatch->height + offset) * gr_viewsin;
|
||||
shadowVerts[2].x = shadowVerts[3].x = fx + offset;
|
||||
shadowVerts[1].x = shadowVerts[0].x = fx - offset;
|
||||
shadowVerts[1].z = shadowVerts[2].z = fy - offset;
|
||||
shadowVerts[0].z = shadowVerts[3].z = fy + offset;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
float oldx = shadowVerts[i].x;
|
||||
float oldy = shadowVerts[i].z;
|
||||
shadowVerts[i].x = fx + ((oldx - fx) * gr_viewcos) - ((oldy - fy) * gr_viewsin);
|
||||
shadowVerts[i].z = fy + ((oldx - fx) * gr_viewsin) + ((oldy - fy) * gr_viewcos);
|
||||
}
|
||||
|
||||
// We also need to move the bottom ones away when shadowoffs is on
|
||||
if (cv_shadowoffs.value)
|
||||
if (floorslope)
|
||||
{
|
||||
swallVerts[0].x = spr->x1 + offset * gr_viewcos;
|
||||
swallVerts[1].x = spr->x2 + offset * gr_viewcos;
|
||||
swallVerts[0].z = spr->z1 + offset * gr_viewsin;
|
||||
swallVerts[1].z = spr->z2 + offset * gr_viewsin;
|
||||
}
|
||||
|
||||
if (spr->flip)
|
||||
{
|
||||
swallVerts[0].sow = swallVerts[3].sow = gpatch->max_s;
|
||||
swallVerts[2].sow = swallVerts[1].sow = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
swallVerts[0].sow = swallVerts[3].sow = 0;
|
||||
swallVerts[2].sow = swallVerts[1].sow = gpatch->max_s;
|
||||
}
|
||||
|
||||
// flip the texture coords (look familiar?)
|
||||
if (spr->vflip)
|
||||
{
|
||||
swallVerts[3].tow = swallVerts[2].tow = gpatch->max_t;
|
||||
swallVerts[0].tow = swallVerts[1].tow = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
swallVerts[3].tow = swallVerts[2].tow = 0;
|
||||
swallVerts[0].tow = swallVerts[1].tow = gpatch->max_t;
|
||||
}
|
||||
|
||||
sSurf.FlatColor.s.red = 0x00;
|
||||
sSurf.FlatColor.s.blue = 0x00;
|
||||
sSurf.FlatColor.s.green = 0x00;
|
||||
|
||||
/*if (spr->mobj->frame & FF_TRANSMASK || spr->mobj->flags2 & MF2_SHADOW)
|
||||
{
|
||||
sector_t *sector = spr->mobj->subsector->sector;
|
||||
UINT8 lightlevel = 255;
|
||||
extracolormap_t *colormap = sector->extra_colormap;
|
||||
|
||||
if (sector->numlights)
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
INT32 light = R_GetPlaneLight(sector, spr->mobj->floorz, false);
|
||||
|
||||
if (!(spr->mobj->frame & FF_FULLBRIGHT))
|
||||
{
|
||||
lightlevel = *sector->lightlist[light].lightlevel;
|
||||
if (spr->mobj->frame & FF_SEMIBRIGHT)
|
||||
lightlevel = 128 + (lightlevel>>1);
|
||||
}
|
||||
|
||||
if (sector->lightlist[light].extra_colormap)
|
||||
colormap = sector->lightlist[light].extra_colormap;
|
||||
slopez = P_GetZAt(floorslope, FLOAT_TO_FIXED(shadowVerts[i].x), FLOAT_TO_FIXED(shadowVerts[i].z));
|
||||
shadowVerts[i].y = FIXED_TO_FLOAT(slopez) + 0.05f;
|
||||
}
|
||||
else
|
||||
{
|
||||
lightlevel = sector->lightlevel;
|
||||
|
||||
if (sector->extra_colormap)
|
||||
colormap = sector->extra_colormap;
|
||||
}
|
||||
|
||||
if (colormap)
|
||||
sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, colormap->rgba, colormap->fadergba, false, true);
|
||||
else
|
||||
sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, NORMALFOG, FADEFOG, false, true);
|
||||
}*/
|
||||
|
||||
// shadow is always half as translucent as the sprite itself
|
||||
if (!cv_translucency.value) // use default translucency (main sprite won't have any translucency)
|
||||
sSurf.FlatColor.s.alpha = 0x80; // default
|
||||
else if (spr->mobj->flags2 & MF2_SHADOW)
|
||||
sSurf.FlatColor.s.alpha = 0x20;
|
||||
else if (spr->mobj->frame & FF_TRANSMASK)
|
||||
{
|
||||
HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &sSurf);
|
||||
sSurf.FlatColor.s.alpha /= 2; //cut alpha in half!
|
||||
}
|
||||
else
|
||||
sSurf.FlatColor.s.alpha = 0x80; // default
|
||||
|
||||
if (sSurf.FlatColor.s.alpha > floorheight/4)
|
||||
{
|
||||
sSurf.FlatColor.s.alpha = (UINT8)(sSurf.FlatColor.s.alpha - floorheight/4);
|
||||
HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated|PF_Clip);
|
||||
for (i = 0; i < 4; i++)
|
||||
shadowVerts[i].y = FIXED_TO_FLOAT(floorz) + 0.05f;
|
||||
}
|
||||
|
||||
shadowVerts[0].sow = shadowVerts[3].sow = 0;
|
||||
shadowVerts[2].sow = shadowVerts[1].sow = gpatch->max_s;
|
||||
|
||||
shadowVerts[3].tow = shadowVerts[2].tow = 0;
|
||||
shadowVerts[0].tow = shadowVerts[1].tow = gpatch->max_t;
|
||||
|
||||
if (thing->subsector->sector->numlights)
|
||||
{
|
||||
light = R_GetPlaneLight(thing->subsector->sector, floorz, false); // Always use the light at the top instead of whatever I was doing before
|
||||
|
||||
if (thing->subsector->sector->lightlist[light].extra_colormap)
|
||||
colormap = thing->subsector->sector->lightlist[light].extra_colormap;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (thing->subsector->sector->extra_colormap)
|
||||
colormap = thing->subsector->sector->extra_colormap;
|
||||
}
|
||||
|
||||
if (colormap)
|
||||
sSurf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
|
||||
else
|
||||
sSurf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
|
||||
|
||||
sSurf.FlatColor.s.alpha = alpha;
|
||||
|
||||
HWD.pfnDrawPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated|PF_Clip);
|
||||
}
|
||||
|
||||
// This is expecting a pointer to an array containing 4 wallVerts for a sprite
|
||||
|
|
@ -4384,22 +4288,6 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
|
|||
//Hurdler: 25/04/2000: now support colormap in hardware mode
|
||||
HWR_GetMappedPatch(gpatch, spr->colormap);
|
||||
|
||||
// Draw shadow BEFORE sprite
|
||||
if (cv_shadow.value // Shadows enabled
|
||||
&& (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow.
|
||||
&& !(spr->mobj->flags2 & MF2_DEBRIS) // Debris have no corona or shadow.
|
||||
#ifdef ALAM_LIGHTING
|
||||
&& !(t_lspr[spr->mobj->sprite]->type // Things with dynamic lights have no shadow.
|
||||
&& (!spr->mobj->player || spr->mobj->player->powers[pw_super])) // Except for non-super players.
|
||||
#endif
|
||||
&& (spr->mobj->z >= spr->mobj->floorz)) // Without this, your shadow shows on the floor, even after you die and fall through the ground.
|
||||
{
|
||||
////////////////////
|
||||
// SHADOW SPRITE! //
|
||||
////////////////////
|
||||
HWR_DrawSpriteShadow(spr, gpatch, this_scale);
|
||||
}
|
||||
|
||||
baseWallVerts[0].x = baseWallVerts[3].x = spr->x1;
|
||||
baseWallVerts[2].x = baseWallVerts[1].x = spr->x2;
|
||||
baseWallVerts[0].z = baseWallVerts[3].z = spr->z1;
|
||||
|
|
@ -4802,22 +4690,6 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
|
|||
//Hurdler: 25/04/2000: now support colormap in hardware mode
|
||||
HWR_GetMappedPatch(gpatch, spr->colormap);
|
||||
|
||||
// Draw shadow BEFORE sprite
|
||||
if (cv_shadow.value // Shadows enabled
|
||||
&& (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow.
|
||||
&& !(spr->mobj->flags2 & MF2_DEBRIS) // Debris have no corona or shadow.
|
||||
#ifdef ALAM_LIGHTING
|
||||
&& !(t_lspr[spr->mobj->sprite]->type // Things with dynamic lights have no shadow.
|
||||
&& (!spr->mobj->player || spr->mobj->player->powers[pw_super])) // Except for non-super players.
|
||||
#endif
|
||||
&& (spr->mobj->z >= spr->mobj->floorz)) // Without this, your shadow shows on the floor, even after you die and fall through the ground.
|
||||
{
|
||||
////////////////////
|
||||
// SHADOW SPRITE! //
|
||||
////////////////////
|
||||
HWR_DrawSpriteShadow(spr, gpatch, this_scale);
|
||||
}
|
||||
|
||||
// if it has a dispoffset, push it a little towards the camera
|
||||
if (spr->dispoffset) {
|
||||
float co = -gr_viewcos*(0.05f*spr->dispoffset);
|
||||
|
|
@ -5430,6 +5302,12 @@ static void HWR_DrawSprites(void)
|
|||
HWR_DrawPrecipitationSprite(spr);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (spr->mobj && spr->mobj->shadowscale && cv_shadow.value)
|
||||
{
|
||||
HWR_DrawDropShadow(spr->mobj, spr->mobj->shadowscale);
|
||||
}
|
||||
|
||||
if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
|
||||
{
|
||||
// 8/1/19: Only don't display player models if no default SPR_PLAY is found.
|
||||
|
|
@ -5445,6 +5323,7 @@ static void HWR_DrawSprites(void)
|
|||
else
|
||||
HWR_DrawMD2(spr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5478,7 +5357,7 @@ static void HWR_AddSprites(sector_t *sec)
|
|||
|
||||
// Handle all things in sector.
|
||||
// If a limit exists, handle things a tiny bit different.
|
||||
if ((limit_dist = (fixed_t)(/*(maptol & TOL_NIGHTS) ? cv_drawdist_nights.value : */cv_drawdist.value) << FRACBITS))
|
||||
if ((limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale))
|
||||
{
|
||||
for (thing = sec->thinglist; thing; thing = thing->snext)
|
||||
{
|
||||
|
|
@ -5545,7 +5424,7 @@ static void HWR_AddSprites(sector_t *sec)
|
|||
|
||||
#ifdef HWPRECIP
|
||||
// No to infinite precipitation draw distance.
|
||||
if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS))
|
||||
if ((limit_dist = (fixed_t)(cv_drawdist_precip.value) * mapobjectscale))
|
||||
{
|
||||
for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
|
||||
{
|
||||
|
|
@ -5882,10 +5761,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
|
|||
// okay, we can't return now... this is a hack, but weather isn't networked, so it should be ok
|
||||
if (!(thing->precipflags & PCF_THUNK))
|
||||
{
|
||||
if (thing->precipflags & PCF_RAIN)
|
||||
P_RainThinker(thing);
|
||||
else
|
||||
P_SnowThinker(thing);
|
||||
P_PrecipThinker(thing);
|
||||
thing->precipflags |= PCF_THUNK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -812,7 +812,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
case SKINCOLOR_PINK:
|
||||
case SKINCOLOR_ROSE:
|
||||
case SKINCOLOR_LEMONADE:
|
||||
case SKINCOLOR_BUBBLEGUM:
|
||||
case SKINCOLOR_LILAC:
|
||||
case SKINCOLOR_TAFFY:
|
||||
cstart = "\x8d"; // V_PINKMAP
|
||||
|
|
@ -828,7 +827,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
cstart = "\x85"; // V_REDMAP
|
||||
break;
|
||||
case SKINCOLOR_DAWN:
|
||||
case SKINCOLOR_SUNSET:
|
||||
case SKINCOLOR_SUNSLAM:
|
||||
case SKINCOLOR_CREAMSICLE:
|
||||
case SKINCOLOR_ORANGE:
|
||||
case SKINCOLOR_ROSEWOOD:
|
||||
|
|
@ -906,7 +905,8 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
|
|||
break;
|
||||
case SKINCOLOR_MAGENTA:
|
||||
case SKINCOLOR_FUCHSIA:
|
||||
case SKINCOLOR_MOONSLAM:
|
||||
case SKINCOLOR_MOONSET:
|
||||
case SKINCOLOR_VIOLET:
|
||||
cstart = "\x8c"; // V_MAGENTAMAP
|
||||
break;
|
||||
case SKINCOLOR_DUSK:
|
||||
|
|
|
|||
232
src/info.c
232
src/info.c
|
|
@ -44,23 +44,23 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"BSZ7","BSZ8","STLG","DBAL","RCRY","ARMA","ARMF","ARMB","WIND","MAGN",
|
||||
"ELEM","FORC","PITY","IVSP","SSPK","GOAL","BIRD","BUNY","MOUS","CHIC",
|
||||
"COWZ","RBRD","SPVY","SPVR","SPVB","SPVG","SPDY","SPDR","SPDB","SPDG",
|
||||
"SPHY","SPHR","SPHB","SPHG","RAIN","SNO1","SPLH","SPLA","SMOK","BUBP",
|
||||
"BUBO","BUBN","BUBM","POPP","TFOG","SEED","PRTL","SCOR","DRWN","TTAG",
|
||||
"GFLG","RRNG","RNGB","RNGR","RNGI","RNGA","RNGE","RNGS","RNGG","PIKB",
|
||||
"PIKR","PIKA","PIKE","PIKS","PIKG","TAUT","TGRE","TSCR","COIN","CPRK",
|
||||
"GOOM","BGOM","FFWR","FBLL","SHLL","PUMA","HAMM","KOOP","BFLM","MAXE",
|
||||
"MUS1","MUS2","TOAD","NDRN","SUPE","SUPZ","NDRL","NSPK","NBMP","HOOP",
|
||||
"NSCR","NPRU","CAPS","SUPT","SPRK","BOM1","BOM2","BOM3","BOM4","ROIA",
|
||||
"ROIB","ROIC","ROID","ROIE","ROIF","ROIG","ROIH","ROII","ROIJ","ROIK",
|
||||
"ROIL","ROIM","ROIN","ROIO","ROIP","BBAL","GWLG","GWLR","SRBA","SRBB",
|
||||
"SRBC","SRBD","SRBE","SRBF","SRBG","SRBH","SRBI","SRBJ","SRBK","SRBL",
|
||||
"SRBM","SRBN","SRBO",
|
||||
"SPHY","SPHR","SPHB","SPHG","RAIN","SNO1","SNO2","SPLH","SPLA","SMOK",
|
||||
"BUBP","BUBO","BUBN","BUBM","POPP","TFOG","SEED","PRTL","SCOR","DRWN",
|
||||
"TTAG","GFLG","RRNG","RNGB","RNGR","RNGI","RNGA","RNGE","RNGS","RNGG",
|
||||
"PIKB","PIKR","PIKA","PIKE","PIKS","PIKG","TAUT","TGRE","TSCR","COIN",
|
||||
"CPRK","GOOM","BGOM","FFWR","FBLL","SHLL","PUMA","HAMM","KOOP","BFLM",
|
||||
"MAXE","MUS1","MUS2","TOAD","NDRN","SUPE","SUPZ","NDRL","NSPK","NBMP",
|
||||
"HOOP","NSCR","NPRU","CAPS","SUPT","SPRK","BOM1","BOM2","BOM3","BOM4",
|
||||
"ROIA","ROIB","ROIC","ROID","ROIE","ROIF","ROIG","ROIH","ROII","ROIJ",
|
||||
"ROIK","ROIL","ROIM","ROIN","ROIO","ROIP","BBAL","GWLG","GWLR","SRBA",
|
||||
"SRBB","SRBC","SRBD","SRBE","SRBF","SRBG","SRBH","SRBI","SRBJ","SRBK",
|
||||
"SRBL","SRBM","SRBN","SRBO",
|
||||
//SRB2kart Sprites
|
||||
"RNDM","RPOP","SGNS","FAST","DSHR","BOST","BOSM","KFRE","KINV","KINF",
|
||||
"WIPD","DRIF","BDRF","DUST","RSHE","FITM","BANA","ORBN","JAWZ","SSMN",
|
||||
"KRBM","BHOG","BHBM","SPBM","THNS","SINK","SITR","KBLN","DEZL","POKE",
|
||||
"AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM","SACO","CRAB",
|
||||
"SHAD","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB","ARRO","ITEM",
|
||||
"WIPD","DRIF","BDRF","DUST","DRWS","RSHE","FITM","BANA","ORBN","JAWZ",
|
||||
"SSMN","KRBM","BHOG","BHBM","SPBM","THNS","SINK","SITR","KBLN","DEZL",
|
||||
"POKE","AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM","SACO",
|
||||
"CRAB","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB","ARRO","ITEM",
|
||||
"ITMO","ITMI","ITMN","WANT","PBOM","HIT1","HIT2","HIT3","RETI","AIDU",
|
||||
"KSPK","LZI1","LZI2","KLIT","FZSM","FZBM","FPRT","SBUS","MARB","FUFO",
|
||||
"RUST","BLON","VAPE","HTZA","HTZB","SGVA","SGVB","SGVC","PGTR","PGF1",
|
||||
|
|
@ -70,7 +70,7 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS","ZTCH","MKMA","MKMP",
|
||||
"RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH","BFRT","OFRT","RFRT",
|
||||
"PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN","FWRK","MXCL","RGSP",
|
||||
"DRAF","GRES","OTFG","XMS4","XMS5","VIEW"
|
||||
"DRAF","GRES","OTFG","DBOS","XMS4","XMS5","VIEW"
|
||||
};
|
||||
|
||||
// Doesn't work with g++, needs actionf_p1 (don't modify this comment)
|
||||
|
|
@ -193,7 +193,7 @@ state_t states[NUMSTATES] =
|
|||
{SPR_NULL, 0, 18, {NULL}, 0, 4, S_NULL}, // S_PLAY_ICON3
|
||||
|
||||
// Level end sign (uses player sprite)
|
||||
{SPR_PLAY, 18, 1, {NULL}, 0, 24, S_PLAY_SIGN}, // S_PLAY_SIGN S
|
||||
{SPR_PLAY, 18|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_PLAY_SIGN}, // S_PLAY_SIGN
|
||||
|
||||
// Blue Crawla
|
||||
{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND}, // S_POSS_STND
|
||||
|
|
@ -1063,27 +1063,10 @@ state_t states[NUMSTATES] =
|
|||
{SPR_BUBL, 1, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES1}, // S_BUBBLES2
|
||||
|
||||
// Level End Sign
|
||||
{SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN2}, // S_SIGN1
|
||||
{SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN3}, // S_SIGN2
|
||||
{SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN4}, // S_SIGN3
|
||||
{SPR_SIGN, 3, 1, {NULL}, 0, 0, S_SIGN5}, // S_SIGN4
|
||||
{SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN6}, // S_SIGN5
|
||||
{SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN7}, // S_SIGN6
|
||||
{SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN8}, // S_SIGN7
|
||||
{SPR_SIGN, 4, 1, {NULL}, 0, 0, S_SIGN9}, // S_SIGN8
|
||||
{SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN10}, // S_SIGN9
|
||||
{SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN11}, // S_SIGN10
|
||||
{SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN12}, // S_SIGN11
|
||||
{SPR_SIGN, 5, 1, {NULL}, 0, 0, S_SIGN13}, // S_SIGN12
|
||||
{SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN14}, // S_SIGN13
|
||||
{SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN15}, // S_SIGN14
|
||||
{SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN16}, // S_SIGN15
|
||||
{SPR_SIGN, 6, 1, {NULL}, 0, 0, S_SIGN17}, // S_SIGN16
|
||||
{SPR_SIGN, 0, 1, {NULL}, 0, 0, S_SIGN18}, // S_SIGN17
|
||||
{SPR_SIGN, 1, 1, {NULL}, 0, 0, S_SIGN19}, // S_SIGN18
|
||||
{SPR_SIGN, 2, 1, {NULL}, 0, 0, S_SIGN20}, // S_SIGN19
|
||||
{SPR_SIGN, 7, 1, {NULL}, 0, 0, S_SIGN1}, // S_SIGN20
|
||||
{SPR_SIGN, 8, -1, {A_SignPlayer}, 0, 0, S_NULL}, // S_SIGN_END
|
||||
{SPR_SIGN, 0, -1, {NULL}, 0, 0, S_SIGN_POLE}, // S_SIGN_POLE
|
||||
{SPR_SIGN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_SIGN_BACK}, // S_SIGN_BACK
|
||||
{SPR_SIGN, 2|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_SIGN_SIDE}, // S_SIGN_SIDE
|
||||
{SPR_SIGN, 3|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_SIGN_FACE}, // S_SIGN_FACE
|
||||
|
||||
// Steam Riser
|
||||
{SPR_STEM, 0, 2, {A_SetSolidSteam}, 0, 0, S_STEAM2}, // S_STEAM1
|
||||
|
|
@ -1868,14 +1851,19 @@ state_t states[NUMSTATES] =
|
|||
{SPR_SPHG, 2, 4, {NULL}, 0, 0, S_GHORIZ1}, // S_GHORIZ4
|
||||
|
||||
// Rain
|
||||
{SPR_RAIN, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1
|
||||
{SPR_RAIN, FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN
|
||||
{SPR_RAIN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1
|
||||
{SPR_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_RAINRETURN
|
||||
|
||||
// Snowflake
|
||||
{SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW1
|
||||
{SPR_SNO1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW2
|
||||
{SPR_SNO1, 2, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW3
|
||||
|
||||
// Blizzard Snowball
|
||||
{SPR_SNO2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLIZZARDSNOW1
|
||||
{SPR_SNO2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BLIZZARDSNOW2
|
||||
{SPR_SNO2, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BLIZZARDSNOW3
|
||||
|
||||
// Water Splish
|
||||
{SPR_SPLH, FF_TRANS50 , 2, {NULL}, 0, 0, S_SPLISH2}, // S_SPLISH1
|
||||
{SPR_SPLH, FF_TRANS50|1, 2, {NULL}, 0, 0, S_SPLISH3}, // S_SPLISH2
|
||||
|
|
@ -1888,9 +1876,9 @@ state_t states[NUMSTATES] =
|
|||
{SPR_SPLH, FF_TRANS50|8, 2, {NULL}, 0, 0, S_NULL}, // S_SPLISH9
|
||||
|
||||
// Water Splash
|
||||
{SPR_SPLA, FF_TRANS50 , 3, {NULL}, 0, 0, S_SPLASH2}, // S_SPLASH1
|
||||
{SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3}, // S_SPLASH2
|
||||
{SPR_SPLA, FF_TRANS90|2, 3, {NULL}, 0, 0, S_RAINRETURN}, // S_SPLASH3
|
||||
{SPR_SPLA, 0, 3, {NULL}, 0, 0, S_SPLASH2}, // S_SPLASH1
|
||||
{SPR_SPLA, 1, 3, {NULL}, 0, 0, S_SPLASH3}, // S_SPLASH2
|
||||
{SPR_SPLA, 2, 3, {NULL}, 0, 0, S_NULL}, // S_SPLASH3
|
||||
|
||||
// Smoke
|
||||
{SPR_SMOK, FF_TRANS50 , 4, {NULL}, 0, 0, S_SMOKE2}, // S_SMOKE1
|
||||
|
|
@ -2599,6 +2587,9 @@ state_t states[NUMSTATES] =
|
|||
{SPR_DRIF, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_DRIFTSPARK_C2}, // S_DRIFTSPARK_C1
|
||||
{SPR_DRIF, FF_FULLBRIGHT|FF_TRANS20, 1, {NULL}, 0, 0, S_DRIFTSPARK_A3}, // S_DRIFTSPARK_C2 (Loop back to A3)
|
||||
|
||||
{SPR_DRIF, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_DRIFTSPARK_D2}, // S_DRIFTSPARK_D1
|
||||
{SPR_DRIF, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_DRIFTSPARK_A2}, // S_DRIFTSPARK_D2 (Loop back to A2)
|
||||
|
||||
{SPR_BDRF, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 5, 2, S_BRAKEDRIFT}, // S_BRAKEDRIFT
|
||||
|
||||
{SPR_DUST, 0, 3, {NULL}, 0, 0, S_DRIFTDUST2}, // S_DRIFTDUST1
|
||||
|
|
@ -2606,6 +2597,11 @@ state_t states[NUMSTATES] =
|
|||
{SPR_DUST, FF_TRANS20|2, 3, {NULL}, 0, 0, S_DRIFTDUST4}, // S_DRIFTDUST3
|
||||
{SPR_DUST, FF_TRANS20|3, 3, {NULL}, 0, 0, S_NULL}, // S_DRIFTDUST4
|
||||
|
||||
{SPR_DRWS, FF_FULLBRIGHT|0, 3, {NULL}, 0, 0, S_DRIFTWARNSPARK2}, // S_DRIFTWARNSPARK1
|
||||
{SPR_DRWS, FF_FULLBRIGHT|1, 3, {NULL}, 0, 0, S_DRIFTWARNSPARK3}, // S_DRIFTWARNSPARK2
|
||||
{SPR_DRWS, FF_FULLBRIGHT|FF_TRANS20|2, 3, {NULL}, 0, 0, S_DRIFTWARNSPARK4}, // S_DRIFTWARNSPARK3
|
||||
{SPR_DRWS, FF_FULLBRIGHT|FF_TRANS20|3, 3, {NULL}, 0, 0, S_NULL}, // S_DRIFTWARNSPARK4
|
||||
|
||||
{SPR_FAST, FF_PAPERSPRITE|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_FASTLINE2}, // S_FASTLINE1
|
||||
{SPR_FAST, FF_PAPERSPRITE|FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_FASTLINE3}, // S_FASTLINE2
|
||||
{SPR_FAST, FF_PAPERSPRITE|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_FASTLINE4}, // S_FASTLINE3
|
||||
|
|
@ -2620,6 +2616,11 @@ state_t states[NUMSTATES] =
|
|||
{SPR_DSHR, FF_PAPERSPRITE|5, 1, {NULL}, 0, 0, S_FASTDUST7}, // S_FASTDUST6
|
||||
{SPR_DSHR, FF_PAPERSPRITE|6, 1, {NULL}, 0, 0, S_NULL}, // S_FASTDUST7
|
||||
|
||||
{SPR_DBOS, FF_FULLBRIGHT, 2, {NULL}, 6, 1, S_DRIFTEXPLODE2}, // S_DRIFTEXPLODE1
|
||||
{SPR_DBOS, FF_FULLBRIGHT|1, 2, {NULL}, 6, 1, S_DRIFTEXPLODE3}, // S_DRIFTEXPLODE2
|
||||
{SPR_DBOS, FF_FULLBRIGHT|2, 2, {NULL}, 6, 1, S_DRIFTEXPLODE4}, // S_DRIFTEXPLODE3
|
||||
{SPR_DBOS, FF_FULLBRIGHT|3, 2, {NULL}, 6, 1, S_DRIFTEXPLODE1}, // S_DRIFTEXPLODE4
|
||||
|
||||
{SPR_BOST, FF_FULLBRIGHT|FF_ANIMATE, TICRATE, {NULL}, 6, 1, S_BOOSTSMOKESPAWNER}, // S_BOOSTFLAME
|
||||
{SPR_NULL, 0, TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_BOOSTSMOKESPAWNER
|
||||
|
||||
|
|
@ -2875,7 +2876,12 @@ state_t states[NUMSTATES] =
|
|||
{SPR_KBLN, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_BATTLEBUMPER2}, // S_BATTLEBUMPER2
|
||||
{SPR_KBLN, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_BATTLEBUMPER3}, // S_BATTLEBUMPER3
|
||||
|
||||
{SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE, 8, {NULL}, 0, 0, S_NULL}, // S_DEZLASER
|
||||
{SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE, 8, {NULL}, 0, 0, S_NULL}, // S_DEZLASER
|
||||
{SPR_DEZL, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL2}, // S_DEZLASER_TRAIL1
|
||||
{SPR_DEZL, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL3}, // S_DEZLASER_TRAIL2
|
||||
{SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE|3, 4, {NULL}, 0, 0, S_DEZLASER_TRAIL4}, // S_DEZLASER_TRAIL3
|
||||
{SPR_DEZL, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL5}, // S_DEZLASER_TRAIL4
|
||||
{SPR_DEZL, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_NULL}, // S_DEZLASER_TRAIL5
|
||||
|
||||
{SPR_NULL, 0, 1, {A_RandomStateRange}, S_AUDIENCE_CHAO_CHEER1, S_AUDIENCE_CHAO_CHEER2, S_RANDOMAUDIENCE}, // S_RANDOMAUDIENCE
|
||||
|
||||
|
|
@ -2988,10 +2994,6 @@ state_t states[NUMSTATES] =
|
|||
{SPR_CRAB, 10, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST
|
||||
{SPR_CRAB, 11, -1, {NULL}, 0, 0, S_NULL}, // S_MOSSYTREE
|
||||
|
||||
// Fake Shadow
|
||||
{SPR_SHAD, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_SHADOW
|
||||
{SPR_SHAD, FF_FULLBRIGHT|FF_TRANS50|1, -1, {NULL}, 0, 0, S_NULL}, // S_WHITESHADOW
|
||||
|
||||
{SPR_BUMP, FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_BUMP2}, // S_BUMP1
|
||||
{SPR_BUMP, FF_FULLBRIGHT|1, 3, {NULL}, 0, 0, S_BUMP3}, // S_BUMP2
|
||||
{SPR_BUMP, FF_FULLBRIGHT|2, 3, {NULL}, 0, 0, S_NULL}, // S_BUMP3
|
||||
|
|
@ -6441,7 +6443,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
501, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_PLAY_SIGN, // seestate
|
||||
S_NULL, // seestate
|
||||
sfx_s3kb8, // seesound
|
||||
8, // reactiontime
|
||||
sfx_s3k7e, // attacksound
|
||||
|
|
@ -6455,7 +6457,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
sfx_None, // deathsound
|
||||
8, // speed
|
||||
8*FRACUNIT, // radius
|
||||
32*FRACUNIT, // height
|
||||
48*FRACUNIT, // height
|
||||
0, // display offset
|
||||
16, // mass
|
||||
0, // damage
|
||||
|
|
@ -6464,6 +6466,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SIGN_PIECE
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
8, // speed
|
||||
8*FRACUNIT, // radius
|
||||
48*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_NOTHINK|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SPIKEBALL
|
||||
-1, // doomednum
|
||||
S_SPIKEBALL1, // spawnstate
|
||||
|
|
@ -11445,22 +11474,22 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_RAIN1, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_rainin, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_SPLASH1, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
-72*FRACUNIT, // speed -- -24*FRACUNIT originally, srb2kart x3 (nya)
|
||||
1*FRACUNIT, // radius
|
||||
8*FRACUNIT, // height
|
||||
0, // display offset
|
||||
4, // mass
|
||||
80, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP, // flags
|
||||
|
|
@ -11473,7 +11502,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
|
|
@ -11487,8 +11516,35 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
4*FRACUNIT, // radius
|
||||
4*FRACUNIT, // height
|
||||
0, // display offset
|
||||
4, // mass
|
||||
0, // damage
|
||||
0, // mass
|
||||
2, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BLIZZARDSNOW
|
||||
-1, // doomednum
|
||||
S_BLIZZARDSNOW1, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
-24*FRACUNIT, // speed
|
||||
4*FRACUNIT, // radius
|
||||
4*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
2, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP, // flags
|
||||
S_NULL // raisestate
|
||||
|
|
@ -15179,6 +15235,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_DRIFTEXPLODE
|
||||
-1, // doomednum
|
||||
S_DRIFTEXPLODE1, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
8, // speed
|
||||
32*FRACUNIT, // radius
|
||||
64*FRACUNIT, // height
|
||||
1, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BOOSTFLAME
|
||||
-1, // doomednum
|
||||
S_BOOSTFLAME, // spawnstate
|
||||
|
|
@ -15951,7 +16034,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_BALLHOG_DEAD, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_hogbom, // deathsound
|
||||
64*FRACUNIT, // speed
|
||||
80*FRACUNIT, // speed
|
||||
16*FRACUNIT, // radius
|
||||
32*FRACUNIT, // height
|
||||
0, // display offset
|
||||
|
|
@ -16005,7 +16088,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_SPB_DEAD, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_s3k5d, // deathsound
|
||||
64*FRACUNIT, // speed
|
||||
80*FRACUNIT, // speed
|
||||
24*FRACUNIT, // radius
|
||||
48*FRACUNIT, // height
|
||||
0, // display offset
|
||||
|
|
@ -16207,7 +16290,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
|
||||
{ // MT_WAYPOINT
|
||||
2001, // doomednum
|
||||
S_NULL, // spawnstate
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
|
|
@ -16228,7 +16311,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY, // flags
|
||||
MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
@ -17258,33 +17341,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SHADOW
|
||||
-1, // doomednum
|
||||
S_SHADOW, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
60*FRACUNIT, // speed
|
||||
50*FRACUNIT, // radius
|
||||
1*FRACUNIT, // height
|
||||
-1, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BUMP
|
||||
-1, // doomednum
|
||||
S_BUMP1, // spawnstate
|
||||
|
|
|
|||
63
src/info.h
63
src/info.h
|
|
@ -63,7 +63,6 @@ void A_ThrownRing(); // Sparkle trail for red ring
|
|||
void A_GrenadeRing(); // SRB2kart
|
||||
void A_SetSolidSteam();
|
||||
void A_UnsetSolidSteam();
|
||||
void A_SignPlayer();
|
||||
void A_OverlayThink();
|
||||
void A_JetChase();
|
||||
void A_JetbThink(); // Jetty-Syn Bomber Thinker
|
||||
|
|
@ -475,6 +474,7 @@ typedef enum sprite
|
|||
// Environmental Effects
|
||||
SPR_RAIN, // Rain
|
||||
SPR_SNO1, // Snowflake
|
||||
SPR_SNO2, // Blizzard Snowball
|
||||
SPR_SPLH, // Water Splish
|
||||
SPR_SPLA, // Water Splash
|
||||
SPR_SMOK,
|
||||
|
|
@ -608,6 +608,7 @@ typedef enum sprite
|
|||
SPR_DRIF, // Drift Sparks
|
||||
SPR_BDRF, // Brake drift sparks
|
||||
SPR_DUST, // Drift Dust
|
||||
SPR_DRWS, // Drift dust sparks
|
||||
|
||||
// Kart Items
|
||||
SPR_RSHE, // Rocket sneaker
|
||||
|
|
@ -639,7 +640,6 @@ typedef enum sprite
|
|||
SPR_CHOM, // Sapphire Coast Chomper
|
||||
SPR_SACO, // Sapphire Coast Fauna
|
||||
SPR_CRAB, // Crystal Abyss mobs
|
||||
SPR_SHAD, // TD shadows
|
||||
SPR_BRNG, // Chaotix Big Ring
|
||||
|
||||
SPR_BUMP, // Player/shell bump
|
||||
|
|
@ -786,6 +786,8 @@ typedef enum sprite
|
|||
|
||||
SPR_OTFG,
|
||||
|
||||
SPR_DBOS, // Drift boost flame
|
||||
|
||||
// Xmas-specific sprites that don't fit aboxe
|
||||
SPR_XMS4,
|
||||
SPR_XMS5,
|
||||
|
|
@ -1776,27 +1778,10 @@ typedef enum state
|
|||
S_BUBBLES2,
|
||||
|
||||
// Level End Sign
|
||||
S_SIGN1,
|
||||
S_SIGN2,
|
||||
S_SIGN3,
|
||||
S_SIGN4,
|
||||
S_SIGN5,
|
||||
S_SIGN6,
|
||||
S_SIGN7,
|
||||
S_SIGN8,
|
||||
S_SIGN9,
|
||||
S_SIGN10,
|
||||
S_SIGN11,
|
||||
S_SIGN12,
|
||||
S_SIGN13,
|
||||
S_SIGN14,
|
||||
S_SIGN15,
|
||||
S_SIGN16,
|
||||
S_SIGN17,
|
||||
S_SIGN18,
|
||||
S_SIGN19,
|
||||
S_SIGN20,
|
||||
S_SIGN_END,
|
||||
S_SIGN_POLE,
|
||||
S_SIGN_BACK,
|
||||
S_SIGN_SIDE,
|
||||
S_SIGN_FACE,
|
||||
|
||||
// Steam Riser
|
||||
S_STEAM1,
|
||||
|
|
@ -2579,6 +2564,11 @@ typedef enum state
|
|||
S_SNOW2,
|
||||
S_SNOW3,
|
||||
|
||||
// Blizzard Snowball
|
||||
S_BLIZZARDSNOW1,
|
||||
S_BLIZZARDSNOW2,
|
||||
S_BLIZZARDSNOW3,
|
||||
|
||||
// Water Splish
|
||||
S_SPLISH1,
|
||||
S_SPLISH2,
|
||||
|
|
@ -3249,6 +3239,8 @@ typedef enum state
|
|||
S_DRIFTSPARK_B1,
|
||||
S_DRIFTSPARK_C1,
|
||||
S_DRIFTSPARK_C2,
|
||||
S_DRIFTSPARK_D1,
|
||||
S_DRIFTSPARK_D2,
|
||||
|
||||
// Brake drift sparks
|
||||
S_BRAKEDRIFT,
|
||||
|
|
@ -3259,6 +3251,12 @@ typedef enum state
|
|||
S_DRIFTDUST3,
|
||||
S_DRIFTDUST4,
|
||||
|
||||
// Drift Sparkles
|
||||
S_DRIFTWARNSPARK1,
|
||||
S_DRIFTWARNSPARK2,
|
||||
S_DRIFTWARNSPARK3,
|
||||
S_DRIFTWARNSPARK4,
|
||||
|
||||
// Fast lines
|
||||
S_FASTLINE1,
|
||||
S_FASTLINE2,
|
||||
|
|
@ -3275,7 +3273,11 @@ typedef enum state
|
|||
S_FASTDUST6,
|
||||
S_FASTDUST7,
|
||||
|
||||
// Magnet Burst
|
||||
// Drift boost effect
|
||||
S_DRIFTEXPLODE1,
|
||||
S_DRIFTEXPLODE2,
|
||||
S_DRIFTEXPLODE3,
|
||||
S_DRIFTEXPLODE4,
|
||||
|
||||
// Sneaker boost effect
|
||||
S_BOOSTFLAME,
|
||||
|
|
@ -3550,6 +3552,11 @@ typedef enum state
|
|||
|
||||
// DEZ Laser respawn
|
||||
S_DEZLASER,
|
||||
S_DEZLASER_TRAIL1,
|
||||
S_DEZLASER_TRAIL2,
|
||||
S_DEZLASER_TRAIL3,
|
||||
S_DEZLASER_TRAIL4,
|
||||
S_DEZLASER_TRAIL5,
|
||||
|
||||
// Audience Members
|
||||
S_RANDOMAUDIENCE,
|
||||
|
|
@ -3668,9 +3675,6 @@ typedef enum state
|
|||
S_LAMPPOST,
|
||||
S_MOSSYTREE,
|
||||
|
||||
S_SHADOW,
|
||||
S_WHITESHADOW,
|
||||
|
||||
S_BUMP1,
|
||||
S_BUMP2,
|
||||
S_BUMP3,
|
||||
|
|
@ -4291,6 +4295,7 @@ typedef enum mobj_type
|
|||
// Interactive Objects
|
||||
MT_BUBBLES, // Bubble source
|
||||
MT_SIGN, // Level end sign
|
||||
MT_SIGN_PIECE,
|
||||
MT_SPIKEBALL, // Spike Ball
|
||||
MT_SPECIALSPIKEBALL,
|
||||
MT_SPINFIRE,
|
||||
|
|
@ -4517,6 +4522,7 @@ typedef enum mobj_type
|
|||
// Environmental Effects
|
||||
MT_RAIN, // Rain
|
||||
MT_SNOWFLAKE, // Snowflake
|
||||
MT_BLIZZARDSNOW, // Blizzard Snowball
|
||||
MT_SPLISH, // Water splish!
|
||||
MT_SMOKE,
|
||||
MT_SMALLBUBBLE, // small bubble
|
||||
|
|
@ -4676,6 +4682,7 @@ typedef enum mobj_type
|
|||
|
||||
MT_FASTLINE,
|
||||
MT_FASTDUST,
|
||||
MT_DRIFTEXPLODE,
|
||||
MT_BOOSTFLAME,
|
||||
MT_BOOSTSMOKE,
|
||||
MT_SNEAKERTRAIL,
|
||||
|
|
@ -4777,8 +4784,6 @@ typedef enum mobj_type
|
|||
MT_LAMPPOST,
|
||||
MT_MOSSYTREE,
|
||||
|
||||
MT_SHADOW,
|
||||
|
||||
MT_BUMP,
|
||||
|
||||
MT_FLINGENERGY,
|
||||
|
|
|
|||
595
src/k_bheap.c
Normal file
595
src/k_bheap.c
Normal file
|
|
@ -0,0 +1,595 @@
|
|||
// SONIC ROBO BLAST 2 KART
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018-2020 by Sean "Sryder" Ryder
|
||||
// Copyright (C) 2018-2020 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file k_bheap.c
|
||||
/// \brief Binary Heap implementation for SRB2 code base.
|
||||
|
||||
#include "k_bheap.h"
|
||||
|
||||
#include "z_zone.h"
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_BHeapItemValidate(bheap_t *heap, bheapitem_t *item)
|
||||
|
||||
Validates an item on a heap to ensure it is correct and on that heap.
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to validate the item with
|
||||
item - The item to validate
|
||||
|
||||
Return:-
|
||||
True if the item is valid, false if it isn't.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_BHeapItemValidate(bheap_t *heap, bheapitem_t *item)
|
||||
{
|
||||
boolean heapitemvalid = false;
|
||||
|
||||
I_Assert(heap != NULL);
|
||||
I_Assert(item != NULL);
|
||||
|
||||
if ((item->data != NULL) && (item->heapindex < SIZE_MAX / 2) && (item->owner == heap))
|
||||
{
|
||||
heapitemvalid = true;
|
||||
}
|
||||
|
||||
return heapitemvalid;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static bheapitem_t *K_BHeapItemsCompare(bheap_t *heap, bheapitem_t *item1, bheapitem_t *item2)
|
||||
|
||||
Compares 2 items in the heap to find the better (lower) value one.
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to compare items
|
||||
item1 - The first item to compare
|
||||
item2 - The second item to compare
|
||||
|
||||
Return:-
|
||||
The item out of the 2 sent in that has the better value, returns item2 if they are identical
|
||||
--------------------------------------------------*/
|
||||
static bheapitem_t *K_BHeapItemsCompare(bheap_t *heap, bheapitem_t *item1, bheapitem_t *item2)
|
||||
{
|
||||
bheapitem_t *lowervalueitem = NULL;
|
||||
|
||||
I_Assert(heap != NULL);
|
||||
I_Assert(K_BHeapValid(heap));
|
||||
I_Assert(item1 != NULL);
|
||||
I_Assert(item2 != NULL);
|
||||
I_Assert(K_BHeapItemValidate(heap, item1));
|
||||
I_Assert(K_BHeapItemValidate(heap, item2));
|
||||
|
||||
(void)heap;
|
||||
|
||||
if (item1->value < item2->value)
|
||||
{
|
||||
lowervalueitem = item1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lowervalueitem = item2;
|
||||
}
|
||||
|
||||
return lowervalueitem;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_BHeapSwapItems(bheap_t *heap, bheapitem_t *item1, bheapitem_t *item2)
|
||||
|
||||
Swaps 2 items in the heap
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to swap items in
|
||||
item1 - The first item to swap in the heap
|
||||
item2 - The second item to swap in the heap
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
static void K_BHeapSwapItems(bheap_t *heap, bheapitem_t *item1, bheapitem_t *item2)
|
||||
{
|
||||
I_Assert(heap != NULL);
|
||||
I_Assert(K_BHeapValid(heap));
|
||||
I_Assert(item1 != NULL);
|
||||
I_Assert(item2 != NULL);
|
||||
I_Assert(K_BHeapItemValidate(heap, item1));
|
||||
I_Assert(K_BHeapItemValidate(heap, item2));
|
||||
|
||||
(void)heap;
|
||||
|
||||
{
|
||||
size_t tempitemindex = item1->heapindex;
|
||||
bheapitem_t tempitemstore = *item1;
|
||||
|
||||
// Swap the items fully with each other
|
||||
*item1 = *item2;
|
||||
*item2 = tempitemstore;
|
||||
|
||||
// Swap the heap index on each item to be correct
|
||||
item2->heapindex = item1->heapindex;
|
||||
item1->heapindex = tempitemindex;
|
||||
|
||||
if (item1->indexchanged != NULL)
|
||||
{
|
||||
item1->indexchanged(item1->data, item1->heapindex);
|
||||
}
|
||||
if (item2->indexchanged != NULL)
|
||||
{
|
||||
item2->indexchanged(item2->data, item2->heapindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static size_t K_BHeapItemGetParentIndex(bheapitem_t *item)
|
||||
|
||||
Gets the parent index of a heap item
|
||||
|
||||
Input Arguments:-
|
||||
item - The item to get the parent index of
|
||||
|
||||
Return:-
|
||||
The parent index of the item
|
||||
--------------------------------------------------*/
|
||||
static size_t K_BHeapItemGetParentIndex(bheapitem_t *item)
|
||||
{
|
||||
size_t parentindex = SIZE_MAX;
|
||||
|
||||
I_Assert(item != NULL);
|
||||
I_Assert(item->heapindex < (SIZE_MAX / 2));
|
||||
|
||||
parentindex = (item->heapindex - 1U) / 2U;
|
||||
|
||||
return parentindex;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static size_t K_BHeapItemGetLeftChildIndex(bheapitem_t *item)
|
||||
|
||||
Gets the left child index of a heap item
|
||||
|
||||
Input Arguments:-
|
||||
item - The item to get the left child index of
|
||||
|
||||
Return:-
|
||||
The left child index of the item
|
||||
--------------------------------------------------*/
|
||||
static size_t K_BHeapItemGetLeftChildIndex(bheapitem_t *item)
|
||||
{
|
||||
size_t leftchildindex = SIZE_MAX;
|
||||
|
||||
I_Assert(item != NULL);
|
||||
I_Assert(item->heapindex < (SIZE_MAX / 2));
|
||||
|
||||
leftchildindex = (item->heapindex * 2U) + 1U;
|
||||
|
||||
return leftchildindex;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static size_t K_BHeapItemGetRightChildIndex(bheapitem_t *item)
|
||||
|
||||
Gets the right child index of a heap item
|
||||
|
||||
Input Arguments:-
|
||||
item - The item to get the right child index of
|
||||
|
||||
Return:-
|
||||
The right child index of the item
|
||||
--------------------------------------------------*/
|
||||
static size_t K_BHeapItemGetRightChildIndex(bheapitem_t *item)
|
||||
{
|
||||
size_t rightchildindex = SIZE_MAX;
|
||||
|
||||
I_Assert(item != NULL);
|
||||
I_Assert(item->heapindex < (SIZE_MAX / 2));
|
||||
|
||||
rightchildindex = (item->heapindex * 2U) + 2U;
|
||||
|
||||
return rightchildindex;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_BHeapSortUp(bheap_t *heap, bheapitem_t *item)
|
||||
|
||||
Sorts a heapitem up the list to its correct index, lower value items are higher up
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to sort the item up.
|
||||
item - The item to sort up the heap
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
static void K_BHeapSortUp(bheap_t *heap, bheapitem_t *item)
|
||||
{
|
||||
I_Assert(heap != NULL);
|
||||
I_Assert(K_BHeapValid(heap));
|
||||
I_Assert(item != NULL);
|
||||
|
||||
if (item->heapindex > 0U)
|
||||
{
|
||||
size_t parentindex = SIZE_MAX;
|
||||
do
|
||||
{
|
||||
parentindex = K_BHeapItemGetParentIndex(item);
|
||||
|
||||
// Swap the nodes if the parent has a higher value
|
||||
if (K_BHeapItemsCompare(heap, item, &heap->array[parentindex]) == item)
|
||||
{
|
||||
K_BHeapSwapItems(heap, item, &heap->array[parentindex]);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (parentindex > 0U);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_BHeapSortDown(bheap_t *heap, bheapitem_t *item)
|
||||
|
||||
Sorts a heapitem down the list to its correct index, higher value items are further down
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to sort the item down.
|
||||
item - The item to sort down the heap
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
static void K_BHeapSortDown(bheap_t *heap, bheapitem_t *item)
|
||||
{
|
||||
I_Assert(heap != NULL);
|
||||
I_Assert(K_BHeapValid(heap));
|
||||
I_Assert(item != NULL);
|
||||
|
||||
if (heap->count > 0U)
|
||||
{
|
||||
size_t leftchildindex = SIZE_MAX;
|
||||
size_t rightchildindex = SIZE_MAX;
|
||||
bheapitem_t *leftchild = NULL;
|
||||
bheapitem_t *rightchild = NULL;
|
||||
bheapitem_t *swapchild = NULL;
|
||||
boolean noswapneeded = false;
|
||||
|
||||
do
|
||||
{
|
||||
leftchildindex = K_BHeapItemGetLeftChildIndex(item);
|
||||
rightchildindex = K_BHeapItemGetRightChildIndex(item);
|
||||
|
||||
if (leftchildindex < heap->count)
|
||||
{
|
||||
leftchild = &heap->array[leftchildindex];
|
||||
swapchild = leftchild;
|
||||
if (rightchildindex < heap->count)
|
||||
{
|
||||
rightchild = &heap->array[rightchildindex];
|
||||
// Choose the lower child node to swap with
|
||||
if (K_BHeapItemsCompare(heap, leftchild, rightchild) == rightchild)
|
||||
{
|
||||
swapchild = rightchild;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap with the lower child, if it's lower than item
|
||||
if (K_BHeapItemsCompare(heap, swapchild, item) == swapchild)
|
||||
{
|
||||
K_BHeapSwapItems(heap, item, swapchild);
|
||||
}
|
||||
else
|
||||
{
|
||||
noswapneeded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
noswapneeded = true;
|
||||
}
|
||||
|
||||
if (noswapneeded)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
} while (item->heapindex < (heap->count - 1U));
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BHeapInit(bheap_t *const heap, size_t initialcapacity)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_BHeapInit(bheap_t *const heap, size_t initialcapacity)
|
||||
{
|
||||
boolean initsuccess = false;
|
||||
|
||||
if (heap == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapInit.\n");
|
||||
}
|
||||
else if (initialcapacity == 0U)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "initialcapacity is 0 in K_BHeapInit.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
heap->array = Z_Calloc(initialcapacity * sizeof(bheapitem_t), PU_STATIC, NULL);
|
||||
|
||||
if (heap->array == NULL)
|
||||
{
|
||||
I_Error("K_BHeapInit: Out of Memory.");
|
||||
}
|
||||
|
||||
heap->capacity = initialcapacity;
|
||||
heap->count = 0U;
|
||||
|
||||
initsuccess = true;
|
||||
}
|
||||
|
||||
return initsuccess;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BHeapValid(bheap_t *const heap)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_BHeapValid(bheap_t *const heap)
|
||||
{
|
||||
boolean heapvalid = false;
|
||||
|
||||
if (heap == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapValid.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((heap->capacity > 0U) && (heap->array != NULL))
|
||||
{
|
||||
heapvalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return heapvalid;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BHeapPush(bheap_t *const heap, void *const item, UINT32 value, updateindexfunc changeindexcallback)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_BHeapPush(bheap_t *const heap, void *const item, UINT32 value, updateindexfunc changeindexcallback)
|
||||
{
|
||||
boolean pushsuccess = false;
|
||||
if (heap == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapPush.\n");
|
||||
}
|
||||
else if (!K_BHeapValid(heap))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Uninitialised heap in K_BHeapPush.\n");
|
||||
}
|
||||
else if (item == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL item in K_BHeapPush.\n");
|
||||
}
|
||||
else if (heap->count >= (SIZE_MAX / 2))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Tried to push too many items on binary heap in K_BHeapPush.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
bheapitem_t *newitem = NULL;
|
||||
// If the capacity of the heap has been reached, a realloc is needed
|
||||
// I'm just doing a basic double of capacity for simplicity
|
||||
if (heap->count >= heap->capacity)
|
||||
{
|
||||
size_t newarraycapacity = heap->capacity * 2;
|
||||
heap->array = Z_Realloc(heap->array, newarraycapacity, PU_STATIC, NULL);
|
||||
|
||||
if (heap->array == NULL)
|
||||
{
|
||||
I_Error("K_BHeapPush: Out of Memory.");
|
||||
}
|
||||
|
||||
heap->capacity = newarraycapacity;
|
||||
}
|
||||
|
||||
newitem = &heap->array[heap->count];
|
||||
|
||||
newitem->heapindex = heap->count;
|
||||
newitem->owner = heap;
|
||||
newitem->data = item;
|
||||
newitem->value = value;
|
||||
newitem->indexchanged = changeindexcallback;
|
||||
|
||||
if (newitem->indexchanged != NULL)
|
||||
{
|
||||
newitem->indexchanged(newitem->data, newitem->heapindex);
|
||||
}
|
||||
|
||||
heap->count++;
|
||||
|
||||
K_BHeapSortUp(heap, &heap->array[heap->count - 1U]);
|
||||
|
||||
pushsuccess = true;
|
||||
}
|
||||
|
||||
return pushsuccess;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BHeapPop(bheap_t *const heap, bheapitem_t *const returnitemstorage)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_BHeapPop(bheap_t *const heap, bheapitem_t *const returnitemstorage)
|
||||
{
|
||||
boolean popsuccess = false;
|
||||
if (heap == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapPop.\n");
|
||||
}
|
||||
else if (!K_BHeapValid(heap))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Uninitialised heap in K_BHeapPop.\n");
|
||||
}
|
||||
else if (heap->count == 0U)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Tried to Pop from empty heap in K_BHeapPop.\n");
|
||||
}
|
||||
else if (returnitemstorage == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL returnitemstorage in K_BHeapPop.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
*returnitemstorage = heap->array[0];
|
||||
|
||||
// Invalidate the heap related data from the return item
|
||||
returnitemstorage->owner = NULL;
|
||||
returnitemstorage->heapindex = SIZE_MAX;
|
||||
|
||||
if (returnitemstorage->indexchanged != NULL)
|
||||
{
|
||||
returnitemstorage->indexchanged(returnitemstorage->data, returnitemstorage->heapindex);
|
||||
}
|
||||
|
||||
heap->count--;
|
||||
|
||||
heap->array[0] = heap->array[heap->count];
|
||||
heap->array[0].heapindex = 0U;
|
||||
memset(&heap->array[heap->count], 0x00, sizeof(bheapitem_t));
|
||||
|
||||
K_BHeapSortDown(heap, &heap->array[0]);
|
||||
popsuccess = true;
|
||||
}
|
||||
|
||||
return popsuccess;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_UpdateBHeapItemValue(bheapitem_t *const item, const UINT32 newvalue)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_UpdateBHeapItemValue(bheapitem_t *const item, const UINT32 newvalue)
|
||||
{
|
||||
boolean updatevaluesuccess = false;
|
||||
if (item == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL item in K_UpdateHeapItemValue.\n");
|
||||
}
|
||||
else if (item->owner == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "item has NULL owner in K_UpdateHeapItemValue.\n");
|
||||
}
|
||||
else if (K_BHeapItemValidate(item->owner, item) == false)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Invalid item in K_UpdateHeapItemValue.\n");
|
||||
}
|
||||
else if (K_BHeapValid(item->owner) == false)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Invalid item owner in K_UpdateHeapItemValue.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t oldvalue = item->value;
|
||||
item->value = newvalue;
|
||||
if (newvalue < oldvalue)
|
||||
{
|
||||
K_BHeapSortUp(item->owner, item);
|
||||
}
|
||||
else if (newvalue > oldvalue)
|
||||
{
|
||||
K_BHeapSortDown(item->owner, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No change is needed as the value is the same
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return updatevaluesuccess;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
size_t K_BHeapContains(bheap_t *const heap, void *const data, size_t index)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
size_t K_BHeapContains(bheap_t *const heap, void *const data, size_t index)
|
||||
{
|
||||
size_t heapindexwithdata = SIZE_MAX;
|
||||
|
||||
if (heap == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapContains.\n");
|
||||
}
|
||||
else if (!K_BHeapValid(heap))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Uninitialised heap in K_BHeapContains.\n");
|
||||
}
|
||||
else if (data == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL data in K_BHeapContains.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((heap->count != 0U) && (index < heap->count))
|
||||
{
|
||||
if (heap->array[index].data == data)
|
||||
{
|
||||
heapindexwithdata = index;
|
||||
}
|
||||
}
|
||||
else if (index == SIZE_MAX)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < heap->count; i++)
|
||||
{
|
||||
if (heap->array[i].data == data)
|
||||
{
|
||||
heapindexwithdata = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return heapindexwithdata;
|
||||
}
|
||||
|
||||
boolean K_BHeapFree(bheap_t *const heap)
|
||||
{
|
||||
boolean freesuccess = false;
|
||||
|
||||
if (heap == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL heap in K_BHeapFree.\n");
|
||||
}
|
||||
else if (!K_BHeapValid(heap))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Uninitialised heap in K_BHeapFree.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Z_Free(heap->array);
|
||||
heap->array = NULL;
|
||||
heap->capacity = 0U;
|
||||
heap->count = 0U;
|
||||
freesuccess = true;
|
||||
}
|
||||
|
||||
return freesuccess;
|
||||
}
|
||||
153
src/k_bheap.h
Normal file
153
src/k_bheap.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
// SONIC ROBO BLAST 2 KART
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018-2020 by Sean "Sryder" Ryder
|
||||
// Copyright (C) 2018-2020 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file k_bheap.h
|
||||
/// \brief Binary Heap implementation for SRB2 code base.
|
||||
|
||||
#ifndef __K_BHEAP__
|
||||
#define __K_BHEAP__
|
||||
|
||||
#include "doomdef.h"
|
||||
|
||||
typedef void(*updateindexfunc)(void *const, const size_t);
|
||||
|
||||
typedef struct bheapitem_s
|
||||
{
|
||||
size_t heapindex; // The index in the heap this item is
|
||||
updateindexfunc indexchanged; // A callback function that is called when this item changes index to alert data
|
||||
struct bheap_s *owner; // The heap that owns this item
|
||||
void *data; // data for this heap item
|
||||
UINT32 value; // The value of this item, the lowest value item is first in the array
|
||||
} bheapitem_t;
|
||||
|
||||
typedef struct bheap_s
|
||||
{
|
||||
size_t capacity; // capacity of the heap
|
||||
size_t count; // number of items in the heap
|
||||
bheapitem_t *array; // pointer to the heap items array
|
||||
} bheap_t;
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BHeapInit(bheap_t *const heap, size_t initialcapacity)
|
||||
|
||||
Initialises a binary heap.
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to initialise
|
||||
initialcapacity - The initial capacity the heap should hold
|
||||
|
||||
Return:-
|
||||
True if the initialisation was successful, false if it wasn't.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_BHeapInit(bheap_t *const heap, size_t initialcapacity);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BHeapValid(bheap_t *const heap)
|
||||
|
||||
Checks a binary heap for validity
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to validate
|
||||
|
||||
Return:-
|
||||
True if the binary heap is valid, false if it isn't
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_BHeapValid(bheap_t *const heap);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BHeapPush(bheap_t *const heap, void *const item, const UINT32 value, updateindexfunc changeindexcallback)
|
||||
|
||||
Adds a new item to a binary heap.
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to add to.
|
||||
item - The item to add to the heap.
|
||||
value - The value of this item for the heap, lowest is first in the heap
|
||||
changeindexcallback - A callback function that is called when the item's index changes, can be NULL
|
||||
|
||||
Return:-
|
||||
True if the push to the heap was successful, false if it wasn't due to invalid parameters
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_BHeapPush(bheap_t *const heap, void *const item, UINT32 value, updateindexfunc changeindexcallback);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BHeapPop(bheap_t *const heap, bheapitem_t *const returnitemstorage)
|
||||
|
||||
Pops the first item off of the heap, then orders it back to be correct.
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to pop from.
|
||||
returnitemstorage - The first item on the Heap is placed in here
|
||||
|
||||
Return:-
|
||||
true if the pop from the heap was successful, false if it wasn't.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_BHeapPop(bheap_t *const heap, bheapitem_t *const returnitemstorage);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_UpdateBHeapItemValue(bheapitem_t *const item, const UINT32 newvalue)
|
||||
|
||||
Updates the heap item's value, and reorders it in the array appropriately. Only works if the item is in a heap
|
||||
validly. If it's a heapitem that is not currently in a heap (ie it's been popped off) just change the value
|
||||
manually.
|
||||
|
||||
Input Arguments:-
|
||||
item - The item to update the value of.
|
||||
newvalue - The new value the item will hold
|
||||
|
||||
Return:-
|
||||
true if the update was successful, false if it wasn't
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_UpdateBHeapItemValue(bheapitem_t *const item, const UINT32 newvalue);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
size_t K_BHeapContains(bheap_t *const heap, void *const data, size_t index)
|
||||
|
||||
Checks to see if data is contained in the heap. If index is not SIZE_MAX, then only the index sent in is
|
||||
checked. Otherwise every index is checked linearly.
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to check the contents of
|
||||
data - The data that is being checked for
|
||||
index - The index of the heap to check, if SIZE_MAX, check every index
|
||||
|
||||
Return:-
|
||||
The heap index that contains data, SIZE_MAX if it is not in the heap
|
||||
--------------------------------------------------*/
|
||||
|
||||
size_t K_BHeapContains(bheap_t *const heap, void *const data, size_t index);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_BHeapFree(bheap_t *const heap)
|
||||
|
||||
Free the binary heap.
|
||||
This does NOT free the data held within the binary heap items. Make sure those can still be freed manually.
|
||||
|
||||
Input Arguments:-
|
||||
heap - The heap to free
|
||||
|
||||
Return:-
|
||||
True if the heap was freed successfully, false if the heap wasn't valid to free
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_BHeapFree(bheap_t *const heap);
|
||||
|
||||
#endif
|
||||
1693
src/k_kart.c
1693
src/k_kart.c
File diff suppressed because it is too large
Load diff
|
|
@ -26,6 +26,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid)
|
|||
void K_KartPainEnergyFling(player_t *player);
|
||||
void K_FlipFromObject(mobj_t *mo, mobj_t *master);
|
||||
void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master);
|
||||
void K_DoIngameRespawn(player_t *player);
|
||||
void K_RespawnChecker(player_t *player);
|
||||
void K_KartMoveAnimation(player_t *player);
|
||||
void K_KartPlayerHUDUpdate(player_t *player);
|
||||
|
|
@ -38,6 +39,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor);
|
|||
void K_StealBumper(player_t *player, player_t *victim, boolean force);
|
||||
void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source);
|
||||
void K_SpawnMineExplosion(mobj_t *source, UINT8 color);
|
||||
UINT8 K_DriftSparkColor(player_t *player, INT32 charge);
|
||||
void K_SpawnBoostTrail(player_t *player);
|
||||
void K_SpawnSparkleTrail(mobj_t *mo);
|
||||
void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent);
|
||||
|
|
|
|||
506
src/k_pathfind.c
Normal file
506
src/k_pathfind.c
Normal file
|
|
@ -0,0 +1,506 @@
|
|||
// SONIC ROBO BLAST 2 KART
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018-2020 by Sean "Sryder" Ryder
|
||||
// Copyright (C) 2018-2020 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file k_pathfind.c
|
||||
/// \brief A* Pathfinding algorithm implementation for SRB2 code base.
|
||||
|
||||
#include "k_pathfind.h"
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "z_zone.h"
|
||||
#include "k_bheap.h"
|
||||
|
||||
static const size_t DEFAULT_NODEARRAY_CAPACITY = 8U;
|
||||
static const size_t DEFAULT_OPENSET_CAPACITY = 8U;
|
||||
static const size_t DEFAULT_CLOSEDSET_CAPACITY = 8U;
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
static UINT32 K_NodeGetFScore(const pathfindnode_t *const node)
|
||||
|
||||
Gets the FScore of a node. The FScore is the GScore plus the HScore.
|
||||
|
||||
Input Arguments:-
|
||||
node - The node to get the FScore of
|
||||
|
||||
Return:-
|
||||
The FScore of the node.
|
||||
--------------------------------------------------*/
|
||||
static UINT32 K_NodeGetFScore(const pathfindnode_t *const node)
|
||||
{
|
||||
UINT32 fscore = UINT32_MAX;
|
||||
|
||||
I_Assert(node != NULL);
|
||||
|
||||
fscore = node->gscore + node->hscore;
|
||||
|
||||
return fscore;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_NodeUpdateHeapIndex(void *const node, const size_t newheapindex)
|
||||
|
||||
A callback for the Openset Binary Heap to be able to update the heapindex of the pathfindnodes when they are
|
||||
moved.
|
||||
|
||||
Input Arguments:-
|
||||
node - The node that has been updated, should be a pointer to a pathfindnode_t
|
||||
newheapindex - The new heapindex of the node.
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
static void K_NodeUpdateHeapIndex(void *const node, const size_t newheapindex)
|
||||
{
|
||||
if (node == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL node in K_NodeUpdateHeapIndex.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
pathfindnode_t *truenode = (pathfindnode_t*)node;
|
||||
truenode->heapindex = newheapindex;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static pathfindnode_t *K_NodesArrayContainsNodeData(
|
||||
pathfindnode_t *nodesarray,
|
||||
void* nodedata,
|
||||
size_t nodesarraycount)
|
||||
|
||||
Checks whether the Nodes Array contains a node with a waypoint. Searches from the end to the start for speed
|
||||
reasons.
|
||||
|
||||
Input Arguments:-
|
||||
nodesarray - The nodes array within the A* algorithm
|
||||
waypoint - The waypoint to check is within the nodes array
|
||||
nodesarraycount - The current size of the nodes array
|
||||
|
||||
Return:-
|
||||
The pathfind node that has the waypoint if there is one. NULL if the waypoint is not in the nodes array.
|
||||
--------------------------------------------------*/
|
||||
static pathfindnode_t *K_NodesArrayContainsNodeData(
|
||||
pathfindnode_t *nodesarray,
|
||||
void* nodedata,
|
||||
size_t nodesarraycount)
|
||||
{
|
||||
pathfindnode_t *foundnode = NULL;
|
||||
size_t i = 0U;
|
||||
|
||||
I_Assert(nodesarray != NULL);
|
||||
I_Assert(nodedata != NULL);
|
||||
|
||||
// It is more likely that we'll find the node we are looking for from the end of the array
|
||||
// Yes, the for loop looks weird, remember that size_t is unsigned and we want to check 0, after it hits 0 it
|
||||
// will loop back up to SIZE_MAX
|
||||
for (i = nodesarraycount - 1U; i < nodesarraycount; i--)
|
||||
{
|
||||
if (nodesarray[i].nodedata == nodedata)
|
||||
{
|
||||
foundnode = &nodesarray[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return foundnode;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_ClosedsetContainsNode(pathfindnode_t **closedset, pathfindnode_t *node, size_t closedsetcount)
|
||||
|
||||
Checks whether the Closedset contains a node. Searches from the end to the start for speed reasons.
|
||||
|
||||
Input Arguments:-
|
||||
closedset - The closed set within the A* algorithm
|
||||
node - The node to check is within the closed set
|
||||
closedsetcount - The current size of the closedset
|
||||
|
||||
Return:-
|
||||
True if the node is in the closed set, false if it isn't
|
||||
--------------------------------------------------*/
|
||||
static boolean K_ClosedsetContainsNode(pathfindnode_t **closedset, pathfindnode_t *node, size_t closedsetcount)
|
||||
{
|
||||
boolean nodeisinclosedset = false;
|
||||
size_t i = 0U;
|
||||
|
||||
I_Assert(closedset != NULL);
|
||||
I_Assert(node != NULL);
|
||||
// It is more likely that we'll find the node we are looking for from the end of the array
|
||||
// Yes, the for loop looks weird, remember that size_t is unsigned and we want to check 0, after it hits 0 it
|
||||
// will loop back up to SIZE_MAX
|
||||
for (i = closedsetcount - 1U; i < closedsetcount; i--)
|
||||
{
|
||||
if (closedset[i] == node)
|
||||
{
|
||||
nodeisinclosedset = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nodeisinclosedset;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_PathfindSetupValid(const pathfindsetup_t *const pathfindsetup)
|
||||
|
||||
Checks that the setup given for pathfinding is valid and can be used.
|
||||
|
||||
Input Arguments:-
|
||||
pathfindsetup - The setup for the pathfinding given
|
||||
|
||||
Return:-
|
||||
True if pathfinding setup is valid, false if it isn't.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_PathfindSetupValid(const pathfindsetup_t *const pathfindsetup)
|
||||
{
|
||||
boolean pathfindsetupvalid = false;
|
||||
size_t sourcenodenumconnectednodes = 0U;
|
||||
size_t endnodenumconnectednodes = 0U;
|
||||
|
||||
if (pathfindsetup == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL pathfindsetup in K_PathfindSetupValid.\n");
|
||||
}
|
||||
else if (pathfindsetup->startnodedata == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL startnodedata.\n");
|
||||
}
|
||||
else if (pathfindsetup->endnodedata == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL endnodedata.\n");
|
||||
}
|
||||
else if (pathfindsetup->getconnectednodes == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL getconnectednodes function.\n");
|
||||
}
|
||||
else if (pathfindsetup->getconnectioncosts == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL getconnectioncosts function.\n");
|
||||
}
|
||||
else if (pathfindsetup->getheuristic == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL getheuristic function.\n");
|
||||
}
|
||||
else if (pathfindsetup->gettraversable == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "Pathfindsetup has NULL gettraversable function.\n");
|
||||
}
|
||||
else if (pathfindsetup->getconnectednodes(pathfindsetup->startnodedata, &sourcenodenumconnectednodes) == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindSetupValid: Source node returned NULL connecting nodes.\n");
|
||||
}
|
||||
else if (sourcenodenumconnectednodes == 0U)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindSetupValid: Source node has 0 connecting nodes.\n");
|
||||
}
|
||||
else if (pathfindsetup->getconnectednodes(pathfindsetup->endnodedata, &endnodenumconnectednodes) == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindSetupValid: End node returned NULL connecting nodes.\n");
|
||||
}
|
||||
else if (endnodenumconnectednodes == 0U)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindSetupValid: End node has 0 connecting nodes.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
pathfindsetupvalid = true;
|
||||
}
|
||||
|
||||
return pathfindsetupvalid;
|
||||
}
|
||||
|
||||
static boolean K_ReconstructPath(path_t *const path, pathfindnode_t *const destinationnode)
|
||||
{
|
||||
boolean reconstructsuccess = false;
|
||||
|
||||
I_Assert(path != NULL);
|
||||
I_Assert(destinationnode != NULL);
|
||||
|
||||
{
|
||||
size_t numnodes = 0U;
|
||||
pathfindnode_t *thisnode = destinationnode;
|
||||
|
||||
// If the path we're placing our new path into already has data, free it
|
||||
if (path->array != NULL)
|
||||
{
|
||||
Z_Free(path->array);
|
||||
path->numnodes = 0U;
|
||||
path->totaldist = 0U;
|
||||
}
|
||||
|
||||
// Do a fast check of how many nodes there are so we know how much space to allocate
|
||||
for (thisnode = destinationnode; thisnode; thisnode = thisnode->camefrom)
|
||||
{
|
||||
numnodes++;
|
||||
}
|
||||
|
||||
if (numnodes > 0U)
|
||||
{
|
||||
// Allocate memory for the path
|
||||
path->numnodes = numnodes;
|
||||
path->array = Z_Calloc(numnodes * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
||||
path->totaldist = destinationnode->gscore;
|
||||
if (path->array == NULL)
|
||||
{
|
||||
I_Error("K_ReconstructPath: Out of memory.");
|
||||
}
|
||||
|
||||
// Put the nodes into the return array
|
||||
for (thisnode = destinationnode; thisnode; thisnode = thisnode->camefrom)
|
||||
{
|
||||
path->array[numnodes - 1U] = *thisnode;
|
||||
// Correct the camefrom element to point to the previous element in the array instead
|
||||
if ((path->array[numnodes - 1U].camefrom != NULL) && (numnodes > 1U))
|
||||
{
|
||||
path->array[numnodes - 1U].camefrom = &path->array[numnodes - 2U];
|
||||
}
|
||||
else
|
||||
{
|
||||
path->array[numnodes - 1U].camefrom = NULL;
|
||||
}
|
||||
|
||||
numnodes--;
|
||||
}
|
||||
|
||||
reconstructsuccess = true;
|
||||
}
|
||||
}
|
||||
|
||||
return reconstructsuccess;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PathfindAStar(path_t *const path, pathfindsetup_t *const pathfindsetup)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PathfindAStar(path_t *const path, pathfindsetup_t *const pathfindsetup)
|
||||
{
|
||||
boolean pathfindsuccess = false;
|
||||
|
||||
if (path == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL path in K_PathfindAStar.\n");
|
||||
}
|
||||
else if (pathfindsetup == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "NULL pathfindsetup in K_PathfindAStar.\n");
|
||||
}
|
||||
else if (!K_PathfindSetupValid(pathfindsetup))
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: Pathfinding setup is not valid.\n");
|
||||
}
|
||||
else if (pathfindsetup->startnodedata == pathfindsetup->endnodedata)
|
||||
{
|
||||
// At the destination, return a simple 1 node path
|
||||
pathfindnode_t singlenode = {};
|
||||
singlenode.camefrom = NULL;
|
||||
singlenode.nodedata = pathfindsetup->endnodedata;
|
||||
singlenode.heapindex = SIZE_MAX;
|
||||
singlenode.hscore = 0U;
|
||||
singlenode.gscore = 0U;
|
||||
|
||||
K_ReconstructPath(path, &singlenode);
|
||||
|
||||
pathfindsuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bheap_t openset = {};
|
||||
bheapitem_t poppedbheapitem = {};
|
||||
pathfindnode_t *nodesarray = NULL;
|
||||
pathfindnode_t **closedset = NULL;
|
||||
pathfindnode_t *newnode = NULL;
|
||||
pathfindnode_t *currentnode = NULL;
|
||||
pathfindnode_t *connectingnode = NULL;
|
||||
void **connectingnodesdata = NULL;
|
||||
void *checknodedata = NULL;
|
||||
UINT32 *connectingnodecosts = NULL;
|
||||
size_t numconnectingnodes = 0U;
|
||||
size_t connectingnodeheapindex = 0U;
|
||||
size_t nodesarraycount = 0U;
|
||||
size_t closedsetcount = 0U;
|
||||
size_t i = 0U;
|
||||
UINT32 tentativegscore = 0U;
|
||||
|
||||
// Set the dynamic structure capacites to defaults if they are 0
|
||||
if (pathfindsetup->nodesarraycapacity == 0U)
|
||||
{
|
||||
pathfindsetup->nodesarraycapacity = DEFAULT_NODEARRAY_CAPACITY;
|
||||
}
|
||||
if (pathfindsetup->opensetcapacity == 0U)
|
||||
{
|
||||
pathfindsetup->opensetcapacity = DEFAULT_OPENSET_CAPACITY;
|
||||
}
|
||||
if (pathfindsetup->closedsetcapacity == 0U)
|
||||
{
|
||||
pathfindsetup->closedsetcapacity = DEFAULT_CLOSEDSET_CAPACITY;
|
||||
}
|
||||
|
||||
// Allocate the necessary memory
|
||||
nodesarray = Z_Calloc(pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
||||
if (nodesarray == NULL)
|
||||
{
|
||||
I_Error("K_PathfindAStar: Out of memory allocating nodes array.");
|
||||
}
|
||||
closedset = Z_Calloc(pathfindsetup->closedsetcapacity * sizeof(pathfindnode_t*), PU_STATIC, NULL);
|
||||
if (closedset == NULL)
|
||||
{
|
||||
I_Error("K_PathfindAStar: Out of memory allocating closed set.");
|
||||
}
|
||||
K_BHeapInit(&openset, pathfindsetup->opensetcapacity);
|
||||
|
||||
// Create the first node and add it to the open set
|
||||
newnode = &nodesarray[nodesarraycount];
|
||||
newnode->heapindex = SIZE_MAX;
|
||||
newnode->nodedata = pathfindsetup->startnodedata;
|
||||
newnode->camefrom = NULL;
|
||||
newnode->gscore = 0U;
|
||||
newnode->hscore = pathfindsetup->getheuristic(newnode->nodedata, pathfindsetup->endnodedata);
|
||||
nodesarraycount++;
|
||||
K_BHeapPush(&openset, newnode, K_NodeGetFScore(newnode), K_NodeUpdateHeapIndex);
|
||||
|
||||
// update openset capacity if it changed
|
||||
if (openset.capacity != pathfindsetup->opensetcapacity)
|
||||
{
|
||||
pathfindsetup->opensetcapacity = openset.capacity;
|
||||
}
|
||||
|
||||
// Go through each node in the openset, adding new ones from each node to it
|
||||
// this continues until a path is found or there are no more nodes to check
|
||||
while (openset.count > 0U)
|
||||
{
|
||||
// pop the best node off of the openset
|
||||
K_BHeapPop(&openset, &poppedbheapitem);
|
||||
currentnode = (pathfindnode_t*)poppedbheapitem.data;
|
||||
|
||||
if (currentnode->nodedata == pathfindsetup->endnodedata)
|
||||
{
|
||||
pathfindsuccess = K_ReconstructPath(path, currentnode);
|
||||
break;
|
||||
}
|
||||
|
||||
// Place the node we just popped into the closed set, as we are now evaluating it
|
||||
if (closedsetcount >= pathfindsetup->closedsetcapacity)
|
||||
{
|
||||
// Need to reallocate closedset to fit another node
|
||||
pathfindsetup->closedsetcapacity = pathfindsetup->closedsetcapacity * 2;
|
||||
closedset =
|
||||
Z_Realloc(closedset, pathfindsetup->closedsetcapacity * sizeof(pathfindnode_t*), PU_STATIC, NULL);
|
||||
if (closedset == NULL)
|
||||
{
|
||||
I_Error("K_PathfindAStar: Out of memory reallocating closed set.");
|
||||
}
|
||||
}
|
||||
closedset[closedsetcount] = currentnode;
|
||||
closedsetcount++;
|
||||
|
||||
// Get the needed data for the next nodes from the current node
|
||||
connectingnodesdata = pathfindsetup->getconnectednodes(currentnode->nodedata, &numconnectingnodes);
|
||||
connectingnodecosts = pathfindsetup->getconnectioncosts(currentnode->nodedata);
|
||||
|
||||
if (connectingnodesdata == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node returned NULL connecting node data.\n");
|
||||
}
|
||||
else if (connectingnodecosts == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node returned NULL connecting node costs.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// For each connecting node add it to the openset if it's unevaluated and not there,
|
||||
// skip it if it's in the closedset or not traversable
|
||||
for (i = 0; i < numconnectingnodes; i++)
|
||||
{
|
||||
checknodedata = connectingnodesdata[i];
|
||||
|
||||
if (checknodedata == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node has a NULL connecting node.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip this node if it isn't traversable
|
||||
if (pathfindsetup->gettraversable(checknodedata) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Figure out what the gscore of this route for the connecting node is
|
||||
tentativegscore = currentnode->gscore + connectingnodecosts[i];
|
||||
|
||||
// find this data in the nodes array if it's been generated before
|
||||
connectingnode = K_NodesArrayContainsNodeData(nodesarray, checknodedata, nodesarraycount);
|
||||
|
||||
if (connectingnode != NULL)
|
||||
{
|
||||
// The connecting node has been seen before, so it must be in either the closedset (skip it)
|
||||
// or the openset (re-evaluate it's gscore)
|
||||
if (K_ClosedsetContainsNode(closedset, connectingnode, closedsetcount) == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (tentativegscore < connectingnode->gscore)
|
||||
{
|
||||
// The node is not in the closedset, update it's gscore if this path to it is faster
|
||||
connectingnode->gscore = tentativegscore;
|
||||
connectingnode->camefrom = currentnode;
|
||||
|
||||
connectingnodeheapindex =
|
||||
K_BHeapContains(&openset, connectingnode, connectingnode->heapindex);
|
||||
if (connectingnodeheapindex != SIZE_MAX)
|
||||
{
|
||||
K_UpdateBHeapItemValue(
|
||||
&openset.array[connectingnodeheapindex], K_NodeGetFScore(connectingnode));
|
||||
}
|
||||
else
|
||||
{
|
||||
// SOMEHOW the node is not in either the closed set OR the open set
|
||||
CONS_Debug(DBG_GAMELOGIC, "K_PathfindAStar: A Node is not in either set.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Node is not created yet, so it hasn't been seen so far
|
||||
// Reallocate nodesarray if it's full
|
||||
if (nodesarraycount >= pathfindsetup->nodesarraycapacity)
|
||||
{
|
||||
pathfindsetup->nodesarraycapacity = pathfindsetup->nodesarraycapacity * 2;
|
||||
nodesarray = Z_Realloc(nodesarray, pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
|
||||
|
||||
if (nodesarray == NULL)
|
||||
{
|
||||
I_Error("K_PathfindAStar: Out of memory reallocating nodes array.");
|
||||
}
|
||||
}
|
||||
|
||||
// Create the new node and add it to the nodes array and open set
|
||||
newnode = &nodesarray[nodesarraycount];
|
||||
newnode->heapindex = SIZE_MAX;
|
||||
newnode->nodedata = checknodedata;
|
||||
newnode->camefrom = currentnode;
|
||||
newnode->gscore = tentativegscore;
|
||||
newnode->hscore = pathfindsetup->getheuristic(newnode->nodedata, pathfindsetup->endnodedata);
|
||||
nodesarraycount++;
|
||||
K_BHeapPush(&openset, newnode, K_NodeGetFScore(newnode), K_NodeUpdateHeapIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up the memory
|
||||
K_BHeapFree(&openset);
|
||||
Z_Free(closedset);
|
||||
Z_Free(nodesarray);
|
||||
}
|
||||
|
||||
return pathfindsuccess;
|
||||
}
|
||||
82
src/k_pathfind.h
Normal file
82
src/k_pathfind.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
// SONIC ROBO BLAST 2 KART
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018-2020 by Sean "Sryder" Ryder
|
||||
// Copyright (C) 2018-2020 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file k_pathfind.h
|
||||
/// \brief A* Pathfinding algorithm implementation for SRB2 code base.
|
||||
|
||||
#ifndef __K_PATHFIND__
|
||||
#define __K_PATHFIND__
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
// function pointer for returning a node's connected node data
|
||||
// should return a pointer to an array of pointers to the data, as arguments takes a node's data and a pointer that the
|
||||
// number of connected nodes should be placed into
|
||||
typedef void**(*getconnectednodesfunc)(void*, size_t*);
|
||||
|
||||
// function pointer for getting the list of connected node costs/distances
|
||||
typedef UINT32*(*getnodeconnectioncostsfunc)(void*);
|
||||
|
||||
// function pointer for getting a heuristic between 2 nodes from their base data
|
||||
typedef UINT32(*getnodeheuristicfunc)(void*, void*);
|
||||
|
||||
// function pointer for getting if a node is traversable from its base data
|
||||
typedef boolean(*getnodetraversablefunc)(void*);
|
||||
|
||||
|
||||
// A pathfindnode contains information about a node from the pathfinding
|
||||
// heapindex is only used within the pathfinding algorithm itself, and is always 0 after it is completed
|
||||
typedef struct pathfindnode_s {
|
||||
size_t heapindex; // The index in the openset binary heap. Only valid while the node is in the openset.
|
||||
void *nodedata;
|
||||
struct pathfindnode_s *camefrom; // should eventually be the most efficient predecessor node
|
||||
UINT32 gscore; // The accumulated distance from the start to this node
|
||||
UINT32 hscore; // The heuristic from this node to the goal
|
||||
} pathfindnode_t;
|
||||
|
||||
// Contains the final created path after pathfinding is completed
|
||||
typedef struct path_s {
|
||||
size_t numnodes;
|
||||
struct pathfindnode_s *array;
|
||||
UINT32 totaldist;
|
||||
} path_t;
|
||||
|
||||
// Contains info about the pathfinding used to setup the algorithm
|
||||
// (e.g. the base capacities of the dynamically allocated arrays)
|
||||
// should be setup by the caller before starting pathfinding
|
||||
// base capacities will be 8 if they aren't setup, missing callback functions will cause an error.
|
||||
// Can be accessed after the pathfinding is complete to get the final capacities of them
|
||||
typedef struct pathfindsetup_s {
|
||||
size_t opensetcapacity;
|
||||
size_t closedsetcapacity;
|
||||
size_t nodesarraycapacity;
|
||||
void *startnodedata;
|
||||
void *endnodedata;
|
||||
getconnectednodesfunc getconnectednodes;
|
||||
getnodeconnectioncostsfunc getconnectioncosts;
|
||||
getnodeheuristicfunc getheuristic;
|
||||
getnodetraversablefunc gettraversable;
|
||||
} pathfindsetup_t;
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PathfindAStar(path_t *const path, pathfindsetup_t *const pathfindsetup);
|
||||
|
||||
From a source waypoint and destination waypoint, find the best path between them using the A* algorithm.
|
||||
|
||||
Input Arguments:-
|
||||
path - The return location of the found path
|
||||
pathfindsetup - The information regarding pathfinding setup, see pathfindsetup_t
|
||||
|
||||
Return:-
|
||||
True if a path was found between source and destination, false otherwise.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PathfindAStar(path_t *const path, pathfindsetup_t *const pathfindsetup);
|
||||
|
||||
#endif
|
||||
1763
src/k_waypoint.c
Normal file
1763
src/k_waypoint.c
Normal file
File diff suppressed because it is too large
Load diff
338
src/k_waypoint.h
Normal file
338
src/k_waypoint.h
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
// SONIC ROBO BLAST 2 KART
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018-2020 by Sean "Sryder" Ryder
|
||||
// Copyright (C) 2018-2020 by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file k_waypoint.h
|
||||
/// \brief Waypoint handling from the relevant mobjs
|
||||
/// Setup and interfacing with waypoints for the main game
|
||||
|
||||
#ifndef __K_WAYPOINT__
|
||||
#define __K_WAYPOINT__
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "p_mobj.h"
|
||||
#include "k_pathfind.h"
|
||||
|
||||
typedef struct waypoint_s
|
||||
{
|
||||
mobj_t *mobj;
|
||||
struct waypoint_s **nextwaypoints;
|
||||
struct waypoint_s **prevwaypoints;
|
||||
UINT32 *nextwaypointdistances;
|
||||
UINT32 *prevwaypointdistances;
|
||||
size_t numnextwaypoints;
|
||||
size_t numprevwaypoints;
|
||||
} waypoint_t;
|
||||
|
||||
|
||||
// AVAILABLE FOR LUA
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
waypoint_t *K_GetFinishLineWaypoint(void);
|
||||
|
||||
Returns the waypoint actually being used as the finish line.
|
||||
|
||||
Input Arguments:-
|
||||
None
|
||||
|
||||
Return:-
|
||||
The waypoint that is being used as the finishline.
|
||||
--------------------------------------------------*/
|
||||
|
||||
waypoint_t *K_GetFinishLineWaypoint(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_GetWaypointIsFinishline(waypoint_t *waypoint)
|
||||
|
||||
Returns whether the waypoint is marked as the finishline. This may not actually be the finishline.
|
||||
|
||||
Input Arguments:-
|
||||
waypoint - The waypoint to return finishline status of.
|
||||
|
||||
Return:-
|
||||
true if the waypoint is marked as being the finishline, false if it isn't.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_GetWaypointIsFinishline(waypoint_t *waypoint);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_GetWaypointIsShortcut(waypoint_t *waypoint)
|
||||
|
||||
Returns whether the waypoint is part of a shortcut.
|
||||
|
||||
Input Arguments:-
|
||||
waypoint - The waypoint to return shortcut status of.
|
||||
|
||||
Return:-
|
||||
true if the waypoint is a shortcut, false if it isn't.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_GetWaypointIsShortcut(waypoint_t *waypoint);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_GetWaypointIsEnabled(waypoint_t *waypoint)
|
||||
|
||||
Returns whether the waypoint is enabled.
|
||||
|
||||
Input Arguments:-
|
||||
waypoint - The waypoint to return enabled status of.
|
||||
|
||||
Return:-
|
||||
true if the waypoint is enabled, false if it isn't.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_GetWaypointIsEnabled(waypoint_t *waypoint);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_GetWaypointIsSpawnpoint(waypoint_t *waypoint)
|
||||
|
||||
Returns whether the waypoint is a spawnpoint.
|
||||
|
||||
Input Arguments:-
|
||||
waypoint - The waypoint to return spawnpoint status of.
|
||||
|
||||
Return:-
|
||||
true if the waypoint is a spawnpoint, false if it isn't.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_GetWaypointIsSpawnpoint(waypoint_t *waypoint);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
INT32 K_GetWaypointNextID(waypoint_t *waypoint)
|
||||
|
||||
Returns the waypoint's next waypoint ID.
|
||||
|
||||
Input Arguments:-
|
||||
waypoint - The waypoint to return the next waypoint ID of.
|
||||
|
||||
Return:-
|
||||
The next waypoint ID, -1 if there is no waypoint or mobj.
|
||||
--------------------------------------------------*/
|
||||
|
||||
INT32 K_GetWaypointNextID(waypoint_t *waypoint);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
INT32 K_GetWaypointID(waypoint_t *waypoint)
|
||||
|
||||
Returns the waypoint's ID.
|
||||
|
||||
Input Arguments:-
|
||||
waypoint - The waypoint to return the ID of.
|
||||
|
||||
Return:-
|
||||
The waypoint ID, -1 if there is no waypoint or mobj.
|
||||
--------------------------------------------------*/
|
||||
INT32 K_GetWaypointID(waypoint_t *waypoint);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT32 K_GetCircuitLength(void)
|
||||
|
||||
Returns the circuit length, 0 on sprint maps.
|
||||
|
||||
Input Arguments:-
|
||||
|
||||
Return:-
|
||||
The circuit length.
|
||||
--------------------------------------------------*/
|
||||
UINT32 K_GetCircuitLength(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
waypoint_t *K_GetClosestWaypointToMobj(mobj_t *const mobj)
|
||||
|
||||
Returns the closest waypoint to an mobj
|
||||
|
||||
Input Arguments:-
|
||||
mobj - mobj to get the closest waypoint of.
|
||||
|
||||
Return:-
|
||||
The closest waypoint to the mobj
|
||||
--------------------------------------------------*/
|
||||
waypoint_t *K_GetClosestWaypointToMobj(mobj_t *const mobj);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj)
|
||||
|
||||
Similar to K_GetClosestWaypointToMobj, but prioritizes horizontal distance over vertical distance, and
|
||||
sight checks to ensure that the waypoint and mobj are the in same area. Can potentially return NULL if
|
||||
there are no visible waypoints.
|
||||
|
||||
Input Arguments:-
|
||||
mobj - mobj to get the waypoint for.
|
||||
|
||||
Return:-
|
||||
The best waypoint for the mobj, or NULL if there were no matches
|
||||
--------------------------------------------------*/
|
||||
waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PathfindToWaypoint(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
waypoint_t *const destinationwaypoint,
|
||||
path_t *const returnpath,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards)
|
||||
|
||||
Use pathfinding to try and find the best route to the destination. Data is allocated into the returnpath,
|
||||
and should be freed when done with. A call to this with a path already in the returnpath will free the data
|
||||
already in there if one is found.
|
||||
|
||||
Input Arguments:-
|
||||
sourcewaypoint - The waypoint to start searching from
|
||||
destinationwaypoint - The waypoint to try and get to.
|
||||
returnpath - The path_t that will contain the final found path
|
||||
useshortcuts - Whether to use waypoints that are marked as being shortcuts in the search
|
||||
huntbackwards - Goes through the waypoints backwards if true
|
||||
|
||||
Return:-
|
||||
True if a path was found to the waypoint, false if there wasn't.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_PathfindToWaypoint(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
waypoint_t *const destinationwaypoint,
|
||||
path_t *const returnpath,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
waypoint_t *K_GetNextWaypointToDestination(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
waypoint_t *const destinationwaypoint,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards)
|
||||
|
||||
Uses pathfinding to find the next waypoint to go to in order to get to the destination waypoint, from the source
|
||||
waypoint. If the source waypoint only has one next waypoint it will always pick that one and not do any
|
||||
pathfinding.
|
||||
|
||||
Input Arguments:-
|
||||
sourcewaypoint - The waypoint to start searching from
|
||||
destinationwaypoint - The waypoint to try and get to.
|
||||
useshortcuts - Whether to use waypoints that are marked as being shortcuts in the search
|
||||
huntbackwards - Goes through the waypoints backwards if true
|
||||
|
||||
Return:-
|
||||
The next waypoint on the way to the destination waypoint. Returns the source waypoint if the source and
|
||||
destination are the same.
|
||||
--------------------------------------------------*/
|
||||
|
||||
waypoint_t *K_GetNextWaypointToDestination(
|
||||
waypoint_t *const sourcewaypoint,
|
||||
waypoint_t *const destinationwaypoint,
|
||||
const boolean useshortcuts,
|
||||
const boolean huntbackwards);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
waypoint_t *K_SearchWaypointGraphForMobj(mobj_t *const mobj)
|
||||
|
||||
Searches through the waypoint graph for a waypoint that has an mobj, if a waypoint can be found through here it
|
||||
does mean that the waypoint graph can be traversed to find it
|
||||
|
||||
Input Arguments:-
|
||||
mobj - The mobj that we are searching for, cannot be changed to a different pointer
|
||||
|
||||
Return:-
|
||||
The waypoint that uses that mobj, NULL if it wasn't found, NULL if it isn't an MT_WAYPOINT
|
||||
--------------------------------------------------*/
|
||||
|
||||
waypoint_t *K_SearchWaypointGraphForMobj(mobj_t * const mobj);
|
||||
|
||||
/*--------------------------------------------------
|
||||
waypoint_t *K_SearchWaypointHeapForMobj(mobj_t *const mobj)
|
||||
|
||||
Searches through the waypoint heap for a waypoint that has an mobj, this does not necessarily mean the waypoint
|
||||
can be reached from another waypoint
|
||||
|
||||
Input Arguments:-
|
||||
mobj - The mobj that we are searching for, cannot be changed to a different pointer
|
||||
|
||||
Return:-
|
||||
The waypoint that uses that mobj, NULL if it wasn't found, NULL if it isn't an MT_WAYPOINT
|
||||
--------------------------------------------------*/
|
||||
|
||||
waypoint_t *K_SearchWaypointHeapForMobj(mobj_t * const mobj);
|
||||
|
||||
|
||||
// NOT AVAILABLE FOR LUA
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
size_t K_GetWaypointHeapIndex(waypoint_t *waypoint)
|
||||
|
||||
Returns the waypoint's index in the waypoint heap.
|
||||
|
||||
Input Arguments:-
|
||||
waypoint - The waypoint to return the index of.
|
||||
|
||||
Return:-
|
||||
The waypoint heap index, SIZE_MAX if there's an issue with the waypoint.
|
||||
--------------------------------------------------*/
|
||||
size_t K_GetWaypointHeapIndex(waypoint_t *waypoint);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
waypoint_t *K_GetWaypointFromIndex(size_t waypointindex)
|
||||
|
||||
Returns the waypoint from an index to the heap.
|
||||
|
||||
Input Arguments:-
|
||||
waypointindex - The index of the waypoint to get
|
||||
|
||||
Return:-
|
||||
The waypoint from the heap index, NULL if the index if too high
|
||||
--------------------------------------------------*/
|
||||
waypoint_t *K_GetWaypointFromIndex(size_t waypointindex);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_DebugWaypointsVisualise()
|
||||
|
||||
Creates mobjs in order to visualise waypoints for debugging.
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_DebugWaypointsVisualise(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_SetupWaypointList(void)
|
||||
|
||||
Sets up the waypoint list for Kart race maps, prints out warnings if something is wrong.
|
||||
|
||||
Return:-
|
||||
true if waypoint setup was seemingly successful, false if no waypoints were setup
|
||||
A true return value does not necessarily mean that the waypoints on the map are completely correct
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_SetupWaypointList(void);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_ClearWaypoints(void)
|
||||
|
||||
Clears waypointheap, firstwaypoint, numwaypoints, and numwaypointmobjs
|
||||
WARNING: This does *not* Free waypointheap or any waypoints! They are stored in PU_LEVEL so they are freed once
|
||||
the level is completed! This is called just before K_SetupWaypointList in P_SetupLevel as they are freed then.
|
||||
A separate method is called in K_SetupWaypointList that will free everything specifically if they aren't already
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_ClearWaypoints(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -640,16 +640,6 @@ static int lib_pCheckSolidLava(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int lib_pSpawnShadowMobj(lua_State *L)
|
||||
{
|
||||
mobj_t *caster = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
|
||||
NOHUD
|
||||
if (!caster)
|
||||
return LUA_ErrInvalid(L, "mobj_t");
|
||||
P_SpawnShadowMobj(caster);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// P_USER
|
||||
////////////
|
||||
|
||||
|
|
@ -1314,15 +1304,16 @@ static int lib_pExplodeMissile(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lib_pPlayerTouchingSectorSpecial(lua_State *L)
|
||||
static int lib_pMobjTouchingSectorSpecial(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
|
||||
INT32 section = (INT32)luaL_checkinteger(L, 2);
|
||||
INT32 number = (INT32)luaL_checkinteger(L, 3);
|
||||
boolean touchground = lua_optboolean(L, 4);
|
||||
//HUDSAFE
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
LUA_PushUserdata(L, P_PlayerTouchingSectorSpecial(player, section, number), META_SECTOR);
|
||||
if (!mo)
|
||||
return LUA_ErrInvalid(L, "mobj_t");
|
||||
LUA_PushUserdata(L, P_MobjTouchingSectorSpecial(mo, section, number, touchground), META_SECTOR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2673,7 +2664,6 @@ static luaL_Reg lib[] = {
|
|||
{"P_InsideANonSolidFFloor",lib_pInsideANonSolidFFloor},
|
||||
{"P_CheckDeathPitCollide",lib_pCheckDeathPitCollide},
|
||||
{"P_CheckSolidLava",lib_pCheckSolidLava},
|
||||
{"P_SpawnShadowMobj",lib_pSpawnShadowMobj},
|
||||
|
||||
// p_user
|
||||
{"P_GetPlayerHeight",lib_pGetPlayerHeight},
|
||||
|
|
@ -2737,7 +2727,7 @@ static luaL_Reg lib[] = {
|
|||
{"P_SetMobjStateNF",lib_pSetMobjStateNF},
|
||||
{"P_DoSuperTransformation",lib_pDoSuperTransformation},
|
||||
{"P_ExplodeMissile",lib_pExplodeMissile},
|
||||
{"P_PlayerTouchingSectorSpecial",lib_pPlayerTouchingSectorSpecial},
|
||||
{"P_MobjTouchingSectorSpecial",lib_pMobjTouchingSectorSpecial},
|
||||
{"P_FindSpecialLineFromTag",lib_pFindSpecialLineFromTag},
|
||||
{"P_SwitchWeather",lib_pSwitchWeather},
|
||||
{"P_LinedefExecute",lib_pLinedefExecute},
|
||||
|
|
|
|||
|
|
@ -139,6 +139,8 @@ enum cameraf {
|
|||
camera_momx,
|
||||
camera_momy,
|
||||
camera_momz,
|
||||
camera_pan,
|
||||
camera_pitch,
|
||||
camera_pnum
|
||||
};
|
||||
|
||||
|
|
@ -158,6 +160,8 @@ static const char *const camera_opt[] = {
|
|||
"momx",
|
||||
"momy",
|
||||
"momz",
|
||||
"pan",
|
||||
"pitch",
|
||||
"pnum",
|
||||
NULL};
|
||||
|
||||
|
|
@ -314,6 +318,12 @@ static int camera_get(lua_State *L)
|
|||
case camera_momz:
|
||||
lua_pushinteger(L, cam->momz);
|
||||
break;
|
||||
case camera_pan:
|
||||
lua_pushinteger(L, cam->pan);
|
||||
break;
|
||||
case camera_pitch:
|
||||
lua_pushinteger(L, cam->pitch);
|
||||
break;
|
||||
case camera_pnum:
|
||||
lua_pushinteger(L, camnum);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -85,7 +85,9 @@ enum mobj_e {
|
|||
#ifdef ESLOPE
|
||||
mobj_standingslope,
|
||||
#endif
|
||||
mobj_colorized
|
||||
mobj_colorized,
|
||||
mobj_shadowscale,
|
||||
mobj_whiteshadow
|
||||
};
|
||||
|
||||
static const char *const mobj_opt[] = {
|
||||
|
|
@ -149,6 +151,8 @@ static const char *const mobj_opt[] = {
|
|||
"standingslope",
|
||||
#endif
|
||||
"colorized",
|
||||
"shadowscale",
|
||||
"whiteshadow",
|
||||
NULL};
|
||||
|
||||
#define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field])
|
||||
|
|
@ -360,6 +364,12 @@ static int mobj_get(lua_State *L)
|
|||
case mobj_colorized:
|
||||
lua_pushboolean(L, mo->colorized);
|
||||
break;
|
||||
case mobj_shadowscale:
|
||||
lua_pushfixed(L, mo->shadowscale);
|
||||
break;
|
||||
case mobj_whiteshadow:
|
||||
lua_pushboolean(L, mo->whiteshadow);
|
||||
break;
|
||||
default: // extra custom variables in Lua memory
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
|
||||
I_Assert(lua_istable(L, -1));
|
||||
|
|
@ -677,6 +687,12 @@ static int mobj_set(lua_State *L)
|
|||
case mobj_colorized:
|
||||
mo->colorized = luaL_checkboolean(L, 3);
|
||||
break;
|
||||
case mobj_shadowscale:
|
||||
mo->shadowscale = luaL_checkfixed(L, 3);
|
||||
break;
|
||||
case mobj_whiteshadow:
|
||||
mo->whiteshadow = luaL_checkboolean(L, 3);
|
||||
break;
|
||||
default:
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
|
||||
I_Assert(lua_istable(L, -1));
|
||||
|
|
|
|||
|
|
@ -292,9 +292,18 @@ void Command_CheatNoClip_f(void)
|
|||
REQUIRE_NOULTIMATE;
|
||||
|
||||
plyr = &players[consoleplayer];
|
||||
|
||||
if (!plyr->mo || P_MobjWasRemoved(plyr->mo))
|
||||
return;
|
||||
|
||||
plyr->pflags ^= PF_NOCLIP;
|
||||
CONS_Printf(M_GetText("No Clipping %s\n"), plyr->pflags & PF_NOCLIP ? M_GetText("On") : M_GetText("Off"));
|
||||
|
||||
if (plyr->pflags & PF_NOCLIP)
|
||||
plyr->mo->flags |= MF_NOCLIP;
|
||||
else
|
||||
plyr->mo->flags &= ~MF_NOCLIP;
|
||||
|
||||
G_SetGameModified(multiplayer, true);
|
||||
}
|
||||
|
||||
|
|
|
|||
201
src/p_enemy.c
201
src/p_enemy.c
|
|
@ -24,6 +24,7 @@
|
|||
#include "i_video.h"
|
||||
#include "lua_hook.h"
|
||||
#include "k_kart.h" // SRB2kart
|
||||
#include "k_waypoint.h"
|
||||
|
||||
#ifdef HW3SOUND
|
||||
#include "hardware/hw3sound.h"
|
||||
|
|
@ -117,7 +118,6 @@ void A_ThrownRing(mobj_t *actor);
|
|||
void A_GrenadeRing(mobj_t *actor);
|
||||
void A_SetSolidSteam(mobj_t *actor);
|
||||
void A_UnsetSolidSteam(mobj_t *actor);
|
||||
void A_SignPlayer(mobj_t *actor);
|
||||
void A_OverlayThink(mobj_t *actor);
|
||||
void A_JetChase(mobj_t *actor);
|
||||
void A_JetbThink(mobj_t *actor);
|
||||
|
|
@ -4180,38 +4180,6 @@ void A_UnsetSolidSteam(mobj_t *actor)
|
|||
actor->flags |= MF_NOCLIP;
|
||||
}
|
||||
|
||||
// Function: A_SignPlayer
|
||||
//
|
||||
// Description: Changes the state of a level end sign to reflect the player that hit it.
|
||||
//
|
||||
// var1 = unused
|
||||
// var2 = unused
|
||||
//
|
||||
void A_SignPlayer(mobj_t *actor)
|
||||
{
|
||||
mobj_t *ov;
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_SignPlayer", actor))
|
||||
return;
|
||||
#endif
|
||||
if (!actor->target)
|
||||
return;
|
||||
|
||||
if (!actor->target->player)
|
||||
return;
|
||||
|
||||
// Set the sign to be an appropriate background color for this player's skincolor.
|
||||
actor->color = KartColor_Opposite[actor->target->player->skincolor*2];
|
||||
actor->frame += KartColor_Opposite[actor->target->player->skincolor*2+1];
|
||||
|
||||
// spawn an overlay of the player's face.
|
||||
ov = P_SpawnMobj(actor->x, actor->y, actor->z, MT_OVERLAY);
|
||||
P_SetTarget(&ov->target, actor);
|
||||
ov->color = actor->target->player->skincolor;
|
||||
ov->skin = &skins[actor->target->player->skin];
|
||||
P_SetMobjState(ov, actor->info->seestate); // S_PLAY_SIGN
|
||||
}
|
||||
|
||||
// Function: A_OverlayThink
|
||||
//
|
||||
// Description: Moves the overlay to the position of its target.
|
||||
|
|
@ -8477,14 +8445,31 @@ void A_JawzExplode(mobj_t *actor)
|
|||
return;
|
||||
}
|
||||
|
||||
static void SpawnSPBTrailRings(mobj_t *actor)
|
||||
{
|
||||
I_Assert(actor != NULL);
|
||||
|
||||
if (leveltime % 6 == 0)
|
||||
{
|
||||
mobj_t *ring = P_SpawnMobj(actor->x - actor->momx, actor->y - actor->momy,
|
||||
actor->z - actor->momz + (24*mapobjectscale), MT_RING);
|
||||
ring->threshold = 10;
|
||||
ring->fuse = 120*TICRATE;
|
||||
}
|
||||
}
|
||||
|
||||
void A_SPBChase(mobj_t *actor)
|
||||
{
|
||||
player_t *player = NULL;
|
||||
player_t *scplayer = NULL; // secondary target for seeking
|
||||
UINT8 i;
|
||||
UINT8 bestrank = UINT8_MAX;
|
||||
fixed_t dist;
|
||||
angle_t hang, vang;
|
||||
fixed_t wspeed, xyspeed, zspeed;
|
||||
fixed_t pdist = 1536<<FRACBITS; // best player distance when seeking
|
||||
angle_t pangle; // angle between us and the player
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUA_CallAction("A_SPBChase", actor))
|
||||
return;
|
||||
|
|
@ -8496,9 +8481,9 @@ void A_SPBChase(mobj_t *actor)
|
|||
if (actor->threshold) // Just fired, go straight.
|
||||
{
|
||||
actor->lastlook = -1;
|
||||
actor->cusval = -1;
|
||||
spbplace = -1;
|
||||
P_InstaThrust(actor, actor->angle, wspeed);
|
||||
actor->flags &= ~MF_NOCLIPTHING; // just in case.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -8524,18 +8509,22 @@ void A_SPBChase(mobj_t *actor)
|
|||
}
|
||||
}
|
||||
|
||||
// lastlook = last player num targetted
|
||||
// cvmem = stored speed
|
||||
// cusval = next waypoint heap index
|
||||
// extravalue1 = SPB movement mode
|
||||
// extravalue2 = mode misc option
|
||||
|
||||
if (actor->extravalue1 == 1) // MODE: TARGETING
|
||||
{
|
||||
actor->cusval = -1; // Reset waypoint
|
||||
|
||||
if (actor->tracer && actor->tracer->health)
|
||||
{
|
||||
|
||||
fixed_t defspeed = wspeed;
|
||||
fixed_t range = (160*actor->tracer->scale);
|
||||
fixed_t cx = 0, cy =0;
|
||||
|
||||
// we're tailing a player, now's a good time to regain our damage properties
|
||||
actor->flags &= ~MF_NOCLIPTHING;
|
||||
|
||||
// Play the intimidating gurgle
|
||||
if (!S_SoundPlaying(actor, actor->info->activesound))
|
||||
S_StartSound(actor, actor->info->activesound);
|
||||
|
|
@ -8633,13 +8622,7 @@ void A_SPBChase(mobj_t *actor)
|
|||
actor->momz = FixedMul(zspeed, FINESINE(actor->movedir>>ANGLETOFINESHIFT));
|
||||
|
||||
// Spawn a trail of rings behind the SPB!
|
||||
if (leveltime % 6 == 0)
|
||||
{
|
||||
mobj_t *ring = P_SpawnMobj(actor->x - actor->momx, actor->y - actor->momx,
|
||||
actor->z - actor->momz + (24*mapobjectscale), MT_RING);
|
||||
ring->threshold = 10;
|
||||
ring->fuse = 120*TICRATE;
|
||||
}
|
||||
SpawnSPBTrailRings(actor);
|
||||
|
||||
// Red speed lines for when it's gaining on its target. A tell for when you're starting to lose too much speed!
|
||||
if (R_PointToDist2(0, 0, actor->momx, actor->momy) > (actor->tracer->player ? (16*actor->tracer->player->speed)/15
|
||||
|
|
@ -8672,9 +8655,7 @@ void A_SPBChase(mobj_t *actor)
|
|||
else if (actor->extravalue1 == 2) // MODE: WAIT...
|
||||
{
|
||||
actor->momx = actor->momy = actor->momz = 0; // Stoooop
|
||||
|
||||
// don't hurt players that have nothing to do with this:
|
||||
actor->flags |= MF_NOCLIPTHING;
|
||||
actor->cusval = -1; // Reset waypoint
|
||||
|
||||
if (actor->lastlook != -1
|
||||
&& playeringame[actor->lastlook]
|
||||
|
|
@ -8700,6 +8681,11 @@ void A_SPBChase(mobj_t *actor)
|
|||
}
|
||||
else // MODE: SEEKING
|
||||
{
|
||||
waypoint_t *lastwaypoint = NULL;
|
||||
waypoint_t *bestwaypoint = NULL;
|
||||
waypoint_t *nextwaypoint = NULL;
|
||||
waypoint_t *tempwaypoint = NULL;
|
||||
|
||||
actor->lastlook = -1; // Just make sure this is reset
|
||||
|
||||
if (!player || !player->mo || player->mo->health <= 0 || player->kartstuff[k_respawn])
|
||||
|
|
@ -8712,17 +8698,72 @@ void A_SPBChase(mobj_t *actor)
|
|||
}
|
||||
|
||||
// Found someone, now get close enough to initiate the slaughter...
|
||||
|
||||
// don't hurt players that have nothing to do with this:
|
||||
actor->flags |= MF_NOCLIPTHING;
|
||||
|
||||
P_SetTarget(&actor->tracer, player->mo);
|
||||
spbplace = bestrank;
|
||||
|
||||
dist = P_AproxDistance(P_AproxDistance(actor->x-actor->tracer->x, actor->y-actor->tracer->y), actor->z-actor->tracer->z);
|
||||
|
||||
hang = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y);
|
||||
vang = R_PointToAngle2(0, actor->z, dist, actor->tracer->z);
|
||||
// Move along the waypoints until you get close enough
|
||||
if (actor->cusval > -1 && actor->extravalue2 > 0)
|
||||
{
|
||||
// Previously set nextwaypoint
|
||||
lastwaypoint = K_GetWaypointFromIndex((size_t)actor->cusval);
|
||||
tempwaypoint = K_GetBestWaypointForMobj(actor);
|
||||
// check if the tempwaypoint corresponds to lastwaypoint's next ID at least;
|
||||
// This is to avoid situations where the SPB decides to suicide jump down a bridge because it found a COMPLETELY unrelated waypoint down there.
|
||||
|
||||
if (K_GetWaypointID(tempwaypoint) == K_GetWaypointNextID(lastwaypoint) || K_GetWaypointID(tempwaypoint) == K_GetWaypointID(lastwaypoint))
|
||||
// either our previous or curr waypoint ID, sure, take it
|
||||
bestwaypoint = tempwaypoint;
|
||||
else
|
||||
bestwaypoint = K_GetWaypointFromIndex((size_t)actor->extravalue2); // keep going from the PREVIOUS wp.
|
||||
}
|
||||
else
|
||||
bestwaypoint = K_GetBestWaypointForMobj(actor);
|
||||
|
||||
if (bestwaypoint == NULL && lastwaypoint == NULL)
|
||||
{
|
||||
// We have invalid waypoints all around, so use closest to try and make it non-NULL.
|
||||
bestwaypoint = K_GetClosestWaypointToMobj(actor);
|
||||
}
|
||||
|
||||
if (bestwaypoint != NULL)
|
||||
{
|
||||
const boolean huntbackwards = false;
|
||||
boolean useshortcuts = false;
|
||||
|
||||
// If the player is on a shortcut, use shortcuts. No escape.
|
||||
if (K_GetWaypointIsShortcut(player->nextwaypoint))
|
||||
{
|
||||
useshortcuts = true;
|
||||
}
|
||||
|
||||
nextwaypoint = K_GetNextWaypointToDestination(
|
||||
bestwaypoint, player->nextwaypoint, useshortcuts, huntbackwards);
|
||||
}
|
||||
|
||||
if (nextwaypoint == NULL && lastwaypoint != NULL)
|
||||
{
|
||||
// Restore to the last nextwaypoint
|
||||
nextwaypoint = lastwaypoint;
|
||||
}
|
||||
|
||||
if (nextwaypoint != NULL)
|
||||
{
|
||||
const fixed_t xywaypointdist = P_AproxDistance(
|
||||
actor->x - nextwaypoint->mobj->x, actor->y - nextwaypoint->mobj->y);
|
||||
|
||||
hang = R_PointToAngle2(actor->x, actor->y, nextwaypoint->mobj->x, nextwaypoint->mobj->y);
|
||||
vang = R_PointToAngle2(0, actor->z, xywaypointdist, nextwaypoint->mobj->z);
|
||||
|
||||
actor->cusval = (INT32)K_GetWaypointHeapIndex(nextwaypoint);
|
||||
actor->extravalue2 = (INT32)K_GetWaypointHeapIndex(bestwaypoint); // save our last best, used above.
|
||||
}
|
||||
else
|
||||
{
|
||||
// continue straight ahead... Shouldn't happen.
|
||||
hang = actor->angle;
|
||||
vang = 0U;
|
||||
}
|
||||
|
||||
{
|
||||
// Smoothly rotate horz angle
|
||||
|
|
@ -8731,13 +8772,13 @@ void A_SPBChase(mobj_t *actor)
|
|||
if (invert)
|
||||
input = InvAngle(input);
|
||||
|
||||
input = FixedAngle(AngleFixed(input)/8);
|
||||
|
||||
// Slow down when turning; it looks better and makes U-turns not unfair
|
||||
xyspeed = FixedMul(wspeed, max(0, (((180<<FRACBITS) - AngleFixed(input)) / 90) - FRACUNIT));
|
||||
|
||||
input = FixedAngle(AngleFixed(input)/4);
|
||||
if (invert)
|
||||
input = InvAngle(input);
|
||||
|
||||
actor->angle += input;
|
||||
|
||||
// Smoothly rotate vert angle
|
||||
|
|
@ -8746,13 +8787,13 @@ void A_SPBChase(mobj_t *actor)
|
|||
if (invert)
|
||||
input = InvAngle(input);
|
||||
|
||||
input = FixedAngle(AngleFixed(input)/8);
|
||||
|
||||
// Slow down when turning; might as well do it for momz, since we do it above too
|
||||
zspeed = FixedMul(wspeed, max(0, (((180<<FRACBITS) - AngleFixed(input)) / 90) - FRACUNIT));
|
||||
|
||||
input = FixedAngle(AngleFixed(input)/4);
|
||||
if (invert)
|
||||
input = InvAngle(input);
|
||||
|
||||
actor->movedir += input;
|
||||
}
|
||||
|
||||
|
|
@ -8760,15 +8801,49 @@ void A_SPBChase(mobj_t *actor)
|
|||
actor->momy = FixedMul(FixedMul(xyspeed, FINESINE(actor->angle>>ANGLETOFINESHIFT)), FINECOSINE(actor->movedir>>ANGLETOFINESHIFT));
|
||||
actor->momz = FixedMul(zspeed, FINESINE(actor->movedir>>ANGLETOFINESHIFT));
|
||||
|
||||
if (dist <= (3072*actor->tracer->scale)) // Close enough to target?
|
||||
// see if a player is near us, if they are, try to hit them by slightly thrusting towards them, otherwise, bleh!
|
||||
for (i=0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
S_StartSound(actor, actor->info->attacksound); // Siren sound; might not need this anymore, but I'm keeping it for now just for debugging.
|
||||
if (!playeringame[i] || players[i].spectator || players[i].exiting)
|
||||
continue; // not in-game
|
||||
|
||||
if (R_PointToDist2(actor->x, actor->y, players[i].mo->x, players[i].mo->y) < pdist)
|
||||
{
|
||||
pdist = R_PointToDist2(actor->x, actor->y, players[i].mo->x, players[i].mo->y);
|
||||
scplayer = &players[i]; // it doesn't matter if we override this guy now.
|
||||
}
|
||||
}
|
||||
|
||||
// different player from our main target, try and ram into em~!
|
||||
if (scplayer && scplayer != player)
|
||||
{
|
||||
pangle = actor->angle - R_PointToAngle2(actor->x, actor->y,scplayer->mo->x, scplayer->mo->y);
|
||||
// check if the angle wouldn't make us LOSE speed...
|
||||
if ((INT32)pangle/ANG1 >= -80 && (INT32)pangle/ANG1 <= 80) // allow for around 80 degrees
|
||||
{
|
||||
// Thrust us towards the guy, try to screw em up!
|
||||
P_Thrust(actor, R_PointToAngle2(actor->x, actor->y, scplayer->mo->x, scplayer->mo->y), actor->movefactor/4); // not too fast though.
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn a trail of rings behind the SPB!
|
||||
SpawnSPBTrailRings(actor);
|
||||
|
||||
if (dist <= (1024*actor->tracer->scale)) // Close enough to target?
|
||||
{
|
||||
S_StartSound(actor, actor->info->attacksound);
|
||||
actor->extravalue1 = 1; // TARGET ACQUIRED
|
||||
actor->extravalue2 = 7*TICRATE;
|
||||
actor->cvmem = wspeed;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, no matter what, the spb should not be able to be under the ground, or above the ceiling;
|
||||
if (actor->z < actor->floorz)
|
||||
actor->z = actor->floorz;
|
||||
else if (actor->z > actor->ceilingz - actor->height)
|
||||
actor->z = actor->ceilingz - actor->height;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -10610,8 +10685,8 @@ void A_RemoteDamage(mobj_t *actor)
|
|||
|
||||
if (locvar2 == 1) // Kill mobj!
|
||||
{
|
||||
if (target->player) // players die using P_DamageMobj instead for some reason
|
||||
P_DamageMobj(target, source, source, 10000);
|
||||
if (target->player)
|
||||
K_DoIngameRespawn(target->player);
|
||||
else
|
||||
P_KillMobj(target, source, source);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1769,6 +1769,7 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
|
|||
case MT_SUPERSPARK:
|
||||
case MT_RAIN:
|
||||
case MT_SNOWFLAKE:
|
||||
case MT_BLIZZARDSNOW:
|
||||
case MT_SPLISH:
|
||||
case MT_SMOKE:
|
||||
case MT_SMALLBUBBLE:
|
||||
|
|
@ -2275,7 +2276,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
|
|||
continue;
|
||||
|
||||
if (!(players[i].mo->subsector->sector == sec
|
||||
|| P_PlayerTouchingSectorSpecial(&players[i], 2, (GETSECSPECIAL(sec->special, 2))) == sec))
|
||||
|| P_MobjTouchingSectorSpecial(players[i].mo, 2, (GETSECSPECIAL(sec->special, 2)), false) == sec))
|
||||
continue;
|
||||
|
||||
if (floortouch == true && P_IsObjectOnRealGround(players[i].mo, sec))
|
||||
|
|
|
|||
|
|
@ -926,7 +926,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
special->fuse = 1;
|
||||
special->flags2 |= MF2_JUSTATTACKED;
|
||||
|
||||
if (!P_PlayerTouchingSectorSpecial(player, 4, 2 + flagteam))
|
||||
if (!P_MobjTouchingSectorSpecial(player->mo, 4, 2 + flagteam, false))
|
||||
{
|
||||
CONS_Printf(M_GetText("%s returned the %c%s%c to base.\n"), plname, flagcolor, flagtext, 0x80);
|
||||
|
||||
|
|
@ -1463,15 +1463,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
case MT_STARPOST:
|
||||
if (player->bot)
|
||||
return;
|
||||
// SRB2kart - 150117
|
||||
if (player->exiting) //STOP MESSING UP MY STATS FASDFASDF
|
||||
{
|
||||
player->kartstuff[k_starpostwp] = player->kartstuff[k_waypoint];
|
||||
return;
|
||||
}
|
||||
//
|
||||
// SRB2kart: make sure the player will have enough checkpoints to touch
|
||||
if (circuitmap && special->health >= ((numstarposts/2) + player->starpostnum))
|
||||
if (circuitmap && special->health - player->starpostnum > 1)
|
||||
{
|
||||
// blatant reuse of a variable that's normally unused in circuit
|
||||
if (!player->tossdelay)
|
||||
|
|
@ -1492,13 +1486,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
|
||||
// Save the player's time and position.
|
||||
player->starposttime = player->realtime; //this makes race mode's timers work correctly whilst not affecting sp -x
|
||||
//player->starposttime = leveltime;
|
||||
player->starpostx = toucher->x>>FRACBITS;
|
||||
player->starposty = toucher->y>>FRACBITS;
|
||||
player->starpostz = special->z>>FRACBITS;
|
||||
player->starpostangle = special->angle;
|
||||
player->starpostnum = special->health;
|
||||
player->kartstuff[k_starpostflip] = special->spawnpoint->options & MTF_OBJECTFLIP; // store flipping
|
||||
|
||||
//S_StartSound(toucher, special->info->painsound);
|
||||
return;
|
||||
|
|
@ -2158,6 +2146,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
|
|||
target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SPECIAL);
|
||||
target->flags2 &= ~(MF2_SKULLFLY|MF2_NIGHTSPULL);
|
||||
target->health = 0; // This makes it easy to check if something's dead elsewhere.
|
||||
target->shadowscale = 0;
|
||||
|
||||
#ifdef HAVE_BLUA
|
||||
if (LUAh_MobjDeath(target, inflictor, source) || P_MobjWasRemoved(target))
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@ typedef struct camera_s
|
|||
|
||||
// SRB2Kart: camera pans while drifting
|
||||
fixed_t pan;
|
||||
// SRB2Kart: camera pitches on slopes
|
||||
angle_t pitch;
|
||||
} camera_t;
|
||||
|
||||
extern camera_t camera[MAXSPLITSCREENPLAYERS];
|
||||
|
|
@ -180,7 +182,6 @@ boolean P_LookForEnemies(player_t *player);
|
|||
void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius);
|
||||
void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user
|
||||
//boolean P_SuperReady(player_t *player);
|
||||
boolean P_AnalogMove(player_t *player);
|
||||
/*boolean P_TransferToNextMare(player_t *player);
|
||||
UINT8 P_FindLowestMare(void);*/
|
||||
UINT8 P_FindLowestLap(void);
|
||||
|
|
@ -216,8 +217,6 @@ void P_RespawnSpecials(void);
|
|||
|
||||
mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
|
||||
|
||||
mobj_t *P_SpawnShadowMobj(mobj_t * caster);
|
||||
|
||||
void P_RecalcPrecipInSector(sector_t *sector);
|
||||
void P_PrecipitationEffects(void);
|
||||
|
||||
|
|
@ -228,8 +227,6 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state);
|
|||
boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
|
||||
//void P_RunShields(void);
|
||||
void P_RunOverlays(void);
|
||||
fixed_t P_CalculateShadowFloor(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player);
|
||||
void P_RunShadows(void);
|
||||
void P_MobjThinker(mobj_t *mobj);
|
||||
boolean P_RailThinker(mobj_t *mobj);
|
||||
void P_PushableThinker(mobj_t *mobj);
|
||||
|
|
|
|||
207
src/p_map.c
207
src/p_map.c
|
|
@ -69,6 +69,20 @@ line_t *ceilingline;
|
|||
// that is, for any line which is 'solid'
|
||||
line_t *blockingline;
|
||||
|
||||
// Mostly re-ported from DOOM Legacy
|
||||
// Keep track of special lines as they are hit, process them when the move is valid
|
||||
static size_t *spechit = NULL;
|
||||
static size_t spechit_max = 0U;
|
||||
static size_t numspechit = 0U;
|
||||
|
||||
// Need a intermediate buffer for P_TryMove because it performs multiple moves
|
||||
// the lines put into spechit will be moved into here after each checkposition,
|
||||
// then and duplicates will be removed before processing
|
||||
static size_t *spechitint = NULL;
|
||||
static size_t spechitint_max = 0U;
|
||||
static size_t numspechitint = 0U;
|
||||
|
||||
|
||||
msecnode_t *sector_list = NULL;
|
||||
mprecipsecnode_t *precipsector_list = NULL;
|
||||
camera_t *mapcampointer;
|
||||
|
|
@ -82,6 +96,8 @@ camera_t *mapcampointer;
|
|||
//
|
||||
boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
|
||||
{
|
||||
numspechit = 0U;
|
||||
|
||||
// the move is ok,
|
||||
// so link the thing into its new position
|
||||
P_UnsetThingPosition(thing);
|
||||
|
|
@ -114,6 +130,100 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
|
|||
// MOVEMENT ITERATOR FUNCTIONS
|
||||
// =========================================================================
|
||||
|
||||
// For our intermediate buffer, remove any duplicate entries by adding each one to
|
||||
// a temprary buffer if it's not already in there, copy the temporary buffer back over the intermediate afterwards
|
||||
static void spechitint_removedups(void)
|
||||
{
|
||||
// Only needs to be run if there's more than 1 line crossed
|
||||
if (numspechitint > 1U)
|
||||
{
|
||||
boolean valueintemp = false;
|
||||
size_t i = 0U, j = 0U;
|
||||
size_t numspechittemp = 0U;
|
||||
size_t *spechittemp = Z_Calloc(numspechitint * sizeof(size_t), PU_STATIC, NULL);
|
||||
|
||||
// Fill the hashtable
|
||||
for (i = 0U; i < numspechitint; i++)
|
||||
{
|
||||
valueintemp = false;
|
||||
for (j = 0; j < numspechittemp; j++)
|
||||
{
|
||||
if (spechitint[i] == spechittemp[j])
|
||||
{
|
||||
valueintemp = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valueintemp)
|
||||
{
|
||||
spechittemp[numspechittemp] = spechitint[i];
|
||||
numspechittemp++;
|
||||
}
|
||||
}
|
||||
|
||||
// The hash table now IS the result we want to send back
|
||||
// easiest way to handle this is a memcpy
|
||||
if (numspechittemp != numspechitint)
|
||||
{
|
||||
memcpy(spechitint, spechittemp, numspechittemp * sizeof(size_t));
|
||||
numspechitint = numspechittemp;
|
||||
}
|
||||
|
||||
Z_Free(spechittemp);
|
||||
}
|
||||
}
|
||||
|
||||
// copy the contents of spechit into the end of spechitint
|
||||
static void spechitint_copyinto(void)
|
||||
{
|
||||
if (numspechit > 0U)
|
||||
{
|
||||
if (numspechitint + numspechit >= spechitint_max)
|
||||
{
|
||||
spechitint_max = spechitint_max + numspechit;
|
||||
spechitint = Z_Realloc(spechitint, spechitint_max * sizeof(size_t), PU_STATIC, NULL);
|
||||
}
|
||||
|
||||
memcpy(&spechitint[numspechitint], spechit, numspechit * sizeof(size_t));
|
||||
numspechitint += numspechit;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_spechit(line_t *ld)
|
||||
{
|
||||
if (numspechit >= spechit_max)
|
||||
{
|
||||
spechit_max = spechit_max ? spechit_max * 2U : 16U;
|
||||
spechit = Z_Realloc(spechit, spechit_max * sizeof(size_t), PU_STATIC, NULL);
|
||||
}
|
||||
|
||||
spechit[numspechit] = ld - lines;
|
||||
numspechit++;
|
||||
}
|
||||
|
||||
static boolean P_SpecialIsLinedefCrossType(UINT16 ldspecial)
|
||||
{
|
||||
boolean linedefcrossspecial = false;
|
||||
|
||||
switch (ldspecial)
|
||||
{
|
||||
case 2001: // Finish line
|
||||
{
|
||||
linedefcrossspecial = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
linedefcrossspecial = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return linedefcrossspecial;
|
||||
}
|
||||
|
||||
//#define TELEPORTJANK
|
||||
|
||||
boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|
||||
|
|
@ -147,7 +257,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|
|||
object->eflags |= MFE_SPRUNG; // apply this flag asap!
|
||||
spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify
|
||||
|
||||
#ifdef TELEPORTJANK
|
||||
#if 0
|
||||
if (horizspeed && vertispeed) // Mimic SA
|
||||
{
|
||||
object->momx = object->momy = 0;
|
||||
|
|
@ -196,7 +306,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|
|||
if (horizspeed)
|
||||
{
|
||||
angle_t finalAngle = spring->angle;
|
||||
fixed_t finalSpeed = horizspeed;
|
||||
fixed_t finalSpeed = FixedMul(horizspeed, FixedSqrt(FixedMul(hscale, spring->scale)));
|
||||
fixed_t objectSpeed;
|
||||
|
||||
if (object->player)
|
||||
|
|
@ -274,7 +384,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|
|||
// Horizontal speed is used as a minimum thrust, not a direct replacement
|
||||
finalSpeed = max(objectSpeed, finalSpeed);
|
||||
|
||||
P_InstaThrustEvenIn2D(object, finalAngle, FixedMul(finalSpeed, FixedSqrt(FixedMul(hscale, spring->scale))));
|
||||
P_InstaThrustEvenIn2D(object, finalAngle, finalSpeed);
|
||||
}
|
||||
|
||||
// Re-solidify
|
||||
|
|
@ -1007,7 +1117,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
|
||||
thing->angle = tmthing->angle;
|
||||
|
||||
if (!demo.playback || P_AnalogMove(thing->player))
|
||||
if (!demo.playback)
|
||||
{
|
||||
if (thing->player == &players[consoleplayer])
|
||||
localangle[0] = thing->angle;
|
||||
|
|
@ -1252,7 +1362,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
{
|
||||
// Objects kill you if it falls from above.
|
||||
if (thing != tmthing->target)
|
||||
P_DamageMobj(thing, tmthing, tmthing->target, 10000);
|
||||
K_DoIngameRespawn(thing->player);
|
||||
|
||||
tmthing->momz = -tmthing->momz/2; // Bounce, just for fun!
|
||||
// The tmthing->target allows the pusher of the object
|
||||
|
|
@ -1670,7 +1780,7 @@ static boolean PIT_CheckLine(line_t *ld)
|
|||
if (P_BoxOnLineSide(tmbbox, ld) != -1)
|
||||
return true;
|
||||
|
||||
if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag.
|
||||
if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag.
|
||||
{
|
||||
fixed_t cosradius, sinradius;
|
||||
cosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT));
|
||||
|
|
@ -1737,6 +1847,12 @@ if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a
|
|||
if (lowfloor < tmdropoffz)
|
||||
tmdropoffz = lowfloor;
|
||||
|
||||
// we've crossed the line
|
||||
if (P_SpecialIsLinedefCrossType(ld->special))
|
||||
{
|
||||
add_spechit(ld);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2011,6 +2127,9 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
|
|||
|
||||
validcount++;
|
||||
|
||||
// reset special lines
|
||||
numspechit = 0U;
|
||||
|
||||
if (tmflags & MF_NOCLIP)
|
||||
return true;
|
||||
|
||||
|
|
@ -2450,6 +2569,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
{
|
||||
fixed_t tryx = thing->x;
|
||||
fixed_t tryy = thing->y;
|
||||
fixed_t oldx = tryx;
|
||||
fixed_t oldy = tryy;
|
||||
fixed_t radius = thing->radius;
|
||||
fixed_t thingtop = thing->z + thing->height;
|
||||
#ifdef ESLOPE
|
||||
|
|
@ -2457,8 +2578,13 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
#endif
|
||||
floatok = false;
|
||||
|
||||
if (radius < MAXRADIUS/2)
|
||||
radius = MAXRADIUS/2;
|
||||
// reset this to 0 at the start of each trymove call as it's only used here
|
||||
numspechitint = 0U;
|
||||
|
||||
// This makes sure that there are no freezes from computing extremely small movements.
|
||||
// Originally was MAXRADIUS/2, but that causes some inconsistencies for small players.
|
||||
if (radius < mapobjectscale)
|
||||
radius = mapobjectscale;
|
||||
|
||||
do {
|
||||
if (thing->flags & MF_NOCLIP) {
|
||||
|
|
@ -2482,34 +2608,24 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
if (!P_CheckPosition(thing, tryx, tryy))
|
||||
return false; // solid wall or thing
|
||||
|
||||
// copy into the spechitint buffer from spechit
|
||||
spechitint_copyinto();
|
||||
|
||||
if (!(thing->flags & MF_NOCLIP))
|
||||
{
|
||||
//All things are affected by their scale.
|
||||
const fixed_t maxstepmove = FixedMul(MAXSTEPMOVE, mapobjectscale);
|
||||
fixed_t maxstep = maxstepmove;
|
||||
|
||||
if (thing->player)
|
||||
{
|
||||
if (thing->player->kartstuff[k_waterskip])
|
||||
maxstep += maxstepmove; // Force some stepmove when waterskipping
|
||||
if (thing->player && thing->player->kartstuff[k_waterskip])
|
||||
maxstep += maxstepmove; // Add some extra stepmove when waterskipping
|
||||
|
||||
// If using type Section1:13, double the maxstep.
|
||||
if (P_PlayerTouchingSectorSpecial(thing->player, 1, 13)
|
||||
|| GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 13)
|
||||
maxstep += maxstepmove;
|
||||
// If using type Section1:12, no maxstep. For ledges you don't want the player to climb! (see: Egg Zeppelin & SMK port walls)
|
||||
else if (P_PlayerTouchingSectorSpecial(thing->player, 1, 12)
|
||||
|| GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 12)
|
||||
maxstep -= maxstepmove;
|
||||
|
||||
// Don't 'step up' while springing,
|
||||
// Only step up "if needed".
|
||||
/* // SRB2kart - don't need
|
||||
if (thing->state == &states[S_PLAY_SPRING]
|
||||
&& P_MobjFlip(thing)*thing->momz > FixedMul(FRACUNIT, thing->scale))
|
||||
maxstep = 0;
|
||||
*/
|
||||
}
|
||||
// If using type Section1:13, double the maxstep.
|
||||
if (P_MobjTouchingSectorSpecial(thing, 1, 13, false))
|
||||
maxstep <<= 1;
|
||||
// If using type Section1:12, no maxstep. For short walls, like Egg Zeppelin
|
||||
else if (P_MobjTouchingSectorSpecial(thing, 1, 12, false))
|
||||
maxstep = 0;
|
||||
|
||||
if (thing->type == MT_SKIM)
|
||||
maxstep = 0;
|
||||
|
|
@ -2532,12 +2648,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
return false; // mobj must lower itself to fit
|
||||
|
||||
// Ramp test
|
||||
if (maxstep > 0 && !(
|
||||
thing->player && (
|
||||
P_PlayerTouchingSectorSpecial(thing->player, 1, 14)
|
||||
|| GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 14)
|
||||
)
|
||||
)
|
||||
if ((maxstep > 0) && !(P_MobjTouchingSectorSpecial(thing, 1, 14, false)))
|
||||
{
|
||||
// If the floor difference is MAXSTEPMOVE or less, and the sector isn't Section1:14, ALWAYS
|
||||
// step down! Formerly required a Section1:13 sector for the full MAXSTEPMOVE, but no more.
|
||||
|
|
@ -2672,6 +2783,30 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
thing->eflags |= MFE_ONGROUND;
|
||||
|
||||
P_SetThingPosition(thing);
|
||||
|
||||
// remove any duplicates that may be in spechitint
|
||||
spechitint_removedups();
|
||||
|
||||
// handle any of the special lines that were crossed
|
||||
if (!(thing->flags & (MF_NOCLIP)))
|
||||
{
|
||||
line_t *ld = NULL;
|
||||
INT32 side = 0, oldside = 0;
|
||||
while (numspechitint--)
|
||||
{
|
||||
ld = &lines[spechitint[numspechitint]];
|
||||
side = P_PointOnLineSide(thing->x, thing->y, ld);
|
||||
oldside = P_PointOnLineSide(oldx, oldy, ld);
|
||||
if (side != oldside)
|
||||
{
|
||||
if (ld->special)
|
||||
{
|
||||
P_CrossSpecialLine(ld, oldside, thing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -3383,8 +3518,6 @@ void P_BouncePlayerMove(mobj_t *mo)
|
|||
mmomx = mo->player->rmomx;
|
||||
mmomy = mo->player->rmomy;
|
||||
|
||||
mo->player->kartstuff[k_drift] = 0;
|
||||
mo->player->kartstuff[k_driftcharge] = 0;
|
||||
mo->player->kartstuff[k_pogospring] = 0;
|
||||
|
||||
// trace along the three leading corners
|
||||
|
|
|
|||
1126
src/p_mobj.c
1126
src/p_mobj.c
File diff suppressed because it is too large
Load diff
41
src/p_mobj.h
41
src/p_mobj.h
|
|
@ -253,25 +253,23 @@ typedef enum
|
|||
// PRECIPITATION flags ?! ?! ?!
|
||||
//
|
||||
typedef enum {
|
||||
// Don't draw.
|
||||
PCF_INVISIBLE = 1,
|
||||
// Above pit.
|
||||
PCF_PIT = 2,
|
||||
// Above FOF.
|
||||
PCF_FOF = 4,
|
||||
// Above MOVING FOF (this means we need to keep floorz up to date...)
|
||||
PCF_MOVINGFOF = 8,
|
||||
// Is rain.
|
||||
PCF_RAIN = 16,
|
||||
// Ran the thinker this tic.
|
||||
PCF_THUNK = 32,
|
||||
PCF_INVISIBLE = 1, // Don't draw.
|
||||
PCF_PIT = 1<<1, // Above pit.
|
||||
PCF_FOF = 1<<2, // Above FOF.
|
||||
PCF_MOVINGFOF = 1<<3, // Above MOVING FOF (this means we need to keep floorz up to date...)
|
||||
PCF_SPLASH = 1<<4, // Splashed on the ground, return to the ceiling after the animation's over
|
||||
PCF_THUNK = 1<<5, // Ran the thinker this tic.
|
||||
} precipflag_t;
|
||||
|
||||
// Map Object definition.
|
||||
typedef struct mobj_s
|
||||
{
|
||||
// List: thinker links.
|
||||
thinker_t thinker;
|
||||
|
||||
mobjtype_t type;
|
||||
const mobjinfo_t *info; // &mobjinfo[mobj->type]
|
||||
|
||||
// Info for drawing: position.
|
||||
fixed_t x, y, z;
|
||||
|
||||
|
|
@ -321,8 +319,8 @@ typedef struct mobj_s
|
|||
struct mobj_s *hnext;
|
||||
struct mobj_s *hprev;
|
||||
|
||||
mobjtype_t type;
|
||||
const mobjinfo_t *info; // &mobjinfo[mobj->type]
|
||||
// One last pointer for kart item lists
|
||||
struct mobj_s *itnext;
|
||||
|
||||
INT32 health; // for player this is rings + 1
|
||||
|
||||
|
|
@ -377,6 +375,9 @@ typedef struct mobj_s
|
|||
|
||||
boolean colorized; // Whether the mobj uses the rainbow colormap
|
||||
|
||||
fixed_t shadowscale; // If this object casts a shadow, and the size relative to radius
|
||||
boolean whiteshadow; // Use white shadow, set to true by default for fullbright objects
|
||||
|
||||
// WARNING: New fields must be added separately to savegame and Lua.
|
||||
} mobj_t;
|
||||
|
||||
|
|
@ -392,6 +393,9 @@ typedef struct precipmobj_s
|
|||
// List: thinker links.
|
||||
thinker_t thinker;
|
||||
|
||||
mobjtype_t type;
|
||||
const mobjinfo_t *info; // &mobjinfo[mobj->type]
|
||||
|
||||
// Info for drawing: position.
|
||||
fixed_t x, y, z;
|
||||
|
||||
|
|
@ -436,12 +440,18 @@ typedef struct actioncache_s
|
|||
|
||||
extern actioncache_t actioncachehead;
|
||||
|
||||
extern mobj_t *kitemcap;
|
||||
extern mobj_t *waypointcap;
|
||||
|
||||
void P_InitCachedActions(void);
|
||||
void P_RunCachedActions(void);
|
||||
void P_AddCachedAction(mobj_t *mobj, INT32 statenum);
|
||||
|
||||
// kartitem stuff: Returns true if the specified 'type' is one of the kart item constants we want in the kitemcap list
|
||||
boolean P_IsKartItem(INT32 type);
|
||||
void P_AddKartItem(mobj_t *thing); // needs to be called in k_kart.c
|
||||
void P_RunKartItems(void);
|
||||
|
||||
// check mobj against water content, before movement code
|
||||
void P_MobjCheckWater(mobj_t *mobj);
|
||||
|
||||
|
|
@ -459,8 +469,7 @@ void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 numb
|
|||
boolean P_BossTargetPlayer(mobj_t *actor, boolean closest);
|
||||
boolean P_SupermanLook4Players(mobj_t *actor);
|
||||
void P_DestroyRobots(void);
|
||||
void P_SnowThinker(precipmobj_t *mobj);
|
||||
void P_RainThinker(precipmobj_t *mobj);
|
||||
void P_PrecipThinker(precipmobj_t *mobj);
|
||||
void P_NullPrecipThinker(precipmobj_t *mobj);
|
||||
void P_RemovePrecipMobj(precipmobj_t *mobj);
|
||||
void P_SetScale(mobj_t *mobj, fixed_t newscale);
|
||||
|
|
|
|||
|
|
@ -280,6 +280,9 @@ static void P_NetArchivePlayers(void)
|
|||
WRITEINT16(save_p, players[i].lturn_max[j]);
|
||||
WRITEINT16(save_p, players[i].rturn_max[j]);
|
||||
}
|
||||
|
||||
WRITEUINT32(save_p, players[i].distancetofinish);
|
||||
WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].nextwaypoint));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -448,6 +451,9 @@ static void P_NetUnArchivePlayers(void)
|
|||
players[i].lturn_max[j] = READINT16(save_p);
|
||||
players[i].rturn_max[j] = READINT16(save_p);
|
||||
}
|
||||
|
||||
players[i].distancetofinish = READUINT32(save_p);
|
||||
players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save_p);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -952,9 +958,11 @@ typedef enum
|
|||
MD2_HNEXT = 1<<7,
|
||||
MD2_HPREV = 1<<8,
|
||||
MD2_COLORIZED = 1<<9,
|
||||
MD2_WAYPOINTCAP = 1<<10
|
||||
MD2_WAYPOINTCAP = 1<<10,
|
||||
MD2_KITEMCAP = 1<<11,
|
||||
MD2_ITNEXT = 1<<12
|
||||
#ifdef ESLOPE
|
||||
, MD2_SLOPE = 1<<11
|
||||
, MD2_SLOPE = 1<<13
|
||||
#endif
|
||||
} mobj_diff2_t;
|
||||
|
||||
|
|
@ -1146,6 +1154,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
|
|||
diff2 |= MD2_HNEXT;
|
||||
if (mobj->hprev)
|
||||
diff2 |= MD2_HPREV;
|
||||
if (mobj->itnext)
|
||||
diff2 |= MD2_ITNEXT;
|
||||
#ifdef ESLOPE
|
||||
if (mobj->standingslope)
|
||||
diff2 |= MD2_SLOPE;
|
||||
|
|
@ -1154,6 +1164,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
|
|||
diff2 |= MD2_COLORIZED;
|
||||
if (mobj == waypointcap)
|
||||
diff2 |= MD2_WAYPOINTCAP;
|
||||
if (mobj == kitemcap)
|
||||
diff2 |= MD2_KITEMCAP;
|
||||
if (diff2 != 0)
|
||||
diff |= MD_MORE;
|
||||
|
||||
|
|
@ -1269,6 +1281,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
|
|||
WRITEUINT32(save_p, mobj->hnext->mobjnum);
|
||||
if (diff2 & MD2_HPREV)
|
||||
WRITEUINT32(save_p, mobj->hprev->mobjnum);
|
||||
if (diff2 & MD2_ITNEXT)
|
||||
WRITEUINT32(save_p, mobj->itnext->mobjnum);
|
||||
#ifdef ESLOPE
|
||||
if (diff2 & MD2_SLOPE)
|
||||
WRITEUINT16(save_p, mobj->standingslope->id);
|
||||
|
|
@ -2146,6 +2160,8 @@ static void LoadMobjThinker(actionf_p1 thinker)
|
|||
mobj->hnext = (mobj_t *)(size_t)READUINT32(save_p);
|
||||
if (diff2 & MD2_HPREV)
|
||||
mobj->hprev = (mobj_t *)(size_t)READUINT32(save_p);
|
||||
if (diff2 & MD2_ITNEXT)
|
||||
mobj->itnext = (mobj_t *)(size_t)READUINT32(save_p);
|
||||
#ifdef ESLOPE
|
||||
if (diff2 & MD2_SLOPE)
|
||||
{
|
||||
|
|
@ -2187,6 +2203,9 @@ static void LoadMobjThinker(actionf_p1 thinker)
|
|||
if (diff2 & MD2_WAYPOINTCAP)
|
||||
P_SetTarget(&waypointcap, mobj);
|
||||
|
||||
if (diff2 & MD2_KITEMCAP)
|
||||
P_SetTarget(&kitemcap, mobj);
|
||||
|
||||
mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function
|
||||
}
|
||||
|
||||
|
|
@ -3039,6 +3058,13 @@ static void P_RelinkPointers(void)
|
|||
if (!(mobj->hprev = P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "hprev not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->itnext)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->itnext;
|
||||
mobj->itnext = NULL;
|
||||
if (!(mobj->itnext = P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "itnext not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->player && mobj->player->capsule)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->player->capsule;
|
||||
|
|
@ -3067,6 +3093,15 @@ static void P_RelinkPointers(void)
|
|||
if (!P_SetTarget(&mobj->player->awayviewmobj, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "awayviewmobj not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->player && mobj->player->nextwaypoint)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->player->nextwaypoint;
|
||||
mobj->player->nextwaypoint = K_GetWaypointFromIndex(temp);
|
||||
if (mobj->player->nextwaypoint == NULL)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "nextwaypoint not found on %d\n", mobj->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3312,7 +3347,7 @@ static void P_NetArchiveMisc(void)
|
|||
WRITEUINT32(save_p, hyubgone);
|
||||
WRITEUINT32(save_p, mapreset);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
WRITEINT16(save_p, nospectategrief[i]);
|
||||
|
||||
WRITEUINT8(save_p, thwompsactive);
|
||||
|
|
@ -3437,7 +3472,7 @@ static inline boolean P_NetUnArchiveMisc(void)
|
|||
hyubgone = READUINT32(save_p);
|
||||
mapreset = READUINT32(save_p);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
nospectategrief[i] = READINT16(save_p);
|
||||
|
||||
thwompsactive = (boolean)READUINT8(save_p);
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
#include "k_kart.h"
|
||||
#include "k_battle.h" // K_SpawnBattleCapsules
|
||||
#include "k_pwrlv.h"
|
||||
#include "k_waypoint.h"
|
||||
|
||||
//
|
||||
// Map MD5, calculated on level load.
|
||||
|
|
@ -182,6 +183,8 @@ FUNCNORETURN static ATTRNORETURN void CorruptMapError(const char *msg)
|
|||
static void P_ClearSingleMapHeaderInfo(INT16 i)
|
||||
{
|
||||
const INT16 num = (INT16)(i-1);
|
||||
INT32 exists = (mapheaderinfo[num]->menuflags & LF2_EXISTSHACK);
|
||||
|
||||
DEH_WriteUndoline("LEVELNAME", mapheaderinfo[num]->lvlttl, UNDO_NONE);
|
||||
mapheaderinfo[num]->lvlttl[0] = '\0';
|
||||
DEH_WriteUndoline("SUBTITLE", mapheaderinfo[num]->subttl, UNDO_NONE);
|
||||
|
|
@ -247,7 +250,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
|
|||
DEH_WriteUndoline("LEVELFLAGS", va("%d", mapheaderinfo[num]->levelflags), UNDO_NONE);
|
||||
mapheaderinfo[num]->levelflags = 0;
|
||||
DEH_WriteUndoline("MENUFLAGS", va("%d", mapheaderinfo[num]->menuflags), UNDO_NONE);
|
||||
mapheaderinfo[num]->menuflags = (mainwads ? 0 : LF2_EXISTSHACK); // see p_setup.c - prevents replacing maps in addons with easier versions
|
||||
mapheaderinfo[num]->menuflags = exists; // see p_setup.c - prevents replacing maps in addons with easier versions
|
||||
// TODO grades support for delfile (pfft yeah right)
|
||||
P_DeleteGrades(num);
|
||||
// SRB2Kart
|
||||
|
|
@ -3126,6 +3129,17 @@ boolean P_SetupLevel(boolean skipprecip)
|
|||
if (loadprecip) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame)
|
||||
P_SpawnPrecipitation();
|
||||
|
||||
|
||||
// The waypoint data that's in PU_LEVEL needs to be reset back to 0/NULL now since PU_LEVEL was cleared
|
||||
K_ClearWaypoints();
|
||||
// Load the waypoints please!
|
||||
if (G_RaceGametype())
|
||||
{
|
||||
if (K_SetupWaypointList() == false)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, "Waypoints were not able to be setup! Player positions will not work correctly.\n");
|
||||
}
|
||||
}
|
||||
#ifdef HWRENDER // not win32 only 19990829 by Kin
|
||||
if (rendermode != render_soft && rendermode != render_none)
|
||||
{
|
||||
|
|
|
|||
163
src/p_sight.c
163
src/p_sight.c
|
|
@ -2,7 +2,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
||||
// Copyright (C) 1999-2018 by Sonic Team Junior.
|
||||
// Copyright (C) 1999-2020 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "p_local.h"
|
||||
#include "p_slopes.h"
|
||||
#include "r_main.h"
|
||||
#include "r_state.h"
|
||||
|
||||
|
|
@ -103,12 +104,20 @@ static fixed_t P_InterceptVector2(divline_t *v2, divline_t *v1)
|
|||
static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los)
|
||||
{
|
||||
size_t i;
|
||||
sector_t *polysec;
|
||||
|
||||
if (!(po->flags & POF_RENDERALL))
|
||||
return true; // the polyobject isn't visible, so we can ignore it
|
||||
|
||||
polysec = po->lines[0]->backsector;
|
||||
|
||||
for (i = 0; i < po->numLines; ++i)
|
||||
{
|
||||
line_t *line = po->lines[i];
|
||||
divline_t divl;
|
||||
const vertex_t *v1,*v2;
|
||||
fixed_t frac;
|
||||
fixed_t topslope, bottomslope;
|
||||
|
||||
// already checked other side?
|
||||
if (line->validcount == validcount)
|
||||
|
|
@ -140,7 +149,22 @@ static boolean P_CrossSubsecPolyObj(polyobj_t *po, register los_t *los)
|
|||
continue;
|
||||
|
||||
// stop because it is not two sided
|
||||
return false;
|
||||
//if (!(po->flags & POF_TESTHEIGHT))
|
||||
//return false;
|
||||
|
||||
frac = P_InterceptVector2(&los->strace, &divl);
|
||||
|
||||
// get slopes of top and bottom of this polyobject line
|
||||
topslope = FixedDiv(polysec->ceilingheight - los->sightzstart , frac);
|
||||
bottomslope = FixedDiv(polysec->floorheight - los->sightzstart , frac);
|
||||
|
||||
if (topslope >= los->topslope && bottomslope <= los->bottomslope)
|
||||
return false; // view completely blocked
|
||||
|
||||
// TODO: figure out if it's worth considering partially blocked cases or not?
|
||||
// maybe to adjust los's top/bottom slopes if needed
|
||||
//if (los->topslope <= los->bottomslope)
|
||||
//return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -193,6 +217,15 @@ static boolean P_CrossSubsector(size_t num, register los_t *los)
|
|||
const sector_t *front, *back;
|
||||
const vertex_t *v1,*v2;
|
||||
fixed_t frac;
|
||||
fixed_t frontf, backf, frontc, backc;
|
||||
#ifdef ESLOPE
|
||||
fixed_t fracx, fracy;
|
||||
#endif
|
||||
|
||||
/* SRB2Kart doesn't have this?
|
||||
if (seg->glseg)
|
||||
continue;
|
||||
*/
|
||||
|
||||
// already checked other side?
|
||||
if (line->validcount == validcount)
|
||||
|
|
@ -227,36 +260,51 @@ static boolean P_CrossSubsector(size_t num, register los_t *los)
|
|||
if (!(line->flags & ML_TWOSIDED))
|
||||
return false;
|
||||
|
||||
// calculate fractional intercept (how far along we are divided by how far we are from t2)
|
||||
frac = P_InterceptVector2(&los->strace, &divl);
|
||||
|
||||
front = seg->frontsector;
|
||||
back = seg->backsector;
|
||||
#ifdef ESLOPE
|
||||
// calculate position at intercept
|
||||
fracx = los->strace.x + FixedMul(los->strace.dx, frac);
|
||||
fracy = los->strace.y + FixedMul(los->strace.dy, frac);
|
||||
// calculate sector heights
|
||||
frontf = (front->f_slope) ? P_GetZAt(front->f_slope, fracx, fracy) : front->floorheight;
|
||||
frontc = (front->c_slope) ? P_GetZAt(front->c_slope, fracx, fracy) : front->ceilingheight;
|
||||
backf = (back->f_slope) ? P_GetZAt(back->f_slope, fracx, fracy) : back->floorheight;
|
||||
backc = (back->c_slope) ? P_GetZAt(back->c_slope, fracx, fracy) : back->ceilingheight;
|
||||
#else
|
||||
frontf = front->floorheight;
|
||||
frontc = front->ceilingheight;
|
||||
backf = back->floorheight;
|
||||
backc = back->ceilingheight;
|
||||
#endif
|
||||
// crosses a two sided line
|
||||
// no wall to block sight with?
|
||||
if ((front = seg->frontsector)->floorheight ==
|
||||
(back = seg->backsector)->floorheight &&
|
||||
front->ceilingheight == back->ceilingheight)
|
||||
if (frontf == backf && frontc == backc
|
||||
&& !front->ffloors & !back->ffloors) // (and no FOFs)
|
||||
continue;
|
||||
|
||||
// possible occluder
|
||||
// because of ceiling height differences
|
||||
popentop = front->ceilingheight < back->ceilingheight ?
|
||||
front->ceilingheight : back->ceilingheight ;
|
||||
popentop = min(frontc, backc);
|
||||
|
||||
// because of floor height differences
|
||||
popenbottom = front->floorheight > back->floorheight ?
|
||||
front->floorheight : back->floorheight ;
|
||||
popenbottom = max(frontf, backf);
|
||||
|
||||
// quick test for totally closed doors
|
||||
if (popenbottom >= popentop)
|
||||
return false;
|
||||
|
||||
frac = P_InterceptVector2(&los->strace, &divl);
|
||||
|
||||
if (front->floorheight != back->floorheight)
|
||||
if (frontf != backf)
|
||||
{
|
||||
fixed_t slope = FixedDiv(popenbottom - los->sightzstart , frac);
|
||||
if (slope > los->bottomslope)
|
||||
los->bottomslope = slope;
|
||||
}
|
||||
|
||||
if (front->ceilingheight != back->ceilingheight)
|
||||
if (frontc != backc)
|
||||
{
|
||||
fixed_t slope = FixedDiv(popentop - los->sightzstart , frac);
|
||||
if (slope < los->topslope)
|
||||
|
|
@ -265,6 +313,58 @@ static boolean P_CrossSubsector(size_t num, register los_t *los)
|
|||
|
||||
if (los->topslope <= los->bottomslope)
|
||||
return false;
|
||||
|
||||
// Monster Iestyn: check FOFs!
|
||||
if (front->ffloors || back->ffloors)
|
||||
{
|
||||
ffloor_t *rover;
|
||||
fixed_t topslope, bottomslope;
|
||||
fixed_t topz, bottomz;
|
||||
// check front sector's FOFs first
|
||||
for (rover = front->ffloors; rover; rover = rover->next)
|
||||
{
|
||||
if (!(rover->flags & FF_EXISTS)
|
||||
|| !(rover->flags & FF_RENDERSIDES) || rover->flags & FF_TRANSLUCENT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef ESLOPE
|
||||
topz = (*rover->t_slope) ? P_GetZAt(*rover->t_slope, fracx, fracy) : *rover->topheight;
|
||||
bottomz = (*rover->b_slope) ? P_GetZAt(*rover->b_slope, fracx, fracy) : *rover->bottomheight;
|
||||
#else
|
||||
topz = *rover->topheight;
|
||||
bottomz = *rover->bottomheight;
|
||||
#endif
|
||||
topslope = FixedDiv(topz - los->sightzstart , frac);
|
||||
bottomslope = FixedDiv(bottomz - los->sightzstart , frac);
|
||||
if (topslope >= los->topslope && bottomslope <= los->bottomslope)
|
||||
return false; // view completely blocked
|
||||
}
|
||||
// check back sector's FOFs as well
|
||||
for (rover = back->ffloors; rover; rover = rover->next)
|
||||
{
|
||||
if (!(rover->flags & FF_EXISTS)
|
||||
|| !(rover->flags & FF_RENDERSIDES) || rover->flags & FF_TRANSLUCENT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef ESLOPE
|
||||
topz = (*rover->t_slope) ? P_GetZAt(*rover->t_slope, fracx, fracy) : *rover->topheight;
|
||||
bottomz = (*rover->b_slope) ? P_GetZAt(*rover->b_slope, fracx, fracy) : *rover->bottomheight;
|
||||
#else
|
||||
topz = *rover->topheight;
|
||||
bottomz = *rover->bottomheight;
|
||||
#endif
|
||||
topslope = FixedDiv(topz - los->sightzstart , frac);
|
||||
bottomslope = FixedDiv(bottomz - los->sightzstart , frac);
|
||||
if (topslope >= los->topslope && bottomslope <= los->bottomslope)
|
||||
return false; // view completely blocked
|
||||
}
|
||||
// TODO: figure out if it's worth considering partially blocked cases or not?
|
||||
// maybe to adjust los's top/bottom slopes if needed
|
||||
}
|
||||
}
|
||||
|
||||
// passed the subsector ok
|
||||
|
|
@ -375,6 +475,8 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
|
|||
if (s1 == s2) // Both sectors are the same.
|
||||
{
|
||||
ffloor_t *rover;
|
||||
fixed_t topz1, bottomz1; // top, bottom heights at t1's position
|
||||
fixed_t topz2, bottomz2; // likewise but for t2
|
||||
|
||||
for (rover = s1->ffloors; rover; rover = rover->next)
|
||||
{
|
||||
|
|
@ -382,14 +484,35 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
|
|||
/// \todo Improve by checking fog density/translucency
|
||||
/// and setting a sight limit.
|
||||
if (!(rover->flags & FF_EXISTS)
|
||||
|| !(rover->flags & FF_RENDERPLANES) || rover->flags & FF_TRANSLUCENT)
|
||||
|| !(rover->flags & FF_RENDERPLANES) /*|| (rover->flags & FF_TRANSLUCENT)*/)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef ESLOPE
|
||||
if (*rover->t_slope)
|
||||
{
|
||||
topz1 = P_GetZAt(*rover->t_slope, t1->x, t1->y);
|
||||
topz2 = P_GetZAt(*rover->t_slope, t2->x, t2->y);
|
||||
}
|
||||
else
|
||||
topz1 = topz2 = *rover->topheight;
|
||||
|
||||
if (*rover->b_slope)
|
||||
{
|
||||
bottomz1 = P_GetZAt(*rover->b_slope, t1->x, t1->y);
|
||||
bottomz2 = P_GetZAt(*rover->b_slope, t2->x, t2->y);
|
||||
}
|
||||
else
|
||||
bottomz1 = bottomz2 = *rover->bottomheight;
|
||||
#else
|
||||
topz1 = topz2 = *rover->topheight;
|
||||
bottomz1 = bottomz2 = *rover->bottomheight;
|
||||
#endif
|
||||
|
||||
// Check for blocking floors here.
|
||||
if ((los.sightzstart < *rover->bottomheight && t2->z >= *rover->topheight)
|
||||
|| (los.sightzstart >= *rover->topheight && t2->z + t2->height < *rover->bottomheight))
|
||||
if ((los.sightzstart < bottomz1 && t2->z >= topz2)
|
||||
|| (los.sightzstart >= topz1 && t2->z + t2->height < bottomz2))
|
||||
{
|
||||
// no way to see through that
|
||||
return false;
|
||||
|
|
@ -400,19 +523,19 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
|
|||
|
||||
if (!(rover->flags & FF_INVERTPLANES))
|
||||
{
|
||||
if (los.sightzstart >= *rover->topheight && t2->z + t2->height < *rover->topheight)
|
||||
if (los.sightzstart >= topz1 && t2->z + t2->height < topz2)
|
||||
return false; // blocked by upper outside plane
|
||||
|
||||
if (los.sightzstart < *rover->bottomheight && t2->z >= *rover->bottomheight)
|
||||
if (los.sightzstart < bottomz1 && t2->z >= bottomz2)
|
||||
return false; // blocked by lower outside plane
|
||||
}
|
||||
|
||||
if (rover->flags & FF_INVERTPLANES || rover->flags & FF_BOTHPLANES)
|
||||
{
|
||||
if (los.sightzstart < *rover->topheight && t2->z >= *rover->topheight)
|
||||
if (los.sightzstart < topz1 && t2->z >= topz2)
|
||||
return false; // blocked by upper inside plane
|
||||
|
||||
if (los.sightzstart >= *rover->bottomheight && t2->z + t2->height < *rover->bottomheight)
|
||||
if (los.sightzstart >= bottomz1 && t2->z + t2->height < bottomz2)
|
||||
return false; // blocked by lower inside plane
|
||||
}
|
||||
}
|
||||
|
|
|
|||
796
src/p_spec.c
796
src/p_spec.c
File diff suppressed because it is too large
Load diff
|
|
@ -37,7 +37,7 @@ void P_SpawnSpecials(INT32 fromnetsave);
|
|||
|
||||
// every tic
|
||||
void P_UpdateSpecials(void);
|
||||
sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 number);
|
||||
sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number, boolean touchground);
|
||||
void P_PlayerInSpecialSector(player_t *player);
|
||||
void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *roversector);
|
||||
|
||||
|
|
@ -56,10 +56,12 @@ INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start);
|
|||
|
||||
INT32 P_FindMinSurroundingLight(sector_t *sector, INT32 max);
|
||||
|
||||
void P_CrossSpecialLine(line_t *ld, INT32 side, mobj_t *thing);
|
||||
|
||||
void P_SetupSignExit(player_t *player);
|
||||
boolean P_IsFlagAtBase(mobjtype_t flag);
|
||||
|
||||
void P_SwitchWeather(INT32 weathernum);
|
||||
void P_SwitchWeather(UINT8 newWeather);
|
||||
|
||||
boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller);
|
||||
void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller);
|
||||
|
|
|
|||
22
src/p_tick.c
22
src/p_tick.c
|
|
@ -24,6 +24,7 @@
|
|||
#include "lua_hook.h"
|
||||
#include "k_kart.h"
|
||||
#include "k_battle.h"
|
||||
#include "k_waypoint.h"
|
||||
|
||||
// Object place
|
||||
#include "m_cheat.h"
|
||||
|
|
@ -59,8 +60,6 @@ void Command_Numthinkers_f(void)
|
|||
CONS_Printf(M_GetText("numthinkers <#>: Count number of thinkers\n"));
|
||||
CONS_Printf(
|
||||
"\t1: P_MobjThinker\n"
|
||||
/*"\t2: P_RainThinker\n"
|
||||
"\t3: P_SnowThinker\n"*/
|
||||
"\t2: P_NullPrecipThinker\n"
|
||||
"\t3: T_Friction\n"
|
||||
"\t4: T_Pusher\n"
|
||||
|
|
@ -76,14 +75,6 @@ void Command_Numthinkers_f(void)
|
|||
action = (actionf_p1)P_MobjThinker;
|
||||
CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker");
|
||||
break;
|
||||
/*case 2:
|
||||
action = (actionf_p1)P_RainThinker;
|
||||
CONS_Printf(M_GetText("Number of %s: "), "P_RainThinker");
|
||||
break;
|
||||
case 3:
|
||||
action = (actionf_p1)P_SnowThinker;
|
||||
CONS_Printf(M_GetText("Number of %s: "), "P_SnowThinker");
|
||||
break;*/
|
||||
case 2:
|
||||
action = (actionf_p1)P_NullPrecipThinker;
|
||||
CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker");
|
||||
|
|
@ -183,6 +174,7 @@ void P_InitThinkers(void)
|
|||
{
|
||||
thinkercap.prev = thinkercap.next = &thinkercap;
|
||||
waypointcap = NULL;
|
||||
kitemcap = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -639,6 +631,9 @@ void P_Ticker(boolean run)
|
|||
if (runemeraldmanager)
|
||||
P_EmeraldManager(); // Power stone mode*/
|
||||
|
||||
// formality so kitemcap gets updated properly each frame.
|
||||
P_RunKartItems();
|
||||
|
||||
if (run)
|
||||
{
|
||||
P_RunThinkers();
|
||||
|
|
@ -660,8 +655,6 @@ void P_Ticker(boolean run)
|
|||
//P_RunShields();
|
||||
P_RunOverlays();
|
||||
|
||||
P_RunShadows();
|
||||
|
||||
P_UpdateSpecials();
|
||||
P_RespawnSpecials();
|
||||
|
||||
|
|
@ -750,6 +743,11 @@ void P_Ticker(boolean run)
|
|||
&& --mapreset <= 1
|
||||
&& server) // Remember: server uses it for mapchange, but EVERYONE ticks down for the animation
|
||||
D_MapChange(gamemap, gametype, encoremode, true, 0, false, false);
|
||||
|
||||
if (cv_kartdebugwaypoints.value != 0)
|
||||
{
|
||||
K_DebugWaypointsVisualise();
|
||||
}
|
||||
}
|
||||
|
||||
// Always move the camera.
|
||||
|
|
|
|||
184
src/p_user.c
184
src/p_user.c
|
|
@ -1253,7 +1253,7 @@ void P_RestoreMusic(player_t *player)
|
|||
#if 0
|
||||
// Event - Final Lap
|
||||
// Still works for GME, but disabled for consistency
|
||||
if (G_RaceGametype() && player->laps >= (UINT8)(cv_numlaps.value - 1))
|
||||
if (G_RaceGametype() && player->laps >= (UINT8)(cv_numlaps.value))
|
||||
S_SpeedMusic(1.2f);
|
||||
#endif
|
||||
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
|
||||
|
|
@ -3716,11 +3716,6 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range)
|
|||
player->pflags |= PF_THOKKED;
|
||||
}
|
||||
|
||||
boolean P_AnalogMove(player_t *player)
|
||||
{
|
||||
return player->pflags & PF_ANALOGMODE;
|
||||
}
|
||||
|
||||
//
|
||||
// P_GetPlayerControlDirection
|
||||
//
|
||||
|
|
@ -3763,14 +3758,6 @@ boolean P_AnalogMove(player_t *player)
|
|||
origtempangle = tempangle = 0; // relative to the axis rather than the player!
|
||||
controlplayerdirection = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
|
||||
}
|
||||
else if (P_AnalogMove(player) && thiscam->chase)
|
||||
{
|
||||
if (player->awayviewtics)
|
||||
origtempangle = tempangle = player->awayviewmobj->angle;
|
||||
else
|
||||
origtempangle = tempangle = thiscam->angle;
|
||||
controlplayerdirection = player->mo->angle;
|
||||
}
|
||||
else
|
||||
{
|
||||
origtempangle = tempangle = player->mo->angle;
|
||||
|
|
@ -3994,7 +3981,6 @@ static void P_3dMovement(player_t *player)
|
|||
angle_t dangle; // replaces old quadrants bits
|
||||
//boolean dangleflip = false; // SRB2kart - toaster
|
||||
//fixed_t normalspd = FixedMul(player->normalspeed, player->mo->scale);
|
||||
boolean analogmove = false;
|
||||
fixed_t oldMagnitude, newMagnitude;
|
||||
#ifdef ESLOPE
|
||||
vector3_t totalthrust;
|
||||
|
|
@ -4006,8 +3992,6 @@ static void P_3dMovement(player_t *player)
|
|||
// Get the old momentum; this will be needed at the end of the function! -SH
|
||||
oldMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0);
|
||||
|
||||
analogmove = P_AnalogMove(player);
|
||||
|
||||
cmd = &player->cmd;
|
||||
|
||||
if ((player->exiting || mapreset) || player->pflags & PF_STASIS || player->kartstuff[k_spinouttimer]) // pw_introcam?
|
||||
|
|
@ -4020,19 +4004,13 @@ static void P_3dMovement(player_t *player)
|
|||
if (!(player->pflags & PF_FORCESTRAFE) && !player->kartstuff[k_pogospring])
|
||||
cmd->sidemove = 0;
|
||||
|
||||
if (analogmove)
|
||||
{
|
||||
movepushangle = (cmd->angleturn<<16 /* not FRACBITS */);
|
||||
}
|
||||
if (player->kartstuff[k_drift] != 0)
|
||||
movepushangle = player->mo->angle-(ANGLE_45/5)*player->kartstuff[k_drift];
|
||||
else if (player->kartstuff[k_spinouttimer] || player->kartstuff[k_wipeoutslow]) // if spun out, use the boost angle
|
||||
movepushangle = (angle_t)player->kartstuff[k_boostangle];
|
||||
else
|
||||
{
|
||||
if (player->kartstuff[k_drift] != 0)
|
||||
movepushangle = player->mo->angle-(ANGLE_45/5)*player->kartstuff[k_drift];
|
||||
else if (player->kartstuff[k_spinouttimer] || player->kartstuff[k_wipeoutslow]) // if spun out, use the boost angle
|
||||
movepushangle = (angle_t)player->kartstuff[k_boostangle];
|
||||
else
|
||||
movepushangle = player->mo->angle;
|
||||
}
|
||||
movepushangle = player->mo->angle;
|
||||
|
||||
movepushsideangle = movepushangle-ANGLE_90;
|
||||
|
||||
// cmomx/cmomy stands for the conveyor belt speed.
|
||||
|
|
@ -6191,69 +6169,6 @@ static void P_MovePlayer(player_t *player)
|
|||
player->pflags &= ~PF_STARTDASH;
|
||||
*/
|
||||
|
||||
//////////////////
|
||||
//ANALOG CONTROL//
|
||||
//////////////////
|
||||
|
||||
#if 0
|
||||
// This really looks like it should be moved to P_3dMovement. -Red
|
||||
if (P_AnalogMove(player)
|
||||
&& (cmd->forwardmove != 0 || cmd->sidemove != 0) && !player->climbing && !twodlevel && !(player->mo->flags2 & MF2_TWOD))
|
||||
{
|
||||
// If travelling slow enough, face the way the controls
|
||||
// point and not your direction of movement.
|
||||
if (player->speed < FixedMul(5*FRACUNIT, player->mo->scale) || player->pflags & PF_GLIDING || !onground)
|
||||
{
|
||||
angle_t tempangle;
|
||||
|
||||
tempangle = (cmd->angleturn << 16);
|
||||
|
||||
#ifdef REDSANALOG // Ease to it. Chillax. ~Red
|
||||
tempangle += R_PointToAngle2(0, 0, cmd->forwardmove*FRACUNIT, -cmd->sidemove*FRACUNIT);
|
||||
{
|
||||
fixed_t tweenvalue = max(abs(cmd->forwardmove), abs(cmd->sidemove));
|
||||
|
||||
if (tweenvalue < 10 && (cmd->buttons & (BT_FORWARD|BT_BACKWARD)) == (BT_FORWARD|BT_BACKWARD)) {
|
||||
tempangle = (cmd->angleturn << 16);
|
||||
tweenvalue = 16;
|
||||
}
|
||||
|
||||
tweenvalue *= tweenvalue*tweenvalue*1536;
|
||||
|
||||
//if (player->pflags & PF_GLIDING)
|
||||
//tweenvalue >>= 1;
|
||||
|
||||
tempangle -= player->mo->angle;
|
||||
|
||||
if (tempangle < ANGLE_180 && tempangle > tweenvalue)
|
||||
player->mo->angle += tweenvalue;
|
||||
else if (tempangle >= ANGLE_180 && InvAngle(tempangle) > tweenvalue)
|
||||
player->mo->angle -= tweenvalue;
|
||||
else
|
||||
player->mo->angle += tempangle;
|
||||
}
|
||||
#else
|
||||
// Less math this way ~Red
|
||||
player->mo->angle = R_PointToAngle2(0, 0, cmd->forwardmove*FRACUNIT, -cmd->sidemove*FRACUNIT)+tempangle;
|
||||
#endif
|
||||
}
|
||||
// Otherwise, face the direction you're travelling.
|
||||
else if (player->panim == PA_WALK || player->panim == PA_RUN || player->panim == PA_ROLL
|
||||
/*|| ((player->mo->state >= &states[S_PLAY_ABL1] && player->mo->state <= &states[S_PLAY_SPC4]) && player->charability == CA_FLY)*/) // SRB2kart - idk
|
||||
player->mo->angle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy);
|
||||
|
||||
// Update the local angle control.
|
||||
if (player == &players[consoleplayer])
|
||||
localangle[0] = player->mo->angle;
|
||||
else if (player == &players[displayplayers[1]])
|
||||
localangle[1] = player->mo->angle;
|
||||
else if (player == &players[displayplayers[2]])
|
||||
localangle[2] = player->mo->angle;
|
||||
else if (player == &players[displayplayers[3]])
|
||||
localangle[3] = player->mo->angle;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////
|
||||
//BOMB SHIELD ACTIVATION,//
|
||||
//HOMING, AND OTHER COOL //
|
||||
|
|
@ -7234,8 +7149,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
{
|
||||
static UINT8 lookbackdelay[4] = {0,0,0,0};
|
||||
UINT8 num;
|
||||
angle_t angle = 0, focusangle = 0, focusaiming = 0;
|
||||
fixed_t x, y, z, dist, height, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight;
|
||||
angle_t angle = 0, focusangle = 0, focusaiming = 0, pitch = 0;
|
||||
fixed_t x, y, z, dist, distxy, distz, height, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight;
|
||||
fixed_t pan, xpan, ypan;
|
||||
INT32 camrotate;
|
||||
boolean camstill, lookback;
|
||||
|
|
@ -7487,8 +7402,36 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
height -= FixedMul(height, player->karthud[khud_boostcam]);
|
||||
}
|
||||
|
||||
x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist);
|
||||
y = mo->y - FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), dist);
|
||||
if (mo->standingslope)
|
||||
{
|
||||
pitch = (angle_t)FixedMul(P_ReturnThrustX(mo, player->frameangle - mo->standingslope->xydirection, FRACUNIT), (fixed_t)mo->standingslope->zangle);
|
||||
if (mo->eflags & MFE_VERTICALFLIP)
|
||||
{
|
||||
if (pitch >= ANGLE_180)
|
||||
pitch = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pitch < ANGLE_180)
|
||||
pitch = 0;
|
||||
}
|
||||
}
|
||||
pitch = thiscam->pitch + (angle_t)FixedMul(pitch - thiscam->pitch, camspeed/4);
|
||||
|
||||
if (rendermode == render_opengl
|
||||
#ifdef GL_SHADERS/* just so we can't possibly forget about it */
|
||||
&& !cv_grshearing.value
|
||||
#endif
|
||||
)
|
||||
distxy = FixedMul(dist, FINECOSINE((pitch>>ANGLETOFINESHIFT) & FINEMASK));
|
||||
else
|
||||
distxy = dist;
|
||||
distz = -FixedMul(dist, FINESINE((pitch>>ANGLETOFINESHIFT) & FINEMASK));
|
||||
if (splitscreen == 1) // 2 player is weird, this helps keep players on screen
|
||||
distz = 3*distz/5;
|
||||
|
||||
x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy);
|
||||
y = mo->y - FixedMul(FINESINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy);
|
||||
|
||||
// SRB2Kart: set camera panning
|
||||
if (camstill || resetcalled || player->playerstate == PST_DEAD)
|
||||
|
|
@ -7498,7 +7441,14 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
if (player->kartstuff[k_drift] != 0)
|
||||
{
|
||||
fixed_t panmax = (dist/5);
|
||||
pan = FixedDiv(FixedMul(min((fixed_t)player->kartstuff[k_driftcharge], K_GetKartDriftSparkValue(player)), panmax), K_GetKartDriftSparkValue(player));
|
||||
INT32 driftval = K_GetKartDriftSparkValue(player);
|
||||
INT32 dc = player->kartstuff[k_driftcharge];
|
||||
|
||||
if (dc > driftval || dc < 0)
|
||||
dc = driftval;
|
||||
|
||||
pan = FixedDiv(FixedMul((fixed_t)dc, panmax), driftval);
|
||||
|
||||
if (pan > panmax)
|
||||
pan = panmax;
|
||||
if (player->kartstuff[k_drift] < 0)
|
||||
|
|
@ -7519,9 +7469,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
pviewheight = FixedMul(32<<FRACBITS, mo->scale);
|
||||
|
||||
if (mo->eflags & MFE_VERTICALFLIP)
|
||||
z = mo->z + mo->height - pviewheight - camheight;
|
||||
z = mo->z + mo->height - pviewheight - camheight + distz;
|
||||
else
|
||||
z = mo->z + pviewheight + camheight;
|
||||
z = mo->z + pviewheight + camheight + distz;
|
||||
|
||||
#ifndef NOCLIPCAM // Disable all z-clipping for noclip cam
|
||||
// move camera down to move under lower ceilings
|
||||
|
|
@ -7756,6 +7706,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
}
|
||||
|
||||
thiscam->pan = pan;
|
||||
thiscam->pitch = pitch;
|
||||
|
||||
// compute aming to look the viewed point
|
||||
f1 = viewpointx-thiscam->x;
|
||||
|
|
@ -7763,9 +7714,17 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
dist = FixedHypot(f1, f2);
|
||||
|
||||
if (mo->eflags & MFE_VERTICALFLIP)
|
||||
{
|
||||
angle = R_PointToAngle2(0, thiscam->z + thiscam->height, dist, mo->z + mo->height - P_GetPlayerHeight(player));
|
||||
if (thiscam->pitch < ANGLE_180 && thiscam->pitch > angle)
|
||||
angle = thiscam->pitch;
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = R_PointToAngle2(0, thiscam->z, dist, mo->z + P_GetPlayerHeight(player));
|
||||
if (thiscam->pitch >= ANGLE_180 && thiscam->pitch < angle)
|
||||
angle = thiscam->pitch;
|
||||
}
|
||||
|
||||
if (player->playerstate != PST_DEAD && !((player->pflags & PF_NIGHTSMODE) && player->exiting))
|
||||
angle += (focusaiming < ANGLE_180 ? focusaiming/2 : InvAngle(InvAngle(focusaiming)/2)); // overcomplicated version of '((signed)focusaiming)/2;'
|
||||
|
|
@ -8132,12 +8091,6 @@ void P_PlayerThink(player_t *player)
|
|||
// The timer might've reached zero, but we'll run the remote view camera anyway by setting it to -1.
|
||||
}
|
||||
|
||||
/// \note do this in the cheat code
|
||||
if (player->pflags & PF_NOCLIP)
|
||||
player->mo->flags |= MF_NOCLIP;
|
||||
else
|
||||
player->mo->flags &= ~MF_NOCLIP;
|
||||
|
||||
cmd = &player->cmd;
|
||||
|
||||
// SRB2kart
|
||||
|
|
@ -8370,26 +8323,7 @@ void P_PlayerThink(player_t *player)
|
|||
player->mo->reactiontime--;
|
||||
else if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT)
|
||||
{
|
||||
// SRB2kart - don't need no rope hangin'
|
||||
//if (player->pflags & PF_ROPEHANG)
|
||||
//{
|
||||
// if (!P_AnalogMove(player))
|
||||
// player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */);
|
||||
|
||||
// ticruned++;
|
||||
// if ((cmd->angleturn & TICCMD_RECEIVED) == 0)
|
||||
// ticmiss++;
|
||||
|
||||
// P_DoRopeHang(player);
|
||||
// P_SetPlayerMobjState(player->mo, S_PLAY_CARRY);
|
||||
// P_DoJumpStuff(player, &player->cmd);
|
||||
//}
|
||||
//else
|
||||
{
|
||||
P_DoZoomTube(player);
|
||||
//if (!(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH) // SRB2kart
|
||||
// P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
|
||||
}
|
||||
P_DoZoomTube(player);
|
||||
player->rmomx = player->rmomy = 0; // no actual momentum from your controls
|
||||
P_ResetScore(player);
|
||||
}
|
||||
|
|
|
|||
17
src/r_bsp.c
17
src/r_bsp.c
|
|
@ -57,6 +57,16 @@ static boolean R_NoEncore(sector_t *sector, boolean ceiling)
|
|||
return ((boolean)(sector->flags & SF_FLIPSPECIAL_FLOOR));
|
||||
}
|
||||
|
||||
static void R_PlaneLightOverride(sector_t *sector, boolean ceiling, INT32 *lightlevel)
|
||||
{
|
||||
if (GETSECSPECIAL(sector->special, 4) == 6) // Fullbright sneaker panels
|
||||
{
|
||||
if ((ceiling && (sector->flags & SF_FLIPSPECIAL_CEILING))
|
||||
|| (!ceiling && (sector->flags & SF_FLIPSPECIAL_FLOOR)))
|
||||
*lightlevel = 255;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// R_ClearDrawSegs
|
||||
//
|
||||
|
|
@ -895,6 +905,9 @@ static void R_Subsector(size_t num)
|
|||
|
||||
sub->sector->extra_colormap = frontsector->extra_colormap;
|
||||
|
||||
R_PlaneLightOverride(frontsector, false, &floorlightlevel);
|
||||
R_PlaneLightOverride(frontsector, true, &ceilinglightlevel);
|
||||
|
||||
if (((
|
||||
#ifdef ESLOPE
|
||||
frontsector->f_slope ? P_GetZAt(frontsector->f_slope, viewx, viewy) :
|
||||
|
|
@ -923,8 +936,8 @@ static void R_Subsector(size_t num)
|
|||
|| (frontsector->heightsec != -1
|
||||
&& sectors[frontsector->heightsec].floorpic == skyflatnum)))
|
||||
{
|
||||
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
|
||||
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
|
||||
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic, ceilinglightlevel,
|
||||
frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
|
||||
ceilingcolormap, NULL
|
||||
#ifdef POLYOBJECTS_PLANES
|
||||
, NULL
|
||||
|
|
|
|||
|
|
@ -168,8 +168,7 @@ consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo,
|
|||
consvar_t cv_flipcam3 = {"flipcam3", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam3_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_flipcam4 = {"flipcam4", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam4_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
consvar_t cv_shadow = {"shadow", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_shadowoffs = {"offsetshadows", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_shadow = {"shadow", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_skybox = {"skybox", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_soniccd = {"soniccd", "Off", CV_NETVAR|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
|
@ -177,7 +176,7 @@ consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0,
|
|||
consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
||||
consvar_t cv_translucency = {"translucency", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_drawdist = {"drawdist", "Infinite", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_drawdist = {"drawdist", "8192", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
//consvar_t cv_drawdist_nights = {"drawdist_nights", "2048", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
//consvar_t cv_precipdensity = {"precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||
|
|
@ -834,7 +833,7 @@ static void R_SetupFreelook(void)
|
|||
// clip it in the case we are looking a hardware 90 degrees full aiming
|
||||
// (lmps, network and use F12...)
|
||||
G_SoftwareClipAimingPitch((INT32 *)&aimingangle);
|
||||
dy = AIMINGTODY(aimingangle) * viewwidth/BASEVIDWIDTH;
|
||||
dy = AIMINGTODY(aimingangle) * viewheight/BASEVIDHEIGHT;
|
||||
yslope = &yslopetab[viewheight*8 - (viewheight/2 + dy)];
|
||||
}
|
||||
centery = (viewheight/2) + dy;
|
||||
|
|
@ -1505,7 +1504,6 @@ void R_RegisterEngineStuff(void)
|
|||
CV_RegisterVar(&cv_chasecam3);
|
||||
CV_RegisterVar(&cv_chasecam4);
|
||||
CV_RegisterVar(&cv_shadow);
|
||||
CV_RegisterVar(&cv_shadowoffs);
|
||||
CV_RegisterVar(&cv_skybox);
|
||||
|
||||
CV_RegisterVar(&cv_cam_dist);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ extern consvar_t cv_showhud, cv_translucenthud;
|
|||
extern consvar_t cv_homremoval;
|
||||
extern consvar_t cv_chasecam, cv_chasecam2, cv_chasecam3, cv_chasecam4;
|
||||
extern consvar_t cv_flipcam, cv_flipcam2, cv_flipcam3, cv_flipcam4;
|
||||
extern consvar_t cv_shadow, cv_shadowoffs;
|
||||
extern consvar_t cv_shadow;
|
||||
extern consvar_t cv_translucency;
|
||||
extern consvar_t /*cv_precipdensity,*/ cv_drawdist, /*cv_drawdist_nights,*/ cv_drawdist_precip;
|
||||
extern consvar_t cv_fov;
|
||||
|
|
|
|||
464
src/r_things.c
464
src/r_things.c
|
|
@ -802,9 +802,7 @@ static void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight)
|
|||
static void R_DrawVisSprite(vissprite_t *vis)
|
||||
{
|
||||
column_t *column;
|
||||
#ifdef RANGECHECK
|
||||
INT32 texturecolumn;
|
||||
#endif
|
||||
fixed_t frac;
|
||||
patch_t *patch = W_CacheLumpNum(vis->patch, PU_CACHE);
|
||||
fixed_t this_scale = vis->mobj->scale;
|
||||
|
|
@ -920,6 +918,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
|
|||
if (!(vis->scalestep))
|
||||
{
|
||||
sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
|
||||
sprtopscreen += vis->shear.tan * vis->shear.offset;
|
||||
dc_iscale = FixedDiv(FRACUNIT, vis->scale);
|
||||
}
|
||||
|
||||
|
|
@ -942,31 +941,50 @@ static void R_DrawVisSprite(vissprite_t *vis)
|
|||
vis->x2--;
|
||||
#endif
|
||||
|
||||
for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale)
|
||||
// Split drawing loops for paper and non-paper to reduce conditional checks per sprite
|
||||
if (vis->scalestep)
|
||||
{
|
||||
if (vis->scalestep) // currently papersprites only
|
||||
// Papersprite drawing loop
|
||||
for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += vis->scalestep)
|
||||
{
|
||||
#ifndef RANGECHECK
|
||||
if ((frac>>FRACBITS) < 0 || (frac>>FRACBITS) >= SHORT(patch->width)) // if this doesn't work i'm removing papersprites
|
||||
break;
|
||||
#endif
|
||||
angle_t angle = ((vis->centerangle + xtoviewangle[dc_x]) >> ANGLETOFINESHIFT) & 0xFFF;
|
||||
texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / this_scale;
|
||||
|
||||
if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
|
||||
continue;
|
||||
|
||||
if (vis->xiscale < 0) // Flipped sprite
|
||||
texturecolumn = SHORT(patch->width) - 1 - texturecolumn;
|
||||
|
||||
sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale));
|
||||
dc_iscale = (0xffffffffu / (unsigned)spryscale);
|
||||
spryscale += vis->scalestep;
|
||||
}
|
||||
#ifdef RANGECHECK
|
||||
texturecolumn = frac>>FRACBITS;
|
||||
|
||||
if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
|
||||
I_Error("R_DrawSpriteRange: bad texturecolumn");
|
||||
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn]));
|
||||
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn]));
|
||||
|
||||
if (vis->cut & SC_VFLIP)
|
||||
R_DrawFlippedMaskedColumn(column, patch->height);
|
||||
else
|
||||
R_DrawMaskedColumn(column);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-paper drawing loop
|
||||
for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale, sprtopscreen += vis->shear.tan)
|
||||
{
|
||||
#ifdef RANGECHECK
|
||||
texturecolumn = frac>>FRACBITS;
|
||||
if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
|
||||
I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x);
|
||||
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn]));
|
||||
#else
|
||||
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS]));
|
||||
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS]));
|
||||
#endif
|
||||
if (vis->cut & SC_VFLIP)
|
||||
R_DrawFlippedMaskedColumn(column, patch->height);
|
||||
else
|
||||
R_DrawMaskedColumn(column);
|
||||
if (vis->cut & SC_VFLIP)
|
||||
R_DrawFlippedMaskedColumn(column, patch->height);
|
||||
else
|
||||
R_DrawMaskedColumn(column);
|
||||
}
|
||||
}
|
||||
|
||||
colfunc = basecolfunc;
|
||||
|
|
@ -1138,6 +1156,278 @@ static void R_SplitSprite(vissprite_t *sprite)
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// R_GetShadowZ(thing, shadowslope)
|
||||
// Get the first visible floor below the object for shadows
|
||||
// shadowslope is filled with the floor's slope, if provided
|
||||
//
|
||||
fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope)
|
||||
{
|
||||
fixed_t z, floorz = INT32_MIN;
|
||||
pslope_t *slope, *floorslope = NULL;
|
||||
msecnode_t *node;
|
||||
sector_t *sector;
|
||||
ffloor_t *rover;
|
||||
|
||||
for (node = thing->touching_sectorlist; node; node = node->m_sectorlist_next)
|
||||
{
|
||||
sector = node->m_sector;
|
||||
|
||||
slope = (sector->heightsec != -1) ? NULL : sector->f_slope;
|
||||
z = slope ? P_GetZAt(slope, thing->x, thing->y) : (
|
||||
(sector->heightsec != -1) ? sectors[sector->heightsec].floorheight : sector->floorheight
|
||||
);
|
||||
|
||||
if (z < thing->z+thing->height/2 && z > floorz)
|
||||
{
|
||||
floorz = z;
|
||||
floorslope = slope;
|
||||
}
|
||||
|
||||
if (sector->ffloors)
|
||||
for (rover = sector->ffloors; rover; rover = rover->next)
|
||||
{
|
||||
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES) || (rover->alpha < 90 && !(rover->flags & FF_SWIMMABLE)))
|
||||
continue;
|
||||
|
||||
z = *rover->t_slope ? P_GetZAt(*rover->t_slope, thing->x, thing->y) : *rover->topheight;
|
||||
if (z < thing->z+thing->height/2 && z > floorz)
|
||||
{
|
||||
floorz = z;
|
||||
floorslope = *rover->t_slope;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (thing->floorz > floorz + (!floorslope ? 0 : FixedMul(abs(floorslope->zdelta), thing->radius*3/2)))
|
||||
{
|
||||
floorz = thing->floorz;
|
||||
floorslope = NULL;
|
||||
}
|
||||
|
||||
#if 0 // Unfortunately, this drops CEZ2 down to sub-17 FPS on my i7.
|
||||
//#ifdef POLYOBJECTS
|
||||
// Check polyobjects and see if floorz needs to be altered, for rings only because they don't update floorz
|
||||
if (thing->type == MT_RING)
|
||||
{
|
||||
INT32 xl, xh, yl, yh, bx, by;
|
||||
|
||||
xl = (unsigned)(thing->x - thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
xh = (unsigned)(thing->x + thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
yl = (unsigned)(thing->y - thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
yh = (unsigned)(thing->y + thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
|
||||
BMBOUNDFIX(xl, xh, yl, yh);
|
||||
|
||||
validcount++;
|
||||
|
||||
for (by = yl; by <= yh; by++)
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
{
|
||||
INT32 offset;
|
||||
polymaplink_t *plink; // haleyjd 02/22/06
|
||||
|
||||
if (bx < 0 || by < 0 || bx >= bmapwidth || by >= bmapheight)
|
||||
continue;
|
||||
|
||||
offset = by*bmapwidth + bx;
|
||||
|
||||
// haleyjd 02/22/06: consider polyobject lines
|
||||
plink = polyblocklinks[offset];
|
||||
|
||||
while (plink)
|
||||
{
|
||||
polyobj_t *po = plink->po;
|
||||
|
||||
if (po->validcount != validcount) // if polyobj hasn't been checked
|
||||
{
|
||||
po->validcount = validcount;
|
||||
|
||||
if (!P_MobjInsidePolyobj(po, thing) || !(po->flags & POF_RENDERPLANES))
|
||||
{
|
||||
plink = (polymaplink_t *)(plink->link.next);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We're inside it! Yess...
|
||||
z = po->lines[0]->backsector->ceilingheight;
|
||||
|
||||
if (z < thing->z+thing->height/2 && z > floorz)
|
||||
{
|
||||
floorz = z;
|
||||
floorslope = NULL;
|
||||
}
|
||||
}
|
||||
plink = (polymaplink_t *)(plink->link.next);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (shadowslope != NULL)
|
||||
*shadowslope = floorslope;
|
||||
|
||||
return floorz;
|
||||
}
|
||||
|
||||
static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, fixed_t tx, fixed_t tz)
|
||||
{
|
||||
vissprite_t *shadow;
|
||||
patch_t *patch;
|
||||
fixed_t xscale, yscale, shadowxscale, shadowyscale, shadowskew, x1, x2;
|
||||
INT32 light = 0;
|
||||
fixed_t scalemul; UINT8 trans;
|
||||
fixed_t floordiff;
|
||||
fixed_t floorz;
|
||||
pslope_t *floorslope;
|
||||
|
||||
floorz = R_GetShadowZ(thing, &floorslope);
|
||||
|
||||
if (abs(floorz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes
|
||||
|
||||
floordiff = abs(thing->z - floorz);
|
||||
|
||||
trans = floordiff / (100*FRACUNIT) + 3;
|
||||
if (trans >= 9) return;
|
||||
|
||||
scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
|
||||
|
||||
if (thing->whiteshadow)
|
||||
patch = W_CachePatchName("LSHADOW", PU_CACHE);
|
||||
else
|
||||
patch = W_CachePatchName("DSHADOW", PU_CACHE);
|
||||
|
||||
xscale = FixedDiv(projection, tz);
|
||||
yscale = FixedDiv(projectiony, tz);
|
||||
shadowxscale = FixedMul(thing->radius*2, scalemul);
|
||||
shadowyscale = FixedMul(FixedMul(thing->radius*2, scalemul), FixedDiv(abs(floorz - viewz), tz));
|
||||
shadowyscale = min(shadowyscale, shadowxscale) / patch->height;
|
||||
shadowxscale /= patch->width;
|
||||
shadowskew = 0;
|
||||
|
||||
if (floorslope)
|
||||
{
|
||||
// haha let's try some dumb stuff
|
||||
fixed_t xslope, zslope;
|
||||
angle_t sloperelang = (R_PointToAngle(thing->x, thing->y) - floorslope->xydirection) >> ANGLETOFINESHIFT;
|
||||
|
||||
xslope = FixedMul(FINESINE(sloperelang), floorslope->zdelta);
|
||||
zslope = FixedMul(FINECOSINE(sloperelang), floorslope->zdelta);
|
||||
|
||||
//CONS_Printf("Shadow is sloped by %d %d\n", xslope, zslope);
|
||||
|
||||
if (viewz < floorz)
|
||||
shadowyscale += FixedMul(FixedMul(thing->radius*2 / patch->height, scalemul), zslope);
|
||||
else
|
||||
shadowyscale -= FixedMul(FixedMul(thing->radius*2 / patch->height, scalemul), zslope);
|
||||
|
||||
shadowyscale = abs(shadowyscale);
|
||||
|
||||
shadowskew = xslope;
|
||||
}
|
||||
|
||||
tx -= patch->width * shadowxscale/2;
|
||||
x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
|
||||
if (x1 >= viewwidth) return;
|
||||
|
||||
tx += patch->width * shadowxscale;
|
||||
x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--;
|
||||
if (x2 < 0 || x2 <= x1) return;
|
||||
|
||||
if (shadowyscale < FRACUNIT/patch->height) return; // fix some crashes?
|
||||
|
||||
shadow = R_NewVisSprite();
|
||||
|
||||
if (thing->whiteshadow)
|
||||
shadow->patch = W_CheckNumForName("LSHADOW");
|
||||
else
|
||||
shadow->patch = W_CheckNumForName("DSHADOW");
|
||||
|
||||
shadow->heightsec = vis->heightsec;
|
||||
|
||||
shadow->thingheight = FRACUNIT;
|
||||
shadow->pz = floorz;
|
||||
shadow->pzt = shadow->pz + shadow->thingheight;
|
||||
|
||||
shadow->mobjflags = 0;
|
||||
shadow->sortscale = vis->sortscale;
|
||||
shadow->dispoffset = vis->dispoffset - 5;
|
||||
shadow->gx = thing->x;
|
||||
shadow->gy = thing->y;
|
||||
shadow->gzt = shadow->pz + patch->height * shadowyscale / 2;
|
||||
shadow->gz = shadow->gzt - patch->height * shadowyscale;
|
||||
shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale));
|
||||
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
|
||||
shadow->texturemid = FixedMul(shadow->texturemid, ((skin_t *)thing->skin)->highresscale);
|
||||
shadow->scalestep = 0;
|
||||
shadow->shear.tan = shadowskew; // repurposed variable
|
||||
|
||||
shadow->mobj = thing; // Easy access! Tails 06-07-2002
|
||||
|
||||
shadow->x1 = x1 < 0 ? 0 : x1;
|
||||
shadow->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
|
||||
|
||||
// PORTAL SEMI-CLIPPING
|
||||
if (portalrender)
|
||||
{
|
||||
if (shadow->x1 < portalclipstart)
|
||||
shadow->x1 = portalclipstart;
|
||||
if (shadow->x2 >= portalclipend)
|
||||
shadow->x2 = portalclipend-1;
|
||||
}
|
||||
|
||||
shadow->xscale = FixedMul(xscale, shadowxscale); //SoM: 4/17/2000
|
||||
shadow->scale = FixedMul(yscale, shadowyscale);
|
||||
shadow->sector = vis->sector;
|
||||
shadow->szt = (INT16)((centeryfrac - FixedMul(shadow->gzt - viewz, yscale))>>FRACBITS);
|
||||
shadow->sz = (INT16)((centeryfrac - FixedMul(shadow->gz - viewz, yscale))>>FRACBITS);
|
||||
shadow->cut = SC_ISSCALED|SC_SHADOW; //check this
|
||||
|
||||
shadow->startfrac = 0;
|
||||
//shadow->xiscale = 0x7ffffff0 / (shadow->xscale/2);
|
||||
shadow->xiscale = (patch->width<<FRACBITS)/(x2-x1+1); // fuck it
|
||||
|
||||
if (shadow->x1 > x1)
|
||||
shadow->startfrac += shadow->xiscale*(shadow->x1-x1);
|
||||
|
||||
// reusing x1 variable
|
||||
x1 += (x2-x1)/2;
|
||||
shadow->shear.offset = shadow->x1-x1;
|
||||
|
||||
if (thing->subsector->sector->numlights)
|
||||
{
|
||||
INT32 lightnum;
|
||||
#ifdef ESLOPE // R_GetPlaneLight won't work on sloped lights!
|
||||
light = thing->subsector->sector->numlights - 1;
|
||||
|
||||
for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) {
|
||||
fixed_t h = thing->subsector->sector->lightlist[lightnum].slope ? P_GetZAt(thing->subsector->sector->lightlist[lightnum].slope, thing->x, thing->y)
|
||||
: thing->subsector->sector->lightlist[lightnum].height;
|
||||
if (h <= shadow->gzt) {
|
||||
light = lightnum - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
light = R_GetPlaneLight(thing->subsector->sector, shadow->gzt, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (thing->subsector->sector->numlights)
|
||||
shadow->extra_colormap = thing->subsector->sector->lightlist[light].extra_colormap;
|
||||
else
|
||||
shadow->extra_colormap = thing->subsector->sector->extra_colormap;
|
||||
|
||||
shadow->transmap = transtables + (trans<<FF_TRANSSHIFT);
|
||||
|
||||
if (thing->whiteshadow)
|
||||
shadow->colormap = scalelight[LIGHTLEVELS - 1][0]; // full bright!
|
||||
else
|
||||
shadow->colormap = scalelight[0][0]; // full dark!
|
||||
|
||||
objectsdrawn++;
|
||||
}
|
||||
|
||||
//
|
||||
// R_ProjectSprite
|
||||
// Generates a vissprite for a thing
|
||||
|
|
@ -1168,7 +1458,11 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
fixed_t iscale;
|
||||
fixed_t scalestep; // toast '16
|
||||
fixed_t offset, offset2;
|
||||
boolean papersprite = (thing->frame & FF_PAPERSPRITE);
|
||||
|
||||
fixed_t basetx; // drop shadows
|
||||
|
||||
boolean papersprite = !!(thing->frame & FF_PAPERSPRITE);
|
||||
fixed_t paperoffset = 0, paperdistance = 0; angle_t centerangle = 0;
|
||||
|
||||
//SoM: 3/17/2000
|
||||
fixed_t gz, gzt;
|
||||
|
|
@ -1176,8 +1470,6 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
INT32 light = 0;
|
||||
fixed_t this_scale = thing->scale;
|
||||
|
||||
fixed_t ang_scale = FRACUNIT;
|
||||
|
||||
// transform the origin point
|
||||
tr_x = thing->x - viewx;
|
||||
tr_y = thing->y - viewy;
|
||||
|
|
@ -1188,15 +1480,15 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
tz = gxt-gyt;
|
||||
|
||||
// thing is behind view plane?
|
||||
if (!(papersprite) && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later
|
||||
if (!papersprite && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later
|
||||
return;
|
||||
|
||||
gxt = -FixedMul(tr_x, viewsin);
|
||||
gyt = FixedMul(tr_y, viewcos);
|
||||
tx = -(gyt + gxt);
|
||||
basetx = tx = -(gyt + gxt);
|
||||
|
||||
// too far off the side?
|
||||
if (abs(tx) > tz<<2)
|
||||
if (!papersprite && abs(tx) > tz<<2) // papersprite clipping is handled later
|
||||
return;
|
||||
|
||||
// aspect ratio stuff
|
||||
|
|
@ -1249,8 +1541,6 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
ang = R_PointToAngle (thing->x, thing->y) - thing->player->frameangle;
|
||||
else
|
||||
ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
|
||||
if (papersprite)
|
||||
ang_scale = abs(FINESINE(ang>>ANGLETOFINESHIFT));
|
||||
}
|
||||
|
||||
if (sprframe->rotate == SRF_SINGLE)
|
||||
|
|
@ -1288,27 +1578,12 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
else
|
||||
offset = -spritecachedinfo[lump].offset;
|
||||
offset = FixedMul(offset, this_scale);
|
||||
tx += FixedMul(offset, ang_scale);
|
||||
x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS;
|
||||
|
||||
// off the right side?
|
||||
if (x1 > viewwidth)
|
||||
return;
|
||||
|
||||
offset2 = FixedMul(spritecachedinfo[lump].width, this_scale);
|
||||
tx += FixedMul(offset2, ang_scale);
|
||||
x2 = ((centerxfrac + FixedMul (tx,xscale)) >> FRACBITS) - 1;
|
||||
|
||||
// off the left side
|
||||
if (x2 < 0)
|
||||
return;
|
||||
|
||||
if (papersprite)
|
||||
{
|
||||
fixed_t yscale2, cosmul, sinmul, tz2;
|
||||
|
||||
if (x2 <= x1)
|
||||
return;
|
||||
fixed_t xscale2, yscale2, cosmul, sinmul, tx2, tz2;
|
||||
INT32 range;
|
||||
|
||||
if (ang >= ANGLE_180)
|
||||
{
|
||||
|
|
@ -1325,7 +1600,23 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
gyt = -FixedMul(tr_y, viewsin);
|
||||
tz = gxt-gyt;
|
||||
yscale = FixedDiv(projectiony, tz);
|
||||
if (yscale < 64) return; // Fix some funky visuals
|
||||
//if (yscale < 64) return; // Fix some funky visuals
|
||||
|
||||
gxt = -FixedMul(tr_x, viewsin);
|
||||
gyt = FixedMul(tr_y, viewcos);
|
||||
tx = -(gyt + gxt);
|
||||
xscale = FixedDiv(projection, tz);
|
||||
x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
|
||||
|
||||
// Get paperoffset (offset) and paperoffset (distance)
|
||||
paperoffset = -FixedMul(tr_x, cosmul) - FixedMul(tr_y, sinmul);
|
||||
paperdistance = -FixedMul(tr_x, sinmul) + FixedMul(tr_y, cosmul);
|
||||
if (paperdistance < 0)
|
||||
{
|
||||
paperoffset = -paperoffset;
|
||||
paperdistance = -paperdistance;
|
||||
}
|
||||
centerangle = viewangle - thing->angle;
|
||||
|
||||
tr_x += FixedMul(offset2, cosmul);
|
||||
tr_y += FixedMul(offset2, sinmul);
|
||||
|
|
@ -1333,13 +1624,52 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
gyt = -FixedMul(tr_y, viewsin);
|
||||
tz2 = gxt-gyt;
|
||||
yscale2 = FixedDiv(projectiony, tz2);
|
||||
if (yscale2 < 64) return; // ditto
|
||||
//if (yscale2 < 64) return; // ditto
|
||||
|
||||
gxt = -FixedMul(tr_x, viewsin);
|
||||
gyt = FixedMul(tr_y, viewcos);
|
||||
tx2 = -(gyt + gxt);
|
||||
xscale2 = FixedDiv(projection, tz2);
|
||||
x2 = ((centerxfrac + FixedMul(tx2,xscale2))>>FRACBITS);
|
||||
|
||||
if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier
|
||||
return;
|
||||
|
||||
scalestep = (yscale2 - yscale)/(x2 - x1);
|
||||
scalestep = scalestep ? scalestep : 1;
|
||||
// Needs partially clipped
|
||||
if (tz < FixedMul(MINZ, this_scale))
|
||||
{
|
||||
fixed_t div = FixedDiv(tz2-tz, FixedMul(MINZ, this_scale)-tz);
|
||||
tx += FixedDiv(tx2-tx, div);
|
||||
tz = FixedMul(MINZ, this_scale);
|
||||
yscale = FixedDiv(projectiony, tz);
|
||||
xscale = FixedDiv(projection, tz);
|
||||
x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
|
||||
}
|
||||
else if (tz2 < FixedMul(MINZ, this_scale))
|
||||
{
|
||||
fixed_t div = FixedDiv(tz-tz2, FixedMul(MINZ, this_scale)-tz2);
|
||||
tx2 += FixedDiv(tx-tx2, div);
|
||||
tz2 = FixedMul(MINZ, this_scale);
|
||||
yscale2 = FixedDiv(projectiony, tz2);
|
||||
xscale2 = FixedDiv(projection, tz2);
|
||||
x2 = (centerxfrac + FixedMul(tx2,xscale2))>>FRACBITS;
|
||||
}
|
||||
|
||||
// off the right side?
|
||||
if (x1 > viewwidth)
|
||||
return;
|
||||
|
||||
// off the left side
|
||||
if (x2 < 0)
|
||||
return;
|
||||
|
||||
if ((range = x2 - x1) <= 0)
|
||||
return;
|
||||
|
||||
range++; // fencepost problem
|
||||
|
||||
scalestep = ((yscale2 - yscale)/range) ?: 1;
|
||||
xscale = FixedDiv(range<<FRACBITS, abs(offset2));
|
||||
|
||||
// The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2?
|
||||
// sortscale = max(yscale, yscale2);
|
||||
|
|
@ -1349,9 +1679,20 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
{
|
||||
scalestep = 0;
|
||||
yscale = sortscale;
|
||||
}
|
||||
tx += offset;
|
||||
x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
|
||||
|
||||
xscale = FixedMul(xscale, ang_scale);
|
||||
// off the right side?
|
||||
if (x1 > viewwidth)
|
||||
return;
|
||||
|
||||
tx += offset2;
|
||||
x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--;
|
||||
|
||||
// off the left side
|
||||
if (x2 < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// PORTAL SPRITE CLIPPING
|
||||
if (portalrender)
|
||||
|
|
@ -1445,6 +1786,11 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
vis->pzt = vis->pz + vis->thingheight;
|
||||
vis->texturemid = vis->gzt - viewz;
|
||||
vis->scalestep = scalestep;
|
||||
vis->paperoffset = paperoffset;
|
||||
vis->paperdistance = paperdistance;
|
||||
vis->centerangle = centerangle;
|
||||
vis->shear.tan = 0;
|
||||
vis->shear.offset = 0;
|
||||
|
||||
vis->mobj = thing; // Easy access! Tails 06-07-2002
|
||||
|
||||
|
|
@ -1537,6 +1883,9 @@ static void R_ProjectSprite(mobj_t *thing)
|
|||
if (thing->subsector->sector->numlights)
|
||||
R_SplitSprite(vis);
|
||||
|
||||
if (thing->shadowscale && cv_shadow.value)
|
||||
R_ProjectDropShadow(thing, vis, thing->shadowscale, basetx, tz);
|
||||
|
||||
// Debug
|
||||
++objectsdrawn;
|
||||
}
|
||||
|
|
@ -1639,14 +1988,10 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
|
|||
// okay, we can't return now except for vertical clipping... this is a hack, but weather isn't networked, so it should be ok
|
||||
if (!(thing->precipflags & PCF_THUNK))
|
||||
{
|
||||
if (thing->precipflags & PCF_RAIN)
|
||||
P_RainThinker(thing);
|
||||
else
|
||||
P_SnowThinker(thing);
|
||||
P_PrecipThinker(thing);
|
||||
thing->precipflags |= PCF_THUNK;
|
||||
}
|
||||
|
||||
|
||||
//SoM: 3/17/2000: Disregard sprites that are out of view..
|
||||
gzt = thing->z + spritecachedinfo[lump].topoffset;
|
||||
gz = gzt - spritecachedinfo[lump].height;
|
||||
|
|
@ -1670,6 +2015,9 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
|
|||
vis->pzt = vis->pz + vis->thingheight;
|
||||
vis->texturemid = vis->gzt - viewz;
|
||||
vis->scalestep = 0;
|
||||
vis->paperdistance = 0;
|
||||
vis->shear.tan = 0;
|
||||
vis->shear.offset = 0;
|
||||
|
||||
vis->x1 = x1 < 0 ? 0 : x1;
|
||||
vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
|
||||
|
|
@ -1754,7 +2102,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
|
|||
|
||||
// Handle all things in sector.
|
||||
// If a limit exists, handle things a tiny bit different.
|
||||
if ((limit_dist = (fixed_t)(/*(maptol & TOL_NIGHTS) ? cv_drawdist_nights.value : */cv_drawdist.value) << FRACBITS))
|
||||
if ((limit_dist = (fixed_t)(cv_drawdist.value) * mapobjectscale))
|
||||
{
|
||||
for (thing = sec->thinglist; thing; thing = thing->snext)
|
||||
{
|
||||
|
|
@ -1820,7 +2168,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
|
|||
}
|
||||
|
||||
// no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off
|
||||
if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS))
|
||||
if ((limit_dist = (fixed_t)(cv_drawdist_precip.value) * mapobjectscale))
|
||||
{
|
||||
for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ void R_SortVisSprites(void);
|
|||
// (only sprites from namelist are added or replaced)
|
||||
void R_AddSpriteDefs(UINT16 wadnum);
|
||||
|
||||
fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope);
|
||||
|
||||
#ifdef DELFILE
|
||||
void R_DelSpriteDefs(UINT16 wadnum);
|
||||
#endif
|
||||
|
|
@ -114,7 +116,8 @@ typedef enum
|
|||
SC_FULLBRIGHT = 1<<4,
|
||||
SC_SEMIBRIGHT = 1<<5,
|
||||
SC_VFLIP = 1<<6,
|
||||
SC_ISSCALED = 1>>7,
|
||||
SC_ISSCALED = 1<<7,
|
||||
SC_SHADOW = 1<<8,
|
||||
// masks
|
||||
SC_CUTMASK = SC_TOP|SC_BOTTOM,
|
||||
SC_FLAGMASK = ~SC_CUTMASK
|
||||
|
|
@ -139,8 +142,16 @@ typedef struct vissprite_s
|
|||
fixed_t startfrac; // horizontal position of x1
|
||||
fixed_t scale, sortscale; // sortscale only differs from scale for flat sprites
|
||||
fixed_t scalestep; // only for flat sprites, 0 otherwise
|
||||
fixed_t paperoffset, paperdistance; // for paper sprites, offset/dist relative to the angle
|
||||
fixed_t xiscale; // negative if flipped
|
||||
|
||||
angle_t centerangle; // for paper sprites
|
||||
|
||||
struct {
|
||||
fixed_t tan; // The amount to shear the sprite vertically per row
|
||||
INT32 offset; // The center of the shearing location offset from x1
|
||||
} shear;
|
||||
|
||||
fixed_t texturemid;
|
||||
lumpnum_t patch;
|
||||
|
||||
|
|
|
|||
|
|
@ -1382,8 +1382,11 @@ void I_FinishUpdate(void)
|
|||
if (cv_ticrate.value)
|
||||
SCR_DisplayTicRate();
|
||||
|
||||
if (cv_showping.value && netgame && consoleplayer != serverplayer)
|
||||
if (cv_showping.value && netgame &&
|
||||
( consoleplayer != serverplayer || ! server_lagless ))
|
||||
{
|
||||
SCR_DisplayLocalPing();
|
||||
}
|
||||
}
|
||||
|
||||
if (rendermode == render_soft && screens[0])
|
||||
|
|
|
|||
|
|
@ -817,6 +817,7 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
{"toada", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Arid Sands Toad scream
|
||||
{"bhurry", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // v1.0.2 Battle overtime
|
||||
{"bsnipe", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Banana sniping
|
||||
{"sploss", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Down to yellow sparks
|
||||
{"itfree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // :shitsfree:
|
||||
{"dbgsal", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Debug notification
|
||||
|
||||
|
|
|
|||
|
|
@ -894,6 +894,7 @@ typedef enum
|
|||
sfx_toada,
|
||||
sfx_bhurry,
|
||||
sfx_bsnipe,
|
||||
sfx_sploss,
|
||||
sfx_itfree,
|
||||
sfx_dbgsal,
|
||||
|
||||
|
|
|
|||
|
|
@ -1514,7 +1514,7 @@ static inline void ST_drawRaceHUD(void) // SRB2kart - unused.
|
|||
if (stplyr->exiting)
|
||||
V_DrawString(hudinfo[HUD_LAP].x, STRINGY(hudinfo[HUD_LAP].y), V_YELLOWMAP, "FINISHED!");
|
||||
else
|
||||
V_DrawString(hudinfo[HUD_LAP].x, STRINGY(hudinfo[HUD_LAP].y), 0, va("Lap: %u/%d", stplyr->laps+1, cv_numlaps.value));
|
||||
V_DrawString(hudinfo[HUD_LAP].x, STRINGY(hudinfo[HUD_LAP].y), 0, va("Lap: %u/%d", stplyr->laps, cv_numlaps.value));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
@ -1894,38 +1894,40 @@ static void ST_overlayDrawer(void)
|
|||
V_DrawScaledPatch(hudinfo[HUD_GRAVBOOTSICO].x, STRINGY(hudinfo[HUD_GRAVBOOTSICO].y), V_SNAPTORIGHT, gravboots);
|
||||
*/
|
||||
|
||||
if (!(multiplayer && demo.playback))
|
||||
if (cv_showviewpointtext.value)
|
||||
{
|
||||
if(!P_IsLocalPlayer(stplyr))
|
||||
if (!(multiplayer && demo.playback))
|
||||
{
|
||||
/*char name[MAXPLAYERNAME+1];
|
||||
// shorten the name if its more than twelve characters.
|
||||
strlcpy(name, player_names[stplyr-players], 13);*/
|
||||
if(!P_IsLocalPlayer(stplyr))
|
||||
{
|
||||
/*char name[MAXPLAYERNAME+1];
|
||||
// shorten the name if its more than twelve characters.
|
||||
strlcpy(name, player_names[stplyr-players], 13);*/
|
||||
|
||||
// Show name of player being displayed
|
||||
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, 0, M_GetText("Viewpoint:"));
|
||||
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[stplyr-players]);
|
||||
// Show name of player being displayed
|
||||
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, 0, M_GetText("VIEWPOINT:"));
|
||||
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_ALLOWLOWERCASE, player_names[stplyr-players]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!demo.title)
|
||||
{
|
||||
else if (!demo.title)
|
||||
{
|
||||
if (!splitscreen)
|
||||
{
|
||||
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("VIEWPOINT:"));
|
||||
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_HUDTRANSHALF|V_ALLOWLOWERCASE, player_names[stplyr-players]);
|
||||
}
|
||||
else if (splitscreen == 1)
|
||||
{
|
||||
char name[MAXPLAYERNAME+12];
|
||||
|
||||
if (!splitscreen)
|
||||
{
|
||||
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("Viewpoint:"));
|
||||
V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_HUDTRANSHALF|V_ALLOWLOWERCASE, player_names[stplyr-players]);
|
||||
}
|
||||
else if (splitscreen == 1)
|
||||
{
|
||||
char name[MAXPLAYERNAME+12];
|
||||
|
||||
INT32 y = (stplyr == &players[displayplayers[0]]) ? 4 : BASEVIDHEIGHT/2-12;
|
||||
sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]);
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT), name);
|
||||
}
|
||||
else if (splitscreen)
|
||||
{
|
||||
V_DrawCenteredThinString((vid.width/vid.dupx)/4, BASEVIDHEIGHT/2 - 12, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT), player_names[stplyr-players]);
|
||||
INT32 y = (stplyr == &players[displayplayers[0]]) ? 4 : BASEVIDHEIGHT/2-12;
|
||||
sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]);
|
||||
V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT), name);
|
||||
}
|
||||
else if (splitscreen)
|
||||
{
|
||||
V_DrawCenteredThinString((vid.width/vid.dupx)/4, BASEVIDHEIGHT/2 - 12, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT), player_names[stplyr-players]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -436,6 +436,7 @@ void Y_IntermissionDrawer(void)
|
|||
INT32 y = 41, gutter = ((data.match.numplayers > NUMFORNEWCOLUMN) ? 0 : (BASEVIDWIDTH/2));
|
||||
INT32 dupadjust = (vid.width/vid.dupx), duptweak = (dupadjust - BASEVIDWIDTH)/2;
|
||||
const char *timeheader;
|
||||
int y2;
|
||||
|
||||
if (data.match.rankingsmode)
|
||||
timeheader = "PWR.LV";
|
||||
|
|
@ -493,10 +494,41 @@ void Y_IntermissionDrawer(void)
|
|||
|
||||
STRBUFCPY(strtime, data.match.name[i]);
|
||||
|
||||
y2 = y;
|
||||
|
||||
if (data.match.num[i] == 0 && server_lagless)
|
||||
{
|
||||
static int alagles_timer = 0;
|
||||
patch_t *alagles;
|
||||
|
||||
y2 = ( y - 4 );
|
||||
|
||||
V_DrawScaledPatch(x + 36, y2, 0, W_CachePatchName(va("BLAGLES%d", (intertic / 3) % 6), PU_CACHE));
|
||||
// every 70 tics
|
||||
if (( leveltime % 70 ) == 0)
|
||||
{
|
||||
alagles_timer = 9;
|
||||
}
|
||||
if (alagles_timer > 0)
|
||||
{
|
||||
alagles = W_CachePatchName(va("ALAGLES%d", alagles_timer), PU_CACHE);
|
||||
V_DrawScaledPatch(x + 36, y2, 0, alagles);
|
||||
if (( leveltime % 2 ) == 0)
|
||||
alagles_timer--;
|
||||
}
|
||||
else
|
||||
{
|
||||
alagles = W_CachePatchName("ALAGLES0", PU_CACHE);
|
||||
V_DrawScaledPatch(x + 36, y2, 0, alagles);
|
||||
}
|
||||
|
||||
y2 += SHORT (alagles->height) + 1;
|
||||
}
|
||||
|
||||
if (data.match.numplayers > NUMFORNEWCOLUMN)
|
||||
V_DrawThinString(x+36, y-1, ((data.match.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
|
||||
V_DrawThinString(x+36, y2-1, ((data.match.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
|
||||
else
|
||||
V_DrawString(x+36, y, ((data.match.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE, strtime);
|
||||
V_DrawString(x+36, y2, ((data.match.num[i] == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE, strtime);
|
||||
|
||||
if (data.match.rankingsmode)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue