Merge branch 'master' of git@git.magicalgirl.moe:KartKrew/Kart.git into waypoints

# Conflicts:
#	src/Makefile
#	src/k_kart.c
#	src/p_map.c
#	src/p_setup.c
#	src/p_spec.c
This commit is contained in:
Sryder 2020-03-16 00:13:42 +00:00
commit c268313f0a
72 changed files with 4745 additions and 2636 deletions

View file

@ -17,7 +17,7 @@ set(SRB2_ASSET_HASHED
gfx.pk3;\
textures.pk3;\
chars.pk3;\
maps.wad;\
maps.pk3;\
patch.pk3"
CACHE STRING "Asset filenames to apply MD5 checks. No spaces between entries!"
)

View file

@ -60,6 +60,7 @@
# Compile with GCC 4.6x version, add 'GCC46=1'
# Compile a profile version, add 'PROFILEMODE=1'
# Compile a debug version, add 'DEBUGMODE=1'
# Compile for the testers group (they don't get to play unless we're watching *wink*), add 'TESTERS=1'
# Compile with extra warnings, add 'WARNINGMODE=1'
# Compile without NASM's tmap.nas, add 'NOASM=1'
# Compile without 3D hardware support, add 'NOHW=1'
@ -434,6 +435,10 @@ else
endif
CFLAGS+=-g $(OPTS) $(ARCHOPTS) $(WINDRESFLAGS)
ifdef TESTERS
OPTS+=-DTESTERS
endif
ifdef YASM
ifdef STABS
NASMOPTS?= -g stabs
@ -489,6 +494,7 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/y_inter.o \
$(OBJDIR)/st_stuff.o \
$(OBJDIR)/k_kart.o \
$(OBJDIR)/k_pwrlv.o \
$(OBJDIR)/k_waypoint.o\
$(OBJDIR)/k_pathfind.o\
$(OBJDIR)/k_bheap.o \

View file

@ -68,10 +68,14 @@ CV_PossibleValue_t CV_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}};
CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}};
CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
//SRB2kart
// SRB2kart
CV_PossibleValue_t kartspeed_cons_t[] = {
{0, "Easy"}, {1, "Normal"}, {2, "Hard"},
{0, NULL}};
{KARTSPEED_AUTO, "Auto"},
{KARTSPEED_EASY, "Easy"},
{KARTSPEED_NORMAL, "Normal"},
{KARTSPEED_HARD, "Hard"},
{0, NULL}
};
// Filter consvars by EXECVERSION
// First implementation is 2 (1.0.2), so earlier configs default at 1 (1.0.0)
@ -1769,7 +1773,7 @@ void CV_AddValue(consvar_t *var, INT32 increment)
{
newvalue = var->value + 1;
if (newvalue > maxspeed)
newvalue = 0;
newvalue = -1;
var->value = newvalue;
var->string = var->PossibleValue[var->value].strvalue;
var->func();
@ -1778,7 +1782,7 @@ void CV_AddValue(consvar_t *var, INT32 increment)
else if (increment < 0) // Going down!
{
newvalue = var->value - 1;
if (newvalue < 0)
if (newvalue < -1)
newvalue = maxspeed;
var->value = newvalue;
var->string = var->PossibleValue[var->value].strvalue;

View file

@ -131,6 +131,10 @@ extern CV_PossibleValue_t CV_Unsigned[];
extern CV_PossibleValue_t CV_Natural[];
// SRB2kart
#define KARTSPEED_AUTO -1
#define KARTSPEED_EASY 0
#define KARTSPEED_NORMAL 1
#define KARTSPEED_HARD 2
extern CV_PossibleValue_t kartspeed_cons_t[];
extern consvar_t cv_execversion;

View file

@ -15,7 +15,7 @@
#define ASSET_HASH_GFX_PK3 "${SRB2_ASSET_gfx.pk3_HASH}"
#define ASSET_HASH_TEXTURES_PK3 "${SRB2_ASSET_textures.pk3_HASH}"
#define ASSET_HASH_CHARS_PK3 "${SRB2_ASSET_chars.pk3_HASH}"
#define ASSET_HASH_MAPS_WAD "${SRB2_ASSET_maps.wad_HASH}"
#define ASSET_HASH_MAPS_PK3 "${SRB2_ASSET_maps.pk3_HASH}"
#ifdef USE_PATCH_FILE
#define ASSET_HASH_PATCH_PK3 "${SRB2_ASSET_patch.pk3_HASH}"
#endif
@ -36,7 +36,7 @@
#define ASSET_HASH_GFX_PK3 "00000000000000000000000000000000"
#define ASSET_HASH_TEXTURES_PK3 "00000000000000000000000000000000"
#define ASSET_HASH_CHARS_PK3 "00000000000000000000000000000000"
#define ASSET_HASH_MAPS_WAD "00000000000000000000000000000000"
#define ASSET_HASH_MAPS_PK3 "00000000000000000000000000000000"
#ifdef USE_PATCH_FILE
#define ASSET_HASH_PATCH_PK3 "00000000000000000000000000000000"
#endif

View file

@ -47,6 +47,7 @@
#include "lua_script.h"
#include "lua_hook.h"
#include "k_kart.h"
#include "k_pwrlv.h"
#ifdef CLIENT_LOADINGSCREEN
// cl loading screen
@ -96,6 +97,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)
@ -1240,6 +1243,7 @@ static inline void CL_DrawConnectionStatus(void)
case CL_ASKDOWNLOADFILES:
case CL_WAITDOWNLOADFILESRESPONSE:
cltext = M_GetText("Waiting to download files...");
break;
default:
cltext = M_GetText("Connecting to server...");
break;
@ -1350,7 +1354,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
netbuffer->u.serverinfo.kartvars = (UINT8) (
(cv_kartspeed.value & SV_SPEEDMASK) |
(gamespeed & SV_SPEEDMASK) |
(dedicated ? SV_DEDICATED : 0) |
(D_IsJoinPasswordOn() ? SV_PASSWORD : 0)
);
@ -1420,6 +1424,11 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
p = PutFileNeeded(0);
if (cv_kartusepwrlv.value)
netbuffer->u.serverinfo.avgpwrlv = K_CalculatePowerLevelAvg();
else
netbuffer->u.serverinfo.avgpwrlv = -1;
HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u));
}
@ -1494,7 +1503,7 @@ static void SV_SendPlayerInfo(INT32 node)
*/
static boolean SV_SendServerConfig(INT32 node)
{
INT32 i;
INT32 i, j;
UINT8 *p, *op;
boolean waspacketsent;
@ -1517,10 +1526,13 @@ static boolean SV_SendServerConfig(INT32 node)
memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor));
memset(netbuffer->u.servercfg.adminplayers, -1, sizeof(netbuffer->u.servercfg.adminplayers));
memset(netbuffer->u.servercfg.powerlevels, 0, sizeof(netbuffer->u.servercfg.powerlevels));
for (i = 0; i < MAXPLAYERS; i++)
{
netbuffer->u.servercfg.adminplayers[i] = (SINT8)adminplayers[i];
for (j = 0; j < PWRLV_NUMTYPES; j++)
netbuffer->u.servercfg.powerlevels[i][j] = clientpowerlevels[i][j];
if (!playeringame[i])
continue;
@ -2306,6 +2318,7 @@ static void CL_ConnectToServer(boolean viams)
wipegamestate = GS_WAITINGPLAYERS;
ClearAdminPlayers();
K_ClearClientPowerLevels();
pnumnodes = 1;
oldtic = I_GetTime() - 1;
#ifndef NONET
@ -3156,6 +3169,21 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
break;
}
// SRB2Kart: kicks count as forfeit
switch (kickreason)
{
case KR_KICK:
case KR_BAN:
case KR_LEAVE:
// Intentional removals should be hit with a true forfeit.
K_PlayerForfeit(pnum, true);
break;
default:
// Otherwise, give remaining players the point compensation, but doesn't penalize who left.
K_PlayerForfeit(pnum, false);
break;
}
if (playernode[pnum] == playernode[consoleplayer])
{
#ifdef DUMPCONSISTENCY
@ -3324,6 +3352,7 @@ void SV_ResetServer(void)
playernode[i] = UINT8_MAX;
sprintf(player_names[i], "Player %d", i + 1);
adminplayers[i] = -1; // Populate the entire adminplayers array with -1.
K_ClearClientPowerLevels();
}
mynode = 0;
@ -3399,6 +3428,7 @@ void D_QuitNetGame(void)
D_CloseConnection();
ClearAdminPlayers();
K_ClearClientPowerLevels();
DEBFILE("===========================================================================\n"
" Log finish\n"
@ -3445,11 +3475,12 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
return;
}
node = READUINT8(*p);
newplayernum = READUINT8(*p);
splitscreenplayer = newplayernum/MAXPLAYERS;
newplayernum %= MAXPLAYERS;
node = (UINT8)READUINT8(*p);
newplayernum = (UINT8)READUINT8(*p);
splitscreenplayer = (UINT8)READUINT8(*p);
CONS_Debug(DBG_NETPLAY, "addplayer: %d %d %d\n", node, newplayernum, splitscreenplayer);
// Clear player before joining, lest some things get set incorrectly
CL_ClearPlayer(newplayernum);
@ -3466,7 +3497,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
if (splitscreenplayer)
{
displayplayers[splitscreenplayer] = newplayernum;
DEBFILE(va("spawning one of my sister number %d\n", splitscreenplayer));
DEBFILE(va("spawning sister # %d\n", splitscreenplayer));
if (splitscreenplayer == 1 && botingame)
players[newplayernum].bot = 1;
}
@ -3477,6 +3508,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
displayplayers[i] = newplayernum;
DEBFILE("spawning me\n");
}
D_SendPlayerConfig();
addedtogame = true;
}
@ -3532,7 +3564,6 @@ static void Got_RemovePlayer(UINT8 **p, INT32 playernum)
static boolean SV_AddWaitingPlayers(void)
{
INT32 node, n, newplayer = false;
XBOXSTATIC UINT8 buf[2];
UINT8 newplayernum = 0;
// What is the reason for this? Why can't newplayernum always be 0?
@ -3545,6 +3576,9 @@ static boolean SV_AddWaitingPlayers(void)
// splitscreen can allow 2+ players in one node
for (; nodewaiting[node] > 0; nodewaiting[node]--)
{
UINT8 buf[3];
UINT8 *buf_p = buf;
newplayer = true;
// search for a free playernum
@ -3552,8 +3586,10 @@ static boolean SV_AddWaitingPlayers(void)
for (; newplayernum < MAXPLAYERS; newplayernum++)
{
for (n = 0; n < MAXNETNODES; n++)
if (nodetoplayer[n] == newplayernum || nodetoplayer2[n] == newplayernum
|| nodetoplayer3[n] == newplayernum || nodetoplayer4[n] == newplayernum)
if (nodetoplayer[n] == newplayernum
|| nodetoplayer2[n] == newplayernum
|| nodetoplayer3[n] == newplayernum
|| nodetoplayer4[n] == newplayernum)
break;
if (n == MAXNETNODES)
break;
@ -3565,28 +3601,23 @@ static boolean SV_AddWaitingPlayers(void)
playernode[newplayernum] = (UINT8)node;
buf[0] = (UINT8)node;
buf[1] = newplayernum;
WRITEUINT8(buf_p, (UINT8)node);
WRITEUINT8(buf_p, newplayernum);
if (playerpernode[node] < 1)
nodetoplayer[node] = newplayernum;
else if (playerpernode[node] < 2)
{
nodetoplayer2[node] = newplayernum;
buf[1] += MAXPLAYERS;
}
else if (playerpernode[node] < 3)
{
nodetoplayer3[node] = newplayernum;
buf[1] += MAXPLAYERS*2;
}
else
{
else if (playerpernode[node] < 4)
nodetoplayer4[node] = newplayernum;
buf[1] += MAXPLAYERS*3;
}
WRITEUINT8(buf_p, playerpernode[node]); // splitscreen num
playerpernode[node]++;
SendNetXCmd(XD_ADDPLAYER, &buf, 2);
SendNetXCmd(XD_ADDPLAYER, buf, buf_p - buf);
DEBFILE(va("Server added player %d node %d\n", newplayernum, node));
// use the next free slot (we can't put playeringame[newplayernum] = true here)
@ -3623,6 +3654,11 @@ boolean Playing(void)
boolean SV_SpawnServer(void)
{
#ifdef TESTERS
/* Just don't let the testers play. Easy. */
I_Error("What do you think you're doing?");
return false;
#else
if (demo.playback)
G_StopDemo(); // reset engine parameter
if (metalplayback)
@ -3649,6 +3685,7 @@ boolean SV_SpawnServer(void)
}
return SV_AddWaitingPlayers();
#endif
}
void SV_StopServer(void)
@ -4075,7 +4112,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
case PT_SERVERCFG: // Positive response of client join request
{
INT32 j;
INT32 j, k;
UINT8 *scp;
if (server && serverrunning && node != servernode)
@ -4098,7 +4135,11 @@ static void HandlePacketFromAwayNode(SINT8 node)
I_Error("Bad gametype in cliserv!");
modifiedgame = netbuffer->u.servercfg.modifiedgame;
for (j = 0; j < MAXPLAYERS; j++)
{
adminplayers[j] = netbuffer->u.servercfg.adminplayers[j];
for (k = 0; k < PWRLV_NUMTYPES; k++)
clientpowerlevels[j][k] = netbuffer->u.servercfg.powerlevels[j][k];
}
memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
}
@ -4921,6 +4962,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)
@ -5389,16 +5433,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

@ -18,6 +18,7 @@
#include "d_netcmd.h"
#include "tables.h"
#include "d_player.h"
#include "k_pwrlv.h" // PWRLV_NUMTYPES
#include "md5.h"
@ -325,6 +326,7 @@ typedef struct
UINT8 gametype;
UINT8 modifiedgame;
SINT8 adminplayers[MAXPLAYERS]; // Needs to be signed
UINT16 powerlevels[MAXPLAYERS][PWRLV_NUMTYPES]; // SRB2kart: player power levels
char server_context[8]; // Unique context id, generated at server startup.
@ -387,6 +389,10 @@ typedef struct
UINT8 actnum;
UINT8 iszone;
UINT8 fileneeded[MAXFILENEEDED]; // is filled with writexxx (byteptr.h)
// Anything beyond this point won't be read by the normal SRB2 Master Server display.
// The MS uses a simple unpack, so the size of the packet above shouldn't be changed, either.
// As long as those two conditions are met, we can add as much information as we want to the end.
INT16 avgpwrlv; // Kart avg power level
} ATTRPACK serverinfo_pak;
typedef struct
@ -537,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

@ -308,13 +308,6 @@ static void D_Display(void)
wipedefindex = gamestate; // wipe_xxx_toblack
if (gamestate == GS_TITLESCREEN && wipegamestate != GS_INTRO)
wipedefindex = wipe_timeattack_toblack;
else if (gamestate == GS_INTERMISSION)
{
if (intertype == int_spec) // Special Stage
wipedefindex = wipe_specinter_toblack;
else //if (intertype != int_coop) // Multiplayer
wipedefindex = wipe_multinter_toblack;
}
if (rendermode != render_none)
{
@ -325,7 +318,7 @@ static void D_Display(void)
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeEndScreen();
F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK);
F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK, "FADEMAP0", false, false);
}
if (gamestate != GS_LEVEL && rendermode != render_none)
@ -447,7 +440,7 @@ static void D_Display(void)
{
if (i > 0) // Splitscreen-specific
{
switch (i)
switch (i)
{
case 1:
if (splitscreen > 1)
@ -556,7 +549,7 @@ static void D_Display(void)
if (rendermode != render_none)
{
F_WipeEndScreen();
F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK);
F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK, "FADEMAP0", true, false);
}
}
@ -896,11 +889,18 @@ static void IdentifyVersion(void)
D_AddFile(va(pandf,srb2waddir,"gfx.pk3"), startupwadfiles);
D_AddFile(va(pandf,srb2waddir,"textures.pk3"), startupwadfiles);
D_AddFile(va(pandf,srb2waddir,"chars.pk3"), startupwadfiles);
D_AddFile(va(pandf,srb2waddir,"maps.wad"), startupwadfiles); // TODO: make this a pk3 too!
D_AddFile(va(pandf,srb2waddir,"maps.pk3"), startupwadfiles);
#ifdef USE_PATCH_FILE
D_AddFile(va(pandf,srb2waddir,"patch.pk3"), startupwadfiles);
#endif
#if 0
// TODO: pk3 doesn't support music replacement IIRC
// music barely benefits from the compression anyway
// would be nice for the folders, though
D_AddFile(va(pandf,srb2waddir,"sounds.pk3"), startupwadfiles);
D_AddFile(va(pandf,srb2waddir,"music.pk3"), startupwadfiles);
#else
#if !defined (HAVE_SDL) || defined (HAVE_MIXER)
#define MUSICTEST(str) \
{\
@ -915,6 +915,7 @@ static void IdentifyVersion(void)
MUSICTEST("music.wad")
#undef MUSICTEST
#endif
#endif
}
/* ======================================================================== */
@ -1182,12 +1183,12 @@ void D_SRB2Main(void)
M_InitCharacterTables();
// load wad, including the main wad file
CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n");
CONS_Printf("W_InitMultipleFiles(): Adding main IWAD and PWADs.\n");
if (!W_InitMultipleFiles(startupwadfiles, false))
#ifdef _DEBUG
CONS_Error("A WAD file was not found or not valid.\nCheck the log to see which ones.\n");
CONS_Error("A main WAD file was not found or not valid.\nCheck the log to see which ones.\n");
#else
I_Error("A WAD file was not found or not valid.\nCheck the log to see which ones.\n");
I_Error("A main WAD file was not found or not valid.\nCheck the log to see which ones.\n");
#endif
D_CleanFile(startupwadfiles);
@ -1200,7 +1201,7 @@ void D_SRB2Main(void)
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_GFX_PK3); // gfx.pk3
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_TEXTURES_PK3); // textures.pk3
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_CHARS_PK3); // chars.pk3
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_WAD); // maps.wad -- 4 - If you touch this, make sure to touch up the majormods stuff below.
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_MAPS_PK3); // maps.pk3 -- 4 - If you touch this, make sure to touch up the majormods stuff below.
#ifdef USE_PATCH_FILE
mainwads++; W_VerifyFileMD5(mainwads, ASSET_HASH_PATCH_PK3); // patch.pk3
#endif
@ -1208,7 +1209,7 @@ void D_SRB2Main(void)
mainwads++; // gfx.pk3
mainwads++; // textures.pk3
mainwads++; // chars.pk3
mainwads++; // maps.wad
mainwads++; // maps.pk3
#ifdef USE_PATCH_FILE
mainwads++; // patch.pk3
#endif
@ -1241,8 +1242,9 @@ void D_SRB2Main(void)
}
}
CONS_Printf("W_InitMultipleFiles(): Adding external PWADs.\n");
if (!W_InitMultipleFiles(startuppwads, true))
CONS_Error("A PWAD file was not found or not valid.\nCheck the log to see which ones.\n");
M_StartMessage(M_GetText("A PWAD file was not found or not valid.\nCheck log.txt to see which ones.\n\nPress ESC\n"), NULL, MM_NOTHING);
D_CleanFile(startuppwads);
//
@ -1534,10 +1536,11 @@ void D_SRB2Main(void)
newskill = (INT16)kartspeed_cons_t[j].value;
break;
}
if (!kartspeed_cons_t[j].strvalue) // reached end of the list with no match
{
j = atoi(sskill); // assume they gave us a skill number, which is okay too
if (j >= 0 && j <= 2)
if (j >= KARTSPEED_EASY && j <= KARTSPEED_HARD)
newskill = (INT16)j;
}
@ -1557,7 +1560,7 @@ void D_SRB2Main(void)
else if (!dedicated && M_MapLocked(pstartmap))
I_Error("You need to unlock this level before you can warp to it!\n");
else
D_MapChange(pstartmap, gametype, (boolean)cv_kartencore.value, true, 0, false, false);
D_MapChange(pstartmap, gametype, (cv_kartencore.value == 1), true, 0, false, false);
}
}
else if (M_CheckParm("-skipintro"))

View file

