Merge branch 'master' into targets

This commit is contained in:
Sally Cochenour 2020-03-22 14:31:17 -04:00
commit b1ec5654bc
52 changed files with 7334 additions and 2203 deletions

View file

@ -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 \

View file

@ -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;
}
}
}
}

View file

@ -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,

View file

@ -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;

View file

@ -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.

View file

@ -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;

View file

@ -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.

View file

@ -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},

View file

@ -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

View file

@ -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,

View file

@ -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;

View file

@ -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!

View file

@ -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;
}

View file

@ -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:

View file

@ -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

View file

@ -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
View 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
View 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

File diff suppressed because it is too large Load diff

View file

@ -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
View 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
View 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

File diff suppressed because it is too large Load diff

338
src/k_waypoint.h Normal file
View 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

View file

@ -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},

View file

@ -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;

View file

@ -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));

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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))

View file

@ -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))

View file

@ -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);

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -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);

View file

@ -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)
{

View file

@ -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
}
}

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -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.

View file

@ -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);
}

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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)
{

View file

@ -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;

View file

@ -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])

View file

@ -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

View file

@ -894,6 +894,7 @@ typedef enum
sfx_toada,
sfx_bhurry,
sfx_bsnipe,
sfx_sploss,
sfx_itfree,
sfx_dbgsal,

View file

@ -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]);
}
}
}

View file

@ -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)
{