@ -47,6 +47,7 @@
#include "m_cond.h"
#include "m_anigif.h"
#include "k_kart.h" // SRB2kart
#include "k_pwrlv.h"
#include "y_inter.h"
#ifdef NETGAME_DEVMODE
@ -61,6 +62,7 @@
static void Got_NameAndColor(UINT8 **cp, INT32 playernum);
static void Got_WeaponPref(UINT8 **cp, INT32 playernum);
static void Got_PowerLevel(UINT8 **cp, INT32 playernum);
static void Got_Mapcmd(UINT8 **cp, INT32 playernum);
static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum);
static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum);
@ -91,6 +93,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);
@ -358,12 +362,13 @@ consvar_t cv_kartminimap = {"kartminimap", "4", CV_SAVE, kartminimap_cons_t, NUL
consvar_t cv_kartcheck = {"kartcheck", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartinvinsfx_cons_t[] = {{0, "Music"}, {1, "SFX"}, {0, NULL}};
consvar_t cv_kartinvinsfx = {"kartinvinsfx", "SFX", CV_SAVE, kartinvinsfx_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartspeed = {"kartspeed", "Normal", CV_NETVAR|CV_CALL|CV_NOINIT, kartspeed_cons_t, KartSpeed_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartspeed = {"kartspeed", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartspeed_cons_t, KartSpeed_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartbumpers_cons_t[] = {{1, "MIN"}, {12, "MAX"}, {0, NULL}};
consvar_t cv_kartbumpers = {"kartbumpers", "3", CV_NETVAR|CV_CHEAT, kartbumpers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartfrantic = {"kartfrantic", "Off", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartFrantic_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartcomeback = {"kartcomeback", "On", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOINIT, CV_OnOff, KartComeback_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartencore = {"kartencore", "Off", CV_NETVAR|CV_CALL|CV_NOINIT, CV_OnOff, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartencore_cons_t[] = {{-1, "Auto"}, {0, "Off"}, {1, "On"}, {0, NULL}};
consvar_t cv_kartencore = {"kartencore", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartencore_cons_t, KartEncore_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}};
consvar_t cv_kartvoterulechanges = {"kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Percentage"}, {2, "Kilometers"}, {3, "Miles"}, {4, "Fracunits"}, {0, NULL}};
@ -373,6 +378,8 @@ consvar_t cv_kartvoices = {"kartvoices", "Tasteful", CV_SAVE, kartvoices_cons_t,
consvar_t cv_karteliminatelast = {"karteliminatelast", "Yes", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOSHOWHELP, CV_YesNo, KartEliminateLast_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kartusepwrlv = {"kartusepwrlv", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartdebugitem_cons_t[] = {{-1, "MIN"}, {NUMKARTITEMS-1, "MAX"}, {0, NULL}};
consvar_t cv_kartdebugitem = {"kartdebugitem", "0", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, kartdebugitem_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t kartdebugamount_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}};
@ -411,7 +418,8 @@ consvar_t cv_itemfinder = {"itemfinder", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff,
// Scoring type options
consvar_t cv_match_scoring = {"matchscoring", "Normal", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, match_scoring_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t overtime_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Super"}, {0, NULL}};
consvar_t cv_overtime = {"overtime", "Yes", CV_NETVAR|CV_CHEAT, overtime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_rollingdemos = {"rollingdemos", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -420,13 +428,13 @@ consvar_t cv_timetic = {"timerres", "Normal", CV_SAVE|CV_NOSHOWHELP, timetic_con
static CV_PossibleValue_t pointlimit_cons_t[] = {{0, "MIN"}, {999999990, "MAX"}, {0, NULL}};
consvar_t cv_pointlimit = {"pointlimit", "0", CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t,
PointLimit_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t timelimit_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}};
static CV_PossibleValue_t timelimit_cons_t[] = {{0, "MIN"}, {1800, "MAX"}, {0, NULL}};
consvar_t cv_timelimit = {"timelimit", "0", CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t,
TimeLimit_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, NULL}};
static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}};
consvar_t cv_numlaps = {"numlaps", "3", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t,
NumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}};
static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, "Map default"}, {0, NULL}};
consvar_t cv_basenumlaps = {"basenumlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_forceskin = {"forceskin", "Off", CV_NETVAR|CV_CALL|CV_CHEAT, Forceskin_cons_t, ForceSkin_OnChange, 0, NULL, NULL, 0, 0, NULL};
@ -443,6 +451,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};
@ -501,6 +511,7 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
"MODIFYVOTE",
"PICKVOTE",
"REMOVEPLAYER",
"POWERLEVEL",
#ifdef HAVE_BLUA
"LUACMD",
"LUAVAR"
@ -538,6 +549,7 @@ void D_RegisterServerCommands(void)
}
RegisterNetXCmd(XD_NAMEANDCOLOR, Got_NameAndColor);
RegisterNetXCmd(XD_WEAPONPREF, Got_WeaponPref);
RegisterNetXCmd(XD_POWERLEVEL, Got_PowerLevel);
RegisterNetXCmd(XD_MAP, Got_Mapcmd);
RegisterNetXCmd(XD_EXITLEVEL, Got_ExitLevelcmd);
RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd);
@ -705,6 +717,7 @@ 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);
@ -1925,6 +1938,17 @@ static void Got_WeaponPref(UINT8 **cp,INT32 playernum)
players[playernum].pflags |= PF_ANALOGMODE;
}
static void Got_PowerLevel(UINT8 **cp,INT32 playernum)
{
UINT16 race = (UINT16)READUINT16(*cp);
UINT16 battle = (UINT16)READUINT16(*cp);
clientpowerlevels[playernum][PWRLV_RACE] = min(PWRLVRECORD_MAX, race);
clientpowerlevels[playernum][PWRLV_BATTLE] = min(PWRLVRECORD_MAX, battle);
CONS_Debug(DBG_GAMELOGIC, "set player %d to power %d\n", playernum, race);
}
void D_SendPlayerConfig(void)
{
SendNameAndColor();
@ -1941,6 +1965,31 @@ void D_SendPlayerConfig(void)
SendWeaponPref3();
if (splitscreen > 2)
SendWeaponPref4();
{
UINT8 buf[4];
UINT8 *buf_p = buf;
WRITEUINT16(buf_p, vspowerlevel[PWRLV_RACE]);
WRITEUINT16(buf_p, vspowerlevel[PWRLV_BATTLE]);
SendNetXCmd(XD_POWERLEVEL, buf, 4);
}
if (splitscreen)
{
UINT8 buf[4];
UINT8 *buf_p = buf;
WRITEUINT16(buf_p, 0);
WRITEUINT16(buf_p, 0);
SendNetXCmd2(XD_POWERLEVEL, buf, 4);
if (splitscreen > 1)
SendNetXCmd3(XD_POWERLEVEL, buf, 4);
if (splitscreen > 2)
SendNetXCmd4(XD_POWERLEVEL, buf, 4);
}
}
// Only works for displayplayer, sorry!
@ -2353,7 +2402,7 @@ void D_SetupVote(void)
UINT8 secondgt = G_SometimesGetDifferentGametype();
INT16 votebuffer[3] = {-1,-1,-1};
if (cv_kartencore.value && G_RaceGametype())
if ((cv_kartencore.value == 1) && G_RaceGametype())
WRITEUINT8(p, (gametype|0x80));
else
WRITEUINT8(p, gametype);
@ -2524,7 +2573,7 @@ static void Command_Map_f(void)
// new encoremode value
// use cvar by default
newencoremode = (boolean)cv_kartencore.value;
newencoremode = (cv_kartencore.value == 1);
if (COM_CheckParm("-encore"))
{
@ -3651,6 +3700,9 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
if (K_IsPlayerWanted(&players[playernum]))
K_CalculateBattleWanted();
}
K_PlayerForfeit(playernum, true);
players[playernum].health = 1;
if (players[playernum].mo)
players[playernum].mo->health = 1;
@ -4724,6 +4776,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.
@ -4745,8 +4805,8 @@ static void TimeLimit_OnChange(void)
if (cv_timelimit.value != 0)
{
CONS_Printf(M_GetText("Levels will end after %d minute%s.\n"),cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003
timelimitintics = cv_timelimit.value * 60 * TICRATE;
CONS_Printf(M_GetText("Levels will end after %d second%s.\n"),cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003
timelimitintics = cv_timelimit.value * TICRATE;
//add hidetime for tag too!
if (G_TagGametype())
@ -4796,9 +4856,9 @@ void D_GameTypeChanged(INT32 lastgametype)
case GT_TEAMMATCH:
if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits
{
// default settings for match: no timelimit, no pointlimit
CV_SetValue(&cv_pointlimit, 0);
CV_SetValue(&cv_timelimit, 0);
// default settings for match: 2 mins, no pointlimit
CV_SetValue(&cv_pointlimit, 0);
CV_SetValue(&cv_timelimit, 120);
}
if (!cv_itemrespawntime.changed)
CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally
@ -5104,7 +5164,7 @@ static void Hidetime_OnChange(void)
//uh oh, gotta change timelimitintics now too
if (G_TagGametype())
timelimitintics = (cv_timelimit.value * 60 * TICRATE) + (hidetime * TICRATE);
timelimitintics = (cv_timelimit.value * TICRATE) + (hidetime * TICRATE);
}
static void Command_Showmap_f(void)
@ -5734,22 +5794,24 @@ static void KartFrantic_OnChange(void)
static void KartSpeed_OnChange(void)
{
if (!M_SecretUnlocked(SECRET_HARDSPEED) && cv_kartspeed.value == 2)
if (!M_SecretUnlocked(SECRET_HARDSPEED) && cv_kartspeed.value == KARTSPEED_HARD)
{
CONS_Printf(M_GetText("You haven't earned this yet.\n"));
CV_StealthSetValue(&cv_kartspeed, 1);
CV_StealthSet(&cv_kartspeed, cv_kartspeed.defaultvalue);
return;
}
if (G_RaceGametype())
{
if ((UINT8)cv_kartspeed.value != gamespeed && gamestate == GS_LEVEL && leveltime > starttime)
CONS_Printf(M_GetText("Game speed will be changed to \"%s\" next round.\n"), cv_kartspeed.string);
else
if ((gamestate == GS_LEVEL && leveltime < starttime) && (cv_kartspeed.value != KARTSPEED_AUTO))
{
CONS_Printf(M_GetText("Game speed has been changed to \"%s\".\n"), cv_kartspeed.string);
gamespeed = (UINT8)cv_kartspeed.value;
}
else if (cv_kartspeed.value != (signed)gamespeed)
{
CONS_Printf(M_GetText("Game speed will be changed to \"%s\" next round.\n"), cv_kartspeed.string);
}
}
}
@ -5757,10 +5819,10 @@ static void KartEncore_OnChange(void)
{
if (G_RaceGametype())
{
if ((boolean)cv_kartencore.value != encoremode && gamestate == GS_LEVEL /*&& leveltime > starttime*/)
CONS_Printf(M_GetText("Encore Mode will be turned %s next round.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off"));
if ((cv_kartencore.value == 1) != encoremode && gamestate == GS_LEVEL /*&& leveltime > starttime*/)
CONS_Printf(M_GetText("Encore Mode will be set to %s next round.\n"), cv_kartencore.string);
else
CONS_Printf(M_GetText("Encore Mode has been turned %s.\n"), cv_kartencore.value ? M_GetText("on") : M_GetText("off"));
CONS_Printf(M_GetText("Encore Mode has been set to %s.\n"), cv_kartencore.string);
}
}

View file

@ -120,8 +120,8 @@ extern consvar_t cv_kartencore;
extern consvar_t cv_kartvoterulechanges;
extern consvar_t cv_kartspeedometer;
extern consvar_t cv_kartvoices;
extern consvar_t cv_karteliminatelast;
extern consvar_t cv_kartusepwrlv;
extern consvar_t cv_votetime;
@ -145,6 +145,7 @@ 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;
@ -179,9 +180,10 @@ typedef enum
XD_MODIFYVOTE, // 23
XD_PICKVOTE, // 24
XD_REMOVEPLAYER,// 25
XD_POWERLEVEL, // 26
#ifdef HAVE_BLUA
XD_LUACMD, // 26
XD_LUAVAR, // 27
XD_LUACMD, // 27
XD_LUAVAR, // 28
#endif
MAXNETXCMD
} netxcmd_t;

View file

@ -326,6 +326,10 @@ typedef enum
k_jawztargetdelay, // Delay for Jawz target switching, to make it less twitchy
k_spectatewait, // How long have you been waiting as a spectator
k_growcancel, // Hold the item button down to cancel Grow
k_tiregrease, // Reduced friction timer after hitting a horizontal spring
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
NUMKARTSTUFF
} kartstufftype_t;

View file

@ -1230,8 +1230,9 @@ static void readlevelheader(MYFILE *f, INT32 num)
}
else if (fastcmp(word, "WEATHER"))
mapheaderinfo[num-1]->weather = (UINT8)get_number(word2);
else if (fastcmp(word, "SKYNUM"))
mapheaderinfo[num-1]->skynum = (INT16)i;
else if (fastcmp(word, "SKYTEXTURE"))
deh_strlcpy(mapheaderinfo[num-1]->skytexture, word2,
sizeof(mapheaderinfo[num-1]->skytexture), va("Level header %d: sky texture", num));
else if (fastcmp(word, "INTERSCREEN"))
strncpy(mapheaderinfo[num-1]->interscreen, word2, 8);
else if (fastcmp(word, "PRECUTSCENENUM"))
@ -1773,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"},
@ -2552,6 +2552,19 @@ static void readcondition(UINT8 set, UINT32 id, char *word2)
ty = UC_PLAYTIME + offset;
re = atoi(params[1]);
}
else if ((offset=0) || fastcmp(params[0], "POWERLEVEL"))
{
PARAMCHECK(2);
ty = UC_POWERLEVEL;
re = atoi(params[1]);
x1 = atoi(params[2]);
if (x1 < 0 || x1 >= PWRLV_NUMTYPES)
{
deh_warning("Power level type %d out of range (0 - %d)", x1, PWRLV_NUMTYPES-1);
return;
}
}
else if ((offset=0) || fastcmp(params[0], "GAMECLEAR")
|| (++offset && fastcmp(params[0], "ALLEMERALDS")))
//|| (++offset && fastcmp(params[0], "ULTIMATECLEAR")))
@ -2604,7 +2617,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2)
if (x1 < 0 || x1 >= NUMMAPS)
{
deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS);
deh_warning("Level number %d out of range (1 - %d)", x1, NUMMAPS);
return;
}
}
@ -3256,29 +3269,13 @@ static void readwipes(MYFILE *f)
else if (fastcmp(pword, "FINAL"))
wipeoffset = wipe_intermission_final;
}
else if (fastncmp(word, "SPECINTER_", 10))
{
pword = word + 10;
if (fastcmp(pword, "TOBLACK"))
wipeoffset = wipe_specinter_toblack;
else if (fastcmp(pword, "FINAL"))
wipeoffset = wipe_specinter_final;
}
else if (fastncmp(word, "VOTING_", 7))
{
pword = word + 7;
if (fastcmp(pword, "TOBLACK"))
wipeoffset = wipe_specinter_toblack;
wipeoffset = wipe_voting_toblack;
else if (fastcmp(pword, "FINAL"))
wipeoffset = wipe_specinter_final;
}
else if (fastncmp(word, "MULTINTER_", 10))
{
pword = word + 10;
if (fastcmp(pword, "TOBLACK"))
wipeoffset = wipe_multinter_toblack;
else if (fastcmp(pword, "FINAL"))
wipeoffset = wipe_multinter_final;
wipeoffset = wipe_voting_final;
}
else if (fastncmp(word, "CONTINUING_", 11))
{
@ -3330,11 +3327,13 @@ static void readwipes(MYFILE *f)
else if (fastcmp(pword, "FINAL"))
wipeoffset = wipe_gameend_final;
}
else if (fastncmp(word, "SPECLEVEL_", 10))
else if (fastncmp(word, "ENCORE_", 7))
{
pword = word + 10;
if (fastcmp(pword, "TOWHITE"))
wipeoffset = wipe_speclevel_towhite;
pword = word + 7;
if (fastcmp(pword, "TOINVERT"))
wipeoffset = wipe_encore_toinvert;
else if (fastcmp(pword, "TOWHITE"))
wipeoffset = wipe_encore_towhite;
}
if (wipeoffset < 0)
@ -3344,10 +3343,10 @@ static void readwipes(MYFILE *f)
}
if (value == UINT8_MAX
&& (wipeoffset <= wipe_level_toblack || wipeoffset >= wipe_speclevel_towhite))
&& (wipeoffset <= wipe_level_toblack || wipeoffset >= wipe_encore_toinvert))
{
// Cannot disable non-toblack wipes
// (or the level toblack wipe, or the special towhite wipe)
// (or the level toblack wipe, or the special encore wipe)
deh_warning("Wipes: can't disable wipe of type '%s'", word);
continue;
}
@ -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",
@ -5609,44 +5591,77 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_RBIRD2",
"S_RBIRD3",
"S_YELLOWSPRING",
// Yellow Spring
"S_YELLOWSPRING1",
"S_YELLOWSPRING2",
"S_YELLOWSPRING3",
"S_YELLOWSPRING4",
"S_YELLOWSPRING5",
"S_REDSPRING",
// Red Spring
"S_REDSPRING1",
"S_REDSPRING2",
"S_REDSPRING3",
"S_REDSPRING4",
"S_REDSPRING5",
// Blue Springs
"S_BLUESPRING",
// Blue Spring
"S_BLUESPRING1",
"S_BLUESPRING2",
"S_BLUESPRING3",
"S_BLUESPRING4",
"S_BLUESPRING5",
// Grey Spring
"S_GREYSPRING1",
"S_GREYSPRING2",
"S_GREYSPRING3",
"S_GREYSPRING4",
// Yellow Diagonal Spring
"S_YDIAG1",
"S_YDIAG2",
"S_YDIAG3",
"S_YDIAG4",
"S_YDIAG5",
"S_YDIAG6",
"S_YDIAG7",
"S_YDIAG8",
// Red Diagonal Spring
"S_RDIAG1",
"S_RDIAG2",
"S_RDIAG3",
"S_RDIAG4",
"S_RDIAG5",
"S_RDIAG6",
"S_RDIAG7",
"S_RDIAG8",
// Blue Diagonal Spring
"S_BDIAG1",
"S_BDIAG2",
"S_BDIAG3",
"S_BDIAG4",
// Grey Diagonal Spring
"S_GDIAG1",
"S_GDIAG2",
"S_GDIAG3",
"S_GDIAG4",
// Yellow Horizontal Spring
"S_YHORIZ1",
"S_YHORIZ2",
"S_YHORIZ3",
"S_YHORIZ4",
// Red Horizontal Spring
"S_RHORIZ1",
"S_RHORIZ2",
"S_RHORIZ3",
"S_RHORIZ4",
// Blue Horizontal Spring
"S_BHORIZ1",
"S_BHORIZ2",
"S_BHORIZ3",
"S_BHORIZ4",
// Grey Horizontal Spring
"S_GHORIZ1",
"S_GHORIZ2",
"S_GHORIZ3",
"S_GHORIZ4",
// Rain
"S_RAIN1",
@ -5657,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",
@ -6271,26 +6291,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_SRB1_GENREX1",
"S_SRB1_GENREX2",
// Gray Springs
"S_GRAYSPRING",
"S_GRAYSPRING2",
"S_GRAYSPRING3",
"S_GRAYSPRING4",
"S_GRAYSPRING5",
// Invis-spring - this is used just for the sproing sound.
"S_INVISSPRING",
// Blue Diagonal Spring
"S_BDIAG1",
"S_BDIAG2",
"S_BDIAG3",
"S_BDIAG4",
"S_BDIAG5",
"S_BDIAG6",
"S_BDIAG7",
"S_BDIAG8",
//{ Random Item Box
"S_RANDOMITEM1",
"S_RANDOMITEM2",
@ -6766,9 +6766,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",
@ -7199,6 +7196,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_DRAFTDUST4",
"S_DRAFTDUST5",
"S_TIREGREASE",
"S_OVERTIMEFOG",
"S_OVERTIMEORB",
"S_OVERTIMEBEAM",
#ifdef SEENAMES
"S_NAMECHECK",
#endif
@ -7328,15 +7331,23 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
// Springs and others
"MT_FAN",
"MT_STEAM", // Steam riser
"MT_BLUESPRING",
"MT_YELLOWSPRING",
"MT_REDSPRING",
"MT_BLUESPRING",
"MT_GREYSPRING",
"MT_YELLOWDIAG", // Yellow Diagonal Spring
"MT_REDDIAG", // Red Diagonal Spring
"MT_BLUEDIAG", // Blue Diagonal Spring
"MT_GREYDIAG", // Grey Diagonal Spring
"MT_YELLOWHORIZ", // Yellow Horizontal Spring
"MT_REDHORIZ", // Red Horizontal Spring
"MT_BLUEHORIZ", // Blue Horizontal Spring
"MT_GREYHORIZ", // Grey Horizontal Spring
// Interactive Objects
"MT_BUBBLES", // Bubble source
"MT_SIGN", // Level end sign
"MT_SIGN_PIECE",
"MT_SPIKEBALL", // Spike Ball
"MT_SPECIALSPIKEBALL",
"MT_SPINFIRE",
@ -7563,6 +7574,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
@ -7714,9 +7726,6 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_SRB1_GENREX",
// SRB2kart
"MT_GRAYSPRING",
"MT_INVISSPRING",
"MT_BLUEDIAG",
"MT_RANDOMITEM",
"MT_RANDOMITEMPOP",
"MT_FLOATINGITEM",
@ -7826,8 +7835,6 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_LAMPPOST",
"MT_MOSSYTREE",
"MT_SHADOW",
"MT_BUMP",
"MT_FLINGENERGY",
@ -7987,6 +7994,11 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_KARMAFIREWORK",
"MT_RINGSPARKS",
"MT_DRAFTDUST",
"MT_TIREGREASE",
"MT_OVERTIMEFOG",
"MT_OVERTIMEORB",
"MT_OVERTIMEBEAM",
#ifdef SEENAMES
"MT_NAMECHECK",
@ -8469,7 +8481,11 @@ static const char *const KARTSTUFF_LIST[] = {
"GETSPARKS",
"JAWZTARGETDELAY",
"SPECTATEWAIT",
"GROWCANCEL"
"GROWCANCEL",
"TIREGREASE",
"SPRINGSTARS",
"SPRINGCOLOR",
"KILLFIELD"
};
#endif
@ -8664,10 +8680,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},
@ -9899,11 +9915,11 @@ static inline int lib_getenum(lua_State *L)
} else if (fastcmp(word,"globalweather")) {
lua_pushinteger(L, globalweather);
return 1;
} else if (fastcmp(word,"levelskynum")) {
lua_pushinteger(L, levelskynum);
} else if (fastcmp(word,"levelskytexture")) {
lua_pushstring(L, levelskytexture);
return 1;
} else if (fastcmp(word,"globallevelskynum")) {
lua_pushinteger(L, globallevelskynum);
} else if (fastcmp(word,"globallevelskytexture")) {
lua_pushstring(L, globallevelskytexture);
return 1;
} else if (fastcmp(word,"mapmusname")) {
lua_pushstring(L, mapmusname);

View file

@ -59,6 +59,8 @@
#include "../z_zone.h"
#include "../g_input.h"
#include "../k_pwrlv.h"
#include "../console.h"
#ifdef __GNUG__
@ -618,6 +620,11 @@ void I_Quit (void)
#ifndef NONET
D_SaveBan(); // save the ban list
#endif
// Make sure you lose points for ALT-F4
if (Playing())
K_PlayerForfeit(consoleplayer, true);
G_SaveGameData(); // Tails 12-08-2002
if (demorecording)
G_CheckDemoStatus();

View file

@ -158,9 +158,6 @@ extern FILE *logstream;
// AND appveyor.yml, for the build bots!
#endif
// Maintain compatibility with 1.0.x record attack replays?
//#define DEMO_COMPAT_100
// Does this version require an added patch file?
// Comment or uncomment this as necessary.
#define USE_PATCH_FILE

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;
@ -227,7 +245,7 @@ typedef struct
UINT32 muspos; ///< Music position to jump to.
char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable.
UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave.
INT16 skynum; ///< Sky number to use.
char skytexture[9]; ///< Sky texture to use.
INT16 skybox_scalex; ///< Skybox X axis scale. (0 = no movement, 1 = 1:1 movement, 16 = 16:1 slow movement, -4 = 1:4 fast movement, etc.)
INT16 skybox_scaley; ///< Skybox Y axis scale.
INT16 skybox_scalez; ///< Skybox Z axis scale.
@ -435,6 +453,7 @@ extern INT32 sneakertime;
extern INT32 itemtime;
extern INT32 comebacktime;
extern INT32 bumptime;
extern INT32 greasetics;
extern INT32 wipeoutslowtime;
extern INT32 wantedreduce;
extern INT32 wantedfrequency;
@ -474,7 +493,6 @@ extern tic_t wantedcalcdelay;
extern tic_t indirectitemcooldown;
extern tic_t hyubgone;
extern tic_t mapreset;
extern UINT8 nospectategrief;
extern boolean thwompsactive;
extern SINT8 spbplace;
@ -486,6 +504,15 @@ extern INT16 votelevels[5][2];
extern SINT8 votes[MAXPLAYERS];
extern SINT8 pickedvote;
/** Battle overtime information
*/
extern struct battleovertime
{
UINT16 enabled; ///< Has this been initalized yet?
fixed_t radius, minradius; ///< Radius of kill field
fixed_t x, y, z; ///< Position to center on
} battleovertime;
extern tic_t hidetime;
extern UINT32 timesBeaten; // # of times the game has been beaten.

View file

@ -220,7 +220,7 @@ void F_StartIntro(void)
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeEndScreen();
F_RunWipe(wipedefs[wipe_level_final], false);
F_RunWipe(wipedefs[wipe_intro_toblack], false, "FADEMAP0", false, false);
}
if (introtoplay)
@ -306,7 +306,7 @@ void F_IntroDrawer(void)
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeEndScreen();
F_RunWipe(99,true);
F_RunWipe(99, true, "FADEMAP0", false, false);
}
// Stay on black for a bit. =)
@ -1420,7 +1420,7 @@ void F_CutsceneDrawer(void)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, cutscenes[cutnum]->scene[scenenum].fadecolor);
F_WipeEndScreen();
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true);
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true, NULL, false, false);
F_WipeStartScreen();
}
@ -1440,7 +1440,7 @@ void F_CutsceneDrawer(void)
if (dofadenow && rendermode != render_none)
{
F_WipeEndScreen();
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true);
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true, NULL, false, false);
}
V_DrawString(textxpos, textypos, 0, cutscene_disptext);

View file

@ -74,12 +74,13 @@ extern INT32 lastwipetic;
void F_WipeStartScreen(void);
void F_WipeEndScreen(void);
void F_RunWipe(UINT8 wipetype, boolean drawMenu);
void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean reverse, boolean encorewiggle);
enum
{
wipe_credits_intermediate, // makes a good 0 I guess.
// Gamestate wipes
wipe_level_toblack,
wipe_intermission_toblack,
wipe_voting_toblack,
@ -92,11 +93,11 @@ enum
wipe_intro_toblack,
wipe_cutscene_toblack,
// custom intermissions
wipe_specinter_toblack,
wipe_multinter_toblack,
wipe_speclevel_towhite,
// Specialized wipes
wipe_encore_toinvert,
wipe_encore_towhite,
// "From black" wipes
wipe_level_final,
wipe_intermission_final,
wipe_voting_final,
@ -109,10 +110,6 @@ enum
wipe_intro_final,
wipe_cutscene_final,
// custom intermissions
wipe_specinter_final,
wipe_multinter_final,
NUMWIPEDEFS,
WIPEFINALSHIFT = wipe_level_final - wipe_level_toblack
};

View file

@ -16,8 +16,10 @@
#include "i_video.h"
#include "v_video.h"
#include "r_data.h" // NearestColor
#include "r_draw.h" // transtable
#include "p_pspr.h" // tr_transxxx
#include "w_wad.h"
#include "z_zone.h"
@ -47,35 +49,31 @@ UINT8 wipedefs[NUMWIPEDEFS] = {
99, // wipe_credits_intermediate (0)
0, // wipe_level_toblack
UINT8_MAX, // wipe_intermission_toblack
0, // wipe_intermission_toblack
0, // wipe_voting_toblack,
UINT8_MAX, // wipe_continuing_toblack
3, // wipe_titlescreen_toblack
0, // wipe_continuing_toblack
0, // wipe_titlescreen_toblack
0, // wipe_timeattack_toblack
99, // wipe_credits_toblack
0, // wipe_evaluation_toblack
0, // wipe_gameend_toblack
UINT8_MAX, // wipe_intro_toblack (hardcoded)
UINT8_MAX, // wipe_cutscene_toblack (hardcoded)
99, // wipe_cutscene_toblack (hardcoded)
UINT8_MAX, // wipe_specinter_toblack
UINT8_MAX, // wipe_multinter_toblack
99, // wipe_speclevel_towhite
72, // wipe_encore_toinvert
99, // wipe_encore_towhite
3, // wipe_level_final
UINT8_MAX, // wipe_level_final
0, // wipe_intermission_final
0, // wipe_voting_final
0, // wipe_continuing_final
3, // wipe_titlescreen_final
0, // wipe_titlescreen_final
0, // wipe_timeattack_final
99, // wipe_credits_final
0, // wipe_evaluation_final
0, // wipe_gameend_final
99, // wipe_intro_final (hardcoded)
99, // wipe_cutscene_final (hardcoded)
0, // wipe_specinter_final
0 // wipe_multinter_final
99 // wipe_cutscene_final (hardcoded)
};
//--------------------------------------------------------------------------
@ -86,9 +84,13 @@ boolean WipeInAction = false;
INT32 lastwipetic = 0;
#ifndef NOWIPE
#define GENLEN 31
static UINT8 *wipe_scr_start; //screen 3
static UINT8 *wipe_scr_end; //screen 4
static UINT8 *wipe_scr; //screen 0 (main drawing)
static UINT8 pallen;
static fixed_t paldiv;
/** Create fademask_t from lump
@ -181,7 +183,7 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) {
*
* \param fademask pixels to change
*/
static void F_DoWipe(fademask_t *fademask)
static void F_DoWipe(fademask_t *fademask, lighttable_t *fadecolormap, boolean reverse)
{
// Software mask wipe -- optimized; though it might not look like it!
// Okay, to save you wondering *how* this is more optimized than the simpler
@ -199,6 +201,10 @@ static void F_DoWipe(fademask_t *fademask)
// look a little messy; sorry!) but it simultaneously runs at twice the speed.
// In addition, we precalculate all the X and Y positions that we need to draw
// from and to, so it uses a little extra memory, but again, helps it run faster.
// ---
// Sal: I kinda destroyed some of this code by introducing Genesis-style fades.
// A colormap can be provided in F_RunWipe, which the white/black values will be
// remapped to the appropriate entry in the fade colormap.
{
// wipe screen, start, end
UINT8 *w = wipe_scr;
@ -242,6 +248,8 @@ static void F_DoWipe(fademask_t *fademask)
maskx = masky = 0;
do
{
UINT8 m = *mask;
draw_rowstart = scrxpos[maskx];
draw_rowend = scrxpos[maskx + 1];
draw_linestart = scrypos[masky];
@ -250,28 +258,31 @@ static void F_DoWipe(fademask_t *fademask)
relativepos = (draw_linestart * vid.width) + draw_rowstart;
draw_linestogo = draw_lineend - draw_linestart;
if (*mask == 0)
if (reverse)
m = ((pallen-1) - m);
if (m == 0)
{
// shortcut - memcpy source to work
while (draw_linestogo--)
{
M_Memcpy(w_base+relativepos, s_base+relativepos, draw_rowend-draw_rowstart);
M_Memcpy(w_base+relativepos, (reverse ? e_base : s_base)+relativepos, draw_rowend-draw_rowstart);
relativepos += vid.width;
}
}
else if (*mask == 10)
else if (m >= (pallen-1))
{
// shortcut - memcpy target to work
while (draw_linestogo--)
{
M_Memcpy(w_base+relativepos, e_base+relativepos, draw_rowend-draw_rowstart);
M_Memcpy(w_base+relativepos, (reverse ? s_base : e_base)+relativepos, draw_rowend-draw_rowstart);
relativepos += vid.width;
}
}
else
{
// pointer to transtable that this mask would use
transtbl = transtables + ((9 - *mask)<<FF_TRANSSHIFT);
transtbl = transtables + ((9 - m)<<FF_TRANSSHIFT);
// DRAWING LOOP
while (draw_linestogo--)
@ -282,7 +293,17 @@ static void F_DoWipe(fademask_t *fademask)
draw_rowstogo = draw_rowend - draw_rowstart;
while (draw_rowstogo--)
*w++ = transtbl[ ( *e++ << 8 ) + *s++ ];
{
if (fadecolormap != NULL)
{
if (reverse)
*w++ = fadecolormap[ ( m << 8 ) + *e++ ];
else
*w++ = fadecolormap[ ( m << 8 ) + *s++ ];
}
else
*w++ = transtbl[ ( *e++ << 8 ) + *s++ ];
}
relativepos += vid.width;
}
@ -334,20 +355,86 @@ void F_WipeEndScreen(void)
#endif
}
/** Wiggle post processor for encore wipes
*/
static void F_DoEncoreWiggle(UINT8 time)
{
UINT8 *tmpscr = wipe_scr_start;
UINT8 *srcscr = wipe_scr;
angle_t disStart = (time * 128) & FINEMASK;
INT32 y, sine, newpix, scanline;
for (y = 0; y < vid.height; y++)
{
sine = (FINESINE(disStart) * (time*12))>>FRACBITS;
scanline = y / vid.dupy;
if (scanline & 1)
sine = -sine;
newpix = abs(sine);
if (sine < 0)
{
M_Memcpy(&tmpscr[(y*vid.width)+newpix], &srcscr[(y*vid.width)], vid.width-newpix);
// Cleanup edge
while (newpix)
{
tmpscr[(y*vid.width)+newpix] = srcscr[(y*vid.width)];
newpix--;
}
}
else
{
M_Memcpy(&tmpscr[(y*vid.width)], &srcscr[(y*vid.width) + sine], vid.width-newpix);
// Cleanup edge
while (newpix)
{
tmpscr[(y*vid.width) + vid.width - newpix] = srcscr[(y*vid.width) + (vid.width-1)];
newpix--;
}
}
disStart += (time*8); //the offset into the displacement map, increment each game loop
disStart &= FINEMASK; //clip it to FINEMASK
}
}
/** After setting up the screens you want to wipe,
* calling this will do a 'typical' wipe.
*/
void F_RunWipe(UINT8 wipetype, boolean drawMenu)
void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean reverse, boolean encorewiggle)
{
#ifdef NOWIPE
(void)wipetype;
(void)drawMenu;
(void)colormap;
(void)reverse;
(void)encorewiggle;
#else
tic_t nowtime;
UINT8 wipeframe = 0;
fademask_t *fmask;
paldiv = FixedDiv(257<<FRACBITS, 11<<FRACBITS);
lumpnum_t clump = LUMPERROR;
lighttable_t *fcolor = NULL;
if (colormap != NULL)
clump = W_GetNumForName(colormap);
if (clump != LUMPERROR && wipetype != UINT8_MAX)
{
pallen = 32;
fcolor = Z_MallocAlign((256 * pallen), PU_STATIC, NULL, 8);
W_ReadLump(clump, fcolor);
}
else
{
pallen = 11;
reverse = false;
}
paldiv = FixedDiv(257<<FRACBITS, pallen<<FRACBITS);
// Init the wipe
WipeInAction = true;
@ -372,7 +459,16 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
HWR_DoWipe(wipetype, wipeframe-1); // send in the wipe type and wipeframe because we need to cache the graphic
else
#endif
F_DoWipe(fmask);
F_DoWipe(fmask, fcolor, reverse);
if (encorewiggle)
{
#ifdef HWRENDER
if (rendermode != render_opengl)
#endif
F_DoEncoreWiggle(wipeframe);
}
I_OsPolling();
I_UpdateNoBlit();
@ -386,6 +482,13 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
NetKeepAlive(); // Update the network so we don't cause timeouts
}
WipeInAction = false;
if (fcolor)
{
Z_Free(fcolor);
fcolor = NULL;
}
#endif
}

View file

@ -48,6 +48,7 @@
#include "m_cond.h" // condition sets
#include "md5.h" // demo checksums
#include "k_kart.h" // SRB2kart
#include "k_pwrlv.h"
gameaction_t gameaction;
gamestate_t gamestate = GS_NULL;
@ -82,8 +83,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;
@ -216,6 +230,7 @@ INT32 sneakertime = TICRATE + (TICRATE/3);
INT32 itemtime = 8*TICRATE;
INT32 comebacktime = 10*TICRATE;
INT32 bumptime = 6;
INT32 greasetics = 3*TICRATE;
INT32 wipeoutslowtime = 20;
INT32 wantedreduce = 5*TICRATE;
INT32 wantedfrequency = 10*TICRATE;
@ -260,13 +275,15 @@ INT16 votelevels[5][2]; // Levels that were rolled by the host
SINT8 votes[MAXPLAYERS]; // Each player's vote
SINT8 pickedvote; // What vote the host rolls
// Battle overtime system
struct battleovertime battleovertime;
// Server-sided, synched variables
SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points
tic_t wantedcalcdelay; // Time before it recalculates WANTED
tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded
tic_t hyubgone; // Cooldown before hyudoro is allowed to be rerolled
tic_t mapreset; // Map reset delay when enough players have joined an empty game
UINT8 nospectategrief; // How many players need to be in-game to eliminate last; for preventing spectate griefing
boolean thwompsactive; // Thwomps activate on lap 2
SINT8 spbplace; // SPB exists, give the person behind better items
@ -1777,6 +1794,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;
@ -2336,7 +2355,7 @@ void G_Ticker(boolean run)
G_DoReborn(consoleplayer);*/
D_MapChange(gamemap, gametype, cv_kartencore.value, true, 1, false, false);
D_MapChange(gamemap, gametype, (cv_kartencore.value == 1), true, 1, false, false);
}
for (i = 0; i < MAXPLAYERS; i++)
@ -2368,21 +2387,7 @@ void G_Ticker(boolean run)
if (playeringame[i])
{
//@TODO all this throwdir stuff shouldn't be here! But it stays for now to maintain 1.0.4 compat...
// Remove for 1.1!
// SRB2kart
// Save the dir the player is holding
// to allow items to be thrown forward or backward.
if (cmd->buttons & BT_FORWARD)
players[i].kartstuff[k_throwdir] = 1;
else if (cmd->buttons & BT_BACKWARD)
players[i].kartstuff[k_throwdir] = -1;
else
players[i].kartstuff[k_throwdir] = 0;
G_CopyTiccmd(cmd, &netcmds[buf][i], 1);
// Use the leveltime sent in the player's ticcmd to determine control lag
cmd->latency = modeattacking ? 0 : min(((leveltime & 0xFF) - cmd->latency) & 0xFF, MAXPREDICTTICS-1); //@TODO add a cvar to allow setting this max
}
@ -3041,8 +3046,17 @@ mapthing_t *G_FindRaceStart(INT32 playernum)
continue;
if (j == i)
continue;
if (players[j].score == players[i].score)
num++;
if (netgame && cv_kartusepwrlv.value)
{
if (clientpowerlevels[j][PWRLV_RACE] == clientpowerlevels[i][PWRLV_RACE])
num++;
}
else
{
if (players[j].score == players[i].score)
num++;
}
}
if (num > 1) // found dupes
@ -3050,8 +3064,21 @@ mapthing_t *G_FindRaceStart(INT32 playernum)
}
else
{
if (players[i].score > players[playernum].score || i < playernum)
if (i < playernum)
pos++;
else
{
if (netgame && cv_kartusepwrlv.value)
{
if (clientpowerlevels[i][PWRLV_RACE] > clientpowerlevels[playernum][PWRLV_RACE])
pos++;
}
else
{
if (players[i].score > players[playernum].score)
pos++;
}
}
}
}
@ -3381,9 +3408,10 @@ boolean G_BattleGametype(void)
//
INT16 G_SometimesGetDifferentGametype(void)
{
boolean encorepossible = (M_SecretUnlocked(SECRET_ENCORE) && G_RaceGametype());
boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE) || encorescramble == 1) && G_RaceGametype());
if (!cv_kartvoterulechanges.value) // never
if (!cv_kartvoterulechanges.value // never
&& encorescramble != 1) // destroying the code for this one instance
return gametype;
if (randmapbuffer[NUMMAPS] > 0 && (encorepossible || cv_kartvoterulechanges.value != 3))
@ -3391,25 +3419,33 @@ INT16 G_SometimesGetDifferentGametype(void)
randmapbuffer[NUMMAPS]--;
if (encorepossible)
{
switch (cv_kartvoterulechanges.value)
if (encorescramble != -1)
encorepossible = (boolean)encorescramble; // FORCE to what was scrambled on intermission
else
{
case 3: // always
randmapbuffer[NUMMAPS] = 0; // gotta prep this in case it isn't already set
break;
case 2: // frequent
encorepossible = M_RandomChance(FRACUNIT>>1);
break;
case 1: // sometimes
default:
encorepossible = M_RandomChance(FRACUNIT>>2);
break;
switch (cv_kartvoterulechanges.value)
{
case 3: // always
randmapbuffer[NUMMAPS] = 0; // gotta prep this in case it isn't already set
break;
case 2: // frequent
encorepossible = M_RandomChance(FRACUNIT>>1);
break;
case 1: // sometimes
default:
encorepossible = M_RandomChance(FRACUNIT>>2);
break;
}
}
if (encorepossible != (boolean)cv_kartencore.value)
if (encorepossible != (cv_kartencore.value == 1))
return (gametype|0x80);
}
return gametype;
}
if (!cv_kartvoterulechanges.value) // never (again)
return gametype;
switch (cv_kartvoterulechanges.value) // okay, we're having a gametype change! when's the next one, luv?
{
case 3: // always
@ -3638,7 +3674,7 @@ tryagain:
void G_AddMapToBuffer(INT16 map)
{
INT16 bufx, refreshnum = (TOLMaps(G_TOLFlag(gametype)) / 2) + 1;
INT16 bufx, refreshnum = max(0, TOLMaps(G_TOLFlag(gametype))-3);
// Add the map to the buffer.
for (bufx = NUMMAPS-1; bufx > 0; bufx--)
@ -3662,6 +3698,7 @@ static void G_DoCompleted(void)
{
INT32 i, j = 0;
boolean gottoken = false;
SINT8 powertype = PWRLV_DISABLED;
tokenlist = 0; // Reset the list
@ -3800,13 +3837,23 @@ static void G_DoCompleted(void)
nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, false, 0, false, NULL);
}
// We are committed to this map now.
// We may as well allocate its header if it doesn't exist
// (That is, if it's a real map)
if (nextmap < NUMMAPS && !mapheaderinfo[nextmap])
P_AllocMapHeader(nextmap);
// Set up power level gametype scrambles
if (netgame && cv_kartusepwrlv.value)
{
if (G_RaceGametype())
powertype = PWRLV_RACE;
else if (G_BattleGametype())
powertype = PWRLV_BATTLE;
}
K_SetPowerLevelScrambles(powertype);
demointermission:
if (skipstats && !modeattacking) // Don't skip stats if we're in record attack
@ -3878,7 +3925,7 @@ void G_NextLevel(void)
}
forceresetplayers = false;
deferencoremode = (boolean)cv_kartencore.value;
deferencoremode = (cv_kartencore.value == 1);
}
gameaction = ga_worlddone;
@ -4041,15 +4088,24 @@ void G_LoadGameData(void)
// to new gamedata
G_ClearRecords(); // main and nights records
M_ClearSecrets(); // emblems, unlocks, maps visited, etc
totalplaytime = 0; // total play time (separate from all)
matchesplayed = 0; // SRB2Kart: matches played & finished
for (i = 0; i < PWRLV_NUMTYPES; i++) // SRB2Kart: online rank system
vspowerlevel[i] = PWRLVRECORD_START;
if (M_CheckParm("-nodata"))
return; // Don't load.
// Allow saving of gamedata beyond this point
gamedataloaded = true;
if (M_CheckParm("-gamedata") && M_IsNextParm())
{
strlcpy(gamedatafilename, M_GetNextParm(), sizeof gamedatafilename);
}
if (M_CheckParm("-resetdata"))
return; // Don't load (essentially, reset).
@ -4074,6 +4130,13 @@ void G_LoadGameData(void)
totalplaytime = READUINT32(save_p);
matchesplayed = READUINT32(save_p);
for (i = 0; i < PWRLV_NUMTYPES; i++)
{
vspowerlevel[i] = READUINT16(save_p);
if (vspowerlevel[i] < PWRLVRECORD_MIN || vspowerlevel[i] > PWRLVRECORD_MAX)
goto datacorrupt;
}
modded = READUINT8(save_p);
// Aha! Someone's been screwing with the save file!
@ -4219,6 +4282,9 @@ void G_SaveGameData(boolean force)
WRITEUINT32(save_p, totalplaytime);
WRITEUINT32(save_p, matchesplayed);
for (i = 0; i < PWRLV_NUMTYPES; i++)
WRITEUINT16(save_p, vspowerlevel[i]);
btemp = (UINT8)(savemoddata); // what used to be here was profoundly dunderheaded
WRITEUINT8(save_p, btemp);
@ -4731,7 +4797,7 @@ char *G_BuildMapTitle(INT32 mapnum)
// DEMO RECORDING
//
#define DEMOVERSION 0x0002
#define DEMOVERSION 0x0003
#define DEMOHEADER "\xF0" "KartReplay" "\x0F"
#define DF_GHOST 0x01 // This demo contains ghost data too!
@ -4742,12 +4808,6 @@ char *G_BuildMapTitle(INT32 mapnum)
#define DF_ENCORE 0x40
#define DF_MULTIPLAYER 0x80 // This demo was recorded in multiplayer mode!
#ifdef DEMO_COMPAT_100
#define DF_FILELIST 0x08 // This demo contains an extra files list
#define DF_GAMETYPEMASK 0x30
#define DF_GAMESHIFT 4
#endif
#define DEMO_SPECTATOR 0x40
// For demos
@ -4889,7 +4949,6 @@ void G_ReadDemoExtraData(void)
kartspeed = READUINT8(demo_p);
kartweight = READUINT8(demo_p);
if (stricmp(skins[players[p].skin].name, name) != 0)
FindClosestSkinForStats(p, kartspeed, kartweight);
@ -5607,16 +5666,9 @@ void G_ConsGhostTic(INT32 playernum)
else
ghostext[playernum].desyncframes = 0;
if (
#ifdef DEMO_COMPAT_100
demo.version != 0x0001 &&
#endif
(
players[playernum].kartstuff[k_itemtype] != ghostext[playernum].kartitem ||
players[playernum].kartstuff[k_itemamount] != ghostext[playernum].kartamount ||
players[playernum].kartstuff[k_bumper] != ghostext[playernum].kartbumpers
)
)
if (players[playernum].kartstuff[k_itemtype] != ghostext[playernum].kartitem
|| players[playernum].kartstuff[k_itemamount] != ghostext[playernum].kartamount
|| players[playernum].kartstuff[k_bumper] != ghostext[playernum].kartbumpers)
{
if (demosynced)
CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n"));
@ -5644,10 +5696,6 @@ void G_GhostTicker(void)
// Skip normal demo data.
UINT8 ziptic = READUINT8(g->p);
#ifdef DEMO_COMPAT_100
if (g->version != 0x0001)
{
#endif
while (ziptic != DW_END) // Get rid of extradata stuff
{
if (ziptic == 0) // Only support player 0 info for now
@ -5671,9 +5719,6 @@ void G_GhostTicker(void)
}
ziptic = READUINT8(g->p); // Back to actual ziptic stuff
#ifdef DEMO_COMPAT_100
}
#endif
if (ziptic & ZT_FWD)
g->p++;
@ -5693,18 +5738,12 @@ void G_GhostTicker(void)
// Grab ghost data.
ziptic = READUINT8(g->p);
#ifdef DEMO_COMPAT_100
if (g->version != 0x0001)
{
#endif
if (ziptic == 0xFF)
goto skippedghosttic; // Didn't write ghost info this frame
else if (ziptic != 0)
I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this
ziptic = READUINT8(g->p);
#ifdef DEMO_COMPAT_100
}
#endif
if (ziptic & GZT_XYZ)
{
g->oldmo.x = READFIXED(g->p);
@ -5845,15 +5884,8 @@ void G_GhostTicker(void)
g->p += 12; // kartitem, kartamount, kartbumpers
}
#ifdef DEMO_COMPAT_100
if (g->version != 0x0001)
{
#endif
if (READUINT8(g->p) != 0xFF) // Make sure there isn't other ghost data here.
I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this
#ifdef DEMO_COMPAT_100
}
#endif
skippedghosttic:
// Tick ghost colors (Super and Mario Invincibility flashing)
@ -6363,20 +6395,15 @@ void G_BeginRecording(void)
switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
{
case ATTACKING_NONE: // 0
break;
case ATTACKING_RECORD: // 1
demotime_p = demo_p;
WRITEUINT32(demo_p,UINT32_MAX); // time
WRITEUINT32(demo_p,UINT32_MAX); // lap
break;
/*case ATTACKING_NIGHTS: // 2
demotime_p = demo_p;
WRITEUINT32(demo_p,UINT32_MAX); // time
WRITEUINT32(demo_p,0); // score
break;*/
default: // 3
break;
case ATTACKING_NONE: // 0
break;
case ATTACKING_RECORD: // 1
demotime_p = demo_p;
WRITEUINT32(demo_p,UINT32_MAX); // time
WRITEUINT32(demo_p,UINT32_MAX); // lap
break;
default: // 3
break;
}
WRITEUINT32(demo_p,P_GetInitSeed());
@ -6416,6 +6443,9 @@ void G_BeginRecording(void)
// Score, since Kart uses this to determine where you start on the map
WRITEUINT32(demo_p, player->score);
// Power Levels
WRITEUINT16(demo_p, clientpowerlevels[p][G_BattleGametype() ? PWRLV_BATTLE : PWRLV_RACE]);
// Kart speed and weight
WRITEUINT8(demo_p, skins[player->skin].kartspeed);
WRITEUINT8(demo_p, skins[player->skin].kartweight);
@ -6514,18 +6544,13 @@ void G_SetDemoTime(UINT32 ptime, UINT32 plap)
{
if (!demo.recording || !demotime_p)
return;
if (demoflags & DF_RECORDATTACK)
{
WRITEUINT32(demotime_p, ptime);
WRITEUINT32(demotime_p, plap);
demotime_p = NULL;
}
/*else if (demoflags & DF_NIGHTSATTACK)
{
WRITEUINT32(demotime_p, ptime);
WRITEUINT32(demotime_p, pscore);
demotime_p = NULL;
}*/
}
static void G_LoadDemoExtraFiles(UINT8 **pp)
@ -6768,13 +6793,6 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
case DEMOVERSION: // latest always supported
p += 64; // full demo title
break;
#ifdef DEMO_COMPAT_100
case 0x0001:
// Old replays gotta go :]
CONS_Alert(CONS_NOTICE, M_GetText("File '%s' outdated version. It will be overwritten. Nyeheheh.\n"), oldname);
Z_Free(buffer);
return UINT8_MAX;
#endif
// too old, cannot support.
default:
CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname);
@ -6866,12 +6884,6 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
info_p += 64;
break;
#ifdef DEMO_COMPAT_100
case 0x0001:
pdemo->type = MD_OUTDATED;
sprintf(pdemo->title, "Legacy Replay");
break;
#endif
// too old, cannot support.
default:
CONS_Alert(CONS_ERROR, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemo->filepath);
@ -6906,16 +6918,6 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
Z_Free(infobuffer);
return;
}
#ifdef DEMO_COMPAT_100
else if (pdemoversion == 0x0001)
{
CONS_Alert(CONS_ERROR, M_GetText("%s is a legacy multiplayer replay and cannot be played.\n"), pdemo->filepath);
pdemo->type = MD_INVALID;
sprintf(pdemo->title, "INVALID REPLAY");
Z_Free(infobuffer);
return;
}
#endif
pdemo->gametype = READUINT8(info_p);
@ -6925,7 +6927,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
extrainfo_p = infobuffer + READUINT32(info_p);
// Pared down version of CV_LoadNetVars to find the kart speed
pdemo->kartspeed = 1; // Default to normal speed
pdemo->kartspeed = KARTSPEED_NORMAL; // Default to normal speed
count = READUINT16(info_p);
while (count--)
{
@ -7116,10 +7118,6 @@ void G_DoPlayDemo(char *defdemoname)
demo_p += 64;
break;
#ifdef DEMO_COMPAT_100
case 0x0001:
break;
#endif
// too old, cannot support.
default:
snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname);
@ -7148,24 +7146,6 @@ void G_DoPlayDemo(char *defdemoname)
demo_p += 16; // mapmd5
demoflags = READUINT8(demo_p);
#ifdef DEMO_COMPAT_100
if (demo.version == 0x0001)
{
if (demoflags & DF_MULTIPLAYER)
{
snprintf(msg, 1024, M_GetText("%s is an alpha multiplayer replay and cannot be played.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuffer);
demo.playback = false;
demo.title = false;
return;
}
}
else
{
#endif
gametype = READUINT8(demo_p);
if (demo.title) // Titledemos should always play and ought to always be compatible with whatever wadlist is running.
@ -7223,9 +7203,6 @@ void G_DoPlayDemo(char *defdemoname)
return;
}
}
#ifdef DEMO_COMPAT_100
}
#endif
modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT;
multiplayer = !!(demoflags & DF_MULTIPLAYER);
@ -7253,109 +7230,20 @@ void G_DoPlayDemo(char *defdemoname)
// Random seed
randseed = READUINT32(demo_p);
#ifdef DEMO_COMPAT_100
if (demo.version != 0x0001)
#endif
demo_p += 4; // Extrainfo location
#ifdef DEMO_COMPAT_100
if (demo.version == 0x0001)
// ...*map* not loaded?
if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1] || !(mapheaderinfo[gamemap-1]->menuflags & LF2_EXISTSHACK))
{
// Player name
M_Memcpy(player_names[0],demo_p,16);
demo_p += 16;
// Skin
M_Memcpy(skin,demo_p,16);
demo_p += 16;
// Color
M_Memcpy(color,demo_p,16);
demo_p += 16;
demo_p += 5; // Backwards compat - some stats
// SRB2kart
kartspeed[0] = READUINT8(demo_p);
kartweight[0] = READUINT8(demo_p);
//
demo_p += 9; // Backwards compat - more stats
// Skin not loaded?
if (!SetPlayerSkin(0, skin))
{
snprintf(msg, 1024, M_GetText("%s features a character that is not currently loaded.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuffer);
demo.playback = false;
demo.title = false;
return;
}
// ...*map* not loaded?
if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1] || !(mapheaderinfo[gamemap-1]->menuflags & LF2_EXISTSHACK))
{
snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuffer);
demo.playback = false;
demo.title = false;
return;
}
// Set color
for (i = 0; i < MAXSKINCOLORS; i++)
if (!stricmp(KartColor_Names[i],color)) // SRB2kart
{
players[0].skincolor = i;
break;
}
// net var data
CV_LoadNetVars(&demo_p);
// Sigh ... it's an empty demo.
if (*demo_p == DEMOMARKER)
{
snprintf(msg, 1024, M_GetText("%s contains no data to be played.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuffer);
demo.playback = false;
demo.title = false;
return;
}
snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
memset(&oldcmd,0,sizeof(oldcmd));
memset(&oldghost,0,sizeof(oldghost));
memset(&ghostext,0,sizeof(ghostext));
CONS_Alert(CONS_WARNING, M_GetText("Demo version does not match game version. Desyncs may occur.\n"));
// console warning messages
#if defined(SKIPERRORS) && !defined(DEVELOP)
demosynced = (!skiperrors);
#else
demosynced = true;
#endif
// didn't start recording right away.
demo.deferstart = false;
consoleplayer = 0;
memset(displayplayers, 0, sizeof(displayplayers));
memset(playeringame, 0, sizeof(playeringame));
playeringame[0] = true;
goto post_compat;
Z_Free(demobuffer);
demo.playback = false;
demo.title = false;
return;
}
#endif
// net var data
CV_LoadNetVars(&demo_p);
@ -7470,6 +7358,9 @@ void G_DoPlayDemo(char *defdemoname)
// Score, since Kart uses this to determine where you start on the map
players[p].score = READUINT32(demo_p);
// Power Levels
clientpowerlevels[p][G_BattleGametype() ? PWRLV_BATTLE : PWRLV_RACE] = READUINT16(demo_p);
// Kart stats, temporarily
kartspeed[p] = READUINT8(demo_p);
kartweight[p] = READUINT8(demo_p);
@ -7494,10 +7385,6 @@ void G_DoPlayDemo(char *defdemoname)
R_ExecuteSetViewSize();
#ifdef DEMO_COMPAT_100
post_compat:
#endif
P_SetRandSeed(randseed);
G_InitNew(demoflags & DF_ENCORE, G_BuildMapName(gamemap), true, true); // Doesn't matter whether you reset or not here, given changes to resetplayer.
@ -7588,10 +7475,6 @@ void G_AddGhost(char *defdemoname)
case DEMOVERSION: // latest always supported
p += 64; // title
break;
#ifdef DEMO_COMPAT_100
case 0x0001:
break;
#endif
// too old, cannot support.
default:
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname);
@ -7632,15 +7515,9 @@ void G_AddGhost(char *defdemoname)
return;
}
#ifdef DEMO_COMPAT_100
if (ghostversion != 0x0001)
#endif
p++; // gametype
p++; // gametype
G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts.
#ifdef DEMO_COMPAT_100
if (ghostversion != 0x0001)
#endif
G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts.
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
{
case ATTACKING_NONE: // 0
@ -7656,41 +7533,6 @@ void G_AddGhost(char *defdemoname)
}
p += 4; // random seed
#ifdef DEMO_COMPAT_100
if (ghostversion == 0x0001)
{
// Player name (TODO: Display this somehow if it doesn't match cv_playername!)
M_Memcpy(name, p,16);
p += 16;
// Skin
M_Memcpy(skin, p,16);
p += 16;
// Color
M_Memcpy(color, p,16);
p += 16;
// Ghosts do not have a player structure to put this in.
p++; // charability
p++; // charability2
p++; // actionspd
p++; // mindash
p++; // maxdash
// SRB2kart
p++; // kartspeed
p++; // kartweight
//
p++; // normalspeed
p++; // runspeed
p++; // thrustfactor
p++; // accelstart
p++; // acceleration
p += 4; // jumpfactor
}
else
#endif
p += 4; // Extra data location reference
// net var data
@ -7710,10 +7552,6 @@ void G_AddGhost(char *defdemoname)
return;
}
#ifdef DEMO_COMPAT_100
if (ghostversion != 0x0001)
{
#endif
if (READUINT8(p) != 0)
{
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname);
@ -7735,6 +7573,7 @@ void G_AddGhost(char *defdemoname)
p += 16;
p += 4; // score
p += 2; // powerlevel
kartspeed = READUINT8(p);
kartweight = READUINT8(p);
@ -7746,9 +7585,6 @@ void G_AddGhost(char *defdemoname)
Z_Free(buffer);
return;
}
#ifdef DEMO_COMPAT_100
}
#endif
for (i = 0; i < numskins; i++)
if (!stricmp(skins[i].name,skin))
@ -7848,18 +7684,13 @@ void G_UpdateStaffGhostName(lumpnum_t l)
ghostversion = READUINT16(p);
switch(ghostversion)
{
case DEMOVERSION: // latest always supported
p += 64; // full demo title
break;
case DEMOVERSION: // latest always supported
p += 64; // full demo title
break;
#ifdef DEMO_COMPAT_100
case 0x0001:
break;
#endif
// too old, cannot support.
default:
goto fail;
// too old, cannot support.
default:
goto fail;
}
p += 16; // demo checksum
@ -7879,43 +7710,22 @@ void G_UpdateStaffGhostName(lumpnum_t l)
goto fail; // we don't NEED to do it here, but whatever
}
#ifdef DEMO_COMPAT_100
if (ghostversion != 0x0001)
#endif
p++; // Gametype
#ifdef DEMO_COMPAT_100
if (ghostversion != 0x0001)
#endif
G_SkipDemoExtraFiles(&p);
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
{
case ATTACKING_NONE: // 0
break;
case ATTACKING_RECORD: // 1
p += 8; // demo time, lap
break;
/*case ATTACKING_NIGHTS: // 2
p += 8; // demo time left, score
break;*/
default: // 3
break;
case ATTACKING_NONE: // 0
break;
case ATTACKING_RECORD: // 1
p += 8; // demo time, lap
break;
default: // 3
break;
}
p += 4; // random seed
#ifdef DEMO_COMPAT_100
if (ghostversion == 0x0001)
{
// Player name
M_Memcpy(dummystaffname, p,16);
dummystaffname[16] = '\0';
goto fail; // Not really a failure but whatever
}
#endif
p += 4; // Extrainfo location marker
// Ehhhh don't need ghostversion here (?) so I'll reuse the var here
@ -8000,10 +7810,6 @@ void G_DoPlayMetal(void)
{
case DEMOVERSION: // latest always supported
break;
#ifdef DEMO_COMPAT_100
case 0x0001:
I_Error("You need to implement demo compat here, doofus! %s:%d", __FILE__, __LINE__);
#endif
// too old, cannot support.
default:
CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version incompatible.\n"));

View file

@ -80,7 +80,7 @@ typedef struct menudemo_s {
UINT16 map;
UINT8 addonstatus; // What do we need to do addon-wise to play this demo?
UINT8 gametype;
UINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk
SINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk
UINT8 numlaps;
struct {

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);
}
}
}
}
}
@ -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;
}
@ -5922,13 +5798,15 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
static void HWR_DrawSkyBackground(void)
{
FOutVector v[4];
texture_t *tex;
angle_t angle;
float dimensionmultiply;
float aspectratio;
float angleturn;
tex = textures[texturetranslation[skytexture]];
HWR_GetTexture(texturetranslation[skytexture]);
aspectratio = (float)vid.width/(float)vid.height;
aspectratio = (float)vid.width / (float)vid.height;
//Hurdler: the sky is the only texture who need 4.0f instead of 1.0
// because it's called just after clearing the screen
@ -5952,22 +5830,22 @@ static void HWR_DrawSkyBackground(void)
// software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly
// The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture
angle = (dup_viewangle + gr_xtoviewangle[0]);
dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f);
angle = -(dup_viewangle + gr_xtoviewangle[0]);
dimensionmultiply = ((float)tex->width/256.0f);
if (atransform.mirror)
{
angle = InvAngle(angle);
dimensionmultiply *= -1;
dimensionmultiply = -dimensionmultiply;
}
v[0].sow = v[3].sow = ((float) angle / ((ANGLE_90-1)*dimensionmultiply));
v[2].sow = v[1].sow = (-1.0f/dimensionmultiply)+((float) angle / ((ANGLE_90-1)*dimensionmultiply));
v[2].sow = v[1].sow = (1.0f/dimensionmultiply)+((float) angle / ((ANGLE_90-1)*dimensionmultiply));
// Y
angle = aimingangle;
dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio));
dimensionmultiply = ((float)tex->height/(128.0f*aspectratio));
if (splitscreen == 1)
{

View file

@ -653,13 +653,12 @@ spritemd2found:
// 0.2126 to red
// 0.7152 to green
// 0.0722 to blue
// (See this same define in k_kart.c!)
// (See this same define in hw_md2.c!)
#define SETBRIGHTNESS(brightness,r,g,b) \
brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3)
brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000))
static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolors_t color)
{
UINT8 i;
UINT16 w = gpatch->width, h = gpatch->height;
UINT32 size = w*h;
RGBA_t *image, *blendimage, *cur, blendcolor;
@ -684,102 +683,188 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
image = gpatch->mipmap.grInfo.data;
blendimage = blendgpatch->mipmap.grInfo.data;
blendcolor = V_GetColor(0); // initialize
// Average all of the translation's colors
while (size--)
{
const UINT8 div = 6;
const UINT8 start = 4;
UINT32 r, g, b;
UINT16 brightness;
blendcolor = V_GetColor(colortranslations[color][start]);
r = (UINT32)(blendcolor.s.red*blendcolor.s.red);
g = (UINT32)(blendcolor.s.green*blendcolor.s.green);
b = (UINT32)(blendcolor.s.blue*blendcolor.s.blue);
for (i = 1; i < div; i++)
{
RGBA_t nextcolor = V_GetColor(colortranslations[color][start+i]);
r += (UINT32)(nextcolor.s.red*nextcolor.s.red);
g += (UINT32)(nextcolor.s.green*nextcolor.s.green);
b += (UINT32)(nextcolor.s.blue*nextcolor.s.blue);
}
blendcolor.s.red = (UINT8)(FixedSqrt((r/div)<<FRACBITS)>>FRACBITS);
blendcolor.s.green = (UINT8)(FixedSqrt((g/div)<<FRACBITS)>>FRACBITS);
blendcolor.s.blue = (UINT8)(FixedSqrt((b/div)<<FRACBITS)>>FRACBITS);
}
// rainbow support, could theoretically support boss ones too
if (skinnum == TC_RAINBOW)
{
while (size--)
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
if (skinnum == TC_RAINBOW)
{
if (image->s.alpha == 0 && blendimage->s.alpha == 0)
{
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
cur->rgba = image->rgba;
cur++; image++; blendimage++;
continue;
}
else
{
UINT32 tempcolor;
UINT16 imagebright, blendbright, finalbright, colorbright;
UINT16 imagebright, blendbright;
SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue);
SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
// slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway
finalbright = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255;
SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue);
tempcolor = (finalbright*blendcolor.s.red)/colorbright;
tempcolor = min(255, tempcolor);
cur->s.red = (UINT8)tempcolor;
tempcolor = (finalbright*blendcolor.s.green)/colorbright;
tempcolor = min(255, tempcolor);
cur->s.green = (UINT8)tempcolor;
tempcolor = (finalbright*blendcolor.s.blue)/colorbright;
tempcolor = min(255, tempcolor);
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
brightness = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255;
}
cur++; image++; blendimage++;
}
}
else
{
while (size--)
else
{
if (blendimage->s.alpha == 0)
{
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
cur->rgba = image->rgba;
cur++; image++; blendimage++;
continue;
}
else
{
INT32 tempcolor;
INT16 tempmult, tempalpha;
tempalpha = -(abs(blendimage->s.red-127)-127)*2;
if (tempalpha > 255)
tempalpha = 255;
else if (tempalpha < 0)
tempalpha = 0;
SETBRIGHTNESS(brightness,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
}
}
tempmult = (blendimage->s.red-127)*2;
if (tempmult > 255)
tempmult = 255;
else if (tempmult < 0)
tempmult = 0;
// Calculate a sort of "gradient" for the skincolor
// (Me splitting this into a function didn't work, so I had to ruin this entire function's groove...)
{
RGBA_t nextcolor;
UINT8 firsti, secondi, mul;
UINT32 r, g, b;
tempcolor = (image->s.red*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.red)/255)) * blendimage->s.alpha)/255;
cur->s.red = (UINT8)tempcolor;
tempcolor = (image->s.green*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.green)/255)) * blendimage->s.alpha)/255;
cur->s.green = (UINT8)tempcolor;
tempcolor = (image->s.blue*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.blue)/255)) * blendimage->s.alpha)/255;
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
// Rainbow needs to find the closest match to the textures themselves, instead of matching brightnesses to other colors.
// Ensue horrible mess.
if (skinnum == TC_RAINBOW)
{
UINT16 brightdif = 256;
UINT8 colorbrightnesses[16];
INT32 compare, m, d;
UINT8 i;
// Ignore pure white & pitch black
if (brightness > 253 || brightness < 2)
{
cur->rgba = image->rgba;
cur++; image++; blendimage++;
continue;
}
firsti = 0;
mul = 0;
for (i = 0; i < 16; i++)
{
RGBA_t tempc = V_GetColor(colortranslations[color][i]);
SETBRIGHTNESS(colorbrightnesses[i], tempc.s.red, tempc.s.green, tempc.s.blue); // store brightnesses for comparison
}
for (i = 0; i < 16; i++)
{
if (brightness > colorbrightnesses[i]) // don't allow greater matches (because calculating a makeshift gradient for this is already a huge mess as is)
continue;
compare = abs((INT16)(colorbrightnesses[i]) - (INT16)(brightness));
if (compare < brightdif)
{
brightdif = (UINT16)compare;
firsti = i; // best matching color that's equal brightness or darker
}
}
secondi = firsti+1; // next color in line
if (secondi == 16)
{
m = (INT16)brightness; // - 0;
d = (INT16)colorbrightnesses[firsti]; // - 0;
}
else
{
m = (INT16)brightness - (INT16)colorbrightnesses[secondi];
d = (INT16)colorbrightnesses[firsti] - (INT16)colorbrightnesses[secondi];
}
if (m >= d)
m = d-1;
// calculate the "gradient" multiplier based on how close this color is to the one next in line
if (m <= 0 || d <= 0)
mul = 0;
else
mul = 15 - ((m * 16) / d);
}
else
{
// Thankfully, it's normally way more simple.
// Just convert brightness to a skincolor value, use remainder to find the gradient multipler
firsti = ((UINT8)(255-brightness) / 16);
secondi = firsti+1;
mul = ((UINT8)(255-brightness) % 16);
}
cur++; image++; blendimage++;
blendcolor = V_GetColor(colortranslations[color][firsti]);
if (mul > 0 // If it's 0, then we only need the first color.
&& colortranslations[color][firsti] != colortranslations[color][secondi]) // Some colors have duplicate colors in a row, so let's just save the process
{
if (secondi == 16) // blend to black
nextcolor = V_GetColor(31);
else
nextcolor = V_GetColor(colortranslations[color][secondi]);
// Find difference between points
r = (UINT32)(nextcolor.s.red - blendcolor.s.red);
g = (UINT32)(nextcolor.s.green - blendcolor.s.green);
b = (UINT32)(nextcolor.s.blue - blendcolor.s.blue);
// Find the gradient of the two points
r = ((mul * r) / 16);
g = ((mul * g) / 16);
b = ((mul * b) / 16);
// Add gradient value to color
blendcolor.s.red += r;
blendcolor.s.green += g;
blendcolor.s.blue += b;
}
}
if (skinnum == TC_RAINBOW)
{
UINT32 tempcolor;
UINT16 colorbright;
SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue);
if (colorbright == 0)
colorbright = 1; // no dividing by 0 please
tempcolor = (brightness * blendcolor.s.red) / colorbright;
tempcolor = min(255, tempcolor);
cur->s.red = (UINT8)tempcolor;
tempcolor = (brightness * blendcolor.s.green) / colorbright;
tempcolor = min(255, tempcolor);
cur->s.green = (UINT8)tempcolor;
tempcolor = (brightness * blendcolor.s.blue) / colorbright;
tempcolor = min(255, tempcolor);
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
}
else
{
// Color strength depends on image alpha
INT32 tempcolor;
tempcolor = ((image->s.red * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.red * blendimage->s.alpha) / 255);
tempcolor = min(255, tempcolor);
cur->s.red = (UINT8)tempcolor;
tempcolor = ((image->s.green * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.green * blendimage->s.alpha) / 255);
tempcolor = min(255, tempcolor);
cur->s.green = (UINT8)tempcolor;
tempcolor = ((image->s.blue * (255-blendimage->s.alpha)) / 255) + ((blendcolor.s.blue * blendimage->s.alpha) / 255);
tempcolor = min(255, tempcolor);
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
}
cur++; image++; blendimage++;
}
return;
@ -1091,11 +1176,11 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
#ifdef USE_FTRANSFORM_ANGLEZ
// Slope rotation from Kart
p.anglez = 0.0f;
if (spr->mobj->standingslope)
if (spr->mobj->modeltilt)
{
fixed_t tempz = spr->mobj->standingslope->normal.z;
fixed_t tempy = spr->mobj->standingslope->normal.y;
fixed_t tempx = spr->mobj->standingslope->normal.x;
fixed_t tempz = spr->mobj->modeltilt->normal.z;
fixed_t tempy = spr->mobj->modeltilt->normal.y;
fixed_t tempx = spr->mobj->modeltilt->normal.x;
fixed_t tempangle = AngleFixed(R_PointToAngle2(0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx));
p.anglez = FIXED_TO_FLOAT(tempangle);
tempangle = -AngleFixed(R_PointToAngle2(0, 0, tempz, tempy));

View file

@ -3017,7 +3017,7 @@ static void HU_DrawRankings(void)
}
V_DrawCenteredString(256, 8, 0, "GAME SPEED");
V_DrawCenteredString(256, 16, hilicol, cv_kartspeed.string);
V_DrawCenteredString(256, 16, hilicol, kartspeed_cons_t[1+gamespeed].strvalue);
}
// When you play, you quickly see your score because your name is displayed in white.

File diff suppressed because it is too large Load diff

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
@ -459,15 +458,23 @@ typedef enum sprite
SPR_RBRD, // Red Birdie in Bubble
// Springs
SPR_SPRY, // yellow spring
SPR_SPRR, // red spring
SPR_SPRB, // Blue springs
SPR_YSPR, // Yellow Diagonal Spring
SPR_RSPR, // Red Diagonal Spring
SPR_SPVY, // Yellow Vertical Spring
SPR_SPVR, // Red Vertical Spring
SPR_SPVB, // Blue Vertical Spring
SPR_SPVG, // Grey Vertical Spring
SPR_SPDY, // Yellow Diagonal Spring
SPR_SPDR, // Red Diagonal Spring
SPR_SPDB, // Blue Diagonal Spring
SPR_SPDG, // Grey Diagonal Spring
SPR_SPHY, // Yellow Horizontal Spring
SPR_SPHR, // Red Horizontal Spring
SPR_SPHB, // Blue Horizontal Spring
SPR_SPHG, // Grey Horizontal Spring
// Environmental Effects
SPR_RAIN, // Rain
SPR_SNO1, // Snowflake
SPR_SNO2, // Blizzard Snowball
SPR_SPLH, // Water Splish
SPR_SPLA, // Water Splash
SPR_SMOK,
@ -587,9 +594,6 @@ typedef enum sprite
SPR_SRBO,
// Springs
SPR_SPRG, // Gray Spring
SPR_BSPR, // Blue Diagonal Spring
SPR_RNDM, // Random Item Box
SPR_RPOP, // Random Item Box Pop
SPR_SGNS, // Signpost sparkle
@ -635,7 +639,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
@ -778,6 +781,9 @@ typedef enum sprite
SPR_MXCL,
SPR_RGSP,
SPR_DRAF,
SPR_GRES,
SPR_OTFG,
// Xmas-specific sprites that don't fit aboxe
SPR_XMS4,
@ -1769,27 +1775,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,
@ -2491,44 +2480,77 @@ typedef enum state
S_RBIRD2,
S_RBIRD3,
S_YELLOWSPRING,
// Yellow Spring
S_YELLOWSPRING1,
S_YELLOWSPRING2,
S_YELLOWSPRING3,
S_YELLOWSPRING4,
S_YELLOWSPRING5,
S_REDSPRING,
// Red Spring
S_REDSPRING1,
S_REDSPRING2,
S_REDSPRING3,
S_REDSPRING4,
S_REDSPRING5,
// Blue Springs
S_BLUESPRING,
// Blue Spring
S_BLUESPRING1,
S_BLUESPRING2,
S_BLUESPRING3,
S_BLUESPRING4,
S_BLUESPRING5,
// Grey Spring
S_GREYSPRING1,
S_GREYSPRING2,
S_GREYSPRING3,
S_GREYSPRING4,
// Yellow Diagonal Spring
S_YDIAG1,
S_YDIAG2,
S_YDIAG3,
S_YDIAG4,
S_YDIAG5,
S_YDIAG6,
S_YDIAG7,
S_YDIAG8,
// Red Diagonal Spring
S_RDIAG1,
S_RDIAG2,
S_RDIAG3,
S_RDIAG4,
S_RDIAG5,
S_RDIAG6,
S_RDIAG7,
S_RDIAG8,
// Blue Diagonal Spring
S_BDIAG1,
S_BDIAG2,
S_BDIAG3,
S_BDIAG4,
// Grey Diagonal Spring
S_GDIAG1,
S_GDIAG2,
S_GDIAG3,
S_GDIAG4,
// Yellow Horizontal Spring
S_YHORIZ1,
S_YHORIZ2,
S_YHORIZ3,
S_YHORIZ4,
// Red Horizontal Spring
S_RHORIZ1,
S_RHORIZ2,
S_RHORIZ3,
S_RHORIZ4,
// Blue Horizontal Spring
S_BHORIZ1,
S_BHORIZ2,
S_BHORIZ3,
S_BHORIZ4,
// Grey Horizontal Spring
S_GHORIZ1,
S_GHORIZ2,
S_GHORIZ3,
S_GHORIZ4,
// Rain
S_RAIN1,
@ -2539,6 +2561,11 @@ typedef enum state
S_SNOW2,
S_SNOW3,
// Blizzard Snowball
S_BLIZZARDSNOW1,
S_BLIZZARDSNOW2,
S_BLIZZARDSNOW3,
// Water Splish
S_SPLISH1,
S_SPLISH2,
@ -3153,26 +3180,6 @@ typedef enum state
S_SRB1_GENREX1,
S_SRB1_GENREX2,
// Gray Springs
S_GRAYSPRING,
S_GRAYSPRING2,
S_GRAYSPRING3,
S_GRAYSPRING4,
S_GRAYSPRING5,
// Invis-spring - this is used just for the sproing sound.
S_INVISSPRING,
// Blue Diagonal Spring
S_BDIAG1,
S_BDIAG2,
S_BDIAG3,
S_BDIAG4,
S_BDIAG5,
S_BDIAG6,
S_BDIAG7,
S_BDIAG8,
//{ Random Item Box
S_RANDOMITEM1,
S_RANDOMITEM2,
@ -3648,9 +3655,6 @@ typedef enum state
S_LAMPPOST,
S_MOSSYTREE,
S_SHADOW,
S_WHITESHADOW,
S_BUMP1,
S_BUMP2,
S_BUMP3,
@ -4096,6 +4100,12 @@ typedef enum state
S_DRAFTDUST4,
S_DRAFTDUST5,
S_TIREGREASE,
S_OVERTIMEFOG,
S_OVERTIMEORB,
S_OVERTIMEBEAM,
#ifdef SEENAMES
S_NAMECHECK,
#endif
@ -4242,15 +4252,23 @@ typedef enum mobj_type
// Springs and others
MT_FAN,
MT_STEAM, // Steam riser
MT_BLUESPRING,
MT_YELLOWSPRING,
MT_REDSPRING,
MT_BLUESPRING,
MT_GREYSPRING,
MT_YELLOWDIAG, // Yellow Diagonal Spring
MT_REDDIAG, // Red Diagonal Spring
MT_BLUEDIAG, // Blue Diagonal Spring
MT_GREYDIAG, // Grey Diagonal Spring
MT_YELLOWHORIZ, // Yellow Horizontal Spring
MT_REDHORIZ, // Red Horizontal Spring
MT_BLUEHORIZ, // Blue Horizontal Spring
MT_GREYHORIZ, // Grey Horizontal Spring
// Interactive Objects
MT_BUBBLES, // Bubble source
MT_SIGN, // Level end sign
MT_SIGN_PIECE,
MT_SPIKEBALL, // Spike Ball
MT_SPECIALSPIKEBALL,
MT_SPINFIRE,
@ -4477,6 +4495,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
@ -4628,9 +4647,6 @@ typedef enum mobj_type
MT_SRB1_GENREX,
// SRB2kart
MT_GRAYSPRING,
MT_INVISSPRING,
MT_BLUEDIAG,
MT_RANDOMITEM,
MT_RANDOMITEMPOP,
MT_FLOATINGITEM,
@ -4740,8 +4756,6 @@ typedef enum mobj_type
MT_LAMPPOST,
MT_MOSSYTREE,
MT_SHADOW,
MT_BUMP,
MT_FLINGENERGY,
@ -4901,6 +4915,11 @@ typedef enum mobj_type
MT_KARMAFIREWORK,
MT_RINGSPARKS,
MT_DRAFTDUST,
MT_TIREGREASE,
MT_OVERTIMEFOG,
MT_OVERTIMEORB,
MT_OVERTIMEBEAM,
#ifdef SEENAMES
MT_NAMECHECK,

View file

@ -4,6 +4,8 @@
/// \brief SRB2kart general.
/// All of the SRB2kart-unique stuff.
#include "k_kart.h"
#include "k_pwrlv.h"
#include "doomdef.h"
#include "hu_stuff.h"
#include "g_game.h"
@ -18,7 +20,6 @@
#include "z_zone.h"
#include "m_misc.h"
#include "m_cond.h"
#include "k_kart.h"
#include "f_finale.h"
#include "lua_hud.h" // For Lua hud checks
#include "lua_hook.h" // For MobjDamage and ShouldDamage
@ -33,8 +34,6 @@
// battlewanted is an array of the WANTED player nums, -1 for no player in that slot
// indirectitemcooldown is timer before anyone's allowed another Shrink/SPB
// mapreset is set when enough players fill an empty server
// nospectategrief is the players in-game needed to eliminate the person in last
//{ SRB2kart Color Code
@ -412,7 +411,7 @@ UINT8 colortranslations[MAXTRANSLATIONS][16] = {
// 0.0722 to blue
// (See this same define in hw_md2.c!)
#define SETBRIGHTNESS(brightness,r,g,b) \
brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3)
brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000))
/** \brief Generates the rainbow colourmaps that are used when a player has the invincibility power
@ -582,6 +581,7 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_kartspeedometer);
CV_RegisterVar(&cv_kartvoices);
CV_RegisterVar(&cv_karteliminatelast);
CV_RegisterVar(&cv_kartusepwrlv);
CV_RegisterVar(&cv_votetime);
CV_RegisterVar(&cv_kartdebugitem);
@ -1535,20 +1535,16 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid)
\return boolean
*/
static UINT8 K_CheckOffroadCollide(mobj_t *mo, sector_t *sec)
static UINT8 K_CheckOffroadCollide(mobj_t *mo)
{
UINT8 i;
sector_t *sec2;
I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo));
sec2 = P_ThingOnSpecial3DFloor(mo);
for (i = 2; i < 5; i++)
{
if ((sec2 && GETSECSPECIAL(sec2->special, 1) == i)
|| (P_IsObjectOnRealGround(mo, sec) && GETSECSPECIAL(sec->special, 1) == i))
if (P_MobjTouchingSectorSpecial(mo, 1, i, true))
return i-1;
}
@ -1563,25 +1559,16 @@ static UINT8 K_CheckOffroadCollide(mobj_t *mo, sector_t *sec)
*/
static void K_UpdateOffroad(player_t *player)
{
fixed_t offroad;
sector_t *nextsector = R_PointInSubsector(
player->mo->x + player->mo->momx*2, player->mo->y + player->mo->momy*2)->sector;
UINT8 offroadstrength = K_CheckOffroadCollide(player->mo, nextsector);
fixed_t offroadstrength = (K_CheckOffroadCollide(player->mo) << FRACBITS);
// If you are in offroad, a timer starts.
if (offroadstrength)
{
if (K_CheckOffroadCollide(player->mo, player->mo->subsector->sector) && player->kartstuff[k_offroad] == 0)
player->kartstuff[k_offroad] = TICRATE;
if (player->kartstuff[k_offroad] < offroadstrength)
player->kartstuff[k_offroad] += offroadstrength / TICRATE;
if (player->kartstuff[k_offroad] > 0)
{
offroad = (offroadstrength << FRACBITS) / TICRATE;
player->kartstuff[k_offroad] += offroad;
}
if (player->kartstuff[k_offroad] > (offroadstrength << FRACBITS))
player->kartstuff[k_offroad] = (offroadstrength << FRACBITS);
if (player->kartstuff[k_offroad] > offroadstrength)
player->kartstuff[k_offroad] = offroadstrength;
}
else
player->kartstuff[k_offroad] = 0;
@ -1625,7 +1612,7 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur
cury + (P_RandomRange(-12,12)*mapobjectscale),
curz + (P_RandomRange(24,48)*mapobjectscale),
MT_SIGNSPARKLE);
P_SetMobjState(band, S_SIGNSPARK1 + (abs(leveltime+offset) % 11));
P_SetMobjState(band, S_SIGNSPARK1 + (leveltime % 11));
P_SetScale(band, (band->destscale = (3*player->mo->scale)/2));
band->color = colors[c];
band->colorized = true;
@ -2322,6 +2309,9 @@ fixed_t K_3dKartMovement(player_t *player, boolean onground, fixed_t forwardmove
// ACCELCODE!!!1!11!
oldspeed = R_PointToDist2(0, 0, player->rmomx, player->rmomy); // FixedMul(P_AproxDistance(player->rmomx, player->rmomy), player->mo->scale);
// Don't calculate the acceleration as ever being above top speed
if (oldspeed > p_speed)
oldspeed = p_speed;
newspeed = FixedDiv(FixedDiv(FixedMul(oldspeed, accelmax - p_accel) + FixedMul(p_speed, p_accel), accelmax), ORIG_FRICTION);
if (player->kartstuff[k_pogospring]) // Pogo Spring minimum/maximum thrust
@ -4344,6 +4334,167 @@ void K_RepairOrbitChain(mobj_t *orbit)
}
}
// Simplified version of a code bit in P_MobjFloorZ
static fixed_t K_BananaSlopeZ(pslope_t *slope, fixed_t x, fixed_t y, fixed_t radius, boolean ceiling)
{
fixed_t testx, testy;
if (slope->d.x < 0)
testx = radius;
else
testx = -radius;
if (slope->d.y < 0)
testy = radius;
else
testy = -radius;
if ((slope->zdelta > 0) ^ !!(ceiling))
{
testx = -testx;
testy = -testy;
}
testx += x;
testy += y;
return P_GetZAt(slope, testx, testy);
}
static void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player)
{
fixed_t newz;
sector_t *sec;
#ifdef ESLOPE
pslope_t *slope = NULL;
#endif
sec = R_PointInSubsector(x, y)->sector;
if (flip)
{
#ifdef ESLOPE
if (sec->c_slope)
{
slope = sec->c_slope;
newz = K_BananaSlopeZ(slope, x, y, radius, true);
}
else
#endif
newz = sec->ceilingheight;
}
else
{
#ifdef ESLOPE
if (sec->f_slope)
{
slope = sec->f_slope;
newz = K_BananaSlopeZ(slope, x, y, radius, false);
}
else
#endif
newz = sec->floorheight;
}
// Check FOFs for a better suited slope
if (sec->ffloors)
{
ffloor_t *rover;
for (rover = sec->ffloors; rover; rover = rover->next)
{
fixed_t top, bottom;
fixed_t d1, d2;
if (!(rover->flags & FF_EXISTS))
continue;
if ((!(((rover->flags & FF_BLOCKPLAYER && player)
|| (rover->flags & FF_BLOCKOTHERS && !player))
|| (rover->flags & FF_QUICKSAND))
|| (rover->flags & FF_SWIMMABLE)))
continue;
#ifdef ESLOPE
if (*rover->t_slope)
top = K_BananaSlopeZ(*rover->t_slope, x, y, radius, false);
else
#endif
top = *rover->topheight;
#ifdef ESLOPE
if (*rover->b_slope)
bottom = K_BananaSlopeZ(*rover->b_slope, x, y, radius, true);
else
#endif
bottom = *rover->bottomheight;
if (flip)
{
if (rover->flags & FF_QUICKSAND)
{
if (z < top && (z + height) > bottom)
{
if (newz > (z + height))
{
newz = (z + height);
slope = NULL;
}
}
continue;
}
d1 = (z + height) - (top + ((bottom - top)/2));
d2 = z - (top + ((bottom - top)/2));
if (bottom < newz && abs(d1) < abs(d2))
{
newz = bottom;
#ifdef ESLOPE
if (*rover->b_slope)
slope = *rover->b_slope;
#endif
}
}
else
{
if (rover->flags & FF_QUICKSAND)
{
if (z < top && (z + height) > bottom)
{
if (newz < z)
{
newz = z;
slope = NULL;
}
}
continue;
}
d1 = z - (bottom + ((top - bottom)/2));
d2 = (z + height) - (bottom + ((top - bottom)/2));
if (top > newz && abs(d1) < abs(d2))
{
newz = top;
#ifdef ESLOPE
if (*rover->t_slope)
slope = *rover->t_slope;
#endif
}
}
}
}
#if 0
mobj->standingslope = slope;
#endif
#ifdef HWRENDER
mobj->modeltilt = slope;
#endif
}
// Move the hnext chain!
static void K_MoveHeldObjects(player_t *player)
{
@ -4528,6 +4679,14 @@ static void K_MoveHeldObjects(player_t *player)
if (R_PointToDist2(cur->x, cur->y, targx, targy) > 768*FRACUNIT)
P_TeleportMove(cur, targx, targy, cur->z);
#ifdef ESLOPE
if (P_IsObjectOnGround(cur))
{
K_CalculateBananaSlope(cur, cur->x, cur->y, cur->z,
cur->radius, cur->height, (cur->eflags & MFE_VERTICALFLIP), false);
}
#endif
cur = cur->hnext;
}
}
@ -4617,6 +4776,9 @@ static void K_MoveHeldObjects(player_t *player)
P_TeleportMove(cur, targx, targy, targz);
K_FlipFromObject(cur, player->mo); // Update graviflip in real time thanks.
#ifdef HWRENDER
cur->modeltilt = player->mo->modeltilt;
#endif
num = (num+1) % 2;
cur = cur->hnext;
}
@ -5060,6 +5222,29 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (P_IsDisplayPlayer(player))
debtflag->flags2 |= MF2_DONTDRAW;
}
if (player->kartstuff[k_springstars] && (leveltime & 1))
{
fixed_t randx = P_RandomRange(-40, 40) * player->mo->scale;
fixed_t randy = P_RandomRange(-40, 40) * player->mo->scale;
fixed_t randz = P_RandomRange(0, player->mo->height >> FRACBITS) << FRACBITS;
mobj_t *star = P_SpawnMobj(
player->mo->x + randx,
player->mo->y + randy,
player->mo->z + randz,
MT_KARMAFIREWORK);
star->color = player->kartstuff[k_springcolor];
star->flags |= MF_NOGRAVITY;
star->momx = player->mo->momx / 2;
star->momy = player->mo->momy / 2;
star->momz = player->mo->momz / 2;
star->fuse = 12;
star->scale = player->mo->scale;
star->destscale = star->scale / 2;
player->kartstuff[k_springstars]--;
}
}
if (player->playerstate == PST_DEAD || player->kartstuff[k_respawn] > 1) // Ensure these are set correctly here
@ -5103,6 +5288,25 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->mo->color = player->skincolor;
}
}
else if (player->kartstuff[k_killfield]) // You're gonna REALLY diiiiie
{
const INT32 flashtime = 4<<(4-(player->kartstuff[k_killfield]/TICRATE));
if (player->kartstuff[k_killfield] == 1 || (player->kartstuff[k_killfield] % (flashtime/2) != 0))
{
player->mo->colorized = false;
player->mo->color = player->skincolor;
}
else if (player->kartstuff[k_killfield] % flashtime == 0)
{
player->mo->colorized = true;
player->mo->color = SKINCOLOR_BYZANTIUM;
}
else
{
player->mo->colorized = true;
player->mo->color = SKINCOLOR_RUBY;
}
}
else if (player->kartstuff[k_ringboost] && (leveltime & 1)) // ring boosting
{
player->mo->colorized = true;
@ -5262,6 +5466,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->kartstuff[k_justbumped])
player->kartstuff[k_justbumped]--;
if (player->kartstuff[k_tiregrease])
player->kartstuff[k_tiregrease]--;
// This doesn't go in HUD update because it has potential gameplay ramifications
if (player->karthud[khud_itemblink] && player->karthud[khud_itemblink]-- <= 0)
{
@ -5271,8 +5478,28 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
K_KartPlayerHUDUpdate(player);
if (G_BattleGametype() && player->kartstuff[k_bumper] > 0)
if (G_BattleGametype() && player->kartstuff[k_bumper] > 0
&& !player->kartstuff[k_spinouttimer] && !player->kartstuff[k_squishedtimer]
&& !player->kartstuff[k_respawn] && !player->powers[pw_flashing])
{
player->kartstuff[k_wanted]++;
if (battleovertime.enabled >= 10*TICRATE)
{
if (P_AproxDistance(player->mo->x - battleovertime.x, player->mo->y - battleovertime.y) > battleovertime.radius)
{
player->kartstuff[k_killfield]++;
if (player->kartstuff[k_killfield] > 4*TICRATE)
{
K_SpinPlayer(player, NULL, 0, NULL, false);
//player->kartstuff[k_killfield] = 1;
}
}
else if (player->kartstuff[k_killfield] > 0)
player->kartstuff[k_killfield]--;
}
}
else if (player->kartstuff[k_killfield] > 0)
player->kartstuff[k_killfield]--;
if (P_IsObjectOnGround(player->mo))
player->kartstuff[k_waterskip] = 0;
@ -5302,17 +5529,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
}
}
// ???
/*
if (player->kartstuff[k_jmp] > 1 && onground)
{
S_StartSound(player->mo, sfx_spring);
P_DoJump(player, false);
player->mo->momz *= player->kartstuff[k_jmp];
player->kartstuff[k_jmp] = 0;
}
*/
if (player->kartstuff[k_comebacktimer])
player->kartstuff[k_comebackmode] = 0;
@ -5446,15 +5662,16 @@ static INT16 K_GetKartDriftValue(player_t *player, fixed_t countersteer)
return 0;
if (player->kartstuff[k_driftend] != 0)
{
return -266*player->kartstuff[k_drift]; // Drift has ended and we are tweaking their angle back a bit
}
//basedrift = 90*player->kartstuff[k_drift]; // 450
//basedrift = 93*player->kartstuff[k_drift] - driftweight*3*player->kartstuff[k_drift]/10; // 447 - 303
basedrift = 83*player->kartstuff[k_drift] - (driftweight - 14)*player->kartstuff[k_drift]/5; // 415 - 303
driftangle = abs((252 - driftweight)*player->kartstuff[k_drift]/5);
if (player->kartstuff[k_tiregrease] > 0) // Buff drift-steering while in greasemode
basedrift += (basedrift / greasetics) * player->kartstuff[k_tiregrease];
return basedrift + FixedMul(driftangle, countersteer);
}
@ -6146,7 +6363,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
&& NO_HYUDORO && !(HOLDING_ITEM
|| player->kartstuff[k_itemamount]
|| player->kartstuff[k_itemroulette]
|| player->kartstuff[k_growshrinktimer] // Being disabled during Shrink was unintended but people seemed to be okay with it sooo...
|| player->kartstuff[k_growshrinktimer] > 0
|| player->kartstuff[k_rocketsneakertimer]
|| player->kartstuff[k_eggmanexplode]))
player->kartstuff[k_userings] = 1;
@ -6206,6 +6423,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
P_SetMobjState(ring, S_FASTRING1);
ring->extravalue1 = 1; // Ring use animation timer
ring->extravalue2 = 1; // Ring use animation flag
ring->shadowscale = 0;
P_SetTarget(&ring->target, player->mo); // user
player->kartstuff[k_rings]--;
player->kartstuff[k_ringdelay] = 3;
@ -6714,6 +6932,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if (onground)
{
fixed_t prevfriction = player->mo->friction;
// Reduce friction after hitting a horizontal spring
if (player->kartstuff[k_tiregrease])
player->mo->friction += ((FRACUNIT - prevfriction) / greasetics) * player->kartstuff[k_tiregrease];
// Friction
if (!player->kartstuff[k_offroad])
{
@ -6726,9 +6950,20 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
// Karma ice physics
if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0)
{
player->mo->friction += 1228;
// Wipeout slowdown
if (player->kartstuff[k_spinouttimer] && player->kartstuff[k_wipeoutslow])
{
if (player->kartstuff[k_offroad])
player->mo->friction -= 4912;
if (player->kartstuff[k_wipeoutslow] == 1)
player->mo->friction -= 9824;
}
// Friction was changed, so we must recalculate a bunch of stuff
if (player->mo->friction != prevfriction)
{
if (player->mo->friction > FRACUNIT)
player->mo->friction = FRACUNIT;
if (player->mo->friction < 0)
@ -6739,23 +6974,14 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
if (player->mo->movefactor < FRACUNIT)
player->mo->movefactor = 19*player->mo->movefactor - 18*FRACUNIT;
else
player->mo->movefactor = FRACUNIT; //player->mo->movefactor = ((player->mo->friction - 0xDB34)*(0xA))/0x80;
player->mo->movefactor = FRACUNIT;
if (player->mo->movefactor < 32)
player->mo->movefactor = 32;
}
// Wipeout slowdown
if (player->kartstuff[k_spinouttimer] && player->kartstuff[k_wipeoutslow])
{
if (player->kartstuff[k_offroad])
player->mo->friction -= 4912;
if (player->kartstuff[k_wipeoutslow] == 1)
player->mo->friction -= 9824;
}
}
K_KartDrift(player, onground);
K_KartDrift(player, P_IsObjectOnGround(player->mo)); // Not using onground, since we don't want this affected by spring pads
// Quick Turning
// You can't turn your kart when you're not moving.
@ -7229,6 +7455,10 @@ static patch_t *kp_lapanim_emblem[2];
static patch_t *kp_lapanim_hand[3];
static patch_t *kp_yougotem;
static patch_t *kp_itemminimap;
static patch_t *kp_alagles[10];
static patch_t *kp_blagles[6];
void K_LoadKartHUDGraphics(void)
{
@ -7529,6 +7759,21 @@ void K_LoadKartHUDGraphics(void)
}
kp_yougotem = (patch_t *) W_CachePatchName("YOUGOTEM", PU_HUDGFX);
kp_itemminimap = (patch_t *) W_CachePatchName("MMAPITEM", PU_HUDGFX);
sprintf(buffer, "ALAGLESx");
for (i = 0; i < 10; ++i)
{
buffer[7] = '0'+i;
kp_alagles[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
}
sprintf(buffer, "BLAGLESx");
for (i = 0; i < 6; ++i)
{
buffer[7] = '0'+i;
kp_blagles[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
}
}
// For the item toggle menu
@ -8501,9 +8746,11 @@ static boolean K_drawKartPositionFaces(void)
//
void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol)
{
static tic_t alagles_timer = 9;
INT32 i, rightoffset = 240;
const UINT8 *colormap;
INT32 dupadjust = (vid.width/vid.dupx), duptweak = (dupadjust - BASEVIDWIDTH)/2;
int y2;
//this function is designed for 9 or less score lines only
//I_Assert(scorelines <= 9); -- not today bitch, kart fixed it up
@ -8524,15 +8771,39 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
continue; //ignore them.
if (netgame // don't draw it offline
&& tab[i].num != serverplayer)
&& ( tab[i].num != serverplayer || ! server_lagless ))
HU_drawPing(x + ((i < 8) ? -17 : rightoffset + 11), y-4, playerpingtable[tab[i].num], 0);
STRBUFCPY(strtime, tab[i].name);
y2 = y;
if (tab[i].num == 0 && server_lagless)
{
y2 = ( y - 4 );
V_DrawScaledPatch(x + 20, y2, 0, kp_blagles[(leveltime / 3) % 6]);
// every 70 tics
if (( leveltime % 70 ) == 0)
{
alagles_timer = 9;
}
if (alagles_timer > 0)
{
V_DrawScaledPatch(x + 20, y2, 0, kp_alagles[alagles_timer]);
if (( leveltime % 2 ) == 0)
alagles_timer--;
}
else
V_DrawScaledPatch(x + 20, y2, 0, kp_alagles[0]);
y2 += SHORT (kp_alagles[0]->height) + 1;
}
if (scorelines > 8)
V_DrawThinString(x + 20, y, ((tab[i].num == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
V_DrawThinString(x + 20, y2, ((tab[i].num == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE|V_6WIDTHSPACE, strtime);
else
V_DrawString(x + 20, y, ((tab[i].num == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE, strtime);
V_DrawString(x + 20, y2, ((tab[i].num == whiteplayer) ? hilicol : 0)|V_ALLOWLOWERCASE, strtime);
if (players[tab[i].num].mo->color)
{
@ -9054,7 +9325,7 @@ static void K_drawKartPlayerCheck(void)
}
}
static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, patch_t *AutomapPic)
static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hudy, INT32 flags, patch_t *icon, UINT8 *colormap, patch_t *AutomapPic)
{
// amnum xpos & ypos are the icon's speed around the HUD.
// The number being divided by is for how fast it moves.
@ -9063,8 +9334,6 @@ static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, pat
// am xpos & ypos are the icon's starting position. Withouht
// it, they wouldn't 'spawn' on the top-right side of the HUD.
UINT8 skin = 0;
fixed_t amnumxpos, amnumypos;
INT32 amxpos, amypos;
@ -9075,9 +9344,6 @@ static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, pat
fixed_t xoffset, yoffset;
fixed_t xscale, yscale, zoom;
if (mo->skin)
skin = ((skin_t*)mo->skin)-skins;
maxx = maxy = INT32_MAX;
minx = miny = INT32_MIN;
minx = bsp->bbox[0][BOXLEFT];
@ -9114,39 +9380,23 @@ static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, pat
yscale = FixedDiv(AutomapPic->height, mapheight);
zoom = FixedMul(min(xscale, yscale), FRACUNIT-FRACUNIT/20);
amnumxpos = (FixedMul(mo->x, zoom) - FixedMul(xoffset, zoom));
amnumypos = -(FixedMul(mo->y, zoom) - FixedMul(yoffset, zoom));
amnumxpos = (FixedMul(objx, zoom) - FixedMul(xoffset, zoom));
amnumypos = -(FixedMul(objy, zoom) - FixedMul(yoffset, zoom));
if (encoremode)
amnumxpos = -amnumxpos;
amxpos = amnumxpos + ((x + AutomapPic->width/2 - (facemmapprefix[skin]->width/2))<<FRACBITS);
amypos = amnumypos + ((y + AutomapPic->height/2 - (facemmapprefix[skin]->height/2))<<FRACBITS);
amxpos = amnumxpos + ((hudx + AutomapPic->width/2 - (icon->width/2))<<FRACBITS);
amypos = amnumypos + ((hudy + AutomapPic->height/2 - (icon->height/2))<<FRACBITS);
// do we want this? it feels unnecessary. easier to just modify the amnumxpos?
/*if (encoremode)
{
flags |= V_FLIP;
amxpos = -amnumxpos + ((x + AutomapPic->width/2 + (facemmapprefix[skin]->width/2))<<FRACBITS);
amxpos = -amnumxpos + ((hudx + AutomapPic->width/2 + (icon->width/2))<<FRACBITS);
}*/
if (!mo->color) // 'default' color
V_DrawSciencePatch(amxpos, amypos, flags, facemmapprefix[skin], FRACUNIT);
else
{
UINT8 *colormap;
if (mo->colorized)
colormap = R_GetTranslationColormap(TC_RAINBOW, mo->color, GTC_CACHE);
else
colormap = R_GetTranslationColormap(skin, mo->color, GTC_CACHE);
V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, facemmapprefix[skin], colormap);
if (mo->player
&& ((G_RaceGametype() && mo->player->kartstuff[k_position] == spbplace)
|| (G_BattleGametype() && K_IsPlayerWanted(mo->player))))
{
V_DrawFixedPatch(amxpos - (4<<FRACBITS), amypos - (4<<FRACBITS), FRACUNIT, flags, kp_wantedreticle, NULL);
}
}
V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, icon, colormap);
}
static void K_drawKartMinimap(void)
@ -9155,7 +9405,9 @@ static void K_drawKartMinimap(void)
patch_t *AutomapPic;
INT32 i = 0;
INT32 x, y;
INT32 minimaptrans, splitflags = (splitscreen == 3 ? 0 : V_SNAPTORIGHT); // flags should only be 0 when it's centered (4p split)
INT32 minimaptrans, splitflags = (splitscreen == 3 ? 0 : V_SNAPTORIGHT); // flags should only be 0 when it's centered (4p split)
UINT8 skin = 0;
UINT8 *colormap = NULL;
SINT8 localplayers[4];
SINT8 numlocalplayers = 0;
@ -9164,6 +9416,8 @@ static void K_drawKartMinimap(void)
if (gamestate != GS_LEVEL)
return;
// Only draw for the first player
// Maybe move this somewhere else where this won't be a concern?
if (stplyr != &players[displayplayers[0]])
return;
@ -9209,6 +9463,20 @@ static void K_drawKartMinimap(void)
x -= SHORT(AutomapPic->leftoffset);
y -= SHORT(AutomapPic->topoffset);
// Draw the super item in Battle
if (G_BattleGametype() && battleovertime.enabled)
{
if (battleovertime.enabled >= 10*TICRATE || (battleovertime.enabled & 1))
{
const INT32 prevsplitflags = splitflags;
splitflags &= ~V_HUDTRANSHALF;
splitflags |= V_HUDTRANS;
colormap = R_GetTranslationColormap(TC_RAINBOW, (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1))), GTC_CACHE);
K_drawKartMinimapIcon(battleovertime.x, battleovertime.y, x, y, splitflags, kp_itemminimap, colormap, AutomapPic);
splitflags = prevsplitflags;
}
}
// initialize
for (i = 0; i < 4; i++)
localplayers[i] = -1;
@ -9219,7 +9487,20 @@ static void K_drawKartMinimap(void)
demoghost *g = ghosts;
while (g)
{
K_drawKartMinimapHead(g->mo, x, y, splitflags, AutomapPic);
if (g->mo->skin)
skin = ((skin_t*)g->mo->skin)-skins;
else
skin = 0;
if (g->mo->color)
{
if (g->mo->colorized)
colormap = R_GetTranslationColormap(TC_RAINBOW, g->mo->color, GTC_CACHE);
else
colormap = R_GetTranslationColormap(skin, g->mo->color, GTC_CACHE);
}
else
colormap = NULL;
K_drawKartMinimapIcon(g->mo->x, g->mo->y, x, y, splitflags, facemmapprefix[skin], colormap, AutomapPic);
g = g->next;
}
@ -9252,7 +9533,7 @@ static void K_drawKartMinimap(void)
}
}
if (P_IsDisplayPlayer(&players[i]))
if (i == displayplayers[0] || i == displayplayers[1] || i == displayplayers[2] || i == displayplayers[3])
{
// Draw display players on top of everything else
localplayers[numlocalplayers] = i;
@ -9260,7 +9541,26 @@ static void K_drawKartMinimap(void)
continue;
}
K_drawKartMinimapHead(players[i].mo, x, y, splitflags, AutomapPic);
if (players[i].mo->skin)
skin = ((skin_t*)players[i].mo->skin)-skins;
else
skin = 0;
if (players[i].mo->color)
{
if (players[i].mo->colorized)
colormap = R_GetTranslationColormap(TC_RAINBOW, players[i].mo->color, GTC_CACHE);
else
colormap = R_GetTranslationColormap(skin, players[i].mo->color, GTC_CACHE);
}
else
colormap = NULL;
K_drawKartMinimapIcon(players[i].mo->x, players[i].mo->y, x, y, splitflags, facemmapprefix[skin], colormap, AutomapPic);
// Target reticule
if ((G_RaceGametype() && players[i].kartstuff[k_position] == spbplace)
|| (G_BattleGametype() && K_IsPlayerWanted(&players[i])))
K_drawKartMinimapIcon(players[i].mo->x, players[i].mo->y, x, y, splitflags, kp_wantedreticle, NULL, AutomapPic);
}
}
@ -9272,7 +9572,28 @@ static void K_drawKartMinimap(void)
{
if (i == -1)
continue; // this doesn't interest us
K_drawKartMinimapHead(players[localplayers[i]].mo, x, y, splitflags, AutomapPic);
if (players[localplayers[i]].mo->skin)
skin = ((skin_t*)players[localplayers[i]].mo->skin)-skins;
else
skin = 0;
if (players[localplayers[i]].mo->color)
{
if (players[localplayers[i]].mo->colorized)
colormap = R_GetTranslationColormap(TC_RAINBOW, players[localplayers[i]].mo->color, GTC_CACHE);
else
colormap = R_GetTranslationColormap(skin, players[localplayers[i]].mo->color, GTC_CACHE);
}
else
colormap = NULL;
K_drawKartMinimapIcon(players[localplayers[i]].mo->x, players[localplayers[i]].mo->y, x, y, splitflags, facemmapprefix[skin], colormap, AutomapPic);
// Target reticule
if ((G_RaceGametype() && players[localplayers[i]].kartstuff[k_position] == spbplace)
|| (G_BattleGametype() && K_IsPlayerWanted(&players[localplayers[i]])))
K_drawKartMinimapIcon(players[localplayers[i]].mo->x, players[localplayers[i]].mo->y, x, y, splitflags, kp_wantedreticle, NULL, AutomapPic);
}
}
@ -9784,7 +10105,7 @@ void K_drawKartFreePlay(UINT32 flashtime)
return;
V_DrawKartString((BASEVIDWIDTH - (LAPS_X+1)) - (12*9), // mirror the laps thingy
LAPS_Y+3, V_SNAPTOBOTTOM|V_SNAPTORIGHT, "FREE PLAY");
LAPS_Y+3, V_HUDTRANS|V_SNAPTOBOTTOM|V_SNAPTORIGHT, "FREE PLAY");
}
static void K_drawDistributionDebugger(void)

333
src/k_pwrlv.c Normal file
View file

@ -0,0 +1,333 @@
/// \file k_pwrlv.c
/// \brief SRB2Kart Power Levels
#include "k_pwrlv.h"
#include "d_netcmd.h"
#include "g_game.h"
#include "s_sound.h"
#include "m_random.h"
#include "m_cond.h" // M_UpdateUnlockablesAndExtraEmblems
#include "p_tick.h" // leveltime
// Online rankings for the main gametypes.
// This array is saved to the gamedata.
UINT16 vspowerlevel[PWRLV_NUMTYPES];
// Client-sided calculations done for Power Levels.
// This is done so that clients will never be able to hack someone else's score over the server.
UINT16 clientpowerlevels[MAXPLAYERS][PWRLV_NUMTYPES];
// Which players spec-scummed, and their power level before scumming.
// On race finish, everyone is considered to have "won" against these people.
INT16 nospectategrief[MAXPLAYERS];
// Game setting scrambles based on server Power Level
SINT8 speedscramble = -1;
SINT8 encorescramble = -1;
void K_ClearClientPowerLevels(void)
{
UINT8 i, j;
for (i = 0; i < MAXPLAYERS; i++)
for (j = 0; j < PWRLV_NUMTYPES; j++)
clientpowerlevels[i][j] = 0;
}
// Adapted from this: http://wiki.tockdom.com/wiki/Player_Rating
INT16 K_CalculatePowerLevelInc(INT16 diff)
{
INT16 control[10] = {0,0,0,1,8,50,125,125,125,125};
fixed_t increment = 0;
fixed_t x;
UINT8 j;
#define MAXDIFF (PWRLVRECORD_MAX - 1)
if (diff > MAXDIFF)
diff = MAXDIFF;
if (diff < -MAXDIFF)
diff = -MAXDIFF;
#undef MAXDIFF
x = ((diff-2)<<FRACBITS) / PWRLVRECORD_DEF;
for (j = 3; j < 10; j++) // Just skipping to 3 since 0 thru 2 will always just add 0...
{
fixed_t f = abs(x - ((j-4)<<FRACBITS));
fixed_t add;
if (f >= (2<<FRACBITS))
{
continue; //add = 0;
}
else if (f >= (1<<FRACBITS))
{
fixed_t f2 = (2<<FRACBITS) - f;
add = FixedMul(FixedMul(f2, f2), f2) / 6;
}
else
{
add = ((3*FixedMul(FixedMul(f, f), f)) - (6*FixedMul(f, f)) + (4<<FRACBITS)) / 6;
}
increment += (add * control[j]);
}
return (INT16)(increment >> FRACBITS);
}
INT16 K_CalculatePowerLevelAvg(void)
{
fixed_t avg = 0;
UINT8 div = 0;
SINT8 t = PWRLV_DISABLED;
UINT8 i;
if (!netgame || !cv_kartusepwrlv.value)
{
CONS_Debug(DBG_GAMELOGIC, "Not in a netgame, or not using power levels -- no average.\n");
return 0; // No average.
}
if (G_RaceGametype())
t = PWRLV_RACE;
else if (G_BattleGametype())
t = PWRLV_BATTLE;
if (t == PWRLV_DISABLED)
{
CONS_Debug(DBG_GAMELOGIC, "Could not set a power level type -- no average.\n");
return 0; // Hmm?!
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator
|| clientpowerlevels[i][t] == 0) // splitscreen player
continue;
avg += (clientpowerlevels[i][t] << FRACBITS);
div++;
}
if (!div)
{
CONS_Debug(DBG_GAMELOGIC, "Found no players -- no average.\n");
return 0; // No average.
}
avg /= div;
return (INT16)(avg >> FRACBITS);
}
// -- K_UpdatePowerLevels could not be moved here due to usage of y_data, unfortunately. --
void K_SetPowerLevelScrambles(SINT8 powertype)
{
switch (powertype)
{
case PWRLV_RACE:
if (cv_kartspeed.value == -1 || cv_kartencore.value == -1)
{
UINT8 speed = KARTSPEED_NORMAL;
boolean encore = false;
INT16 avg = 0, min = 0;
UINT8 i, t = 1;
avg = K_CalculatePowerLevelAvg();
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator
|| clientpowerlevels[i][t] == 0) // splitscreen player
continue;
if (min == 0 || clientpowerlevels[i][0] < min)
min = clientpowerlevels[i][0];
}
CONS_Debug(DBG_GAMELOGIC, "Min: %d, Avg: %d\n", min, avg);
if (avg == 0 || min == 0)
{
CONS_Debug(DBG_GAMELOGIC, "No average/minimum, no scramblin'.\n");
speedscramble = encorescramble = -1;
return;
}
if (min >= 7800)
{
if (avg >= 8200)
t = 5;
else
t = 4;
}
else if (min >= 6800)
{
if (avg >= 7200)
t = 4;
else
t = 3;
}
else if (min >= 5800)
{
if (avg >= 6200)
t = 3;
else
t = 2;
}
else if (min >= 3800)
{
if (avg >= 4200)
t = 2;
else
t = 1;
}
#if 1
else
t = 1;
#else
else if (min >= 1800)
{
if (avg >= 2200)
t = 1;
else
t = 0;
}
else
t = 0;
#endif
CONS_Debug(DBG_GAMELOGIC, "Table position: %d\n", t);
switch (t)
{
case 5:
speed = KARTSPEED_HARD;
encore = true;
break;
case 4:
speed = P_RandomChance((7<<FRACBITS)/10) ? KARTSPEED_HARD : KARTSPEED_NORMAL;
encore = P_RandomChance(FRACUNIT>>1);
break;
case 3:
speed = P_RandomChance((3<<FRACBITS)/10) ? KARTSPEED_HARD : KARTSPEED_NORMAL;
encore = P_RandomChance(FRACUNIT>>2);
break;
case 2:
speed = 1;
encore = P_RandomChance(FRACUNIT>>3);
break;
case 1: default:
speed = KARTSPEED_NORMAL;
encore = false;
break;
case 0:
speed = P_RandomChance((3<<FRACBITS)/10) ? KARTSPEED_EASY : KARTSPEED_NORMAL;
encore = false;
break;
}
CONS_Debug(DBG_GAMELOGIC, "Rolled speed: %d\n", speed);
CONS_Debug(DBG_GAMELOGIC, "Rolled encore: %s\n", (encore ? "true" : "false"));
if (cv_kartspeed.value == -1)
speedscramble = speed;
else
speedscramble = -1;
if (cv_kartencore.value == -1)
encorescramble = (encore ? 1 : 0);
else
encorescramble = -1;
}
break;
default:
break;
}
}
void K_PlayerForfeit(UINT8 playernum, boolean pointloss)
{
UINT8 p = 0;
INT32 powertype = PWRLV_DISABLED;
UINT16 yourpower = PWRLVRECORD_DEF;
UINT16 theirpower = PWRLVRECORD_DEF;
INT16 diff = 0; // Loser PWR.LV - Winner PWR.LV
INT16 inc = 0;
UINT8 i;
// power level & spectating is netgames only
if (!netgame)
return;
// This server isn't using power levels anyway!
if (!cv_kartusepwrlv.value)
return;
// Hey, I just got here!
if (players[playernum].jointime <= 1)
return;
// 20 sec into the match counts as a forfeit -- automatic loss against every other player in the match.
if (gamestate != GS_LEVEL || leveltime <= starttime+(20*TICRATE))
return;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator)
p++;
}
if (p < 2) // no players
return;
if (G_RaceGametype())
powertype = PWRLV_RACE;
else if (G_BattleGametype())
powertype = PWRLV_BATTLE;
if (powertype == PWRLV_DISABLED) // No power type?!
return;
if (clientpowerlevels[playernum][powertype] == 0) // splitscreen guests don't record power level changes
return;
yourpower = clientpowerlevels[playernum][powertype];
// Set up the point compensation.
nospectategrief[playernum] = yourpower;
if (!pointloss) // This is set for stuff like sync-outs, which shouldn't be so harsh on the victim!
return;
for (i = 0; i < MAXPLAYERS; i++)
{
if (i == playernum)
continue;
theirpower = PWRLVRECORD_DEF;
if (clientpowerlevels[i][powertype] != 0) // No power level acts as 5000 (used for splitscreen guests)
theirpower = clientpowerlevels[i][powertype];
diff = yourpower - theirpower;
inc -= K_CalculatePowerLevelInc(diff);
}
if (inc == 0) // No change.
return;
if (yourpower + inc > PWRLVRECORD_MAX) // I mean... we're subtracting... but y'know how it is :V
inc -= ((yourpower + inc) - PWRLVRECORD_MAX);
if (yourpower + inc < PWRLVRECORD_MIN)
inc -= ((yourpower + inc) - PWRLVRECORD_MIN);
clientpowerlevels[playernum][powertype] += inc;
if (playernum == consoleplayer)
{
vspowerlevel[powertype] = clientpowerlevels[playernum][powertype];
if (M_UpdateUnlockablesAndExtraEmblems(true))
S_StartSound(NULL, sfx_ncitem);
G_SaveGameData(true); // save your punishment!
}
}

31
src/k_pwrlv.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef __K_PWRLV__
#define __K_PWRLV__
#include "doomtype.h"
#include "doomdef.h"
#define PWRLV_DISABLED -1
#define PWRLV_RACE 0
#define PWRLV_BATTLE 1
#define PWRLV_NUMTYPES 2
#define PWRLVRECORD_START 1000 // 5000?
#define PWRLVRECORD_DEF 5000
#define PWRLVRECORD_MIN 1
#define PWRLVRECORD_MAX 9999
extern SINT8 speedscramble;
extern SINT8 encorescramble;
extern UINT16 vspowerlevel[PWRLV_NUMTYPES];
extern UINT16 clientpowerlevels[MAXPLAYERS][PWRLV_NUMTYPES];
extern INT16 nospectategrief[MAXPLAYERS];
void K_ClearClientPowerLevels(void);
INT16 K_CalculatePowerLevelInc(INT16 diff);
INT16 K_CalculatePowerLevelAvg(void);
//void K_UpdatePowerLevels(void);
void K_SetPowerLevelScrambles(SINT8 powertype);
void K_PlayerForfeit(UINT8 playernum, boolean nopointloss);
#endif

View file

@ -639,16 +639,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
////////////
@ -1313,15 +1303,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;
}
@ -1405,15 +1396,15 @@ static int lib_pIsFlagAtBase(lua_State *L)
static int lib_pSetupLevelSky(lua_State *L)
{
INT32 skynum = (INT32)luaL_checkinteger(L, 1);
const char *skytexname = luaL_checkstring(L, 1);
player_t *user = NULL;
NOHUD
if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) // if a player, setup sky for only the player, otherwise setup sky for all players
user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
if (!user) // global
P_SetupLevelSky(skynum, true);
P_SetupLevelSky(skytexname, true);
else if (P_IsLocalPlayer(user))
P_SetupLevelSky(skynum, false);
P_SetupLevelSky(skytexname, false);
return 0;
}
@ -2672,7 +2663,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},
@ -2736,7 +2726,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

@ -1487,8 +1487,8 @@ static int mapheaderinfo_get(lua_State *L)
lua_pushstring(L, header->forcecharacter);
else if (fastcmp(field,"weather"))
lua_pushinteger(L, header->weather);
else if (fastcmp(field,"skynum"))
lua_pushinteger(L, header->skynum);
else if (fastcmp(field,"skytexture"))
lua_pushstring(L, header->skytexture);
else if (fastcmp(field,"skybox_scalex"))
lua_pushinteger(L, header->skybox_scalex);
else if (fastcmp(field,"skybox_scaley"))

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

@ -422,7 +422,7 @@ static void GIF_headwrite(void)
WRITEUINT16(p, rheight);
// colors, aspect, etc
WRITEUINT8(p, 0xF7);
WRITEUINT8(p, 0xFF); // TRANSPARENTPIXEL
WRITEUINT8(p, 0x00);
WRITEUINT8(p, 0x00);

View file

@ -577,14 +577,14 @@ void Command_Skynum_f(void)
if (COM_Argc() != 2)
{
CONS_Printf(M_GetText("skynum <sky#>: change the sky\n"));
CONS_Printf(M_GetText("Current sky is %d\n"), levelskynum);
CONS_Printf(M_GetText("skynum <texture name>: change the sky\n"));
CONS_Printf(M_GetText("Current sky is %s\n"), levelskytexture);
return;
}
CONS_Printf(M_GetText("Previewing sky %s...\n"), COM_Argv(1));
P_SetupLevelSky(atoi(COM_Argv(1)), false);
P_SetupLevelSky(COM_Argv(1), false);
}
void Command_Weather_f(void)

View file

@ -21,6 +21,7 @@
#include "r_things.h" // numskins
//#include "r_draw.h" // R_GetColorByName
#include "k_kart.h" // K_GetKartColorByName
#include "k_pwrlv.h"
// Map triggers for linedef executors
// 32 triggers, one bit each
@ -289,6 +290,8 @@ UINT8 M_CheckCondition(condition_t *cn)
return (totalplaytime >= (unsigned)cn->requirement);
case UC_MATCHESPLAYED: // Requires any level completed >= x times
return (matchesplayed >= (unsigned)cn->requirement);
case UC_POWERLEVEL: // Requires power level >= x on a certain gametype
return (vspowerlevel[cn->extrainfo1] >= (unsigned)cn->requirement);
case UC_GAMECLEAR: // Requires game beaten >= x times
return (timesBeaten >= (unsigned)cn->requirement);
case UC_ALLEMERALDS: // Requires game beaten with all 7 emeralds >= x times

View file

@ -22,28 +22,29 @@ typedef enum
{
UC_PLAYTIME, // PLAYTIME [tics]
UC_MATCHESPLAYED, // SRB2Kart: MATCHESPLAYED [x played]
UC_GAMECLEAR, // GAMECLEAR <x times>
UC_ALLEMERALDS, // ALLEMERALDS <x times>
//UC_ULTIMATECLEAR, // ULTIMATECLEAR <x times>
//UC_OVERALLSCORE, // OVERALLSCORE [score to beat]
UC_OVERALLTIME, // OVERALLTIME [time to beat, tics]
//UC_OVERALLRINGS, // OVERALLRINGS [rings to beat]
UC_MAPVISITED, // MAPVISITED [map number]
UC_MAPBEATEN, // MAPBEATEN [map number]
UC_MAPALLEMERALDS, // MAPALLEMERALDS [map number]
//UC_MAPULTIMATE, // MAPULTIMATE [map number]
//UC_MAPPERFECT, // MAPPERFECT [map number]
//UC_MAPSCORE, // MAPSCORE [map number] [score to beat]
UC_MAPTIME, // MAPTIME [map number] [time to beat, tics]
//UC_MAPRINGS, // MAPRINGS [map number] [rings to beat]
//UC_NIGHTSSCORE, // NIGHTSSCORE [map number] <mare, omit or "0" for overall> [score to beat]
//UC_NIGHTSTIME, // NIGHTSTIME [map number] <mare, omit "0" overall> [time to beat, tics]
//UC_NIGHTSGRADE, // NIGHTSGRADE [map number] <mare, omit "0" overall> [grade]
UC_TRIGGER, // TRIGGER [trigger number]
UC_TOTALEMBLEMS, // TOTALEMBLEMS [number of emblems]
UC_EMBLEM, // EMBLEM [emblem number]
UC_EXTRAEMBLEM, // EXTRAEMBLEM [extra emblem number]
UC_CONDITIONSET, // CONDITIONSET [condition set number]
UC_POWERLEVEL, // SRB2Kart: POWERLEVEL [power level to reach] [gametype, "0" for race, "1" for battle]
UC_GAMECLEAR, // GAMECLEAR <x times>
UC_ALLEMERALDS, // ALLEMERALDS <x times>
//UC_ULTIMATECLEAR, // ULTIMATECLEAR <x times>
//UC_OVERALLSCORE, // OVERALLSCORE [score to beat]
UC_OVERALLTIME, // OVERALLTIME [time to beat, tics]
//UC_OVERALLRINGS, // OVERALLRINGS [rings to beat]
UC_MAPVISITED, // MAPVISITED [map number]
UC_MAPBEATEN, // MAPBEATEN [map number]
UC_MAPALLEMERALDS, // MAPALLEMERALDS [map number]
//UC_MAPULTIMATE, // MAPULTIMATE [map number]
//UC_MAPPERFECT, // MAPPERFECT [map number]
//UC_MAPSCORE, // MAPSCORE [map number] [score to beat]
UC_MAPTIME, // MAPTIME [map number] [time to beat, tics]
//UC_MAPRINGS, // MAPRINGS [map number] [rings to beat]
//UC_NIGHTSSCORE, // NIGHTSSCORE [map number] <mare, omit or "0" for overall> [score to beat]
//UC_NIGHTSTIME, // NIGHTSTIME [map number] <mare, omit "0" overall> [time to beat, tics]
//UC_NIGHTSGRADE, // NIGHTSGRADE [map number] <mare, omit "0" overall> [grade]
UC_TRIGGER, // TRIGGER [trigger number]
UC_TOTALEMBLEMS, // TOTALEMBLEMS [number of emblems]
UC_EMBLEM, // EMBLEM [emblem number]
UC_EXTRAEMBLEM, // EXTRAEMBLEM [extra emblem number]
UC_CONDITIONSET, // CONDITIONSET [condition set number]
} conditiontype_t;
// Condition Set information

View file

@ -57,6 +57,7 @@
#include "st_stuff.h"
#include "i_sound.h"
#include "k_kart.h" // SRB2kart
#include "k_pwrlv.h"
#include "d_player.h" // KITEM_ constants
#include "i_joy.h" // for joystick menu controls
@ -89,6 +90,10 @@ int snprintf(char *str, size_t n, const char *fmt, ...);
#define SLIDER_WIDTH (8*SLIDER_RANGE+6)
#define SERVERS_PER_PAGE 11
#if defined (NONET) || defined (TESTERS)
#define NOMENUHOST
#endif
typedef enum
{
QUITMSG = 0,
@ -241,14 +246,18 @@ static menu_t SP_TimeAttackDef, SP_ReplayDef, SP_GuestReplayDef, SP_GhostDef;
// Multiplayer
#ifndef NONET
#ifndef TESTERS
static void M_StartServerMenu(INT32 choice);
#endif
static void M_ConnectMenu(INT32 choice);
static void M_ConnectMenuModChecks(INT32 choice);
static void M_Refresh(INT32 choice);
static void M_Connect(INT32 choice);
static void M_ChooseRoom(INT32 choice);
#endif
#ifndef TESTERS
static void M_StartOfflineServerMenu(INT32 choice);
#endif
static void M_StartServer(INT32 choice);
static void M_SetupMultiPlayer(INT32 choice);
static void M_SetupMultiPlayer2(INT32 choice);
@ -474,9 +483,14 @@ static menuitem_t MainMenu[] =
{
{IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_MainDef, 76},
//{IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84},
#ifdef TESTERS
{IT_GRAYEDOUT, NULL, "Time Attack", NULL, 84},
#else
{IT_CALL |IT_STRING, NULL, "Time Attack", M_TimeAttack, 84},
#endif
{IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92},
{IT_CALL |IT_STRING, NULL, "Options", M_Options, 100},
/* I don't think is useful at all... */
{IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 108},
{IT_CALL |IT_STRING, NULL, "Quit Game", M_QuitSRB2, 116},
};
@ -727,7 +741,9 @@ static menuitem_t SR_PandorasBox[] =
// Sky Room Custom Unlocks
static menuitem_t SR_MainMenu[] =
{
#ifndef TESTERS
{IT_STRING|IT_SUBMENU, NULL, "Unlockables", &SR_UnlockChecklistDef, 100},
#endif
{IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 108},
{IT_CALL|IT_STRING, NULL, "Replay Hut", M_ReplayHut, 116},
{IT_DISABLED, NULL, "", NULL, 0}, // Custom1
@ -961,12 +977,16 @@ static menuitem_t MP_MainMenu[] =
{IT_STRING|IT_KEYHANDLER,NULL, "Player setup...", M_SetupMultiHandler,18},
{IT_HEADER, NULL, "Host a game", NULL, 100-24},
#ifndef NONET
#ifndef NOMENUHOST
{IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 110-24},
#else
{IT_GRAYEDOUT, NULL, "Internet/LAN...", NULL, 110-24},
#endif
#ifdef TESTERS
{IT_GRAYEDOUT, NULL, "Offline...", NULL, 118-24},
#else
{IT_STRING|IT_CALL, NULL, "Offline...", M_StartOfflineServerMenu, 118-24},
#endif
{IT_HEADER, NULL, "Join a game", NULL, 132-24},
#ifndef NONET
@ -1482,8 +1502,7 @@ static menuitem_t OP_GameOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Starting Bumpers", &cv_kartbumpers, 110},
{IT_STRING | IT_CVAR, NULL, "Karma Comeback", &cv_kartcomeback, 120},
{IT_STRING | IT_CVAR, NULL, "Force Character", &cv_forceskin, 140},
{IT_STRING | IT_CVAR, NULL, "Restrict Character Changes", &cv_restrictskinchange, 150},
{IT_STRING | IT_CVAR, NULL, "Track Power Levels", &cv_kartusepwrlv, 140},
};
static menuitem_t OP_ServerOptionsMenu[] =
@ -3029,7 +3048,11 @@ void M_StartControlPanel(void)
//MainMenu[secrets].status = (M_AnySecretUnlocked()) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
currentMenu = &MainDef;
#ifdef TESTERS
itemOn = multiplr;
#else
itemOn = singleplr;
#endif
}
else if (modeattacking)
{
@ -4092,6 +4115,14 @@ static void M_DrawCenteredMenu(void)
W_CachePatchName(currentMenu->menuitems[i].patch,PU_CACHE), graymap);
y += LINEHEIGHT;
break;
case IT_TRANSTEXT:
if (currentMenu->menuitems[i].alphaKey)
y = currentMenu->y+currentMenu->menuitems[i].alphaKey;
/* FALLTHRU */
case IT_TRANSTEXT2:
V_DrawCenteredString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text);
y += SMALLLINEHEIGHT;
break;
}
}
@ -5381,7 +5412,7 @@ static void DrawReplayHutReplayInfo(void)
V_DrawThinString(x, y+9, V_SNAPTOTOP|V_ALLOWLOWERCASE, va("(%d laps)", demolist[dir_on[menudepthleft]].numlaps));
V_DrawString(x, y+20, V_SNAPTOTOP|V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].gametype == GT_RACE ?
va("Race (%s speed)", kartspeed_cons_t[demolist[dir_on[menudepthleft]].kartspeed & ~DF_ENCORE].strvalue) :
va("Race (%s speed)", kartspeed_cons_t[(demolist[dir_on[menudepthleft]].kartspeed & ~DF_ENCORE) + 1].strvalue) :
"Battle Mode");
if (!demolist[dir_on[menudepthleft]].standings[0].ranking)
@ -6210,6 +6241,8 @@ static char *M_GetConditionString(condition_t cond)
G_TicsToSeconds(cond.requirement));
case UC_MATCHESPLAYED:
return va("Play %d matches", cond.requirement);
case UC_POWERLEVEL:
return va("Reach power level %d in %s", cond.requirement, (cond.extrainfo1 == PWRLV_BATTLE ? "Battle" : "Race"));
case UC_GAMECLEAR:
if (cond.requirement > 1)
return va("Beat game %d times", cond.requirement);
@ -7294,7 +7327,7 @@ static void M_Statistics(INT32 choice)
static void M_DrawStatsMaps(int location)
{
INT32 y = 80, i = -1;
INT32 y = 88, i = -1;
INT16 mnum;
extraemblem_t *exemblem;
boolean dotopname = true, dobottomarrow = (location < statsMax);
@ -7403,9 +7436,14 @@ static void M_DrawLevelStats(void)
G_TicsToHours(totalplaytime),
G_TicsToMinutes(totalplaytime, false),
G_TicsToSeconds(totalplaytime)));
V_DrawString(20, 42, highlightflags, "Total Matches:");
V_DrawRightAlignedString(BASEVIDWIDTH-16, 42, 0, va("%i played", matchesplayed));
V_DrawString(20, 52, highlightflags, "Online Power Level:");
V_DrawRightAlignedString(BASEVIDWIDTH-16, 52, 0, va("Race: %i", vspowerlevel[PWRLV_RACE]));
V_DrawRightAlignedString(BASEVIDWIDTH-16, 60, 0, va("Battle: %i", vspowerlevel[PWRLV_BATTLE]));
for (i = 0; i < NUMMAPS; i++)
{
if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK))
@ -7420,18 +7458,18 @@ static void M_DrawLevelStats(void)
besttime += mainrecords[i]->time;
}
V_DrawString(20, 62, highlightflags, "Combined time records:");
V_DrawString(20, 70, highlightflags, "Combined time records:");
sprintf(beststr, "%i:%02i:%02i.%02i", G_TicsToHours(besttime), G_TicsToMinutes(besttime, false), G_TicsToSeconds(besttime), G_TicsToCentiseconds(besttime));
V_DrawRightAlignedString(BASEVIDWIDTH-16, 62, (mapsunfinished ? warningflags : 0), beststr);
V_DrawRightAlignedString(BASEVIDWIDTH-16, 70, (mapsunfinished ? warningflags : 0), beststr);
if (mapsunfinished)
V_DrawRightAlignedString(BASEVIDWIDTH-16, 70, warningflags, va("(%d unfinished)", mapsunfinished));
V_DrawRightAlignedString(BASEVIDWIDTH-16, 78, warningflags, va("(%d unfinished)", mapsunfinished));
else
V_DrawRightAlignedString(BASEVIDWIDTH-16, 70, recommendedflags, "(complete)");
V_DrawRightAlignedString(BASEVIDWIDTH-16, 78, recommendedflags, "(complete)");
V_DrawString(32, 70, 0, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems));
V_DrawSmallScaledPatch(20, 70, 0, W_CachePatchName("GOTITA", PU_STATIC));
V_DrawString(32, 78, V_ALLOWLOWERCASE, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems));
V_DrawSmallScaledPatch(20, 78, 0, W_CachePatchName("GOTITA", PU_STATIC));
M_DrawStatsMaps(statsLocation);
}
@ -8261,6 +8299,7 @@ static void M_DrawConnectMenu(void)
UINT16 i;
const char *gt = "Unknown";
const char *spd = "";
const char *pwr = "----";
INT32 numPages = (serverlistcount+(SERVERS_PER_PAGE-1))/SERVERS_PER_PAGE;
for (i = FIRSTSERVERLINE; i < min(localservercount, SERVERS_PER_PAGE)+FIRSTSERVERLINE; i++)
@ -8295,33 +8334,38 @@ static void M_DrawConnectMenu(void)
V_DrawString(currentMenu->x, S_LINEY(i), globalflags, serverlist[slindex].info.servername);
// Don't use color flags intentionally, the global yellow color will auto override the text color code
if (serverlist[slindex].info.modifiedgame)
V_DrawSmallString(currentMenu->x+202, S_LINEY(i)+8, globalflags, "\x85" "Mod");
if (serverlist[slindex].info.cheatsenabled)
V_DrawSmallString(currentMenu->x+222, S_LINEY(i)+8, globalflags, "\x83" "Cheats");
if (serverlist[slindex].info.kartvars & SV_PASSWORD)
V_DrawFixedPatch((currentMenu->x - 9) << FRACBITS, (S_LINEY(i)) << FRACBITS, FRACUNIT, globalflags & (~V_ALLOWLOWERCASE), W_CachePatchName("SERVLOCK", PU_CACHE), NULL);
V_DrawSmallString(currentMenu->x, S_LINEY(i)+8, globalflags,
va("Ping: %u", (UINT32)LONG(serverlist[slindex].info.time)));
V_DrawSmallString(currentMenu->x+44,S_LINEY(i)+8, globalflags,
va("Players: %02d/%02d", serverlist[slindex].info.numberofplayer, serverlist[slindex].info.maxplayer));
gt = "Unknown";
if (serverlist[slindex].info.gametype < NUMGAMETYPES)
gt = Gametype_Names[serverlist[slindex].info.gametype];
V_DrawSmallString(currentMenu->x+46,S_LINEY(i)+8, globalflags,
va("Players: %02d/%02d", serverlist[slindex].info.numberofplayer, serverlist[slindex].info.maxplayer));
V_DrawSmallString(currentMenu->x+112, S_LINEY(i)+8, globalflags, gt);
V_DrawSmallString(currentMenu->x+108, S_LINEY(i)+8, globalflags, gt);
if (serverlist[slindex].info.gametype == GT_RACE)
{
spd = kartspeed_cons_t[serverlist[slindex].info.kartvars & SV_SPEEDMASK].strvalue;
V_DrawSmallString(currentMenu->x+132, S_LINEY(i)+8, globalflags, va("(%s Speed)", spd));
spd = kartspeed_cons_t[(serverlist[slindex].info.kartvars & SV_SPEEDMASK)+1].strvalue;
V_DrawSmallString(currentMenu->x+128, S_LINEY(i)+8, globalflags, va("(%s)", spd));
}
if (serverlist[slindex].info.kartvars & SV_PASSWORD)
V_DrawFixedPatch((currentMenu->x - 9) << FRACBITS, (S_LINEY(i)) << FRACBITS, FRACUNIT, globalflags & (~V_ALLOWLOWERCASE), W_CachePatchName("SERVLOCK", PU_CACHE), NULL);
pwr = "----";
if (serverlist[slindex].info.avgpwrlv == -1)
pwr = "Off";
else if (serverlist[slindex].info.avgpwrlv > 0)
pwr = va("%04d", serverlist[slindex].info.avgpwrlv);
V_DrawSmallString(currentMenu->x+171, S_LINEY(i)+8, globalflags, va("Power Level: %s", pwr));
// Don't use color flags intentionally, the global yellow color will auto override the text color code
if (serverlist[slindex].info.modifiedgame)
V_DrawSmallString(currentMenu->x+245, S_LINEY(i)+8, globalflags, "\x85" "Mod");
if (serverlist[slindex].info.cheatsenabled)
V_DrawSmallString(currentMenu->x+265, S_LINEY(i)+8, globalflags, "\x83" "Cheats");
MP_ConnectMenu[i+FIRSTSERVERLINE].status = IT_STRING | IT_CALL;
}
@ -8600,11 +8644,11 @@ static void M_StartServer(INT32 choice)
paused = false;
SV_StartSinglePlayerServer();
multiplayer = true; // yeah, SV_StartSinglePlayerServer clobbers this...
D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false);
D_MapChange(cv_nextmap.value, cv_newgametype.value, (cv_kartencore.value == 1), 1, 1, false, false);
}
else
{
D_MapChange(cv_nextmap.value, cv_newgametype.value, (boolean)cv_kartencore.value, 1, 1, false, false);
D_MapChange(cv_nextmap.value, cv_newgametype.value, (cv_kartencore.value == 1), 1, 1, false, false);
COM_BufAddText("dummyconsvar 1\n");
}
@ -8641,7 +8685,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade)
V_DrawFill(x-1, y-1, w+2, i+2, trans); // variable reuse...
if (!cv_kartencore.value || gamestate == GS_TIMEATTACK || cv_newgametype.value != GT_RACE)
if ((cv_kartencore.value != 1) || gamestate == GS_TIMEATTACK || cv_newgametype.value != GT_RACE)
V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel);
else
{
@ -8774,6 +8818,7 @@ static void M_MapChange(INT32 choice)
M_SetupNextMenu(&MISC_ChangeLevelDef);
}
#ifndef TESTERS
static void M_StartOfflineServerMenu(INT32 choice)
{
(void)choice;
@ -8781,8 +8826,10 @@ static void M_StartOfflineServerMenu(INT32 choice)
M_PrepareLevelSelect();
M_SetupNextMenu(&MP_OfflineServerDef);
}
#endif
#ifndef NONET
#ifndef TESTERS
static void M_StartServerMenu(INT32 choice)
{
(void)choice;
@ -8792,6 +8839,7 @@ static void M_StartServerMenu(INT32 choice)
M_SetupNextMenu(&MP_ServerDef);
}
#endif
// ==============
// CONNECT VIA IP
@ -8811,7 +8859,7 @@ static void M_DrawMPMainMenu(void)
// use generic drawer for cursor, items and title
M_DrawGenericMenu();
#ifndef NONET
#ifndef NOMENUHOST
#if MAXPLAYERS != 16
Update the maxplayers label...
#endif
@ -8819,10 +8867,12 @@ Update the maxplayers label...
((itemOn == 4) ? highlightflags : 0), "(2-16 players)");
#endif
#ifndef TESTERS
V_DrawRightAlignedString(BASEVIDWIDTH-x, y+MP_MainMenu[5].alphaKey,
((itemOn == 5) ? highlightflags : 0),
"(2-4 players)"
);
#endif
#ifndef NONET
y += MP_MainMenu[8].alphaKey;
@ -9583,6 +9633,8 @@ static UINT8 erasecontext = 0;
static void M_EraseDataResponse(INT32 ch)
{
UINT8 i;
if (ch != 'y' && ch != KEY_ENTER)
return;
@ -9594,6 +9646,8 @@ static void M_EraseDataResponse(INT32 ch)
// SRB2Kart: This actually needs to be done FIRST, so that you don't immediately regain playtime/matches secrets
totalplaytime = 0;
matchesplayed = 0;
for (i = 0; i < PWRLV_NUMTYPES; i++)
vspowerlevel[i] = PWRLVRECORD_START;
F_StartIntro();
}
if (erasecontext != 1)

View file

@ -118,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);
@ -3559,8 +3558,6 @@ void A_BubbleCheck(mobj_t *actor)
//
void A_AttractChase(mobj_t *actor)
{
fixed_t z;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_AttractChase", actor))
return;
@ -3604,12 +3601,11 @@ void A_AttractChase(mobj_t *actor)
{
fixed_t offz = FixedMul(80*actor->target->scale, FINESINE(FixedAngle((90 - (9 * abs(10 - actor->extravalue1))) << FRACBITS) >> ANGLETOFINESHIFT));
//P_SetScale(actor, (actor->destscale = actor->target->scale));
z = actor->target->z;
if (( actor->eflags & MFE_VERTICALFLIP ))
z -= actor->height + offz;
else
z += actor->target->height + offz;
P_TeleportMove(actor, actor->target->x, actor->target->y, z);
actor->z = actor->target->z;
K_MatchGenericExtraFlags(actor, actor->target);
P_TeleportMove(actor, actor->target->x, actor->target->y,
actor->z +
( actor->target->height + offz )* P_MobjFlip(actor));
actor->extravalue1++;
}
}
@ -3636,15 +3632,12 @@ void A_AttractChase(mobj_t *actor)
fixed_t dist = (actor->target->radius/4) * (16 - actor->extravalue1);
P_SetScale(actor, (actor->destscale = actor->target->scale - ((actor->target->scale/14) * actor->extravalue1)));
z = actor->target->z;
if (( actor->eflags & MFE_VERTICALFLIP ))
z += actor->target->height - actor->height - 24 * actor->target->scale;
else
z += 24 * actor->target->scale;
actor->z = actor->target->z;
K_MatchGenericExtraFlags(actor, actor->target);
P_TeleportMove(actor,
actor->target->x + FixedMul(dist, FINECOSINE(actor->angle >> ANGLETOFINESHIFT)),
actor->target->y + FixedMul(dist, FINESINE(actor->angle >> ANGLETOFINESHIFT)),
z);
actor->z + actor->target->scale * 24 * P_MobjFlip(actor));
actor->angle += ANG30;
actor->extravalue1++;
@ -4187,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.
@ -8300,7 +8261,7 @@ void A_ItemPop(mobj_t *actor)
remains->flags = actor->flags; // Transfer flags
remains->flags2 = actor->flags2; // Transfer flags2
remains->fuse = actor->fuse; // Transfer respawn timer
remains->threshold = (actor->threshold == 69 ? 69 : 68);
remains->threshold = (actor->threshold == 70 ? 70 : (actor->threshold == 69 ? 69 : 68));
remains->skin = NULL;
remains->spawnpoint = actor->spawnpoint;
@ -8314,7 +8275,7 @@ void A_ItemPop(mobj_t *actor)
remains->flags2 &= ~MF2_AMBUSH;
if (G_BattleGametype() && actor->threshold != 69)
if (G_BattleGametype() && (actor->threshold != 69 && actor->threshold != 70))
numgotboxes++;
P_RemoveMobj(actor);
@ -8322,7 +8283,11 @@ void A_ItemPop(mobj_t *actor)
void A_JawzChase(mobj_t *actor)
{
const fixed_t currentspeed = R_PointToDist2(0, 0, actor->momx, actor->momy);
player_t *player;
fixed_t thrustamount = 0;
fixed_t frictionsafety = (actor->friction == 0) ? 1 : actor->friction;
fixed_t topspeed = actor->movefactor;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_JawzChase", actor))
return;
@ -8335,20 +8300,100 @@ void A_JawzChase(mobj_t *actor)
if (actor->tracer->health)
{
const angle_t targetangle = R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y);
mobj_t *ret;
angle_t angledelta = actor->angle - targetangle;
boolean turnclockwise = true;
if (G_RaceGametype())
{
const fixed_t distbarrier = FixedMul(512*mapobjectscale, FRACUNIT + ((gamespeed-1) * (FRACUNIT/4)));
const fixed_t distaway = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
if (distaway < distbarrier)
{
if (actor->tracer->player)
{
fixed_t speeddifference = abs(topspeed - min(actor->tracer->player->speed, K_GetKartSpeed(actor->tracer->player, false)));
topspeed = topspeed - FixedMul(speeddifference, FRACUNIT-FixedDiv(distaway, distbarrier));
}
}
}
if (angledelta != 0)
{
angle_t MAX_JAWZ_TURN = ANGLE_90/15; // We can turn a maximum of 6 degrees per frame at regular max speed
// MAX_JAWZ_TURN gets stronger the slower the top speed of jawz
if (topspeed < actor->movefactor)
{
if (topspeed == 0)
{
MAX_JAWZ_TURN = ANGLE_180;
}
else
{
fixed_t anglemultiplier = FixedDiv(actor->movefactor, topspeed);
MAX_JAWZ_TURN += FixedAngle(FixedMul(AngleFixed(MAX_JAWZ_TURN), anglemultiplier));
}
}
if (angledelta > ANGLE_180)
{
angledelta = InvAngle(angledelta);
turnclockwise = false;
}
if (angledelta > MAX_JAWZ_TURN)
{
angledelta = MAX_JAWZ_TURN;
}
if (turnclockwise)
{
actor->angle -= angledelta;
}
else
{
actor->angle += angledelta;
}
}
ret = P_SpawnMobj(actor->tracer->x, actor->tracer->y, actor->tracer->z, MT_PLAYERRETICULE);
P_SetTarget(&ret->target, actor->tracer);
ret->frame |= ((leveltime % 10) / 2) + 5;
ret->color = actor->cvmem;
P_Thrust(actor, R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y), (7*actor->movefactor)/64);
return;
}
else
P_SetTarget(&actor->tracer, NULL);
}
if (!P_IsObjectOnGround(actor))
{
// No friction in the air
frictionsafety = FRACUNIT;
}
if (currentspeed >= topspeed)
{
// Thrust as if you were at top speed, slow down naturally
thrustamount = FixedDiv(topspeed, frictionsafety) - topspeed;
}
else
{
const fixed_t beatfriction = FixedDiv(currentspeed, frictionsafety) - currentspeed;
// Thrust to immediately get to top speed
thrustamount = beatfriction + FixedDiv(topspeed - currentspeed, frictionsafety);
}
if (!actor->tracer)
{
actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy);
}
P_Thrust(actor, actor->angle, thrustamount);
if ((actor->tracer != NULL) && (actor->tracer->health > 0))
return;
if (actor->extravalue1) // Disable looking by setting this
return;

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

@ -27,6 +27,7 @@
#include "m_misc.h"
#include "v_video.h" // video flags for CEchos
#include "k_kart.h" // SRB2kart
#include "k_pwrlv.h"
// CTF player names
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
@ -924,7 +925,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);
@ -1763,6 +1764,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
}
// Easily make it so that overtime works offline
//#define TESTOVERTIMEINFREEPLAY
/** Checks if the level timer is over the timelimit and the round should end,
* unless you are in overtime. In which case leveltime may stretch out beyond
* timelimitintics and overtime's status will be checked here each tick.
@ -1773,7 +1777,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
*/
void P_CheckTimeLimit(void)
{
INT32 i, k;
INT32 i;
if (!cv_timelimit.value)
return;
@ -1807,71 +1811,76 @@ void P_CheckTimeLimit(void)
}
}
}
else*/
//Optional tie-breaker for Match/CTF
else*/ if (cv_overtime.value)
if (cv_overtime.value)
{
INT32 playerarray[MAXPLAYERS];
INT32 tempplayer = 0;
INT32 spectators = 0;
INT32 playercount = 0;
//Figure out if we have enough participating players to care.
#ifndef TESTOVERTIMEINFREEPLAY
boolean foundone = false; // Overtime is used for closing off down to a specific item.
for (i = 0; i < MAXPLAYERS; i++)
{
if (players[i].exiting)
return;
if (playeringame[i] && players[i].spectator)
spectators++;
}
if ((D_NumPlayers() - spectators) > 1)
{
// Play the starpost sfx after the first second of overtime.
if (gamestate == GS_LEVEL && (leveltime == (timelimitintics + TICRATE)))
S_StartSound(NULL, sfx_strpst);
// Normal Match
if (!G_GametypeHasTeams())
if (!playeringame[i] || players[i].spectator)
continue;
if (foundone)
{
//Store the nodes of participating players in an array.
for (i = 0; i < MAXPLAYERS; i++)
#endif
// Initiate the kill zone
if (!battleovertime.enabled)
{
if (playeringame[i] && !players[i].spectator)
INT32 b = 0;
thinker_t *th;
mobj_t *item = NULL;
P_RespawnBattleBoxes(); // FORCE THESE TO BE RESPAWNED FOR THIS!!!!!!!
// Find us an item box to center on.
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
playerarray[playercount] = i;
playercount++;
mobj_t *thismo;
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
thismo = (mobj_t *)th;
if (thismo->type != MT_RANDOMITEM)
continue;
if (thismo->threshold == 69) // Disappears
continue;
b++;
// Only select items that are on the ground, ignore ones in the air. Ambush flag inverts this rule.
if ((!P_IsObjectOnGround(thismo)) != (thismo->flags2 & MF2_AMBUSH))
continue;
if (item == NULL || (b < nummapboxes && P_RandomChance(((nummapboxes-b)*FRACUNIT)/nummapboxes))) // This is to throw off the RNG some
item = thismo;
if (b >= nummapboxes) // end early if we've found them all already
break;
}
}
if (playercount > MAXPLAYERS)
playercount = MAXPLAYERS;
//Sort 'em.
for (i = 1; i < playercount; i++)
{
for (k = i; k < playercount; k++)
if (item == NULL) // no item found, could happen if every item is in the air or has ambush flag, or the map has none
{
if (players[playerarray[i-1]].marescore < players[playerarray[k]].marescore)
{
tempplayer = playerarray[i-1];
playerarray[i-1] = playerarray[k];
playerarray[k] = tempplayer;
}
CONS_Alert(CONS_WARNING, "No usuable items for Battle overtime!\n");
return;
}
}
//End the round if the top players aren't tied.
if (players[playerarray[0]].marescore == players[playerarray[1]].marescore)
return;
item->threshold = 70; // Set constant respawn
battleovertime.x = item->x;
battleovertime.y = item->y;
battleovertime.z = item->z;
battleovertime.radius = 4096*mapobjectscale;
battleovertime.minradius = (cv_overtime.value == 2 ? 40 : 512) * mapobjectscale;
battleovertime.enabled = 1;
S_StartSound(NULL, sfx_kc47);
}
return;
#ifndef TESTOVERTIMEINFREEPLAY
}
else
{
//In team match and CTF, determining a tie is much simpler. =P
if (redscore == bluescore)
return;
}
foundone = true;
}
#endif
}
for (i = 0; i < MAXPLAYERS; i++)
@ -1882,9 +1891,6 @@ void P_CheckTimeLimit(void)
return;
P_DoPlayerExit(&players[i]);
}
/*if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0);*/
}
/** Checks if a player's score is over the pointlimit and the round should end.
@ -2030,7 +2036,8 @@ void P_CheckPointLimit(void)
// Checks whether or not to end a race netgame.
boolean P_CheckRacers(void)
{
INT32 i, j, numplayersingame = 0;
INT32 i, j, numplayersingame = 0, numexiting = 0;
boolean griefed = false;
// Check if all the players in the race have finished. If so, end the level.
for (i = 0; i < MAXPLAYERS; i++)
@ -2047,57 +2054,53 @@ boolean P_CheckRacers(void)
return true;
}
if (cv_karteliminatelast.value)
for (j = 0; j < MAXPLAYERS; j++)
{
for (j = 0; j < MAXPLAYERS; j++)
if (nospectategrief[j] != -1) // prevent spectate griefing
griefed = true;
if (!playeringame[j] || players[j].spectator)
continue;
numplayersingame++;
if (players[j].exiting)
numexiting++;
}
if (cv_karteliminatelast.value && numplayersingame > 1 && !griefed)
{
// check if we just got unlucky and there was only one guy who was a problem
for (j = i+1; j < MAXPLAYERS; j++)
{
if (!playeringame[j] || players[j].spectator)
if (!playeringame[j] || players[j].spectator || players[j].exiting || !players[j].lives)
continue;
numplayersingame++;
break;
}
if (numplayersingame > 1 && nospectategrief > 0 && numplayersingame >= nospectategrief) // prevent spectate griefing
if (j == MAXPLAYERS) // finish anyways, force a time over
{
// check if we just got unlucky and there was only one guy who was a problem
for (j = i+1; j < MAXPLAYERS; j++)
{
if (!playeringame[j] || players[j].spectator || players[j].exiting || !players[j].lives)
continue;
break;
}
if (j == MAXPLAYERS) // finish anyways, force a time over
{
P_DoTimeOver(&players[i]);
countdown = countdown2 = 0;
return true;
}
P_DoTimeOver(&players[i]);
countdown = countdown2 = 0;
return true;
}
}
if (!countdown) // Check to see if the winners have finished, to set countdown.
{
UINT8 numingame = 0, numexiting = 0;
UINT8 winningpos = 1;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
numingame++;
if (players[i].exiting)
numexiting++;
}
winningpos = max(1, numingame/2);
if (numingame % 2) // any remainder?
winningpos = max(1, numplayersingame/2);
if (numplayersingame % 2) // any remainder?
winningpos++;
if (numexiting >= winningpos)
countdown = (((netgame || multiplayer) ? cv_countdowntime.value : 30)*TICRATE) + 1; // 30 seconds to finish, get going!
}
if (numplayersingame < 2) // reset nospectategrief in free play
{
for (j = 0; j < MAXPLAYERS; j++)
nospectategrief[j] = -1;
}
return false;
}
@ -2142,6 +2145,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

@ -211,12 +211,11 @@ extern tic_t itemrespawntime[ITEMQUESIZE];
extern size_t iquehead, iquetail;
extern consvar_t cv_gravity/*, cv_viewheight*/;
void P_RespawnBattleBoxes(void);
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);
@ -227,7 +226,7 @@ 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);
void P_RunShadows(void);
void P_RunBattleOvertime(void);
void P_MobjThinker(mobj_t *mobj);
boolean P_RailThinker(mobj_t *mobj);
void P_PushableThinker(mobj_t *mobj);

View file

@ -129,6 +129,8 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
// MOVEMENT ITERATOR FUNCTIONS
// =========================================================================
//#define TELEPORTJANK
// 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)
@ -228,9 +230,11 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
//INT32 pflags;
const fixed_t hscale = mapobjectscale + (mapobjectscale - object->scale);
const fixed_t vscale = mapobjectscale + (object->scale - mapobjectscale);
fixed_t offx, offy;
fixed_t vertispeed = spring->info->mass;
fixed_t horizspeed = spring->info->damage;
UINT8 starcolor = (spring->info->painchance % MAXTRANSLATIONS);
fixed_t savemomx = 0;
fixed_t savemomy = 0;
if (object->eflags & MFE_SPRUNG) // Object was already sprung this tic
return false;
@ -252,29 +256,36 @@ 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 (horizspeed && vertispeed) // Mimic SA
{
object->momx = object->momy = 0;
P_TryMove(object, spring->x, spring->y, true);
}
#endif
if (spring->eflags & MFE_VERTICALFLIP)
vertispeed *= -1;
// Vertical springs teleport you on TOP of them.
if (vertispeed > 0)
object->z = spring->z + spring->height + 1;
else if (vertispeed < 0)
object->z = spring->z - object->height - 1;
else
{
fixed_t offx, offy;
// Horizontal springs teleport you in FRONT of them.
savemomx = object->momx;
savemomy = object->momy;
object->momx = object->momy = 0;
// Overestimate the distance to position you at
offx = P_ReturnThrustX(spring, spring->angle, (spring->radius + object->radius + 1) * 2);
offy = P_ReturnThrustY(spring, spring->angle, (spring->radius + object->radius + 1) * 2);
// Make it square by clipping
// Then clip it down to a square, so it matches the hitbox size.
if (offx > (spring->radius + object->radius + 1))
offx = spring->radius + object->radius + 1;
else if (offx < -(spring->radius + object->radius + 1))
@ -285,27 +296,94 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
else if (offy < -(spring->radius + object->radius + 1))
offy = -(spring->radius + object->radius + 1);
// Set position!
P_TryMove(object, spring->x + offx, spring->y + offy, true);
}
if (vertispeed)
object->momz = FixedMul(vertispeed,FixedSqrt(FixedMul(vscale, spring->scale)));
object->momz = FixedMul(vertispeed, FixedSqrt(FixedMul(vscale, spring->scale)));
if (horizspeed)
{
if (!object->player)
P_InstaThrustEvenIn2D(object, spring->angle, FixedMul(horizspeed,FixedSqrt(FixedMul(hscale, spring->scale))));
angle_t finalAngle = spring->angle;
fixed_t finalSpeed = horizspeed;
fixed_t objectSpeed;
if (object->player)
objectSpeed = object->player->speed;
else
objectSpeed = R_PointToDist2(0, 0, savemomx, savemomy);
if (!vertispeed)
{
fixed_t finalSpeed = FixedDiv(horizspeed, hscale);
fixed_t pSpeed = object->player->speed;
// Scale to gamespeed
finalSpeed = FixedMul(finalSpeed, K_GetKartGameSpeedScalar(gamespeed));
if (pSpeed > finalSpeed)
finalSpeed = pSpeed;
// Reflect your momentum angle against the surface of horizontal springs.
// This makes it a bit more interesting & unique than just being a speed boost in a pre-defined direction
if (savemomx || savemomy)
{
angle_t momang;
INT32 angoffset;
boolean subtract = false;
P_InstaThrustEvenIn2D(object, spring->angle, FixedMul(finalSpeed,FixedSqrt(FixedMul(hscale, spring->scale))));
momang = R_PointToAngle2(0, 0, savemomx, savemomy);
angoffset = momang;
angoffset -= spring->angle; // Subtract
// Flip on wrong side
if ((angle_t)angoffset > ANGLE_180)
{
angoffset = InvAngle((angle_t)angoffset);
subtract = !subtract;
}
// Fix going directly against the spring's angle sending you the wrong way
if ((spring->angle - momang) > ANGLE_90)
angoffset = ANGLE_180 - angoffset;
// Offset is reduced to cap it (90 / 2 = max of 45 degrees)
angoffset /= 2;
// Reduce further based on how slow your speed is compared to the spring's speed
if (finalSpeed > objectSpeed)
angoffset = FixedDiv(angoffset, FixedDiv(finalSpeed, objectSpeed));
if (subtract)
angoffset = (signed)(spring->angle) - angoffset;
else
angoffset = (signed)(spring->angle) + angoffset;
finalAngle = angoffset;
}
}
if (object->player)
{
// Less friction when hitting horizontal springs
if (!vertispeed)
{
if (!object->player->kartstuff[k_tiregrease])
{
UINT8 i;
for (i = 0; i < 2; i++)
{
mobj_t *grease;
grease = P_SpawnMobj(object->x, object->y, object->z, MT_TIREGREASE);
P_SetTarget(&grease->target, object);
grease->angle = R_PointToAngle2(0, 0, object->momx, object->momy);
grease->extravalue1 = i;
}
}
object->player->kartstuff[k_tiregrease] = greasetics; //FixedMul(greasetics << FRACBITS, finalSpeed/72) >> FRACBITS
}
}
// 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))));
}
// Re-solidify
@ -318,46 +396,12 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
if (spring->flags & MF_ENEMY) // Spring shells
P_SetTarget(&spring->target, object);
if (horizspeed && object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0)
{
object->angle = spring->angle;
if (!demo.playback || P_AnalogMove(object->player))
{
if (object->player == &players[consoleplayer])
localangle[0] = spring->angle;
else if (object->player == &players[displayplayers[1]])
localangle[1] = spring->angle;
else if (object->player == &players[displayplayers[2]])
localangle[2] = spring->angle;
else if (object->player == &players[displayplayers[3]])
localangle[3] = spring->angle;
}
}
//pflags = object->player->pflags & (PF_JUMPED|PF_SPINNING|PF_THOKKED); // I still need these.
P_ResetPlayer(object->player);
/* // SRB2kart - Springs don't need to change player state in kart.
if (P_MobjFlip(object)*vertispeed > 0)
P_SetPlayerMobjState(object, S_PLAY_SPRING);
else if (P_MobjFlip(object)*vertispeed < 0)
P_SetPlayerMobjState(object, S_PLAY_FALL1);
else // horizontal spring
{
if (pflags & (PF_JUMPED|PF_SPINNING) && object->player->panim == PA_ROLL)
object->player->pflags = pflags;
else
P_SetPlayerMobjState(object, S_PLAY_RUN1);
}
if (spring->info->painchance)
{
object->player->pflags |= PF_JUMPED;
P_SetPlayerMobjState(object, S_PLAY_ATK1);
}
*/
object->player->kartstuff[k_springstars] = max(vertispeed, horizspeed) / FRACUNIT / 2;
object->player->kartstuff[k_springcolor] = starcolor;
}
return true;
}
@ -1273,6 +1317,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
//else if (tmz > thzh - sprarea && tmz < thzh) // Don't damage people springing up / down
return true;
}
// missiles can hit other things
if (tmthing->flags & MF_MISSILE || tmthing->type == MT_SHELL)
{
@ -2869,27 +2914,18 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
if (!(thing->flags & MF_NOCLIP))
{
//All things are affected by their scale.
fixed_t maxstep = FixedMul(MAXSTEPMOVE, mapobjectscale);
const fixed_t maxstepmove = FixedMul(MAXSTEPMOVE, mapobjectscale);
fixed_t maxstep = maxstepmove;
if (thing->player)
{
// 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 <<= 1;
// 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 = 0;
if (thing->player && thing->player->kartstuff[k_waterskip])
maxstep += maxstepmove; // Add some extra stepmove when waterskipping
// 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;
@ -2912,12 +2948,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.
@ -3019,14 +3050,24 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
P_HandleSlopeLanding(thing, tmfloorslope);
if (thing->momz <= 0)
{
thing->standingslope = tmfloorslope;
#ifdef HWRENDER
thing->modeltilt = thing->standingslope;
#endif
}
}
else if (thing->z+thing->height >= tmceilingz && (thing->eflags & MFE_VERTICALFLIP)) {
if (!startingonground && tmceilingslope)
P_HandleSlopeLanding(thing, tmceilingslope);
if (thing->momz >= 0)
{
thing->standingslope = tmceilingslope;
#ifdef HWRENDER
thing->modeltilt = thing->standingslope;
#endif
}
}
}
else // don't set standingslope if you're not going to clip against it
@ -4853,7 +4894,7 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
if (!(rover->flags & FF_EXISTS))
continue;
if ((!(rover->flags & FF_SOLID || rover->flags & FF_QUICKSAND) || (rover->flags & FF_SWIMMABLE)))
if (!((rover->flags & FF_SOLID) || (rover->flags & FF_QUICKSAND)) || (rover->flags & FF_SWIMMABLE))
continue;
topheight = *rover->topheight;

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,9 +319,6 @@ typedef struct mobj_s
struct mobj_s *hnext;
struct mobj_s *hprev;
mobjtype_t type;
const mobjinfo_t *info; // &mobjinfo[mobj->type]
INT32 health; // for player this is rings + 1
// Movement direction, movement generation (zig-zagging).
@ -370,10 +365,16 @@ typedef struct mobj_s
#ifdef ESLOPE
struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?)
#ifdef HWRENDER
struct pslope_s *modeltilt; // Slope used for model tilting. Also is not synched, this is totally visual.
#endif
#endif
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;
@ -389,6 +390,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;
@ -456,8 +460,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

@ -34,6 +34,9 @@
#include "p_slopes.h"
#endif
// SRB2Kart
#include "k_pwrlv.h"
savedata_t savedata;
UINT8 *save_p;
@ -953,8 +956,8 @@ typedef enum
MD2_EXTVAL2 = 1<<6,
MD2_HNEXT = 1<<7,
MD2_HPREV = 1<<8,
MD2_COLORIZED = 1<<9,
MD2_WAYPOINTCAP = 1<<10
MD2_COLORIZED = 1<<9,
MD2_WAYPOINTCAP = 1<<10
#ifdef ESLOPE
, MD2_SLOPE = 1<<11
#endif
@ -2150,7 +2153,12 @@ static void LoadMobjThinker(actionf_p1 thinker)
mobj->hprev = (mobj_t *)(size_t)READUINT32(save_p);
#ifdef ESLOPE
if (diff2 & MD2_SLOPE)
{
mobj->standingslope = P_SlopeById(READUINT16(save_p));
#ifdef HWRENDER
mobj->modeltilt = mobj->standingslope;
#endif
}
#endif
if (diff2 & MD2_COLORIZED)
mobj->colorized = READUINT8(save_p);
@ -3106,7 +3114,7 @@ static inline void P_NetArchiveSpecials(void)
WRITEUINT32(save_p, 0xffffffff);
// Sky number
WRITEINT32(save_p, globallevelskynum);
WRITESTRINGN(save_p, globallevelskytexture, 9);
// Current global weather type
WRITEUINT8(save_p, globalweather);
@ -3125,8 +3133,8 @@ static inline void P_NetArchiveSpecials(void)
//
static void P_NetUnArchiveSpecials(void)
{
char skytex[9];
size_t i;
INT32 j;
if (READUINT32(save_p) != ARCHIVEBLOCK_SPECIALS)
I_Error("Bad $$$.sav at archive block Specials");
@ -3139,9 +3147,9 @@ static void P_NetUnArchiveSpecials(void)
itemrespawntime[iquehead++] = READINT32(save_p);
}
j = READINT32(save_p);
if (j != globallevelskynum)
P_SetupLevelSky(j, true);
READSTRINGN(save_p, skytex, sizeof(skytex));
if (strcmp(skytex, globallevelskytexture))
P_SetupLevelSky(skytex, true);
globalweather = READUINT8(save_p);
@ -3297,14 +3305,28 @@ static void P_NetArchiveMisc(void)
WRITEUINT8(save_p, franticitems);
WRITEUINT8(save_p, comeback);
WRITESINT8(save_p, speedscramble);
WRITESINT8(save_p, encorescramble);
for (i = 0; i < 4; i++)
WRITESINT8(save_p, battlewanted[i]);
// battleovertime_t
WRITEUINT16(save_p, battleovertime.enabled);
WRITEFIXED(save_p, battleovertime.radius);
WRITEFIXED(save_p, battleovertime.minradius);
WRITEFIXED(save_p, battleovertime.x);
WRITEFIXED(save_p, battleovertime.y);
WRITEFIXED(save_p, battleovertime.z);
WRITEUINT32(save_p, wantedcalcdelay);
WRITEUINT32(save_p, indirectitemcooldown);
WRITEUINT32(save_p, hyubgone);
WRITEUINT32(save_p, mapreset);
WRITEUINT8(save_p, nospectategrief);
for (i = 0; i < MAXPLAYERS; i++)
WRITEINT16(save_p, nospectategrief[i]);
WRITEUINT8(save_p, thwompsactive);
WRITESINT8(save_p, spbplace);
@ -3406,14 +3428,28 @@ static inline boolean P_NetUnArchiveMisc(void)
franticitems = (boolean)READUINT8(save_p);
comeback = (boolean)READUINT8(save_p);
speedscramble = READSINT8(save_p);
encorescramble = READSINT8(save_p);
for (i = 0; i < 4; i++)
battlewanted[i] = READSINT8(save_p);
// battleovertime_t
battleovertime.enabled = READUINT16(save_p);
battleovertime.radius = READFIXED(save_p);
battleovertime.minradius = READFIXED(save_p);
battleovertime.x = READFIXED(save_p);
battleovertime.y = READFIXED(save_p);
battleovertime.z = READFIXED(save_p);
wantedcalcdelay = READUINT32(save_p);
indirectitemcooldown = READUINT32(save_p);
hyubgone = READUINT32(save_p);
mapreset = READUINT32(save_p);
nospectategrief = READUINT8(save_p);
for (i = 0; i < MAXPLAYERS; i++)
nospectategrief[i] = READINT16(save_p);
thwompsactive = (boolean)READUINT8(save_p);
spbplace = READSINT8(save_p);

View file

@ -84,6 +84,7 @@
// SRB2Kart
#include "k_kart.h"
#include "k_pwrlv.h"
#include "k_waypoint.h"
//
@ -181,6 +182,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);
@ -208,8 +211,9 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
mapheaderinfo[num]->forcecharacter[0] = '\0';
DEH_WriteUndoline("WEATHER", va("%d", mapheaderinfo[num]->weather), UNDO_NONE);
mapheaderinfo[num]->weather = 0;
DEH_WriteUndoline("SKYNUM", va("%d", mapheaderinfo[num]->skynum), UNDO_NONE);
mapheaderinfo[num]->skynum = 1;
DEH_WriteUndoline("SKYTEXTURE", va("%d", mapheaderinfo[num]->skytexture), UNDO_NONE);
snprintf(mapheaderinfo[num]->skytexture, 9, "SKY1");
mapheaderinfo[num]->skytexture[8] = 0;
DEH_WriteUndoline("SKYBOXSCALEX", va("%d", mapheaderinfo[num]->skybox_scalex), UNDO_NONE);
mapheaderinfo[num]->skybox_scalex = 16;
DEH_WriteUndoline("SKYBOXSCALEY", va("%d", mapheaderinfo[num]->skybox_scaley), UNDO_NONE);
@ -245,7 +249,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
@ -2256,17 +2260,18 @@ static inline boolean P_CheckLevel(lumpnum_t lumpnum)
/** Sets up a sky texture to use for the level.
* The sky texture is used instead of F_SKY1.
*/
void P_SetupLevelSky(INT32 skynum, boolean global)
void P_SetupLevelSky(const char *skytexname, boolean global)
{
char skytexname[12];
char tex[9];
strncpy(tex, skytexname, 9);
tex[8] = 0;
sprintf(skytexname, "SKY%d", skynum);
skytexture = R_TextureNumForName(skytexname);
levelskynum = skynum;
skytexture = R_TextureNumForName(tex);
strncpy(levelskytexture, tex, 9);
// Global change
if (global)
globallevelskynum = levelskynum;
strncpy(globallevelskytexture, tex, 9);
// Don't go beyond for dedicated servers
if (dedicated)
@ -2386,22 +2391,30 @@ static void P_LevelInitStuff(void)
// SRB2Kart: map load variables
if (modeattacking) // Just play it safe and set everything
{
gamespeed = 2;
gamespeed = KARTSPEED_HARD;
franticitems = false;
comeback = true;
}
else
{
if (G_BattleGametype())
gamespeed = 0;
gamespeed = KARTSPEED_EASY;
else
gamespeed = (UINT8)cv_kartspeed.value;
{
if (cv_kartspeed.value == KARTSPEED_AUTO)
gamespeed = ((speedscramble == -1) ? KARTSPEED_NORMAL : (UINT8)speedscramble);
else
gamespeed = (UINT8)cv_kartspeed.value;
}
franticitems = (boolean)cv_kartfrantic.value;
comeback = (boolean)cv_kartcomeback.value;
}
for (i = 0; i < 4; i++)
battlewanted[i] = -1;
memset(&battleovertime, 0, sizeof(struct battleovertime));
speedscramble = encorescramble = -1;
}
//
@ -2779,7 +2792,7 @@ boolean P_SetupLevel(boolean skipprecip)
// use gamemap to get map number.
// 99% of the things already did, so.
// Map header should always be in place at this point
INT32 i, loadprecip = 1, ranspecialwipe = 0;
INT32 i, loadprecip = 1;
INT32 loademblems = 1;
INT32 fromnetsave = 0;
boolean loadedbm = false;
@ -2858,36 +2871,50 @@ boolean P_SetupLevel(boolean skipprecip)
S_StartSound(NULL, sfx_ruby1);
// Fade to an inverted screen, with a circle fade...
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 209);
V_EncoreInvertScreen();
F_WipeEndScreen();
F_RunWipe(wipedefs[wipe_speclevel_towhite], false);
F_RunWipe(wipedefs[wipe_encore_toinvert], false, NULL, false, false);
// Hold on invert for extra effect.
// (This define might be useful for other areas of code? Not sure)
#define WAIT(timetowait) \
locstarttime = nowtime = lastwipetic; \
endtime = locstarttime + timetowait; \
while (nowtime < endtime) \
{ \
while (!((nowtime = I_GetTime()) - lastwipetic)) \
I_Sleep(); \
lastwipetic = nowtime; \
if (moviemode) \
M_SaveFrame(); \
NetKeepAlive(); \
} \
WAIT((3*TICRATE)/2);
S_StartSound(NULL, sfx_ruby2);
// Then fade to a white screen
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 0);
F_WipeEndScreen();
F_RunWipe(wipedefs[wipe_level_final], false);
locstarttime = nowtime = lastwipetic;
endtime = locstarttime + (3*TICRATE)/2;
F_RunWipe(wipedefs[wipe_encore_towhite], false, "FADEMAP1", false, true); // wiggle the screen during this!
// Hold on white for extra effect.
while (nowtime < endtime)
{
// wait loop
while (!((nowtime = I_GetTime()) - lastwipetic))
I_Sleep();
lastwipetic = nowtime;
if (moviemode) // make sure we save frames for the white hold too
M_SaveFrame();
// THEN fade to a black screen.
F_WipeStartScreen();
// Keep the network alive
NetKeepAlive();
}
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
F_WipeEndScreen();
ranspecialwipe = 1;
F_RunWipe(wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false);
// Wait a bit longer.
WAIT((3*TICRATE)/4);
}
// Make sure all sounds are stopped before Z_FreeTags.
@ -2898,17 +2925,18 @@ boolean P_SetupLevel(boolean skipprecip)
// We should be fine starting it here.
S_Start();
levelfadecol = (encoremode && !ranspecialwipe ? 209 : 0);
levelfadecol = (encoremode ? 0 : 31);
// Let's fade to white here
// But only if we didn't do the encore startup wipe
if (rendermode != render_none && !ranspecialwipe && !demo.rewinding)
if (rendermode != render_none && !demo.rewinding)
{
F_WipeStartScreen();
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol);
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol);
F_WipeEndScreen();
F_RunWipe(wipedefs[(encoremode ? wipe_level_final : wipe_level_toblack)], false);
F_RunWipe(wipedefs[wipe_level_toblack], false, ((levelfadecol == 0) ? "FADEMAP1" : "FADEMAP0"), false, false);
}
// Reset the palette now all fades have been done
@ -2974,7 +3002,7 @@ boolean P_SetupLevel(boolean skipprecip)
CON_SetupBackColormap();
// SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skytexture, true);
P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5);
@ -3283,7 +3311,10 @@ boolean P_SetupLevel(boolean skipprecip)
indirectitemcooldown = 0;
hyubgone = 0;
mapreset = 0;
nospectategrief = 0;
for (i = 0; i < MAXPLAYERS; i++)
nospectategrief[i] = -1;
thwompsactive = false;
spbplace = -1;

View file

@ -54,7 +54,7 @@ INT32 P_CheckLevelFlat(const char *flatname);
extern size_t nummapthings;
extern mapthing_t *mapthings;
void P_SetupLevelSky(INT32 skynum, boolean global);
void P_SetupLevelSky(const char *skytexname, boolean global);
#ifdef SCANTHINGS
void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
#endif

View file

@ -836,6 +836,9 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
if (P_MobjFlip(thing)*(thing->momz) < 0) { // falling, land on slope
thing->momz = -P_MobjFlip(thing);
thing->standingslope = slope;
#ifdef HWRENDER
thing->modeltilt = thing->standingslope;
#endif
}
return;
}
@ -852,6 +855,9 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
thing->momz = -P_MobjFlip(thing);
thing->standingslope = slope;
#ifdef HWRENDER
thing->modeltilt = thing->standingslope;
#endif
}
}
@ -871,33 +877,31 @@ void P_ButteredSlope(mobj_t *mo)
return; // don't slide down slopes if you can't touch them or you're not affected by gravity
if (mo->player) {
if (abs(mo->standingslope->zdelta) < FRACUNIT/4 && !(mo->player->pflags & PF_SPINNING))
// Changed in kart to only not apply physics on very slight slopes (I think about 4 degree angles)
if (abs(mo->standingslope->zdelta) < FRACUNIT/21 && !(mo->player->pflags & PF_SPINNING))
return; // Don't slide on non-steep slopes unless spinning
// This only means you can be stopped on slopes that aren't steeper than 45 degrees
if (abs(mo->standingslope->zdelta) < FRACUNIT/2 && !(mo->player->rmomx || mo->player->rmomy))
return; // Allow the player to stand still on slopes below a certain steepness
}
thrust = FINESINE(mo->standingslope->zangle>>ANGLETOFINESHIFT) * 15 / 16 * (mo->eflags & MFE_VERTICALFLIP ? 1 : -1);
thrust = FINESINE(mo->standingslope->zangle>>ANGLETOFINESHIFT) * 4 / 5 * (mo->eflags & MFE_VERTICALFLIP ? 1 : -1);
if (mo->player && (mo->player->pflags & PF_SPINNING)) {
fixed_t mult = 0;
if (mo->player) {
fixed_t mult = FRACUNIT;
if (mo->momx || mo->momy) {
angle_t angle = R_PointToAngle2(0, 0, mo->momx, mo->momy) - mo->standingslope->xydirection;
if (P_MobjFlip(mo) * mo->standingslope->zdelta < 0)
angle ^= ANGLE_180;
mult = FINECOSINE(angle >> ANGLETOFINESHIFT);
mult = FRACUNIT + (FRACUNIT + FINECOSINE(angle>>ANGLETOFINESHIFT))*3/2;
}
thrust = FixedMul(thrust, FRACUNIT*2/3 + mult/8);
thrust = FixedMul(thrust, mult);
}
if (mo->momx || mo->momy) // Slightly increase thrust based on the object's speed
thrust = FixedMul(thrust, FRACUNIT+P_AproxDistance(mo->momx, mo->momy)/16);
// This makes it harder to zigzag up steep slopes, as well as allows greater top speed when rolling down
// Let's get the gravity strength for the object...
thrust = FixedMul(thrust, abs(P_GetMobjGravity(mo)));

View file

@ -2003,57 +2003,28 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller)
//
// Switches the weather!
//
void P_SwitchWeather(INT32 weathernum)
void P_SwitchWeather(UINT8 newWeather)
{
boolean purge = false;
INT32 swap = 0;
mobjtype_t swap = MT_NULL;
switch (weathernum)
if (precipprops[newWeather].type == MT_NULL)
{
case PRECIP_NONE: // None
if (curWeather == PRECIP_NONE)
return; // Nothing to do.
purge = true;
break;
case PRECIP_STORM: // Storm
case PRECIP_STORM_NOSTRIKES: // Storm w/ no lightning
case PRECIP_RAIN: // Rain
if (curWeather == PRECIP_SNOW || curWeather == PRECIP_BLANK || curWeather == PRECIP_STORM_NORAIN)
swap = PRECIP_RAIN;
break;
case PRECIP_SNOW: // Snow
if (curWeather == PRECIP_SNOW)
return; // Nothing to do.
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES || curWeather == PRECIP_BLANK || curWeather == PRECIP_STORM_NORAIN)
swap = PRECIP_SNOW; // Need to delete the other precips.
break;
case PRECIP_STORM_NORAIN: // Storm w/o rain
if (curWeather == PRECIP_SNOW
|| curWeather == PRECIP_STORM
|| curWeather == PRECIP_STORM_NOSTRIKES
|| curWeather == PRECIP_RAIN
|| curWeather == PRECIP_BLANK)
swap = PRECIP_STORM_NORAIN;
else if (curWeather == PRECIP_STORM_NORAIN)
return;
break;
case PRECIP_BLANK:
if (curWeather == PRECIP_SNOW
|| curWeather == PRECIP_STORM
|| curWeather == PRECIP_STORM_NOSTRIKES
|| curWeather == PRECIP_RAIN)
swap = PRECIP_BLANK;
else if (curWeather == PRECIP_STORM_NORAIN)
swap = PRECIP_BLANK;
else if (curWeather == PRECIP_BLANK)
return;
break;
default:
CONS_Debug(DBG_GAMELOGIC, "P_SwitchWeather: Unknown weather type %d.\n", weathernum);
break;
// New type is null, we want to purge the weather.
if (precipprops[curWeather].type == MT_NULL)
return; // Nothing to do.
purge = true;
}
else
{
if (precipprops[curWeather].type != MT_NULL)
{
// There are already existing weather particles to reuse.
swap = precipprops[newWeather].type;
}
}
if (purge)
if (purge == true)
{
thinker_t *think;
precipmobj_t *precipmobj;
@ -2068,136 +2039,54 @@ void P_SwitchWeather(INT32 weathernum)
P_RemovePrecipMobj(precipmobj);
}
}
else if (swap && !((swap == PRECIP_BLANK && curWeather == PRECIP_STORM_NORAIN) || (swap == PRECIP_STORM_NORAIN && curWeather == PRECIP_BLANK))) // Rather than respawn all that crap, reuse it!
else if (swap != MT_NULL) // Rather than respawn all that crap, reuse it!
{
UINT8 randomstates = (UINT8)mobjinfo[swap].damage;
thinker_t *think;
precipmobj_t *precipmobj;
state_t *st;
statenum_t st;
for (think = thinkercap.next; think != &thinkercap; think = think->next)
{
if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
continue; // not a precipmobj thinker
precipmobj = (precipmobj_t *)think;
if (swap == PRECIP_RAIN) // Snow To Rain
precipmobj->flags = mobjinfo[swap].flags;
st = mobjinfo[swap].spawnstate;
if (randomstates > 0)
{
precipmobj->flags = mobjinfo[MT_RAIN].flags;
st = &states[mobjinfo[MT_RAIN].spawnstate];
precipmobj->state = st;
precipmobj->tics = st->tics;
precipmobj->sprite = st->sprite;
precipmobj->frame = st->frame;
precipmobj->momz = mobjinfo[MT_RAIN].speed;
UINT8 mrand = M_RandomByte();
UINT8 threshold = UINT8_MAX / (randomstates + 1);
UINT8 i;
precipmobj->precipflags &= ~PCF_INVISIBLE;
precipmobj->precipflags |= PCF_RAIN;
//think->function.acp1 = (actionf_p1)P_RainThinker;
for (i = 0; i < randomstates; i++)
{
if (mrand < (threshold * (i+1)))
{
st += i+1;
break;
}
}
}
else if (swap == PRECIP_SNOW) // Rain To Snow
{
INT32 z;
precipmobj->flags = mobjinfo[MT_SNOWFLAKE].flags;
z = M_RandomByte();
precipmobj->state = &states[st];
precipmobj->tics = precipmobj->state->tics;
precipmobj->sprite = precipmobj->state->sprite;
precipmobj->frame = precipmobj->state->frame;
if (z < 64)
z = 2;
else if (z < 144)
z = 1;
else
z = 0;
st = &states[mobjinfo[MT_SNOWFLAKE].spawnstate+z];
precipmobj->state = st;
precipmobj->tics = st->tics;
precipmobj->sprite = st->sprite;
precipmobj->frame = st->frame;
precipmobj->momz = mobjinfo[MT_SNOWFLAKE].speed;
precipmobj->precipflags &= ~(PCF_INVISIBLE|PCF_RAIN);
//think->function.acp1 = (actionf_p1)P_SnowThinker;
}
else if (swap == PRECIP_BLANK || swap == PRECIP_STORM_NORAIN) // Remove precip, but keep it around for reuse.
{
//think->function.acp1 = (actionf_p1)P_NullPrecipThinker;
precipmobj->precipflags |= PCF_INVISIBLE;
}
precipmobj->momz = mobjinfo[swap].speed;
precipmobj->precipflags &= ~PCF_INVISIBLE;
}
}
switch (weathernum)
{
case PRECIP_SNOW: // snow
curWeather = PRECIP_SNOW;
curWeather = newWeather;
if (!swap)
P_SpawnPrecipitation();
break;
case PRECIP_RAIN: // rain
{
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_RAIN;
if (!dontspawn && !swap)
P_SpawnPrecipitation();
break;
}
case PRECIP_STORM: // storm
{
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_STORM;
if (!dontspawn && !swap)
P_SpawnPrecipitation();
break;
}
case PRECIP_STORM_NOSTRIKES: // storm w/o lightning
{
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_STORM_NOSTRIKES;
if (!dontspawn && !swap)
P_SpawnPrecipitation();
break;
}
case PRECIP_STORM_NORAIN: // storm w/o rain
curWeather = PRECIP_STORM_NORAIN;
if (!swap)
P_SpawnPrecipitation();
break;
case PRECIP_BLANK:
curWeather = PRECIP_BLANK;
if (!swap)
P_SpawnPrecipitation();
break;
default:
curWeather = PRECIP_NONE;
break;
}
if (swap == MT_NULL && precipprops[newWeather].type != MT_NULL)
P_SpawnPrecipitation();
}
// Passed over the finish line forwards
@ -2957,7 +2846,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 423: // Change Sky
if ((mo && mo->player && P_IsLocalPlayer(mo->player)) || (line->flags & ML_NOCLIMB))
P_SetupLevelSky(sides[line->sidenum[0]].textureoffset>>FRACBITS, (line->flags & ML_NOCLIMB));
P_SetupLevelSky(sides[line->sidenum[0]].text, (line->flags & ML_NOCLIMB));
break;
case 424: // Change Weather
@ -3387,6 +3276,76 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
}
}
static void P_SetupSignObject(mobj_t *sign, mobj_t *pmo)
{
mobj_t *cur = sign, *prev = NULL;
// Setup the sign itself
P_SetTarget(&sign->target, pmo);
P_SetMobjState(sign, S_SIGN_POLE);
sign->movefactor = sign->z;
sign->z += (768*sign->scale) * P_MobjFlip(sign);
sign->movecount = 1;
sign->extravalue1 = AngleFixed(sign->angle) >> FRACBITS;
// Setup the overlay pieces
// Front
cur->hnext = P_SpawnMobj(sign->x, sign->y, sign->z, MT_SIGN_PIECE);
P_SetTarget(&cur->hnext->target, sign);
P_SetMobjState(cur->hnext, S_SIGN_FACE);
cur->hnext->extravalue1 = 6;
cur->hnext->extravalue2 = 0;
prev = cur;
cur = cur->hnext;
cur->hprev = prev;
// Player icon
cur->hnext = P_SpawnMobj(sign->x, sign->y, sign->z, MT_SIGN_PIECE);
P_SetTarget(&cur->hnext->target, sign);
cur->hnext->skin = pmo->skin;
P_SetMobjState(cur->hnext, S_PLAY_SIGN);
cur->hnext->extravalue1 = 7;
cur->hnext->extravalue2 = 0;
prev = cur;
cur = cur->hnext;
cur->hprev = prev;
// Back
cur->hnext = P_SpawnMobj(sign->x, sign->y, sign->z, MT_SIGN_PIECE);
P_SetTarget(&cur->hnext->target, sign);
P_SetMobjState(cur->hnext, S_SIGN_BACK);
cur->hnext->extravalue1 = 6;
cur->hnext->extravalue2 = 2;
prev = cur;
cur = cur->hnext;
cur->hprev = prev;
// Sides
cur->hnext = P_SpawnMobj(sign->x, sign->y, sign->z, MT_SIGN_PIECE);
P_SetTarget(&cur->hnext->target, sign);
P_SetMobjState(cur->hnext, S_SIGN_SIDE);
cur->hnext->extravalue1 = 30;
cur->hnext->extravalue2 = 1;
prev = cur;
cur = cur->hnext;
cur->hprev = prev;
cur->hnext = P_SpawnMobj(sign->x, sign->y, sign->z, MT_SIGN_PIECE);
P_SetTarget(&cur->hnext->target, sign);
P_SetMobjState(cur->hnext, S_SIGN_SIDE);
cur->hnext->extravalue1 = 30;
cur->hnext->extravalue2 = 3;
prev = cur;
cur = cur->hnext;
cur->hprev = prev;
}
//
// P_SetupSignExit
//
@ -3412,13 +3371,7 @@ void P_SetupSignExit(player_t *player)
if (thing->state != &states[thing->info->spawnstate])
continue;
P_SetTarget(&thing->target, player->mo);
P_SetMobjState(thing, S_SIGN1);
// SRB2Kart: Set sign spinning variables
thing->movefactor = thing->z;
thing->z += (768*thing->scale) * P_MobjFlip(thing);
thing->movecount = 1;
P_SetupSignObject(thing, player->mo);
++numfound;
}
@ -3440,14 +3393,7 @@ void P_SetupSignExit(player_t *player)
if (thing->state != &states[thing->info->spawnstate])
continue;
P_SetTarget(&thing->target, player->mo);
P_SetMobjState(thing, S_SIGN1);
// SRB2Kart: Set sign spinning variables
thing->movefactor = thing->z;
thing->z += (768*thing->scale) * P_MobjFlip(thing);
thing->movecount = 1;
P_SetupSignObject(thing, player->mo);
++numfound;
}
@ -3455,14 +3401,11 @@ void P_SetupSignExit(player_t *player)
return;
// SRB2Kart: FINALLY, add in an alternative if no place is found
if (player->mo)
if (player->mo && !P_MobjWasRemoved(player->mo))
{
mobj_t *sign = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + (768*mapobjectscale), MT_SIGN);
P_SetTarget(&sign->target, player->mo);
P_SetMobjState(sign, S_SIGN1);
sign->movefactor = player->mo->floorz;
sign->movecount = 1;
thing = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->floorz, MT_SIGN);
thing->angle = player->mo->angle;
P_SetupSignObject(thing, player->mo);
}
}
@ -3516,7 +3459,7 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
}
//
// P_PlayerTouchingSectorSpecial
// P_MobjTouchingSectorSpecial
//
// Replaces the old player->specialsector.
// This allows a player to touch more than
@ -3526,60 +3469,86 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
// the particular type that it finds.
// Returns NULL if it doesn't find it.
//
sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 number)
// Sal: Couldn't see a reason for this to
// be a player_t only function.
//
sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number, boolean touchground)
{
fixed_t topheight, bottomheight;
msecnode_t *node;
ffloor_t *rover;
if (!player->mo)
if (!mo)
return NULL;
// Check default case first
if (GETSECSPECIAL(player->mo->subsector->sector->special, section) == number)
return player->mo->subsector->sector;
if (GETSECSPECIAL(mo->subsector->sector->special, section) == number)
{
if (touchground)
{
topheight = P_GetSpecialTopZ(mo, mo->subsector->sector, mo->subsector->sector);
bottomheight = P_GetSpecialBottomZ(mo, mo->subsector->sector, mo->subsector->sector);
// Thing must be on top of the floor to be affected...
if (mo->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR)
{
if (!(mo->eflags & MFE_VERTICALFLIP) && mo->z <= bottomheight)
return mo->subsector->sector;
}
if (mo->subsector->sector->flags & SF_FLIPSPECIAL_CEILING)
{
if ((mo->eflags & MFE_VERTICALFLIP) && mo->z + mo->height >= topheight)
return mo->subsector->sector;
}
}
else
{
return mo->subsector->sector;
}
}
// Hmm.. maybe there's a FOF that has it...
for (rover = player->mo->subsector->sector->ffloors; rover; rover = rover->next)
for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
{
fixed_t topheight, bottomheight;
if (GETSECSPECIAL(rover->master->frontsector->special, section) != number)
continue;
if (!(rover->flags & FF_EXISTS))
continue;
topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
topheight = P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector);
bottomheight = P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector);
// Check the 3D floor's type...
if (rover->flags & FF_BLOCKPLAYER)
if (((rover->flags & FF_BLOCKPLAYER) && mo->player)
|| ((rover->flags & FF_BLOCKOTHERS) && !mo->player))
{
// Thing must be on top of the floor to be affected...
if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
{
if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != topheight)
continue;
}
else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
{
if (!(player->mo->eflags & MFE_VERTICALFLIP)
|| player->mo->z + player->mo->height != bottomheight)
if (!(mo->eflags & MFE_VERTICALFLIP)
|| mo->z + mo->height != bottomheight)
continue;
}
else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
{
if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottomheight)
|| (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == topheight)))
continue;
}
}
else
{
// Water and DEATH FOG!!! heh
if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
if (mo->z > topheight || (mo->z + mo->height) < bottomheight)
continue;
}
@ -3587,64 +3556,86 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
return rover->master->frontsector;
}
for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (GETSECSPECIAL(node->m_sector->special, section) == number)
{
// This sector has the special we're looking for, but
// are we allowed to touch it?
if (node->m_sector == player->mo->subsector->sector
if (node->m_sector == mo->subsector->sector
|| (node->m_sector->flags & SF_TRIGGERSPECIAL_TOUCH))
return node->m_sector;
{
if (touchground)
{
topheight = P_GetSpecialTopZ(mo, node->m_sector, node->m_sector);
bottomheight = P_GetSpecialBottomZ(mo, node->m_sector, node->m_sector);
// Thing must be on top of the floor to be affected...
if (node->m_sector->flags & SF_FLIPSPECIAL_FLOOR)
{
if (!(mo->eflags & MFE_VERTICALFLIP) && mo->z <= bottomheight)
return node->m_sector;
}
if (node->m_sector->flags & SF_FLIPSPECIAL_CEILING)
{
if ((mo->eflags & MFE_VERTICALFLIP) && mo->z + mo->height >= topheight)
return node->m_sector;
}
}
else
{
return node->m_sector;
}
}
}
// Hmm.. maybe there's a FOF that has it...
for (rover = node->m_sector->ffloors; rover; rover = rover->next)
{
fixed_t topheight, bottomheight;
if (GETSECSPECIAL(rover->master->frontsector->special, section) != number)
continue;
if (!(rover->flags & FF_EXISTS))
continue;
topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
topheight = P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector);
bottomheight = P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector);
// Check the 3D floor's type...
if (rover->flags & FF_BLOCKPLAYER)
if (((rover->flags & FF_BLOCKPLAYER) && mo->player)
|| ((rover->flags & FF_BLOCKOTHERS) && !mo->player))
{
// Thing must be on top of the floor to be affected...
if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
{
if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != topheight)
continue;
}
else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
{
if (!(player->mo->eflags & MFE_VERTICALFLIP)
|| player->mo->z + player->mo->height != bottomheight)
if (!(mo->eflags & MFE_VERTICALFLIP)
|| mo->z + mo->height != bottomheight)
continue;
}
else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
{
if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottomheight)
|| (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == topheight)))
continue;
}
}
else
{
// Water and DEATH FOG!!! heh
if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
if (mo->z > topheight || (mo->z + mo->height) < bottomheight)
continue;
}
// This FOF has the special we're looking for, but are we allowed to touch it?
if (node->m_sector == player->mo->subsector->sector
if (node->m_sector == mo->subsector->sector
|| (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH))
return rover->master->frontsector;
}
@ -3792,10 +3783,9 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
break;
case 9: // Ring Drainer (Floor Touch)
case 10: // Ring Drainer (No Floor Touch)
if (leveltime % (TICRATE/2) == 0 && player->mo->health > 1)
if (leveltime % (TICRATE/2) == 0 && player->kartstuff[k_rings] > 0)
{
player->mo->health--;
player->health--;
player->kartstuff[k_rings]--;
S_StartSound(player->mo, sfx_itemup);
}
break;
@ -5723,25 +5713,10 @@ void P_InitSpecials(void)
CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false;
// Set curWeather
switch (mapheaderinfo[gamemap-1]->weather)
{
case PRECIP_SNOW: // snow
case PRECIP_RAIN: // rain
case PRECIP_STORM: // storm
case PRECIP_STORM_NORAIN: // storm w/o rain
case PRECIP_STORM_NOSTRIKES: // storm w/o lightning
curWeather = mapheaderinfo[gamemap-1]->weather;
break;
default: // blank/none
curWeather = PRECIP_NONE;
break;
}
// Set weather
curWeather = globalweather = mapheaderinfo[gamemap-1]->weather;
// Set globalweather
globalweather = mapheaderinfo[gamemap-1]->weather;
P_InitTagLists(); // Create xref tables for tags
P_InitTagLists(); // Create xref tables for tags
}
/** After the map has loaded, scans for specials that spawn 3Dfloors and

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);
@ -61,7 +61,7 @@ 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

@ -59,8 +59,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 +74,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");
@ -618,33 +608,10 @@ void P_Ticker(boolean run)
}
if (demo.playback)
{
#ifdef DEMO_COMPAT_100
if (demo.version == 0x0001)
{
G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0);
}
else
{
#endif
G_ReadDemoExtraData();
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
{
//@TODO all this throwdir stuff shouldn't be here! But it's added to maintain 1.0.4 compat for now...
// Remove for 1.1!
if (players[i].cmd.buttons & BT_FORWARD)
players[i].kartstuff[k_throwdir] = 1;
else if (players[i].cmd.buttons & BT_BACKWARD)
players[i].kartstuff[k_throwdir] = -1;
else
players[i].kartstuff[k_throwdir] = 0;
G_ReadDemoTiccmd(&players[i].cmd, i);
}
#ifdef DEMO_COMPAT_100
}
#endif
G_ReadDemoExtraData();
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
G_ReadDemoTiccmd(&players[i].cmd, i);
}
for (i = 0; i < MAXPLAYERS; i++)
@ -665,6 +632,8 @@ void P_Ticker(boolean run)
if (run)
{
P_RunThinkers();
if (G_BattleGametype() && battleovertime.enabled)
P_RunBattleOvertime();
// Run any "after all the other thinkers" stuff
for (i = 0; i < MAXPLAYERS; i++)
@ -680,8 +649,6 @@ void P_Ticker(boolean run)
//P_RunShields();
P_RunOverlays();
P_RunShadows();
P_UpdateSpecials();
P_RespawnSpecials();
@ -760,11 +727,6 @@ void P_Ticker(boolean run)
}
else if (demo.playback) // Use Ghost data for consistency checks.
{
#ifdef DEMO_COMPAT_100
if (demo.version == 0x0001)
G_ConsGhostTic(0);
else
#endif
G_ConsAllGhostTics();
}
@ -827,6 +789,8 @@ void P_PreTicker(INT32 frames)
}
P_RunThinkers();
if (G_BattleGametype() && battleovertime.enabled)
P_RunBattleOvertime();
// Run any "after all the other thinkers" stuff
for (i = 0; i < MAXPLAYERS; i++)

View file

@ -1645,12 +1645,16 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
ghost->frame |= tr_trans50<<FF_TRANSSHIFT;
ghost->fuse = ghost->info->damage;
ghost->skin = mobj->skin;
ghost->standingslope = mobj->standingslope;
#ifdef HWRENDER
ghost->modeltilt = mobj->modeltilt;
#endif
if (mobj->flags2 & MF2_OBJECTFLIP)
ghost->flags |= MF2_OBJECTFLIP;
if (!(mobj->flags & MF_DONTENCOREMAP))
mobj->flags &= ~MF_DONTENCOREMAP;
ghost->flags &= ~MF_DONTENCOREMAP;
return ghost;
}
@ -4186,27 +4190,33 @@ static void P_3dMovement(player_t *player)
// If "no" to 2, normalize to topspeed, so we can't suddenly run faster than it of our own accord.
// If "no" to 1, we're not reaching any limits yet, so ignore this entirely!
// -Shadow Hog
newMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0);
if (newMagnitude > K_GetKartSpeed(player, true)) //topspeed)
// Only do this forced cap of speed when in midair, the kart acceleration code takes into account friction, and
// doesn't let you accelerate past top speed, so this is unnecessary on the ground, but in the air is needed to
// allow for being able to change direction on spring jumps without being accelerated into the void - Sryder
if (!P_IsObjectOnGround(player->mo))
{
fixed_t tempmomx, tempmomy;
if (oldMagnitude > K_GetKartSpeed(player, true))
newMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0);
if (newMagnitude > K_GetKartSpeed(player, true)) //topspeed)
{
if (newMagnitude > oldMagnitude)
fixed_t tempmomx, tempmomy;
if (oldMagnitude > K_GetKartSpeed(player, true))
{
tempmomx = FixedMul(FixedDiv(player->mo->momx - player->cmomx, newMagnitude), oldMagnitude);
tempmomy = FixedMul(FixedDiv(player->mo->momy - player->cmomy, newMagnitude), oldMagnitude);
if (newMagnitude > oldMagnitude)
{
tempmomx = FixedMul(FixedDiv(player->mo->momx - player->cmomx, newMagnitude), oldMagnitude);
tempmomy = FixedMul(FixedDiv(player->mo->momy - player->cmomy, newMagnitude), oldMagnitude);
player->mo->momx = tempmomx + player->cmomx;
player->mo->momy = tempmomy + player->cmomy;
}
// else do nothing
}
else
{
tempmomx = FixedMul(FixedDiv(player->mo->momx - player->cmomx, newMagnitude), K_GetKartSpeed(player, true)); //topspeed)
tempmomy = FixedMul(FixedDiv(player->mo->momy - player->cmomy, newMagnitude), K_GetKartSpeed(player, true)); //topspeed)
player->mo->momx = tempmomx + player->cmomx;
player->mo->momy = tempmomy + player->cmomy;
}
// else do nothing
}
else
{
tempmomx = FixedMul(FixedDiv(player->mo->momx - player->cmomx, newMagnitude), K_GetKartSpeed(player, true)); //topspeed)
tempmomy = FixedMul(FixedDiv(player->mo->momy - player->cmomy, newMagnitude), K_GetKartSpeed(player, true)); //topspeed)
player->mo->momx = tempmomx + player->cmomx;
player->mo->momy = tempmomy + player->cmomy;
}
}
}
@ -8130,8 +8140,6 @@ void P_PlayerThink(player_t *player)
cmd = &player->cmd;
//@TODO This fixes a one-tic latency on direction handling, AND makes behavior consistent while paused, but is not BC with 1.0.4. Do this for 1.1!
#if 0
// SRB2kart
// Save the dir the player is holding
// to allow items to be thrown forward or backward.
@ -8141,7 +8149,6 @@ void P_PlayerThink(player_t *player)
player->kartstuff[k_throwdir] = -1;
else
player->kartstuff[k_throwdir] = 0;
#endif
// Add some extra randomization.
if (cmd->forwardmove)

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

@ -267,7 +267,7 @@ static UINT8 *R_GenerateTexture(size_t texnum)
texturememory += blocksize;
block = Z_Malloc(blocksize+1, PU_STATIC, &texturecache[texnum]);
memset(block, 0xF7, blocksize+1); // Transparency hack
memset(block, 0xFF, blocksize+1); // TRANSPARENTPIXEL
// columns lookup table
colofs = (UINT32 *)(void *)block;
@ -1177,7 +1177,6 @@ void R_ClearColormaps(void)
//
static double deltas[256][3], map[256][3];
static UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b);
static int RoundUp(double number);
#ifdef HASINVERT
@ -1403,7 +1402,7 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3)
// Thanks to quake2 source!
// utils3/qdata/images.c
static UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b)
UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b)
{
int dr, dg, db;
int distortion, bestdistortion = 256 * 256 * 4, bestcolor = 0, i;
@ -1631,7 +1630,7 @@ void R_PrecacheLevel(void)
// Sky texture is always present.
// Note that F_SKY1 is the name used to indicate a sky floor/ceiling as a flat,
// while the sky texture is stored like a wall texture, with a skynum dependent name.
// while the sky texture is stored like a wall texture, with a texture name set by the map.
texturepresent[skytexture] = 1;
texturememory = 0;

View file

@ -93,6 +93,7 @@ void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap);
void R_ClearColormaps(void);
INT32 R_ColormapNumForName(char *name);
INT32 R_CreateColormap(char *p1, char *p2, char *p3);
UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b);
#ifdef HASINVERT
void R_MakeInvertmap(void);
#endif

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

@ -734,7 +734,7 @@ void R_DrawPlanes(void)
dc_x = x;
dc_source =
R_GetColumn(texturetranslation[skytexture],
angle);
-angle); // Negative because skies were being drawn horizontally flipped
wallcolfunc();
}
}

View file

@ -47,8 +47,8 @@ fixed_t skyscale;
/** \brief used for keeping track of the current sky
*/
INT32 levelskynum;
INT32 globallevelskynum;
char levelskytexture[9];
char globallevelskytexture[9];
/** \brief The R_SetupSkyDraw function

View file

@ -30,8 +30,8 @@ extern INT32 skytexture, skytexturemid;
extern fixed_t skyscale;
extern INT32 skyflatnum;
extern INT32 levelskynum;
extern INT32 globallevelskynum;
extern char levelskytexture[9];
extern char globallevelskytexture[9];
// call after skytexture is set to adapt for old/new skies
void R_SetupSkyDraw(void);

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;

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

@ -427,13 +427,13 @@ void SCR_DisplayTicRate(void)
ticcntcolor|V_NOSCALESTART, va("%02d/%02u", totaltics, TICRATE));*/
// draw "FPS"
V_DrawFixedPatch(306<<FRACBITS, 183<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT, framecounter, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE));
V_DrawFixedPatch(306<<FRACBITS, 183<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, framecounter, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE));
// draw total frame:
V_DrawPingNum(318, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT, TICRATE, ticcntcolor);
V_DrawPingNum(318, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, TICRATE, ticcntcolor);
// draw "/"
V_DrawFixedPatch(306<<FRACBITS, 190<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT, frameslash, ticcntcolor);
V_DrawFixedPatch(306<<FRACBITS, 190<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, frameslash, ticcntcolor);
// draw our actual framerate
V_DrawPingNum(306, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT, totaltics, ticcntcolor);
V_DrawPingNum(306, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, totaltics, ticcntcolor);
lasttic = ontic;
@ -448,6 +448,6 @@ void SCR_DisplayLocalPing(void)
if (cv_showping.value == 1 || (cv_showping.value == 2 && ping > servermaxping)) // only show 2 (warning) if our ping is at a bad level
{
INT32 dispy = cv_ticrate.value ? 160 : 181;
HU_drawPing(307, dispy, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM);
HU_drawPing(307, dispy, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM | V_HUDTRANS);
}
}

View file

@ -165,6 +165,7 @@ static char returnWadPath[256];
#include "../d_net.h"
#include "../g_game.h"
#include "../filesrch.h"
#include "../k_pwrlv.h"
#include "endtxt.h"
#include "sdlmain.h"
@ -3056,6 +3057,11 @@ void I_Quit(void)
#ifndef NONET
D_SaveBan(); // save the ban list
#endif
// Make sure you lose points for ALT-F4
if (Playing())
K_PlayerForfeit(consoleplayer, true);
G_SaveGameData(false); // Tails 12-08-2002
//added:16-02-98: when recording a demo, should exit using 'q' key,
// but sometimes we forget and use 'F10'.. so save here too.
@ -3177,11 +3183,14 @@ void I_Error(const char *error, ...)
#endif
G_SaveGameData(false); // Tails 12-08-2002
/* Prevent segmentation fault if testers go to Record Attack... */
#ifndef TESTERS
// Shutdown. Here might be other errors.
if (demo.recording)
G_CheckDemoStatus();
if (metalrecording)
G_StopMetalRecording();
#endif
D_QuitNetGame();
I_ShutdownMusic();

View file

@ -1377,11 +1377,17 @@ void I_FinishUpdate(void)
if (I_SkipFrame())
return;
if (cv_ticrate.value)
SCR_DisplayTicRate();
if (st_overlay)
{
if (cv_ticrate.value)
SCR_DisplayTicRate();
if (cv_showping.value && netgame && consoleplayer != serverplayer)
SCR_DisplayLocalPing();
if (cv_showping.value && netgame &&
( consoleplayer != serverplayer || ! server_lagless ))
{
SCR_DisplayLocalPing();
}
}
if (rendermode == render_soft && screens[0])
{

View file

@ -233,6 +233,7 @@ static char returnWadPath[256];
#include "../d_net.h"
#include "../g_game.h"
#include "../filesrch.h"
#include "../k_pwrlv.h"
#include "endtxt.h"
#include "sdlmain.h"
@ -2977,6 +2978,11 @@ void I_Quit(void)
#ifndef NONET
D_SaveBan(); // save the ban list
#endif
// Make sure you lose points for ALT-F4
if (Playing())
K_PlayerForfeit(consoleplayer, true);
G_SaveGameData(); // Tails 12-08-2002
//added:16-02-98: when recording a demo, should exit using 'q' key,
// but sometimes we forget and use 'F10'.. so save here too.

View file

@ -815,6 +815,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"chain", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Mementos Reaper
{"mkuma", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR}, // Trigger Happy Havoc Monokuma
{"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
{"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

@ -890,6 +890,7 @@ typedef enum
sfx_chain,
sfx_mkuma,
sfx_toada,
sfx_bhurry,
sfx_bsnipe,
sfx_itfree,
sfx_dbgsal,

View file

@ -2134,12 +2134,7 @@ void ST_Drawer(void)
ST_MayonakaStatic();
}
// Draw a white fade on level opening
if (timeinmap < 15)
{
if (timeinmap <= 5)
V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,0); // Pure white on first few frames, to hide SRB2's awful level load artifacts
else
V_DrawFadeScreen(0, 15-timeinmap); // Then gradually fade out from there
}
// Draw a fade on level opening
if (timeinmap < 16)
V_DrawCustomFadeScreen(((levelfadecol == 0) ? "FADEMAP1" : "FADEMAP0"), 32-(timeinmap*2)); // Then gradually fade out from there
}

View file

@ -1287,28 +1287,75 @@ void V_DrawVhsEffect(boolean rewind)
void V_DrawFadeScreen(UINT16 color, UINT8 strength)
{
#ifdef HWRENDER
if (rendermode != render_soft && rendermode != render_none)
{
HWR_FadeScreenMenuBack(color, strength);
return;
}
if (rendermode != render_soft && rendermode != render_none)
{
HWR_FadeScreenMenuBack(color, strength);
return;
}
#endif
{
const UINT8 *fadetable =
{
const UINT8 *fadetable =
(color > 0xFFF0) // Grab a specific colormap palette?
? R_GetTranslationColormap(color | 0xFFFF0000, strength, GTC_CACHE)
: ((color & 0xFF00) // Color is not palette index?
? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade.
: ((UINT8 *)transtables + ((9-strength)<<FF_TRANSSHIFT) + color*256)); // Else, do TRANSMAP** fade.
const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
UINT8 *buf = screens[0];
const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
UINT8 *buf = screens[0];
// heavily simplified -- we don't need to know x or y
// position when we're doing a full screen fade
for (; buf < deststop; ++buf)
*buf = fadetable[*buf];
}
// heavily simplified -- we don't need to know x or y
// position when we're doing a full screen fade
for (; buf < deststop; ++buf)
*buf = fadetable[*buf];
}
}
//
// Fade the screen buffer, using a custom COLORMAP lump.
// Split from V_DrawFadeScreen, because that function has
// WAY too many options piled on top of it as is. :V
//
void V_DrawCustomFadeScreen(const char *lump, UINT8 strength)
{
#ifdef HWRENDER
if (rendermode != render_soft && rendermode != render_none)
{
//HWR_DrawCustomFadeScreen(color, strength);
return;
}
#endif
{
lumpnum_t lumpnum = LUMPERROR;
lighttable_t *clm = NULL;
if (lump != NULL)
lumpnum = W_GetNumForName(lump);
else
return;
if (lumpnum != LUMPERROR)
{
clm = Z_MallocAlign((256 * 32), PU_STATIC, NULL, 8);
W_ReadLump(lumpnum, clm);
if (clm != NULL)
{
const UINT8 *fadetable = ((UINT8 *)clm + strength*256);
const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
UINT8 *buf = screens[0];
// heavily simplified -- we don't need to know x or y
// position when we're doing a full screen fade
for (; buf < deststop; ++buf)
*buf = fadetable[*buf];
Z_Free(clm);
clm = NULL;
}
}
}
}
// Simple translucency with one color, over a set number of lines starting from the top.
@ -1332,6 +1379,34 @@ void V_DrawFadeConsBack(INT32 plines)
*buf = consolebgmap[*buf];
}
//
// Invert the entire screen, for Encore fades
//
void V_EncoreInvertScreen(void)
{
#ifdef HWRENDER
if (rendermode != render_soft && rendermode != render_none)
{
//HWR_EncoreInvertScreen();
return;
}
#endif
{
const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
UINT8 *buf = screens[0];
for (; buf < deststop; ++buf)
{
*buf = NearestColor(
256 - pLocalPalette[*buf].s.red,
256 - pLocalPalette[*buf].s.green,
256 - pLocalPalette[*buf].s.blue
);
}
}
}
// Gets string colormap, used for 0x80 color codes
//
UINT8 *V_GetStringColormap(INT32 colorflags)

View file

@ -158,8 +158,9 @@ void V_DrawVhsEffect(boolean rewind);
// fade down the screen buffer before drawing the menu over
void V_DrawFadeScreen(UINT16 color, UINT8 strength);
void V_DrawCustomFadeScreen(const char *lump, UINT8 strength);
void V_DrawFadeConsBack(INT32 plines);
void V_EncoreInvertScreen(void);
// draw a single character
void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);

View file

@ -39,6 +39,7 @@
#include "m_random.h" // M_RandomKey
#include "g_input.h" // PLAYER1INPUTDOWN
#include "k_kart.h" // colortranslations
#include "k_pwrlv.h"
#include "console.h" // cons_menuhighlight
#include "lua_hook.h" // IntermissionThinker hook
@ -90,7 +91,7 @@ typedef union
INT32 numplayers; // Number of players being displayed
char levelstring[64]; // holds levelnames up to 64 characters
// SRB2kart
UINT8 increase[MAXPLAYERS]; // how much did the score increase by?
INT16 increase[MAXPLAYERS]; // how much did the score increase by?
UINT8 jitter[MAXPLAYERS]; // wiggle
UINT32 val[MAXPLAYERS]; // Gametype-specific value
UINT8 pos[MAXPLAYERS]; // player positions. used for ties
@ -110,6 +111,7 @@ static boolean usetile;
boolean usebuffer = false;
static boolean useinterpic;
static INT32 timer;
static INT32 powertype = PWRLV_DISABLED;
static INT32 intertic;
static INT32 endtic = -1;
@ -193,11 +195,13 @@ static void Y_CompareBattle(INT32 i)
static void Y_CompareRank(INT32 i)
{
UINT8 increase = ((data.match.increase[i] == UINT8_MAX) ? 0 : data.match.increase[i]);
if (!(data.match.val[data.match.numplayers] == UINT32_MAX || (players[i].score - increase) > data.match.val[data.match.numplayers]))
INT16 increase = ((data.match.increase[i] == INT16_MIN) ? 0 : data.match.increase[i]);
UINT32 score = (powertype != -1 ? clientpowerlevels[i][powertype] : players[i].score);
if (!(data.match.val[data.match.numplayers] == UINT32_MAX || (score - increase) > data.match.val[data.match.numplayers]))
return;
data.match.val[data.match.numplayers] = (players[i].score - increase);
data.match.val[data.match.numplayers] = (score - increase);
data.match.num[data.match.numplayers] = i;
}
@ -205,7 +209,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
{
INT32 i, j;
boolean completed[MAXPLAYERS];
INT32 numplayersingame = 0;
INT32 numplayersingame = 0, numgriefers = 0;
// Initialize variables
if (rankingsmode > 1)
@ -257,14 +261,17 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
{
data.match.val[i] = UINT32_MAX;
if (nospectategrief[i] != -1)
numgriefers++;
if (!playeringame[i] || players[i].spectator)
{
data.match.increase[i] = UINT8_MAX;
data.match.increase[i] = INT16_MIN;
continue;
}
if (!rankingsmode)
data.match.increase[i] = UINT8_MAX;
data.match.increase[i] = INT16_MIN;
numplayersingame++;
}
@ -276,8 +283,6 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
for (j = 0; j < numplayersingame; j++)
{
INT32 nump = ((G_RaceGametype() && nospectategrief > 0) ? nospectategrief : numplayersingame);
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || completed[i])
@ -299,9 +304,10 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
else
data.match.pos[data.match.numplayers] = data.match.numplayers+1;
if (!rankingsmode && !(players[i].pflags & PF_TIMEOVER) && (data.match.pos[data.match.numplayers] < nump))
if ((!rankingsmode && powertype == -1) // Single player rankings (grand prix). Online rank is handled below.
&& !(players[i].pflags & PF_TIMEOVER) && (data.match.pos[data.match.numplayers] < (numplayersingame + numgriefers)))
{
data.match.increase[i] = nump - data.match.pos[data.match.numplayers];
data.match.increase[i] = (numplayersingame + numgriefers) - data.match.pos[data.match.numplayers];
players[i].score += data.match.increase[i];
}
@ -429,9 +435,10 @@ 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 = "RANK";
timeheader = "PWR.LV";
else
timeheader = (intertype == int_race ? "TIME" : "SCORE");
@ -486,28 +493,61 @@ 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)
{
if (data.match.increase[data.match.num[i]] != UINT8_MAX)
if (!clientpowerlevels[data.match.num[i]][powertype]) // No power level (splitscreen guests)
STRBUFCPY(strtime, "----");
else
{
if (data.match.increase[data.match.num[i]] > 9)
snprintf(strtime, sizeof strtime, "(+%02d)", data.match.increase[data.match.num[i]]);
else
snprintf(strtime, sizeof strtime, "(+ %d)", data.match.increase[data.match.num[i]]);
if (data.match.increase[data.match.num[i]] != INT16_MIN)
{
snprintf(strtime, sizeof strtime, "(%d)", data.match.increase[data.match.num[i]]);
if (data.match.numplayers > NUMFORNEWCOLUMN)
V_DrawRightAlignedThinString(x+135+gutter, y-1, V_6WIDTHSPACE, strtime);
else
V_DrawRightAlignedString(x+120+gutter, y, 0, strtime);
if (data.match.numplayers > NUMFORNEWCOLUMN)
V_DrawRightAlignedThinString(x+133+gutter, y-1, V_6WIDTHSPACE, strtime);
else
V_DrawRightAlignedString(x+118+gutter, y, 0, strtime);
}
snprintf(strtime, sizeof strtime, "%d", data.match.val[i]);
}
snprintf(strtime, sizeof strtime, "%d", data.match.val[i]);
if (data.match.numplayers > NUMFORNEWCOLUMN)
V_DrawRightAlignedThinString(x+152+gutter, y-1, V_6WIDTHSPACE, strtime);
else
@ -591,9 +631,14 @@ dotimer:
break;
}
// Make it obvious that scrambling is happening next round.
if (cv_scrambleonchange.value && cv_teamscramble.value && (intertic/TICRATE % 2 == 0))
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, hilicol, M_GetText("Teams will be scrambled next round!"));
//if ((intertic/TICRATE) & 1) // Make it obvious that scrambling is happening next round. (OR NOT, I GUESS)
//{
/*if (cv_scrambleonchange.value && cv_teamscramble.value)
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, hilicol, M_GetText("Teams will be scrambled next round!"));*/
if (speedscramble != -1 && speedscramble != gamespeed)
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24, hilicol|V_ALLOWLOWERCASE|V_SNAPTOBOTTOM,
va(M_GetText("Next race will be %s Speed!"), kartspeed_cons_t[1+speedscramble].strvalue));
//}
}
//
@ -676,13 +721,46 @@ void Y_Ticker(void)
{
if (data.match.num[q] == MAXPLAYERS
|| !data.match.increase[data.match.num[q]]
|| data.match.increase[data.match.num[q]] == UINT8_MAX)
|| data.match.increase[data.match.num[q]] == INT16_MIN)
continue;
r++;
data.match.jitter[data.match.num[q]] = 1;
if (--data.match.increase[data.match.num[q]])
kaching = false;
if (powertype != -1)
{
// Power Levels
if (abs(data.match.increase[data.match.num[q]]) < 10)
{
// Not a lot of point increase left, just set to 0 instantly
data.match.increase[data.match.num[q]] = 0;
}
else
{
SINT8 remove = 0; // default (should not happen)
if (data.match.increase[data.match.num[q]] < 0)
remove = -10;
else if (data.match.increase[data.match.num[q]] > 0)
remove = 10;
// Remove 10 points at a time
data.match.increase[data.match.num[q]] -= remove;
// Still not zero, no kaching yet
if (data.match.increase[data.match.num[q]] != 0)
kaching = false;
}
}
else
{
// Basic bitch points
if (data.match.increase[data.match.num[q]])
{
if (--data.match.increase[data.match.num[q]])
kaching = false;
}
}
}
if (r)
@ -782,6 +860,153 @@ static void Y_UpdateRecordReplays(void)
CV_AddValue(&cv_nextmap, -1);
}
static void K_UpdatePowerLevels(void)
{
INT32 i, j;
INT32 numplayersingame = 0, numgriefers = 0;
INT16 increment[MAXPLAYERS];
// Compare every single player against each other for power level increases.
// Every player you won against gives you more points, and vice versa.
// The amount of points won per match-up depends on the difference between the loser's power and the winner's power.
// See K_CalculatePowerLevelInc for more info.
for (i = 0; i < MAXPLAYERS; i++)
{
increment[i] = 0;
if (nospectategrief[i] != -1)
numgriefers++;
if (!playeringame[i] || players[i].spectator)
continue;
numplayersingame++;
}
for (i = 0; i < numplayersingame; i++)
{
UINT16 yourpower = PWRLVRECORD_DEF;
UINT16 theirpower = PWRLVRECORD_DEF;
INT16 diff = 0; // Loser PWR.LV - Winner PWR.LV
INT16 inc = 0; // Total pt increment
UINT8 ipnum = data.match.num[i];
UINT8 jpnum;
CONS_Debug(DBG_GAMELOGIC, "Power Level Gain for player %d:\n", ipnum);
if (clientpowerlevels[ipnum][powertype] == 0) // splitscreen guests don't record power level changes
continue;
yourpower = clientpowerlevels[ipnum][powertype];
CONS_Debug(DBG_GAMELOGIC, "Player %d's PWR.LV: %d\n", ipnum, yourpower);
for (j = 0; j < numplayersingame; j++)
{
boolean won = false;
jpnum = data.match.num[j];
if (i == j || ipnum == jpnum) // Same person
continue;
CONS_Debug(DBG_GAMELOGIC, "Player %d VS Player %d:\n", ipnum, jpnum);
if (data.match.val[i] == data.match.val[j]) // Tie -- neither get any points for this match up.
{
CONS_Debug(DBG_GAMELOGIC, "TIE, no change.\n");
continue;
}
theirpower = PWRLVRECORD_DEF;
if (clientpowerlevels[jpnum][powertype] != 0) // No power level acts as 5000 (used for splitscreen guests)
theirpower = clientpowerlevels[jpnum][powertype];
CONS_Debug(DBG_GAMELOGIC, "Player %d's PWR.LV: %d\n", jpnum, theirpower);
if (G_RaceGametype())
{
if (data.match.val[i] < data.match.val[j])
won = true;
}
else
{
if (data.match.val[i] > data.match.val[j])
won = true;
}
if (won) // This player won!
{
diff = theirpower - yourpower;
inc += K_CalculatePowerLevelInc(diff);
CONS_Debug(DBG_GAMELOGIC, "WON! Diff is %d, total increment is %d\n", diff, inc);
}
else // This player lost...
{
diff = yourpower - theirpower;
inc -= K_CalculatePowerLevelInc(diff);
CONS_Debug(DBG_GAMELOGIC, "LOST... Diff is %d, total increment is %d\n", diff, inc);
}
}
if (numgriefers != 0) // Automatic win against quitters.
{
for (jpnum = 0; jpnum < MAXPLAYERS; jpnum++)
{
if (nospectategrief[jpnum] == -1) // Empty slot
continue;
if (ipnum == jpnum) // Same person
continue;
CONS_Debug(DBG_GAMELOGIC, "Player %d VS Player %d (griefer):\n", ipnum, jpnum);
theirpower = PWRLVRECORD_DEF;
if (nospectategrief[jpnum] != 0) // No power level acts as 5000 (used for splitscreen guests)
theirpower = nospectategrief[jpnum];
CONS_Debug(DBG_GAMELOGIC, "Player %d's PWR.LV: %d\n", jpnum, theirpower);
diff = theirpower - yourpower;
inc += K_CalculatePowerLevelInc(diff);
CONS_Debug(DBG_GAMELOGIC, "AUTO-WON! Diff is %d, total increment is %d\n", diff, inc);
}
}
if (inc == 0)
{
data.match.increase[ipnum] = INT16_MIN;
CONS_Debug(DBG_GAMELOGIC, "Total Result: No increment, no change.\n");
continue;
}
if (yourpower + inc > PWRLVRECORD_MAX)
inc -= ((yourpower + inc) - PWRLVRECORD_MAX);
if (yourpower + inc < PWRLVRECORD_MIN)
inc -= ((yourpower + inc) - PWRLVRECORD_MIN);
CONS_Debug(DBG_GAMELOGIC, "Total Result: Increment of %d.\n", inc);
increment[ipnum] = inc;
}
CONS_Debug(DBG_GAMELOGIC, "Setting final power levels...\n");
for (i = 0; i < MAXPLAYERS; i++)
{
if (increment[i] == 0)
continue;
data.match.increase[i] = increment[i];
clientpowerlevels[i][powertype] += data.match.increase[i];
if (i == consoleplayer)
{
CONS_Debug(DBG_GAMELOGIC, "Player %d is you! Saving...\n", i);
vspowerlevel[powertype] = clientpowerlevels[i][powertype];
if (M_UpdateUnlockablesAndExtraEmblems(true))
S_StartSound(NULL, sfx_ncitem);
G_SaveGameData(true);
}
}
}
//
// Y_StartIntermission
//
@ -796,6 +1021,17 @@ void Y_StartIntermission(void)
I_Error("endtic is dirty");
#endif
// set player Power Level type
powertype = PWRLV_DISABLED;
if (netgame && cv_kartusepwrlv.value)
{
if (G_RaceGametype())
powertype = PWRLV_RACE;
else if (G_BattleGametype())
powertype = PWRLV_BATTLE;
}
if (!multiplayer)
{
timer = 0;
@ -872,6 +1108,9 @@ void Y_StartIntermission(void)
break;
}
if (powertype != PWRLV_DISABLED)
K_UpdatePowerLevels();
//if (intertype == int_race || intertype == int_match)
{
//bgtile = W_CachePatchName("SRB2BACK", PU_STATIC);

View file

@ -210,7 +210,11 @@ void Z_Free(void *ptr)
static void *xm(size_t size)
{
const size_t padedsize = size+sizeof (size_t);
void *p = malloc(padedsize);
void *p;
if (padedsize < size)/* overflow check */
I_Error("You are allocating memory too large!");
p = malloc(padedsize);
if (p == NULL)
{
@ -254,6 +258,9 @@ void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits)
CONS_Debug(DBG_MEMORY, "Z_Malloc %s:%d\n", file, line);
#endif
if (blocksize < size)/* overflow check */
I_Error("You are allocating memory too large!");
block = xm(sizeof *block);
#ifdef HAVE_VALGRIND
padsize += (1<<sizeof(size_t))*2;