Merge branch 'master' into the-scary-22-merge

This commit is contained in:
Sally Coolatta 2020-08-12 20:59:09 -04:00
commit f9ca40e673
96 changed files with 11067 additions and 6981 deletions

View file

@ -568,7 +568,7 @@ matrix:
- p7zip-full
- gcc-4.8
compiler: gcc-4.8
dist: xenial
dist: trusty
if: env(DPL_ENABLED) = "1" AND (env(_DPL_JOB_ENABLED) = "1" OR env(DPL_JOB_ENABLE_ALL) = "1")
AND (branch =~ /^.*deployer.*$/ OR (tag IS present AND env(DPL_TAG_ENABLED) = "1"))
AND env(DPL_TERMINATE_MAIN) != "1"

View file

@ -3,7 +3,6 @@
# Core sources
set(SRB2_CORE_SOURCES
am_map.c
b_bot.c
command.c
comptime.c
console.c
@ -20,6 +19,7 @@ set(SRB2_CORE_SOURCES
g_game.c
g_input.c
g_splitscreen.c
font.c
hu_stuff.c
i_tcp.c
info.c
@ -37,6 +37,7 @@ set(SRB2_CORE_SOURCES
m_random.c
md5.c
mserv.c
http-mserv.c
s_sound.c
screen.c
sounds.c
@ -51,7 +52,6 @@ set(SRB2_CORE_SOURCES
set(SRB2_CORE_HEADERS
am_map.h
b_bot.h
byteptr.h
command.h
console.h
@ -77,6 +77,7 @@ set(SRB2_CORE_HEADERS
g_game.h
g_input.h
g_state.h
font.h
hu_stuff.h
i_joy.h
i_net.h
@ -102,6 +103,7 @@ set(SRB2_CORE_HEADERS
m_swap.h
md5.h
mserv.h
http-mserv.h
p5prof.h
s_sound.h
screen.h
@ -176,6 +178,9 @@ set(SRB2_CORE_GAME_SOURCES
k_bot.c
k_botitem.c
k_botsearch.c
k_respawn.c
k_grandprix.c
k_hud.c
p_local.h
p_maputl.h
@ -196,6 +201,9 @@ set(SRB2_CORE_GAME_SOURCES
k_waypoint.h
k_color.h
k_bot.h
k_respawn.h
k_grandprix.h
k_hud.h
)
if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))

View file

@ -446,17 +446,10 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/am_map.o \
$(OBJDIR)/command.o \
$(OBJDIR)/console.o \
$(OBJDIR)/font.o \
$(OBJDIR)/hu_stuff.o \
$(OBJDIR)/y_inter.o \
$(OBJDIR)/st_stuff.o \
$(OBJDIR)/k_kart.o \
$(OBJDIR)/k_collide.o\
$(OBJDIR)/k_color.o \
$(OBJDIR)/k_battle.o \
$(OBJDIR)/k_pwrlv.o \
$(OBJDIR)/k_waypoint.o\
$(OBJDIR)/k_pathfind.o\
$(OBJDIR)/k_bheap.o \
$(OBJDIR)/m_aatree.o \
$(OBJDIR)/m_anigif.o \
$(OBJDIR)/m_argv.o \
@ -510,9 +503,20 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/i_tcp.o \
$(OBJDIR)/lzf.o \
$(OBJDIR)/vid_copy.o \
$(OBJDIR)/k_bot.o \
$(OBJDIR)/k_botitem.o \
$(OBJDIR)/k_botsearch.o \
$(OBJDIR)/k_kart.o \
$(OBJDIR)/k_respawn.o\
$(OBJDIR)/k_collide.o\
$(OBJDIR)/k_color.o \
$(OBJDIR)/k_battle.o \
$(OBJDIR)/k_pwrlv.o \
$(OBJDIR)/k_waypoint.o\
$(OBJDIR)/k_pathfind.o\
$(OBJDIR)/k_bheap.o \
$(OBJDIR)/k_bot.o \
$(OBJDIR)/k_botitem.o\
$(OBJDIR)/k_botsearch.o\
$(OBJDIR)/k_grandprix.o\
$(OBJDIR)/k_hud.o \
$(i_cdmus_o) \
$(i_net_o) \
$(i_system_o) \

View file

@ -228,6 +228,9 @@ endif
ifndef GCC295
WFLAGS+=-Wendif-labels
endif
ifdef GCC40
WFLAGS+=-std=gnu89
endif
ifdef GCC41
WFLAGS+=-Wshadow
endif

View file

@ -1472,6 +1472,8 @@ void CONS_Printf(const char *fmt, ...)
Lock_state();
Lock_state();
// make sure new text is visible
con_scrollup = 0;
startup = con_startup;

View file

@ -51,6 +51,7 @@
#include "k_battle.h"
#include "k_pwrlv.h"
#include "k_bot.h"
#include "k_grandprix.h"
#ifndef NONET
// cl loading screen
@ -532,14 +533,11 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
for (j = 0; j < NUMPOWERS; ++j)
rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]);
for (j = 0; j < NUMKARTSTUFF; ++j)
rsp->kartstuff[j] = LONG(players[i].kartstuff[j]); // SRB2kart
rsp->frameangle = (angle_t)LONG(players[i].frameangle); // SRB2kart
// Score is resynched in the rspfirm resync packet
rsp->rings = SHORT(players[i].rings);
rsp->lives = players[i].lives;
rsp->lostlife = players[i].lostlife;
rsp->continues = players[i].continues;
rsp->scoreadd = players[i].scoreadd;
rsp->xtralife = players[i].xtralife;
@ -574,13 +572,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->weapondelay = LONG(players[i].weapondelay);
rsp->tossdelay = LONG(players[i].tossdelay);
rsp->starpostx = SHORT(players[i].starpostx);
rsp->starposty = SHORT(players[i].starposty);
rsp->starpostz = SHORT(players[i].starpostz);
rsp->starpostnum = LONG(players[i].starpostnum);
rsp->starposttime = (tic_t)LONG(players[i].starposttime);
rsp->starpostangle = (angle_t)LONG(players[i].starpostangle);
rsp->starpostscale = (fixed_t)LONG(players[i].starpostscale);
rsp->maxlink = LONG(players[i].maxlink);
rsp->dashspeed = (fixed_t)LONG(players[i].dashspeed);
@ -608,8 +600,28 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->splitscreenindex = players[i].splitscreenindex;
// SRB2kart
for (j = 0; j < NUMKARTSTUFF; ++j)
rsp->kartstuff[j] = LONG(players[i].kartstuff[j]);
rsp->frameangle = (angle_t)LONG(players[i].frameangle);
rsp->airtime = (tic_t)LONG(players[i].airtime);
// respawnvars_t
rsp->respawn_state = players[i].respawn.state;
rsp->respawn_pointx = (fixed_t)LONG(players[i].respawn.pointx);
rsp->respawn_pointy = (fixed_t)LONG(players[i].respawn.pointy);
rsp->respawn_pointz = (fixed_t)LONG(players[i].respawn.pointz);
rsp->respawn_flip = players[i].respawn.flip;
rsp->respawn_timer = (tic_t)LONG(players[i].respawn.timer);
rsp->respawn_distanceleft = (UINT32)LONG(players[i].respawn.distanceleft);
rsp->respawn_dropdash = (tic_t)LONG(players[i].respawn.dropdash);
// botvars_t
rsp->bot = players[i].bot;
rsp->bot_difficulty = players[i].botvars.difficulty;
rsp->bot_diffincrease = players[i].botvars.diffincrease;
rsp->bot_rival = players[i].botvars.rival;
rsp->bot_itemdelay = players[i].botvars.itemdelay;
rsp->bot_itemconfirm = players[i].botvars.itemconfirm;
rsp->bot_turnconfirm = players[i].botvars.turnconfirm;
@ -668,14 +680,11 @@ static void resynch_read_player(resynch_pak *rsp)
for (j = 0; j < NUMPOWERS; ++j)
players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]);
for (j = 0; j < NUMKARTSTUFF; ++j)
players[i].kartstuff[j] = LONG(rsp->kartstuff[j]); // SRB2kart
players[i].frameangle = (angle_t)LONG(rsp->frameangle); // SRB2kart
// Score is resynched in the rspfirm resync packet
players[i].rings = SHORT(rsp->rings);
players[i].lives = rsp->lives;
players[i].lostlife = rsp->lostlife;
players[i].continues = rsp->continues;
players[i].scoreadd = rsp->scoreadd;
players[i].xtralife = rsp->xtralife;
@ -709,13 +718,7 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].weapondelay = LONG(rsp->weapondelay);
players[i].tossdelay = LONG(rsp->tossdelay);
players[i].starpostx = SHORT(rsp->starpostx);
players[i].starposty = SHORT(rsp->starposty);
players[i].starpostz = SHORT(rsp->starpostz);
players[i].starpostnum = LONG(rsp->starpostnum);
players[i].starposttime = (tic_t)LONG(rsp->starposttime);
players[i].starpostangle = (angle_t)LONG(rsp->starpostangle);
players[i].starpostscale = (fixed_t)LONG(rsp->starpostscale);
players[i].maxlink = LONG(rsp->maxlink);
players[i].dashspeed = (fixed_t)LONG(rsp->dashspeed);
@ -743,8 +746,28 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].splitscreenindex = rsp->splitscreenindex;
// SRB2kart
for (j = 0; j < NUMKARTSTUFF; ++j)
players[i].kartstuff[j] = LONG(rsp->kartstuff[j]);
players[i].frameangle = (angle_t)LONG(rsp->frameangle);
players[i].airtime = (tic_t)LONG(rsp->airtime);
// respawnvars_t
players[i].respawn.state = rsp->respawn_state;
players[i].respawn.pointx = (fixed_t)LONG(rsp->respawn_pointx);
players[i].respawn.pointy = (fixed_t)LONG(rsp->respawn_pointy);
players[i].respawn.pointz = (fixed_t)LONG(rsp->respawn_pointz);
players[i].respawn.flip = (boolean)rsp->respawn_flip;
players[i].respawn.timer = (tic_t)LONG(rsp->respawn_timer);
players[i].respawn.distanceleft = (UINT32)LONG(rsp->respawn_distanceleft);
players[i].respawn.dropdash = (tic_t)LONG(rsp->respawn_dropdash);
// botvars_t
players[i].bot = rsp->bot;
players[i].botvars.difficulty = rsp->bot_difficulty;
players[i].botvars.diffincrease = rsp->bot_diffincrease;
players[i].botvars.rival = rsp->bot_rival;
players[i].botvars.itemdelay = rsp->bot_itemdelay;
players[i].botvars.itemconfirm = rsp->bot_itemconfirm;
players[i].botvars.turnconfirm = rsp->bot_turnconfirm;
@ -1269,7 +1292,7 @@ static boolean CL_AskFileList(INT32 firstfile)
netbuffer->packettype = PT_TELLFILESNEEDED;
netbuffer->u.filesneedednum = firstfile;
return HSendPacket(servernode, true, 0, sizeof (INT32));
return HSendPacket(servernode, false, 0, sizeof (INT32));
}
/** Sends a special packet to declare how many players in local
@ -2043,11 +2066,11 @@ static boolean CL_FinishedFileList(void)
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"You have WAD files loaded or have\n"
"modified the game in some way, and\n"
"your file list does not match\n"
"the server's file list.\n"
"Please restart SRB2Kart before connecting.\n\n"
"You have the wrong addons loaded.\n\n"
"To play on this server, restart\n"
"the game and don't load any addons.\n"
"SRB2Kart will automatically add\n"
"everything you need when you join.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
@ -2068,11 +2091,12 @@ static boolean CL_FinishedFileList(void)
CL_Reset();
D_StartTitle();
M_StartMessage(M_GetText(
"You cannot connect to this server\n"
"because you cannot download the files\n"
"that you are missing from the server.\n\n"
"See the console or log file for\n"
"more details.\n\n"
"An error occured when trying to\n"
"download missing addons.\n"
"(This is almost always a problem\n"
"with the server, not your game.)\n\n"
"See the console or log file\n"
"for additional details.\n\n"
"Press ESC\n"
), NULL, MM_NOTHING);
return false;
@ -2798,8 +2822,8 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
RemoveAdminPlayer(playernum); // don't stay admin after you're gone
}
if (playernum == g_localplayers[0] && !demo.playback)
g_localplayers[0] = consoleplayer; // don't look through someone's view who isn't there
if (playernum == displayplayers[0] && !demo.playback)
displayplayers[0] = consoleplayer; // don't look through someone's view who isn't there
LUA_InvalidatePlayer(&players[playernum]);
@ -4458,7 +4482,6 @@ static void HandlePacketFromAwayNode(SINT8 node)
static boolean CheckForSpeedHacks(UINT8 p)
{
if (netcmds[maketic%TICQUEUE][p].forwardmove > MAXPLMOVE || netcmds[maketic%TICQUEUE][p].forwardmove < -MAXPLMOVE
|| netcmds[maketic%TICQUEUE][p].sidemove > MAXPLMOVE || netcmds[maketic%TICQUEUE][p].sidemove < -MAXPLMOVE
|| netcmds[maketic%TICQUEUE][p].driftturn > KART_FULLTURN || netcmds[maketic%TICQUEUE][p].driftturn < -KART_FULLTURN)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernode[p]);
@ -5450,6 +5473,12 @@ static void SV_Maketic(void)
if (!playeringame[i])
continue;
if (K_PlayerUsesBotMovement(&players[i]))
{
K_BuildBotTiccmd(&players[i], &netcmds[maketic%TICQUEUE][i]);
continue;
}
// We didn't receive this tic
if ((netcmds[maketic % TICQUEUE][i].angleturn & TICCMD_RECEIVED) == 0)
{
@ -5909,6 +5938,18 @@ INT32 D_NumPlayers(void)
return num;
}
/** Return whether a player is a real person (not a CPU) and not spectating.
*/
boolean D_IsPlayerHumanAndGaming (INT32 player_number)
{
player_t * player = &players[player_number];
return (
playeringame[player_number] &&
! player->spectator &&
! player->bot
);
}
tic_t GetLag(INT32 node)
{
return gametic - nettics[node];

View file

@ -214,12 +214,10 @@ typedef struct
angle_t aiming;
UINT16 powers[NUMPOWERS];
INT32 kartstuff[NUMKARTSTUFF]; // SRB2kart
angle_t frameangle; // SRB2kart
// Score is resynched in the confirm resync packet
INT16 rings;
SINT8 lives;
boolean lostlife;
SINT8 continues;
UINT8 scoreadd;
SINT8 xtralife;
@ -254,13 +252,7 @@ typedef struct
INT32 weapondelay;
INT32 tossdelay;
INT16 starpostx;
INT16 starposty;
INT16 starpostz;
INT32 starpostnum;
tic_t starposttime;
angle_t starpostangle;
fixed_t starpostscale;
INT32 maxlink;
fixed_t dashspeed;
@ -287,8 +279,26 @@ typedef struct
UINT8 splitscreenindex;
// SRB2kart
INT32 kartstuff[NUMKARTSTUFF];
angle_t frameangle;
tic_t airtime;
// respawnvars_t
UINT8 respawn_state;
fixed_t respawn_pointx;
fixed_t respawn_pointy;
fixed_t respawn_pointz;
boolean respawn_flip;
tic_t respawn_timer;
UINT32 respawn_distanceleft;
tic_t respawn_dropdash;
// botvars_t
boolean bot;
UINT8 bot_difficulty;
UINT8 bot_diffincrease;
boolean bot_rival;
tic_t bot_itemdelay;
tic_t bot_itemconfirm;
SINT8 bot_turnconfirm;
@ -664,6 +674,7 @@ extern UINT8 playernode[MAXPLAYERS];
extern UINT8 playerconsole[MAXPLAYERS];
INT32 D_NumPlayers(void);
boolean D_IsPlayerHumanAndGaming(INT32 player_number);
void D_ResetTiccmds(void);
tic_t GetLag(INT32 node);

View file

@ -65,9 +65,12 @@
#include "m_cond.h" // condition initialization
#include "fastcmp.h"
#include "keys.h"
#include "filesrch.h" // refreshdirmenu, mainwadstally
#include "filesrch.h" // refreshdirmenu
#include "g_input.h" // tutorial mode control scheming
// SRB2Kart
#include "k_grandprix.h"
#ifdef CMAKECONFIG
#include "config.h"
#else
@ -166,35 +169,6 @@ UINT8 shiftdown = 0; // 0x1 left, 0x2 right
UINT8 ctrldown = 0; // 0x1 left, 0x2 right
UINT8 altdown = 0; // 0x1 left, 0x2 right
boolean capslock = 0; // gee i wonder what this does.
//
// D_ModifierKeyResponder
// Sets global shift/ctrl/alt variables, never actually eats events
//
static inline void D_ModifierKeyResponder(event_t *ev)
{
if (ev->type == ev_keydown || ev->type == ev_console) switch (ev->data1)
{
case KEY_LSHIFT: shiftdown |= 0x1; return;
case KEY_RSHIFT: shiftdown |= 0x2; return;
case KEY_LCTRL: ctrldown |= 0x1; return;
case KEY_RCTRL: ctrldown |= 0x2; return;
case KEY_LALT: altdown |= 0x1; return;
case KEY_RALT: altdown |= 0x2; return;
case KEY_CAPSLOCK: capslock = !capslock; return;
default: return;
}
else if (ev->type == ev_keyup) switch (ev->data1)
{
case KEY_LSHIFT: shiftdown &= ~0x1; return;
case KEY_RSHIFT: shiftdown &= ~0x2; return;
case KEY_LCTRL: ctrldown &= ~0x1; return;
case KEY_RCTRL: ctrldown &= ~0x2; return;
case KEY_LALT: altdown &= ~0x1; return;
case KEY_RALT: altdown &= ~0x2; return;
default: return;
}
}
//
// D_ProcessEvents
@ -1000,6 +974,9 @@ void D_StartTitle(void)
modeattacking = ATTACKING_NONE;
marathonmode = 0;
// Reset GP
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
// empty maptol so mario/etc sounds don't play in sound test when they shouldn't
maptol = 0;
@ -1382,6 +1359,43 @@ void D_SRB2Main(void)
if (M_CheckParm("-server") || dedicated)
netgame = server = true;
if (M_CheckParm("-warp") && M_IsNextParm())
{
const char *word = M_GetNextParm();
char ch; // use this with sscanf to catch non-digits with
if (fastncmp(word, "MAP", 3)) // MAPxx name
pstartmap = M_MapNumber(word[3], word[4]);
else if (sscanf(word, "%d%c", &pstartmap, &ch) != 1) // a plain number
I_Error("Cannot warp to map %s (invalid map name)\n", word);
// Don't check if lump exists just yet because the wads haven't been loaded!
// Just do a basic range check here.
if (pstartmap < 1 || pstartmap > NUMMAPS)
I_Error("Cannot warp to map %d (out of range)\n", pstartmap);
else
{
if (!M_CheckParm("-server"))
{
G_SetGameModified(true, true);
// Start up a "minor" grand prix session
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
grandprixinfo.gamespeed = KARTSPEED_NORMAL;
grandprixinfo.encore = false;
grandprixinfo.masterbots = false;
grandprixinfo.gp = true;
grandprixinfo.roundnum = 0;
grandprixinfo.cup = NULL;
grandprixinfo.wonround = false;
grandprixinfo.initalize = true;
}
autostart = true;
}
}
// adapt tables to SRB2's needs, including extra slots for dehacked file support
P_PatchInfoTables();
@ -1803,18 +1817,46 @@ void D_SRB2Main(void)
INT16 newskill = -1;
const char *sskill = M_GetNextParm();
for (j = 0; kartspeed_cons_t[j].strvalue; j++)
if (!strcasecmp(kartspeed_cons_t[j].strvalue, sskill))
const UINT8 master = KARTSPEED_HARD+1;
const char *masterstr = "Master";
if (!strcasecmp(masterstr, sskill))
{
newskill = master;
}
else
{
for (j = 0; kartspeed_cons_t[j].strvalue; j++)
{
newskill = (INT16)kartspeed_cons_t[j].value;
break;
if (!strcasecmp(kartspeed_cons_t[j].strvalue, sskill))
{
newskill = (INT16)kartspeed_cons_t[j].value;
break;
}
}
if (!kartspeed_cons_t[j].strvalue) // reached end of the list with no match
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 >= KARTSPEED_EASY && j <= master)
newskill = (INT16)j;
}
}
if (grandprixinfo.gp == true)
{
j = atoi(sskill); // assume they gave us a skill number, which is okay too
if (j >= KARTSPEED_EASY && j <= KARTSPEED_HARD)
newskill = (INT16)j;
if (newskill == master)
{
grandprixinfo.masterbots = true;
newskill = KARTSPEED_HARD;
}
grandprixinfo.gamespeed = newskill;
}
else if (newskill == master)
{
grandprixinfo.masterbots = true;
newskill = KARTSPEED_HARD;
}
if (newskill != -1)

View file

@ -19,7 +19,9 @@
#define __D_NET__
// Max computers in a game
#define MAXNETNODES 64
// 127 is probably as high as this can go, because
// SINT8 is used for nodes sometimes >:(
#define MAXNETNODES 127
#define BROADCASTADDR MAXNETNODES
#define NETSPLITSCREEN // Kart's splitscreen netgame feature

View file

@ -54,6 +54,8 @@
#include "k_pwrlv.h"
#include "y_inter.h"
#include "k_color.h"
#include "k_respawn.h"
#include "k_grandprix.h"
#ifdef NETGAME_DEVMODE
#define CV_RESTRICT CV_NETVAR
@ -112,6 +114,16 @@ static void Skin_OnChange(void);
static void Skin2_OnChange(void);
static void Skin3_OnChange(void);
static void Skin4_OnChange(void);
static void Follower_OnChange(void);
static void Follower2_OnChange(void);
static void Follower3_OnChange(void);
static void Follower4_OnChange(void);
static void Followercolor_OnChange(void);
static void Followercolor2_OnChange(void);
static void Followercolor3_OnChange(void);
static void Followercolor4_OnChange(void);
static void Color_OnChange(void);
static void Color2_OnChange(void);
static void Color3_OnChange(void);
@ -270,6 +282,23 @@ consvar_t cv_skin[MAXSPLITSCREENPLAYERS] = {
{"skin4", DEFAULTSKIN4, CV_SAVE|CV_CALL|CV_NOINIT, NULL, Skin4_OnChange, 0, NULL, NULL, 0, 0, NULL}
};
// player's followers. Also saved.
consvar_t cv_follower = {"follower", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_follower2 = {"follower2", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower2_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_follower3 = {"follower3", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower3_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_follower4 = {"follower4", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower4_OnChange, 0, NULL, NULL, 0, 0, NULL};
// player's follower colors... Also saved...
consvar_t cv_followercolor = {"followercolor", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_followercolor2 = {"followercolor2", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor2_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_followercolor3 = {"followercolor3", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor3_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_followercolor4 = {"followercolor4", "Match", CV_SAVE|CV_CALL|CV_NOINIT, Followercolor_cons_t, Followercolor4_OnChange, 0, NULL, NULL, 0, 0, NULL};
// Follower toggle
static CV_PossibleValue_t followers_cons_t[] = {{0, "Yours only"}, {1, "Everyone's"}, {0, NULL}};
consvar_t cv_showfollowers = {"showfollowers", "Everyone's", CV_SAVE, followers_cons_t, 0, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_skipmapcheck = {"skipmapcheck", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
INT32 cv_debug;
@ -330,6 +359,7 @@ consvar_t cv_hyudoro = {"hyudoro", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NU
consvar_t cv_pogospring = {"pogospring", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_kitchensink = {"kitchensink", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_dualsneaker = {"dualsneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_triplesneaker = {"triplesneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_triplebanana = {"triplebanana", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_decabanana = {"decabanana", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -732,16 +762,22 @@ void D_RegisterClientCommands(void)
for (i = 0; i < numskincolors; i++)
{
Color_cons_t[i].value = i;
Color_cons_t[i].strvalue = skincolors[i].name;
Color_cons_t[i].value = Followercolor_cons_t[i].value = i;
Color_cons_t[i].strvalue = Followercolor_cons_t[i].strvalue = skincolors[i].name;
}
Color_cons_t[numskincolors].value = 0;
Color_cons_t[numskincolors].strvalue = NULL;
Color_cons_t[MAXSKINCOLORS].value = Followercolor_cons_t[MAXSKINCOLORS+2].value = 0;
Color_cons_t[MAXSKINCOLORS].strvalue = Followercolor_cons_t[MAXSKINCOLORS+2].strvalue = NULL;
Followercolor_cons_t[MAXSKINCOLORS].value = MAXSKINCOLORS;
Followercolor_cons_t[MAXSKINCOLORS].strvalue = "Match"; // Add "Match" option, which will make the follower color match the player's
Followercolor_cons_t[MAXSKINCOLORS+1].value = MAXSKINCOLORS+1;
Followercolor_cons_t[MAXSKINCOLORS+1].strvalue = "Opposite"; // Add "Opposite" option, ...which is like "Match", but for coloropposite.
// Set default player names
// Monster Iestyn (12/08/19): not sure where else I could have actually put this, but oh well
for (i = 0; i < MAXPLAYERS; i++)
sprintf(player_names[i], "Player %d", 1 + i);
sprintf(player_names[i], "Player %c", 'A' + i); // SRB2Kart: Letters like Sonic 3!
if (dedicated)
return;
@ -816,11 +852,16 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_playername[i]);
CV_RegisterVar(&cv_playercolor[i]);
CV_RegisterVar(&cv_skin[i]);
CV_RegisterVar(&cv_follower[i]);
CV_RegisterVar(&cv_followercolor[i]);
}
// preferred number of players
CV_RegisterVar(&cv_splitplayers);
// Display other players' followers
CV_RegisterVar(&cv_showfollowers);
#ifdef SEENAMES
CV_RegisterVar(&cv_seenames);
#endif
@ -1326,7 +1367,7 @@ static void SendNameAndColor(UINT8 n)
const INT32 playernum = g_localplayers[n];
player_t *player = &players[playernum];
char buf[MAXPLAYERNAME+6];
char buf[MAXPLAYERNAME+9];
char *p;
if (splitscreen < playernum)
@ -1353,6 +1394,14 @@ static void SendNameAndColor(UINT8 n)
}
}
// ditto for follower colour:
if (!cv_followercolor[n].value)
CV_StealthSet(&cv_followercolor[n], "Match"); // set it to "Match". I don't care about your stupidity!
// so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game:
if (cv_follower[n].value > numfollowers-1 || cv_follower[n].value < -1)
CV_StealthSet(&cv_follower[n], "-1");
if (!strcmp(cv_playername[n].string, player_names[playernum])
&& cv_playercolor[n].value == player->skincolor
&& !strcmp(cv_skin[n].string, skins[player->skin].name))
@ -1377,6 +1426,10 @@ static void SendNameAndColor(UINT8 n)
if (player->mo && !player->powers[pw_dye])
player->mo->color = player->skincolor;
// Update follower for local games:
if (cv_follower[n].value >= -1 && cv_follower[n].value != player->followerskin)
SetFollower(playernum, cv_follower[n].value);
if (metalrecording && n == 0)
{ // Starring Metal Sonic as themselves, obviously.
SetPlayerSkinByNum(playernum, 5);
@ -1425,6 +1478,8 @@ static void SendNameAndColor(UINT8 n)
WRITEUINT32(p, (UINT32)player->availabilities);
WRITEUINT16(p, (UINT16)cv_playercolor[n].value);
WRITEUINT8(p, (UINT8)cv_skin[n].value);
WRITESINT8(p, (UINT8)cv_follower[n].value);
WRITESINT8(p, (UINT8)cv_followercolor[n].value);
SendNetXCmdForPlayer(n, XD_NAMEANDCOLOR, buf, p - buf);
}
@ -2259,6 +2314,12 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r
if ((netgame || multiplayer) && !((gametype == newgametype) && (gametypedefaultrules[newgametype] & GTR_CAMPAIGN)))
FLS = false;
if (grandprixinfo.gp == true)
{
// Too lazy to change the input value for every instance of this function.......
pencoremode = grandprixinfo.encore;
}
if (delay != 2)
{
UINT8 flags = 0;
@ -2297,6 +2358,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r
}
chmappending++;
if (netgame)
WRITEUINT32(buf_p, M_RandomizedSeed()); // random seed
SendNetXCmd(XD_MAP, buf, buf_p - buf);
@ -2469,7 +2531,7 @@ static void Command_Map_f(void)
mustmodifygame = !(netgame || multiplayer) && !majormods;
if (mustmodifygame && !option_force)
if (mustmodifygame)
{
/* May want to be more descriptive? */
CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n"));
@ -2526,6 +2588,7 @@ static void Command_Map_f(void)
if (mustmodifygame && option_force)
{
G_SetGameModified(multiplayer, true);
startgp = true;
}
// new gametype value
@ -2580,6 +2643,69 @@ static void Command_Map_f(void)
}
}
if (startgp)
{
i = COM_CheckParm("-skill");
grandprixinfo.gamespeed = (cv_kartspeed.value == KARTSPEED_AUTO ? KARTSPEED_NORMAL : cv_kartspeed.value);
grandprixinfo.masterbots = false;
if (i)
{
const UINT8 master = KARTSPEED_HARD+1;
const char *masterstr = "Master";
const char *skillname = COM_Argv(i+1);
INT32 newskill = -1;
INT32 j;
if (!strcasecmp(masterstr, skillname))
{
newskill = master;
}
else
{
for (j = 0; kartspeed_cons_t[j].strvalue; j++)
{
if (!strcasecmp(kartspeed_cons_t[j].strvalue, skillname))
{
newskill = (INT16)kartspeed_cons_t[j].value;
break;
}
}
if (!kartspeed_cons_t[j].strvalue) // reached end of the list with no match
{
j = atoi(COM_Argv(i+1)); // assume they gave us a skill number, which is okay too
if (j >= KARTSPEED_EASY && j <= master)
newskill = (INT16)j;
}
}
if (newskill != -1)
{
if (newskill == master)
{
grandprixinfo.gamespeed = KARTSPEED_HARD;
grandprixinfo.masterbots = true;
}
else
{
grandprixinfo.gamespeed = newskill;
grandprixinfo.masterbots = false;
}
}
}
grandprixinfo.encore = newencoremode;
grandprixinfo.gp = true;
grandprixinfo.roundnum = 0;
grandprixinfo.cup = NULL;
grandprixinfo.wonround = false;
grandprixinfo.initalize = true;
}
if (!option_force && newgametype == gametype) // SRB2Kart
newresetplayers = false; // if not forcing and gametypes is the same
@ -4087,14 +4213,16 @@ static void PointLimit_OnChange(void)
static void NumLaps_OnChange(void)
{
if (!(gametyperules & GTR_CIRCUIT) || (modeattacking || demo.playback))
if (K_CanChangeRules() == false)
{
return;
}
if (server && Playing()
&& (netgame || multiplayer)
&& (mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE)
&& (cv_numlaps.value > mapheaderinfo[gamemap - 1]->numlaps))
if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE)
&& (cv_numlaps.value > mapheaderinfo[gamemap - 1]->numlaps))
{
CV_StealthSetValue(&cv_numlaps, mapheaderinfo[gamemap - 1]->numlaps);
}
// Just don't be verbose
if (gametyperules & GTR_CIRCUIT)
@ -4636,14 +4764,14 @@ void Command_ExitGame_f(void)
void Command_Retry_f(void)
{
if (!(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING))
if (!(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION))
{
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
else if (netgame || multiplayer)
CONS_Printf(M_GetText("This only works in single player.\n"));
/*else if (!&players[consoleplayer] || players[consoleplayer].lives <= 1)
CONS_Printf(M_GetText("You can't retry without any lives remaining!\n"));
else if (G_IsSpecialStage(gamemap))
CONS_Printf(M_GetText("You can't retry special stages!\n"));*/
}
else if (grandprixinfo.gp == false)
{
CONS_Printf(M_GetText("This only works in Grand Prix.\n"));
}
else
{
M_ClearMenus(true);
@ -4898,6 +5026,198 @@ static void Name4_OnChange(void)
SendNameAndColor(3);
}
// sends the follower change for players
static void Follower_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
INT32 num;
char set[10]; // This isn't Lua and mixed declarations in the middle of code make caveman compilers scream.
// there is a slight chance that we will actually use a string instead so...
// let's investigate the string...
strcpy(str, cv_follower.string);
strcpy(cpy, cv_follower.string);
strlwr(str);
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
{
if (stricmp(cpy, "None") == 0)
{
CV_StealthSet(&cv_follower, "-1");
if (!Playing())
return; // don't send anything there.
SendNameAndColor();
return;
}
num = R_FollowerAvailable(str);
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower, set); // set it to a number. It's easier for us to send later :)
}
if (!Playing())
return; // don't send anything there.
SendNameAndColor();
}
// About the same as Color_OnChange but for followers.
static void Followercolor_OnChange(void)
{
if (!Playing())
return; // do whatever you want if you aren't in the game or don't have a follower.
if (!P_PlayerMoving(consoleplayer))
{
// Color change menu scrolling fix is no longer necessary
SendNameAndColor();
}
}
// repeat for the 3 other players
static void Follower2_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
if (!Playing() || !splitscreen)
return; // do whatever you want
strcpy(str, cv_follower2.string);
strcpy(cpy, cv_follower2.string);
strlwr(str);
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
{
if (stricmp(cpy, "None") == 0)
{
CV_StealthSet(&cv_follower2, "-1");
SendNameAndColor2();
return;
}
{
INT32 num = R_FollowerAvailable(str);
char set[10];
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower2, set); // set it to a number. It's easier for us to send later :)
}
}
SendNameAndColor2();
}
static void Followercolor2_OnChange(void)
{
if (!Playing())
return; // do whatever you want if you aren't in the game or don't have a follower.
if (!P_PlayerMoving(g_localplayers[1]))
{
// Color change menu scrolling fix is no longer necessary
SendNameAndColor2();
}
}
static void Follower3_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
if (!Playing() || !splitscreen)
return; // do whatever you want
strcpy(str, cv_follower3.string);
strcpy(cpy, cv_follower3.string);
strlwr(str);
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
{
if (stricmp(cpy, "None") == 0)
{
CV_StealthSet(&cv_follower3, "-1");
SendNameAndColor3();
return;
}
{
INT32 num = R_FollowerAvailable(str);
char set[10];
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower3, set); // set it to a number. It's easier for us to send later :)
}
}
SendNameAndColor3();
}
static void Followercolor3_OnChange(void)
{
if (!Playing())
return; // do whatever you want if you aren't in the game or don't have a follower.
if (!P_PlayerMoving(g_localplayers[2]))
{
// Color change menu scrolling fix is no longer necessary
SendNameAndColor3();
}
}
static void Follower4_OnChange(void)
{
char str[SKINNAMESIZE+1], cpy[SKINNAMESIZE+1];
if (!Playing() || !splitscreen)
return; // do whatever you want
strcpy(str, cv_follower4.string);
strcpy(cpy, cv_follower4.string);
strlwr(str);
if (stricmp(cpy,"0") !=0 && !atoi(cpy)) // yep, that's a string alright...
{
if (stricmp(cpy, "None") == 0)
{
CV_StealthSet(&cv_follower4, "-1");
SendNameAndColor4();
return;
}
{
INT32 num = R_FollowerAvailable(str);
char set[10];
if (num == -1) // that's an error.
CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str);
sprintf(set, "%d", num);
CV_StealthSet(&cv_follower4, set); // set it to a number. It's easier for us to send later :)
}
}
SendNameAndColor4();
}
static void Followercolor4_OnChange(void)
{
if (!Playing())
return; // do whatever you want if you aren't in the game or don't have a follower.
if (!P_PlayerMoving(g_localplayers[3]))
{
// Color change menu scrolling fix is no longer necessary
SendNameAndColor4();
}
}
/** Sends a skin change for the console player, unless that player is moving.
* \sa cv_skin, Skin2_OnChange, Color_OnChange
* \author Graue <graue@oceanbase.org>
@ -5156,24 +5476,35 @@ static void Command_ShowTime_f(void)
// SRB2Kart: On change messages
static void BaseNumLaps_OnChange(void)
{
if (gametyperules & GTR_CIRCUIT && gamestate == GS_LEVEL)
if (K_CanChangeRules() == true)
{
if (cv_basenumlaps.value)
CONS_Printf(M_GetText("Number of laps will be changed to %d next round.\n"), cv_basenumlaps.value);
else
CONS_Printf(M_GetText("Number of laps will be changed to map defaults next round.\n"));
const char *str = va("%d", cv_basenumlaps.value);
if (cv_basenumlaps.value == 0)
{
str = "map defaults";
}
CONS_Printf(M_GetText("Number of laps will be changed to %s next round.\n"), str);
}
}
static void KartFrantic_OnChange(void)
{
if ((boolean)cv_kartfrantic.value != franticitems && gamestate == GS_LEVEL && leveltime > starttime)
CONS_Printf(M_GetText("Frantic items will be turned %s next round.\n"), cv_kartfrantic.value ? M_GetText("on") : M_GetText("off"));
if (K_CanChangeRules() == false)
{
return;
}
if (leveltime < starttime)
{
CONS_Printf(M_GetText("Frantic items has been set to %s.\n"), cv_kartfrantic.value ? M_GetText("on") : M_GetText("off"));
franticitems = (boolean)cv_kartfrantic.value;
}
else
{
CONS_Printf(M_GetText("Frantic items has been turned %s.\n"), cv_kartfrantic.value ? M_GetText("on") : M_GetText("off"));
franticitems = (boolean)cv_kartfrantic.value;
CONS_Printf(M_GetText("Frantic items will be turned %s next round.\n"), cv_kartfrantic.value ? M_GetText("on") : M_GetText("off"));
}
}
@ -5186,47 +5517,56 @@ static void KartSpeed_OnChange(void)
return;
}
if ((gametyperules & GTR_CIRCUIT))
if (K_CanChangeRules() == false)
{
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);
}
return;
}
if (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
{
CONS_Printf(M_GetText("Game speed will be changed to \"%s\" next round.\n"), cv_kartspeed.string);
}
}
static void KartEncore_OnChange(void)
{
if ((gametyperules & GTR_CIRCUIT))
if (K_CanChangeRules() == false)
{
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 set to %s.\n"), cv_kartencore.string);
return;
}
CONS_Printf(M_GetText("Encore Mode will be set to %s next round.\n"), cv_kartencore.string);
}
static void KartComeback_OnChange(void)
{
if (gametyperules & GTR_KARMA)
if (K_CanChangeRules() == false)
{
if ((boolean)cv_kartcomeback.value != comeback && gamestate == GS_LEVEL && leveltime > starttime)
CONS_Printf(M_GetText("Karma Comeback will be turned %s next round.\n"), cv_kartcomeback.value ? M_GetText("on") : M_GetText("off"));
else
{
CONS_Printf(M_GetText("Karma Comeback has been turned %s.\n"), cv_kartcomeback.value ? M_GetText("on") : M_GetText("off"));
comeback = (boolean)cv_kartcomeback.value;
}
return;
}
if (leveltime < starttime)
{
CONS_Printf(M_GetText("Karma Comeback has been turned %s.\n"), cv_kartcomeback.value ? M_GetText("on") : M_GetText("off"));
comeback = (boolean)cv_kartcomeback.value;
}
else
{
CONS_Printf(M_GetText("Karma Comeback will be turned %s next round.\n"), cv_kartcomeback.value ? M_GetText("on") : M_GetText("off"));
}
}
static void KartEliminateLast_OnChange(void)
{
if ((gametyperules & GTR_CIRCUIT) && cv_karteliminatelast.value)
P_CheckRacers();
if (K_CanChangeRules() == false)
{
CV_StealthSet(&cv_karteliminatelast, cv_karteliminatelast.defaultvalue);
}
P_CheckRacers();
}

View file

@ -21,9 +21,14 @@
extern consvar_t cv_playername[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_playercolor[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_skin[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_follower[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_followercolor[MAXSPLITSCREENPLAYERS];
// preferred number of players
extern consvar_t cv_splitplayers;
extern consvar_t cv_showfollowers;
#ifdef SEENAMES
extern consvar_t cv_seenames, cv_allowseenames;
#endif
@ -69,7 +74,7 @@ extern consvar_t cv_ballhog, cv_selfpropelledbomb, cv_grow, cv_shrink;
extern consvar_t cv_thundershield, cv_bubbleshield, cv_flameshield;
extern consvar_t cv_hyudoro, cv_pogospring, cv_kitchensink;
extern consvar_t cv_triplesneaker, cv_triplebanana, cv_decabanana;
extern consvar_t cv_dualsneaker, cv_triplesneaker, cv_triplebanana, cv_decabanana;
extern consvar_t cv_tripleorbinaut, cv_quadorbinaut, cv_dualjawz;
extern consvar_t cv_kartminimap;

View file

@ -1651,7 +1651,7 @@ void CURLPrepareFile(const char* url, int dfilenum)
// Only allow HTTP and HTTPS
curl_easy_setopt(http_handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
curl_easy_setopt(http_handle, CURLOPT_USERAGENT, va("SRB2Kart/v%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION)); // Set user agent as some servers won't accept invalid user agents.
curl_easy_setopt(http_handle, CURLOPT_USERAGENT, va("SRB2Kart/v%d.%d", VERSION, SUBVERSION)); // Set user agent as some servers won't accept invalid user agents.
// Follow a redirect request, if sent by the server.
curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1L);

View file

@ -270,7 +270,8 @@ typedef enum
NUMKARTITEMS,
// Additional roulette numbers, only used for K_KartGetItemResult
KRITEM_TRIPLESNEAKER = NUMKARTITEMS,
KRITEM_DUALSNEAKER = NUMKARTITEMS,
KRITEM_TRIPLESNEAKER,
KRITEM_TRIPLEBANANA,
KRITEM_TENFOLDBANANA,
KRITEM_TRIPLEORBINAUT,
@ -297,9 +298,6 @@ typedef enum
k_position, // Used for Kart positions, mostly for deterministic stuff
k_oldposition, // Used for taunting when you pass someone
k_positiondelay, // Used for position number, so it can grow when passing/being passed
k_starpostflip, // the last starpost we hit requires flipping?
k_respawn, // Timer for the DEZ laser respawn effect
k_dropdash, // Charge up for respawn Drop Dash
k_throwdir, // Held dir of controls; 1 = forward, 0 = none, -1 = backward (was "player->heldDir")
k_instashield, // Instashield no-damage animation timer
@ -323,13 +321,16 @@ typedef enum
k_jmp, // In Mario Kart, letting go of the jump button stops the drift
k_offroad, // In Super Mario Kart, going offroad has lee-way of about 1 second before you start losing speed
k_pogospring, // Pogo spring bounce effect
k_brakestop, // Wait until you've made a complete stop for a few tics before letting brake go in reverse.
k_spindash, // Spindash charge timer
k_spindashspeed, // Spindash release speed
k_spindashboost, // Spindash release boost timer
k_waterskip, // Water skipping counter
k_dashpadcooldown, // Separate the vanilla SA-style dash pads from using pw_flashing
k_numboosts, // Count of how many boosts are being stacked, for after image spawning
k_boostpower, // Base boost value, for offroad
k_speedboost, // Boost value smoothing for max speed
k_accelboost, // Boost value smoothing for acceleration
k_handleboost, // Boost value smoothing for handling
k_draftpower, // Drafting power (from 0 to FRACUNIT), doubles your top speed & acceleration at max
k_draftleeway, // Leniency timer before removing draft power
k_lastdraft, // Last player being drafted
@ -352,8 +353,8 @@ typedef enum
k_stealingtimer, // You are stealing an item, this is your timer
k_stolentimer, // You are being stolen from, this is your timer
k_superring, // Spawn rings on top of you every tic!
k_sneakertimer, // Duration of the Sneaker Boost itself
k_levelbooster, // Duration of a level booster's boost (same as sneaker, but separated for boost stacking)
k_sneakertimer, // Duration of a Sneaker Boost (from Sneakers or level boosters)
k_numsneakers, // Number of stacked sneaker effects
k_growshrinktimer, // > 0 = Big, < 0 = small
k_squishedtimer, // Squished frame timer
k_rocketsneakertimer, // Rocket Sneaker duration timer
@ -410,6 +411,9 @@ typedef enum
khud_lapanimation, // Used to show the lap start wing logo animation
khud_laphand, // Lap hand gfx to use; 0 = none, 1 = :ok_hand:, 2 = :thumbs_up:, 3 = :thumps_down:
// Start
khud_fault, // Set when faulting during the starting countdown
// Camera
khud_boostcam, // Camera push forward on boost
khud_destboostcam, // Ditto
@ -427,9 +431,6 @@ typedef enum
NUMKARTHUD
} karthudtype_t;
// QUICKLY GET EITHER SNEAKER OR LEVEL BOOSTER SINCE THEY ARE FUNCTIONALLY IDENTICAL
#define EITHERSNEAKER(p) (p->kartstuff[k_sneakertimer] || p->kartstuff[k_levelbooster])
// QUICKLY GET RING TOTAL, INCLUDING RINGS CURRENTLY IN THE PICKUP ANIMATION
#define RINGTOTAL(p) (p->kartstuff[k_rings] + p->kartstuff[k_pickuprings])
@ -453,15 +454,31 @@ typedef enum
RW_RAIL = 32
} ringweapons_t;
// player_t struct for all respawn variables
typedef struct respawnvars_s
{
UINT8 state; // 0: not respawning, 1: heading towards respawn point, 2: about to drop
waypoint_t *wp; // Waypoint that we're going towards, NULL if the position isn't linked to one
fixed_t pointx; // Respawn position coords to go towards
fixed_t pointy;
fixed_t pointz;
boolean flip; // Flip upside down or not
tic_t timer; // Time left on respawn animation once you're there
UINT32 distanceleft; // How far along the course to respawn you
tic_t dropdash; // Drop Dash charge timer
} respawnvars_t;
// player_t struct for all bot variables
typedef struct botvars_s
{
UINT8 difficulty;
UINT8 difficulty; // Bot's difficulty setting
UINT8 diffincrease; // In GP: bot difficulty will increase this much next round
boolean rival; // If true, they're the GP rival
tic_t itemdelay;
tic_t itemconfirm;
tic_t itemdelay; // Delay before using item at all
tic_t itemconfirm; // When high enough, they will use their item
SINT8 turnconfirm;
SINT8 turnconfirm; // Confirm turn direction
} botvars_t;
// ========================================================================
@ -514,6 +531,8 @@ typedef struct player_s
INT16 rturn_max[MAXPREDICTTICS]; // Ditto but for full-right
UINT32 distancetofinish;
waypoint_t *nextwaypoint;
respawnvars_t respawn; // Respawn info
tic_t airtime; // Keep track of how long you've been in the air
// Bit flags.
// See pflags_t, above.
@ -538,6 +557,12 @@ typedef struct player_s
// SRB2kart
UINT8 kartspeed; // Kart speed stat between 1 and 9
UINT8 kartweight; // Kart weight stat between 1 and 9
INT32 followerskin; // Kart: This player's follower "skin"
boolean followerready; // Kart: Used to know when we can have a follower or not. (This is set on the first NameAndColor follower update)
UINT8 followercolor; // Kart: Used to store the follower colour the player wishes to use
mobj_t *follower; // Kart: This is the follower object we have. (If any)
//
UINT32 charflags; // Extra abilities/settings for skins (combinable stuff)
@ -546,7 +571,8 @@ typedef struct player_s
mobjtype_t followitem; // Object # to spawn for Smiles
mobj_t *followmobj; // Smiles all around
SINT8 lives; // number of lives
SINT8 lives;
boolean lostlife;
SINT8 continues; // continues that player has acquired
SINT8 xtralife; // Ring Extra Life counter
@ -583,6 +609,7 @@ typedef struct player_s
INT16 totalring; // Total number of rings obtained for Race Mode
tic_t realtime; // integer replacement for leveltime
UINT8 laps; // Number of laps (optional)
INT32 starpostnum; // The number of the last starpost you hit
////////////////////
// CTF Mode Stuff //
@ -593,15 +620,6 @@ typedef struct player_s
INT32 weapondelay; // Delay (if any) to fire the weapon again
INT32 tossdelay; // Delay (if any) to toss a flag/emeralds again
// Starpost information
INT16 starpostx;
INT16 starposty;
INT16 starpostz;
INT32 starpostnum; // The number of the last starpost you hit
tic_t starposttime; // Your time when you hit the starpost
angle_t starpostangle; // Angle that the starpost is facing - you respawn facing this way
fixed_t starpostscale; // Scale of the player; if negative, player is gravflipped
/////////////////
// NiGHTS Stuff//
/////////////////

View file

@ -34,6 +34,8 @@ typedef enum
BT_BACKWARD = 1<<6, // Aim Item Backward
BT_LOOKBACK = 1<<7, // Look Backward
BT_EBRAKEMASK = (BT_ACCELERATE|BT_BRAKE),
// free: 1<<8 to 1<<12
// Lua garbage
@ -58,7 +60,6 @@ typedef enum
typedef struct
{
SINT8 forwardmove; // -MAXPLMOVE to MAXPLMOVE (50)
SINT8 sidemove; // -MAXPLMOVE to MAXPLMOVE (50)
INT16 angleturn; // <<16 for angle delta - saved as 1 byte into demos
INT16 aiming; // vertical aiming, see G_BuildTicCmd
UINT16 buttons;

View file

@ -38,6 +38,7 @@
#include "lua_script.h"
#include "lua_hook.h"
#include "d_clisrv.h"
#include "r_things.h" // for followers
#include "m_cond.h"
@ -634,6 +635,271 @@ static void readfreeslots(MYFILE *f)
Z_Free(s);
}
// This here is our current only way to make followers.
INT32 numfollowers = 0;
static void readfollower(MYFILE *f)
{
char *s;
char *word, *word2, dname[SKINNAMESIZE+1];
char *tmp;
char testname[SKINNAMESIZE];
boolean nameset;
INT32 fallbackstate = 0;
INT32 res;
INT32 i;
if (numfollowers > MAXSKINS)
{
deh_warning("Error: Too many followers, cannot add anymore.\n");
return;
}
s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
// Ready the default variables for followers. We will overwrite them as we go! We won't set the name or states RIGHT HERE as this is handled down instead.
followers[numfollowers].scale = FRACUNIT;
followers[numfollowers].bubblescale = 0; // No bubble by default
followers[numfollowers].atangle = 230;
followers[numfollowers].dist = 32; // changed from 16 to 32 to better account for ogl models
followers[numfollowers].height = 16;
followers[numfollowers].zoffs = 32;
followers[numfollowers].horzlag = 2;
followers[numfollowers].vertlag = 6;
followers[numfollowers].bobspeed = TICRATE*2;
followers[numfollowers].bobamp = 4;
followers[numfollowers].hitconfirmtime = TICRATE;
followers[numfollowers].defaultcolor = 1;
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
word2 = strtok(NULL, " = ");
if (!word2)
break;
if (word2[strlen(word2)-1] == '\n')
word2[strlen(word2)-1] = '\0';
if (fastcmp(word, "NAME"))
{
DEH_WriteUndoline(word, va("%s", followers[numfollowers].name), UNDO_NONE);
strcpy(followers[numfollowers].name, word2);
nameset = true;
}
else if (fastcmp(word, "DEFAULTCOLOR"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].defaultcolor), UNDO_NONE);
followers[numfollowers].defaultcolor = (UINT8)get_number(word2);
}
else if (fastcmp(word, "SCALE"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].scale), UNDO_NONE);
followers[numfollowers].scale = get_number(word2);
}
else if (fastcmp(word, "BUBBLESCALE"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].bubblescale), UNDO_NONE);
followers[numfollowers].bubblescale = get_number(word2);
}
else if (fastcmp(word, "ATANGLE"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].atangle), UNDO_NONE);
followers[numfollowers].atangle = (INT32)atoi(word2);
}
else if (fastcmp(word, "HORZLAG"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].horzlag), UNDO_NONE);
followers[numfollowers].horzlag = (INT32)atoi(word2);
}
else if (fastcmp(word, "VERTLAG"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].vertlag), UNDO_NONE);
followers[numfollowers].vertlag = (INT32)atoi(word2);
}
else if (fastcmp(word, "BOBSPEED"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].bobspeed), UNDO_NONE);
followers[numfollowers].bobspeed = (INT32)atoi(word2);
}
else if (fastcmp(word, "BOBAMP"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].bobamp), UNDO_NONE);
followers[numfollowers].bobamp = (INT32)atoi(word2);
}
else if (fastcmp(word, "ZOFFSET") || (fastcmp(word, "ZOFFS")))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].zoffs), UNDO_NONE);
followers[numfollowers].zoffs = (INT32)atoi(word2);
}
else if (fastcmp(word, "DISTANCE") || (fastcmp(word, "DIST")))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].dist), UNDO_NONE);
followers[numfollowers].dist = (INT32)atoi(word2);
}
else if (fastcmp(word, "HEIGHT"))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].height), UNDO_NONE);
followers[numfollowers].height = (INT32)atoi(word2);
}
else if (fastcmp(word, "IDLESTATE"))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].idlestate), UNDO_NONE);
followers[numfollowers].idlestate = get_number(word2);
fallbackstate = followers[numfollowers].idlestate;
}
else if (fastcmp(word, "FOLLOWSTATE"))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].followstate), UNDO_NONE);
followers[numfollowers].followstate = get_number(word2);
}
else if (fastcmp(word, "HURTSTATE"))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].hurtstate), UNDO_NONE);
followers[numfollowers].hurtstate = get_number(word2);
}
else if (fastcmp(word, "LOSESTATE"))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].losestate), UNDO_NONE);
followers[numfollowers].losestate = get_number(word2);
}
else if (fastcmp(word, "WINSTATE"))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].winstate), UNDO_NONE);
followers[numfollowers].winstate = get_number(word2);
}
else if (fastcmp(word, "HITSTATE") || (fastcmp(word, "HITCONFIRMSTATE")))
{
if (word2)
strupr(word2);
DEH_WriteUndoline(word, va("%d", followers[numfollowers].hitconfirmstate), UNDO_NONE);
followers[numfollowers].hitconfirmstate = get_number(word2);
}
else if (fastcmp(word, "HITTIME") || (fastcmp(word, "HITCONFIRMTIME")))
{
DEH_WriteUndoline(word, va("%d", followers[numfollowers].hitconfirmtime), UNDO_NONE);
followers[numfollowers].hitconfirmtime = (INT32)atoi(word2);
}
else
deh_warning("Follower %d: unknown word '%s'", numfollowers, word);
}
} while (!myfeof(f)); // finish when the line is empty
if (!nameset) // well this is problematic.
{
strcpy(followers[numfollowers].name, va("Follower%d", numfollowers)); // this is lazy, so what
}
// set skin name (this is just the follower's name in lowercases):
// but before we do, let's... actually check if another follower isn't doing the same shit...
strcpy(testname, followers[numfollowers].name);
// lower testname for skin checks...
strlwr(testname);
res = R_FollowerAvailable(testname);
if (res > -1) // yikes, someone else has stolen our name already
{
INT32 startlen = strlen(testname);
char cpy[2];
//deh_warning("There was already a follower with the same name. (%s)", testname); This warning probably isn't necessary anymore?
sprintf(cpy, "%d", numfollowers);
memcpy(&testname[startlen], cpy, 2);
// in that case, we'll be very lazy and copy numfollowers to the end of our skin name.
}
strcpy(followers[numfollowers].skinname, testname);
strcpy(dname, followers[numfollowers].skinname); // display name, just used for printing succesful stuff or errors later down the line.
// now that the skin name is ready, post process the actual name to turn the underscores into spaces!
for (i = 0; followers[numfollowers].name[i]; i++)
{
if (followers[numfollowers].name[i] == '_')
followers[numfollowers].name[i] = ' ';
}
// fallbacks for variables
// Print a warning if the variable is on a weird value and set it back to the minimum available if that's the case.
#define FALLBACK(field, field2, threshold, set) \
if (followers[numfollowers].field < threshold) \
{ \
followers[numfollowers].field = set; \
deh_warning("Follower '%s': Value for '%s' is too low! Minimum should be %d. Value was overwritten to %d.", dname, field2, set, set); \
} \
FALLBACK(dist, "DIST", 0, 0);
FALLBACK(height, "HEIGHT", 1, 1);
FALLBACK(zoffs, "ZOFFS", 0, 0);
FALLBACK(horzlag, "HORZLAG", 1, 1);
FALLBACK(vertlag, "VERTLAG", 1, 1);
FALLBACK(bobamp, "BOBAMP", 0, 0);
FALLBACK(bobspeed, "BOBSPEED", 0, 0);
FALLBACK(hitconfirmtime, "HITCONFIRMTIME", 1, 1);
FALLBACK(scale, "SCALE", 1, 1); // No null/negative scale
FALLBACK(bubblescale, "BUBBLESCALE", 0, 0); // No negative scale
// Special case for color I suppose
if (followers[numfollowers].defaultcolor > MAXSKINCOLORS-1)
{
followers[numfollowers].defaultcolor = 1;
deh_warning("Follower \'%s\': Value for 'color' should be between 1 and %d.\n", dname, MAXSKINCOLORS-1);
}
#undef FALLBACK
// also check if we forgot states. If we did, we will set any missing state to the follower's idlestate.
// Print a warning in case we don't have a fallback and set the state to S_INVISIBLE (rather than S_NULL) if unavailable.
#define NOSTATE(field, field2) \
if (!followers[numfollowers].field) \
{ \
followers[numfollowers].field = fallbackstate ? fallbackstate : S_INVISIBLE; \
if (!fallbackstate) \
deh_warning("Follower '%s' is missing state definition for '%s', no idlestate fallback was found", dname, field2); \
} \
NOSTATE(idlestate, "IDLESTATE");
NOSTATE(followstate, "FOLLOWSTATE");
NOSTATE(hurtstate, "HURTSTATE");
NOSTATE(losestate, "LOSESTATE");
NOSTATE(winstate, "WINSTATE");
NOSTATE(hitconfirmstate, "HITCONFIRMSTATE");
#undef NOSTATE
CONS_Printf("Added follower '%s'\n", dname);
numfollowers++; // add 1 follower
Z_Free(s);
}
static void readthing(MYFILE *f, INT32 num)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
@ -1875,6 +2141,113 @@ static void readlevelheader(MYFILE *f, INT32 num)
#undef MAXFLICKIES
static void readcupheader(MYFILE *f, cupheader_t *cup)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
char *tmp;
INT32 i;
do
{
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
// First remove trailing newline, if there is one
tmp = strchr(s, '\n');
if (tmp)
*tmp = '\0';
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
// Set / reset word, because some things (Lua.) move it
word = s;
// Get the part before the " = "
tmp = strchr(s, '=');
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
word2 = tmp += 2;
i = atoi(word2); // used for numerical settings
strupr(word2);
if (fastcmp(word, "ICON"))
{
deh_strlcpy(cup->icon, word2,
sizeof(cup->icon), va("%s Cup: icon", cup->name));
}
else if (fastcmp(word, "LEVELLIST"))
{
cup->numlevels = 0;
tmp = strtok(word2,",");
do {
INT32 map = atoi(tmp);
if (tmp[0] >= 'A' && tmp[0] <= 'Z' && tmp[2] == '\0')
map = M_MapNumber(tmp[0], tmp[1]);
if (!map)
break;
if (cup->numlevels >= MAXLEVELLIST)
{
deh_warning("%s Cup: reached max levellist (%d)\n", cup->name, MAXLEVELLIST);
break;
}
cup->levellist[cup->numlevels] = map - 1;
cup->numlevels++;
} while((tmp = strtok(NULL,",")) != NULL);
}
else if (fastcmp(word, "BONUSGAME"))
{
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0')
i = M_MapNumber(word2[0], word2[1]);
cup->bonusgame = (INT16)i - 1;
}
else if (fastcmp(word, "SPECIALSTAGE"))
{
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0')
i = M_MapNumber(word2[0], word2[1]);
cup->specialstage = (INT16)i - 1;
}
else if (fastcmp(word, "EMERALDNUM"))
{
if (i >= 0 && i <= 14)
cup->emeraldnum = (UINT8)i;
else
deh_warning("%s Cup: invalid emerald number %d", cup->name, i);
}
else if (fastcmp(word, "UNLOCKABLE"))
{
if (i >= 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something
cup->unlockrequired = (SINT8)i - 1;
else
deh_warning("%s Cup: invalid unlockable number %d", cup->name, i);
}
else
deh_warning("%s Cup: unknown word '%s'", cup->name, word);
}
} while (!myfeof(f)); // finish when the line is empty
Z_Free(s);
}
static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum)
{
char *s = Z_Calloc(MAXLINELEN, PU_STATIC, NULL);
@ -4484,6 +4857,13 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
readwipes(f);
continue;
}
else if (fastcmp(word, "FOLLOWER"))
{
readfollower(f); // at the same time this will be our only way to ADD followers for now. Yikes.
DEH_WriteUndoline(word, "", UNDO_HEADER);
// This is not a major mod either.
continue; // continue so that we don't error.
}
word2 = strtok(NULL, " ");
if (word2) {
strupr(word2);
@ -4682,6 +5062,42 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
}
}
}
else if (fastcmp(word, "CUP"))
{
cupheader_t *cup = kartcupheaders;
cupheader_t *prev = NULL;
while (cup)
{
if (fastcmp(cup->name, word2))
{
// mark as a major mod if it replaces an already-existing cup
G_SetGameModified(multiplayer, true);
break;
}
prev = cup;
cup = cup->next;
}
// Nothing found, add to the end.
if (!cup)
{
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
cup->id = numkartcupheaders;
deh_strlcpy(cup->name, word2,
sizeof(cup->name), va("Cup header %s: name", word2));
if (prev != NULL)
prev->next = cup;
if (kartcupheaders == NULL)
kartcupheaders = cup;
numkartcupheaders++;
CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name);
}
readcupheader(f, cup);
DEH_WriteUndoline(word, word2, UNDO_HEADER);
}
else if (fastcmp(word, "CUTSCENE"))
{
if (i > 0 && i < 129)
@ -8143,6 +8559,39 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_DRIFTEXPLODE2",
"S_DRIFTEXPLODE3",
"S_DRIFTEXPLODE4",
"S_DRIFTEXPLODE5",
"S_DRIFTEXPLODE6",
"S_DRIFTEXPLODE7",
"S_DRIFTEXPLODE8",
// Drift boost clip
"S_DRIFTCLIPA1",
"S_DRIFTCLIPA2",
"S_DRIFTCLIPA3",
"S_DRIFTCLIPA4",
"S_DRIFTCLIPA5",
"S_DRIFTCLIPA6",
"S_DRIFTCLIPA7",
"S_DRIFTCLIPA8",
"S_DRIFTCLIPA9",
"S_DRIFTCLIPA10",
"S_DRIFTCLIPA11",
"S_DRIFTCLIPA12",
"S_DRIFTCLIPA13",
"S_DRIFTCLIPA14",
"S_DRIFTCLIPA15",
"S_DRIFTCLIPA16",
"S_DRIFTCLIPB1",
"S_DRIFTCLIPB2",
"S_DRIFTCLIPB3",
"S_DRIFTCLIPB4",
"S_DRIFTCLIPB5",
"S_DRIFTCLIPB6",
"S_DRIFTCLIPB7",
"S_DRIFTCLIPB8",
// Drift boost clip spark
"S_DRIFTCLIPSPARK",
// Sneaker boost effect
"S_BOOSTFLAME",
@ -9038,6 +9487,31 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_OPAQUESMOKE4",
"S_OPAQUESMOKE5",
"S_FOLLOWERBUBBLE_FRONT",
"S_FOLLOWERBUBBLE_BACK",
"S_GCHAOIDLE",
"S_GCHAOFLY",
"S_GCHAOSAD1",
"S_GCHAOSAD2",
"S_GCHAOSAD3",
"S_GCHAOSAD4",
"S_GCHAOHAPPY1",
"S_GCHAOHAPPY2",
"S_GCHAOHAPPY3",
"S_GCHAOHAPPY4",
"S_CHEESEIDLE",
"S_CHEESEFLY",
"S_CHEESESAD1",
"S_CHEESESAD2",
"S_CHEESESAD3",
"S_CHEESESAD4",
"S_CHEESEHAPPY1",
"S_CHEESEHAPPY2",
"S_CHEESEHAPPY3",
"S_CHEESEHAPPY4",
"S_RINGDEBT",
"S_RINGSPARKS1",
"S_RINGSPARKS2",
@ -9074,6 +9548,25 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_BATTLECAPSULE_SUPPORT",
"S_BATTLECAPSULE_SUPPORTFLY",
"S_EGOORB",
"S_WATERTRAIL1",
"S_WATERTRAIL2",
"S_WATERTRAIL3",
"S_WATERTRAIL4",
"S_WATERTRAIL5",
"S_WATERTRAIL6",
"S_WATERTRAIL7",
"S_WATERTRAIL8",
"S_WATERTRAILUNDERLAY1",
"S_WATERTRAILUNDERLAY2",
"S_WATERTRAILUNDERLAY3",
"S_WATERTRAILUNDERLAY4",
"S_WATERTRAILUNDERLAY5",
"S_WATERTRAILUNDERLAY6",
"S_WATERTRAILUNDERLAY7",
"S_WATERTRAILUNDERLAY8",
#ifdef SEENAMES
"S_NAMECHECK",
#endif
@ -9888,6 +10381,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_FASTLINE",
"MT_FASTDUST",
"MT_DRIFTEXPLODE",
"MT_DRIFTCLIP",
"MT_DRIFTCLIPSPARK",
"MT_BOOSTFLAME",
"MT_BOOSTSMOKE",
"MT_SNEAKERTRAIL",
@ -10167,6 +10662,13 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BATTLECAPSULE",
"MT_BATTLECAPSULE_PIECE",
"MT_FOLLOWER",
"MT_FOLLOWERBUBBLE_FRONT",
"MT_FOLLOWERBUBBLE_BACK",
"MT_WATERTRAIL",
"MT_WATERTRAILUNDERLAY",
#ifdef SEENAMES
"MT_NAMECHECK",
#endif
@ -10212,7 +10714,7 @@ static const char *const MOBJFLAG2_LIST[] = {
"AXIS", // It's a NiGHTS axis! (For faster checking)
"TWOD", // Moves like it's in a 2D level
"DONTRESPAWN", // Don't respawn this object!
"DONTDRAW", // Don't generate a vissprite
"\x01", // free: 1<<3 (name un-matchable)
"AUTOMATIC", // Thrown ring has automatic properties
"RAILRING", // Thrown ring has rail properties
"BOUNCERING", // Thrown ring has bounce properties
@ -10228,7 +10730,7 @@ static const char *const MOBJFLAG2_LIST[] = {
"JUSTATTACKED", // can be pushed by other moving mobjs
"FIRING", // turret fire
"SUPERFIRE", // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
"SHADOW", // Fuzzy draw, makes targeting harder.
"\x01", // free: 1<<20 (name un-matchable)
"STRONGBOX", // Flag used for "strong" random monitors.
"OBJECTFLIP", // Flag for objects that always have flipped gravity.
"SKULLFLY", // Special handling: skull in flight.
@ -10256,10 +10758,6 @@ static const char *const MOBJEFLAG_LIST[] = {
"APPLYPMOMZ", // Platform movement
"TRACERANGLE", // Compute and trigger on mobj angle relative to tracer
"JUSTBOUNCEDWALL",
"DRAWONLYFORP1", // SRB2Kart: Splitscreen sprite draw flags
"DRAWONLYFORP2",
"DRAWONLYFORP3",
"DRAWONLYFORP4",
NULL
};
@ -10607,9 +11105,6 @@ static const char *const KARTSTUFF_LIST[] = {
"POSITION",
"OLDPOSITION",
"POSITIONDELAY",
"STARPOSTFLIP",
"RESPAWN",
"DROPDASH",
"THROWDIR",
"INSTASHIELD",
@ -10633,13 +11128,16 @@ static const char *const KARTSTUFF_LIST[] = {
"JMP",
"OFFROAD",
"POGOSPRING",
"BRAKESTOP",
"SPINDASH",
"SPINDASHSPEED",
"SPINDASHBOOST",
"WATERSKIP",
"DASHPADCOOLDOWN",
"NUMBOOSTS",
"BOOSTPOWER",
"SPEEDBOOST",
"ACCELBOOST",
"HANDLEBOOST",
"DRAFTPOWER",
"DRAFTLEEWAY",
"LASTDRAFT",
@ -10661,7 +11159,7 @@ static const char *const KARTSTUFF_LIST[] = {
"STOLENTIMER",
"SUPERRING",
"SNEAKERTIMER",
"LEVELBOOSTER",
"NUMSNEAKERS",
"GROWSHRINKTIMER",
"SQUISHEDTIMER",
"ROCKETSNEAKERTIMER",
@ -11248,7 +11746,6 @@ struct {
{"DI_SOUTHEAST",DI_SOUTHEAST},
{"NUMDIRS",NUMDIRS},
// Sprite rotation axis (rotaxis_t)
{"ROTAXIS_X",ROTAXIS_X},
{"ROTAXIS_Y",ROTAXIS_Y},
@ -11340,7 +11837,7 @@ struct {
{"V_WRAPY",V_WRAPY},
{"V_NOSCALESTART",V_NOSCALESTART},
{"V_SPLITSCREEN",V_SPLITSCREEN},
{"V_HORZSCREEN",V_HORZSCREEN},
{"V_SLIDEIN",V_SLIDEIN},
{"V_PARAMMASK",V_PARAMMASK},
{"V_SCALEPATCHMASK",V_SCALEPATCHMASK},
@ -11380,7 +11877,8 @@ struct {
KART_ITEM_ITERATOR, // Actual items (can be set for k_itemtype)
#undef FOREACH
{"NUMKARTITEMS",NUMKARTITEMS},
{"KRITEM_TRIPLESNEAKER",KRITEM_TRIPLESNEAKER}, // Additional roulette IDs (not usable for much in Lua besides K_GetItemPatch)
{"KRITEM_DUALSNEAKER",KRITEM_DUALSNEAKER}, // Additional roulette IDs (not usable for much in Lua besides K_GetItemPatch)
{"KRITEM_TRIPLESNEAKER",KRITEM_TRIPLESNEAKER},
{"KRITEM_TRIPLEBANANA",KRITEM_TRIPLEBANANA},
{"KRITEM_TENFOLDBANANA",KRITEM_TENFOLDBANANA},
{"KRITEM_TRIPLEORBINAUT",KRITEM_TRIPLEORBINAUT},
@ -11395,6 +11893,37 @@ struct {
{"KSHIELD_FLAME",KSHIELD_FLAME},
{"NUMKARTSHIELDS",NUMKARTSHIELDS},
// translation colormaps
{"TC_DEFAULT",TC_DEFAULT},
{"TC_BOSS",TC_BOSS},
{"TC_METALSONIC",TC_METALSONIC},
{"TC_ALLWHITE",TC_ALLWHITE},
{"TC_RAINBOW",TC_RAINBOW},
{"TC_BLINK",TC_BLINK},
// MFD_ draw flag enum
{"MFD_DONTDRAWP1",MFD_DONTDRAWP1},
{"MFD_DONTDRAWP2",MFD_DONTDRAWP2},
{"MFD_DONTDRAWP3",MFD_DONTDRAWP3},
{"MFD_DONTDRAWP4",MFD_DONTDRAWP4},
{"MFD_TRANS10",MFD_TRANS10},
{"MFD_TRANS20",MFD_TRANS20},
{"MFD_TRANS30",MFD_TRANS30},
{"MFD_TRANS40",MFD_TRANS40},
{"MFD_TRANS50",MFD_TRANS50},
{"MFD_TRANS60",MFD_TRANS60},
{"MFD_TRANS70",MFD_TRANS70},
{"MFD_TRANS80",MFD_TRANS80},
{"MFD_TRANS90",MFD_TRANS90},
{"MFD_TRANSMASK",MFD_TRANSMASK},
{"MFD_FULLBRIGHT",MFD_FULLBRIGHT},
{"MFD_SEMIBRIGHT",MFD_SEMIBRIGHT},
{"MFD_NOBRIGHT",MFD_NOBRIGHT},
{"MFD_BRIGHTMASK",MFD_BRIGHTMASK},
{"MFD_DONTDRAW",MFD_DONTDRAW},
{"MFD_SHADOW",MFD_SHADOW},
{"MFD_TRANSSHIFT",MFD_TRANSSHIFT},
{NULL,0}
};

View file

@ -425,8 +425,30 @@ typedef struct
extern mapheader_t* mapheaderinfo[NUMMAPS];
// This could support more, but is that a good idea?
// Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory.
#define MAXLEVELLIST 5
typedef struct cupheader_s
{
UINT16 id; ///< Cup ID
char name[15]; ///< Cup title (14 chars)
char icon[9]; ///< Name of the icon patch
INT16 levellist[MAXLEVELLIST]; ///< List of levels that belong to this cup
UINT8 numlevels; ///< Number of levels defined in levellist
INT16 bonusgame; ///< Map number to use for bonus game
INT16 specialstage; ///< Map number to use for special stage
UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald)
SINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required.
struct cupheader_s *next; ///< Next cup in linked list
} cupheader_t;
extern cupheader_t *kartcupheaders; // Start of cup linked list
extern UINT16 numkartcupheaders;
// Gametypes
#define NUMGAMETYPEFREESLOTS 128
enum GameType
{
GT_RACE = 0,
@ -590,8 +612,13 @@ extern UINT16 nightslinktics;
// SRB2kart
extern tic_t introtime;
extern tic_t starttime;
extern const tic_t bulbtime;
extern UINT8 numbulbs;
extern tic_t raceexittime;
extern tic_t battleexittime;
extern INT32 hyudorotime;
extern INT32 stealtime;
extern INT32 sneakertime;
@ -645,6 +672,7 @@ extern tic_t hyubgone;
extern tic_t mapreset;
extern boolean thwompsactive;
extern SINT8 spbplace;
extern boolean rainbowstartavailable;
extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :)
extern boolean legitimateexit;

View file

@ -24,6 +24,7 @@
#include "z_zone.h"
#include "i_system.h"
#include "i_threads.h"
#include "m_menu.h"
#include "console.h"
#include "d_main.h"
@ -477,7 +478,15 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean r
I_UpdateNoBlit();
if (drawMenu)
{
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
#endif
M_Drawer(); // menu is drawn even on top of wipes
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
#endif
}
I_FinishUpdate(); // page flip or blit buffer

77
src/font.c Normal file
View file

@ -0,0 +1,77 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1999-2018 by Sonic Team Junior.
// Copyright (C) 2019 by Kart Krew.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file font.c
/// \brief Font setup
#include "doomdef.h"
#include "hu_stuff.h"
#include "font.h"
#include "z_zone.h"
font_t fontv[MAX_FONTS];
int fontc;
static void
FontCache (font_t *fnt)
{
int i;
int c;
c = fnt->start;
for (i = 0; i < fnt->size; ++i, ++c)
{
fnt->font[i] = HU_CachePatch(
"%s%.*d",
fnt->prefix,
fnt->digits,
c);
}
}
void
Font_Load (void)
{
int i;
for (i = 0; i < fontc; ++i)
{
FontCache(&fontv[i]);
}
}
int
Font_DumbRegister (const font_t *sfnt)
{
font_t *fnt;
if (fontc == MAX_FONTS)
return -1;
fnt = &fontv[fontc];
memcpy(fnt, sfnt, sizeof (font_t));
if (!( fnt->font = ZZ_Alloc(sfnt->size * sizeof (patch_t *)) ))
return -1;
return fontc++;
}
int
Font_Register (const font_t *sfnt)
{
int d;
d = Font_DumbRegister(sfnt);
if (d >= 0)
FontCache(&fontv[d]);
return d;
}

49
src/font.h Normal file
View file

@ -0,0 +1,49 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1999-2018 by Sonic Team Junior.
// Copyright (C) 2019 by Kart Krew.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file font.h
/// \brief Font setup
#ifndef __FONT_H__
#define __FONT_H__
#define MAX_FONTS 32
typedef struct font font_t;
struct font
{
patch_t **font;
UINT8 start;
UINT8 size;
char prefix[8];/* 7 used at most */
unsigned digits : 2;
};
extern font_t fontv[MAX_FONTS];
extern int fontc;
/*
Reloads already registered fonts.
*/
void Font_Load (void);
/*
Registers and loads a new font.
*/
int Font_Register (const font_t *);
/*
Register a new font, but do not load it yet.
*/
int Font_DumbRegister (const font_t *);
#endif

View file

@ -55,6 +55,8 @@
#include "k_battle.h"
#include "k_pwrlv.h"
#include "k_color.h"
#include "k_respawn.h"
#include "k_grandprix.h"
gameaction_t gameaction;
@ -185,6 +187,10 @@ struct quake quake;
// Map Header Information
mapheader_t* mapheaderinfo[NUMMAPS] = {NULL};
// Kart cup definitions
cupheader_t *kartcupheaders = NULL;
UINT16 numkartcupheaders = 0;
static boolean exitgame = false;
static boolean retrying = false;
static boolean retryingmodeattack = false;
@ -241,10 +247,15 @@ INT32 gameovertics = 15*TICRATE;
UINT8 ammoremovaltics = 2*TICRATE;
// SRB2kart
tic_t introtime = 108+5; // plus 5 for white fade
tic_t starttime = 6*TICRATE + (3*TICRATE/4);
tic_t introtime = 0;
tic_t starttime = 0;
const tic_t bulbtime = TICRATE/2;
UINT8 numbulbs = 0;
tic_t raceexittime = 5*TICRATE + (2*TICRATE/3);
tic_t battleexittime = 8*TICRATE;
INT32 hyudorotime = 7*TICRATE;
INT32 stealtime = TICRATE/2;
INT32 sneakertime = TICRATE + (TICRATE/3);
@ -306,6 +317,7 @@ 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
boolean thwompsactive; // Thwomps activate on lap 2
SINT8 spbplace; // SPB exists, give the person behind better items
boolean rainbowstartavailable; // Boolean, keeps track of if the rainbow start was gotten
// Client-sided, unsynched variables (NEVER use in anything that needs to be synced with other players)
tic_t bombflashtimer = 0; // Cooldown before another FlashPal can be intialized by a bomb exploding near a displayplayer. Avoids seizures.
@ -984,24 +996,24 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
cmd->buttons |= BT_BRAKE;
axis = PlayerJoyAxis(ssplayer, AXISAIM);
if (PlayerInputDown(ssplayer, gc_aimforward) || (usejoystick && axis < 0))
forward += forwardmove[1];
forward += forwardmove;
if (PlayerInputDown(ssplayer, gc_aimbackward) || (usejoystick && axis > 0))
forward -= forwardmove[1];
forward -= forwardmove;
}
else
{
// forward with key or button // SRB2kart - we use an accel/brake instead of forward/backward.
axis = PlayerJoyAxis(ssplayer, AXISMOVE);
if (PlayerInputDown(ssplayer, gc_accelerate) || (gamepadjoystickmove && axis > 0) || EITHERSNEAKER(player))
if (PlayerInputDown(ssplayer, gc_accelerate) || (gamepadjoystickmove && axis > 0) || player->kartstuff[k_sneakertimer])
{
cmd->buttons |= BT_ACCELERATE;
forward = forwardmove[1]; // 50
forward = forwardmove; // 50
}
else if (analogjoystickmove && axis > 0)
{
cmd->buttons |= BT_ACCELERATE;
// JOYAXISRANGE is supposed to be 1023 (divide by 1024)
forward += ((axis * forwardmove[1]) >> 10)*2;
forward += ((axis * forwardmove) >> 10);
}
axis = PlayerJoyAxis(ssplayer, AXISBRAKE);
@ -1009,14 +1021,14 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
{
cmd->buttons |= BT_BRAKE;
if (cmd->buttons & BT_ACCELERATE || cmd->forwardmove <= 0)
forward -= forwardmove[0]; // 25 - Halved value so clutching is possible
forward -= forwardmove;
}
else if (analogjoystickmove && axis > 0)
{
cmd->buttons |= BT_BRAKE;
// JOYAXISRANGE is supposed to be 1023 (divide by 1024)
if (cmd->buttons & BT_ACCELERATE || cmd->forwardmove <= 0)
forward -= ((axis * forwardmove[0]) >> 10);
forward -= ((axis * forwardmove) >> 10);
}
// But forward/backward IS used for aiming.
@ -1064,7 +1076,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
INT32 player_invert = invertmouse ? -1 : 1;
INT32 screen_invert =
(player->mo && (player->mo->eflags & MFE_VERTICALFLIP)
&& (!thiscam->chase || player->pflags & PF_FLIPCAM)) //because chasecam's not inverted
&& (!thiscam->chase)) //because chasecam's not inverted
? -1 : 1; // set to -1 or 1 to multiply
INT32 configlookaxis = ssplayer == 1 ? cv_lookaxis.value : cv_lookaxis2.value;
@ -1111,15 +1123,12 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
mousex = mousey = mlooky = 0;
if (forward > MAXPLMOVE)
forward = MAXPLMOVE;
else if (forward < -MAXPLMOVE)
forward = -MAXPLMOVE;
cmd->forwardmove += (SINT8)forward;
if (forward != 0)
{
cmd->forwardmove = (SINT8)(cmd->forwardmove + forward);
}
if (cmd->forwardmove > MAXPLMOVE)
cmd->forwardmove = MAXPLMOVE;
else if (cmd->forwardmove < -MAXPLMOVE)
cmd->forwardmove = -MAXPLMOVE;
//{ SRB2kart - Drift support
// Not grouped with the rest of turn stuff because it needs to know what buttons you're pressing for rubber-burn turn
@ -1139,11 +1148,12 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
cmd->angleturn *= realtics;
// SRB2kart - no additional angle if not moving
if ((player->mo && player->speed > 0) // Moving
|| (leveltime > starttime && (cmd->buttons & BT_ACCELERATE && cmd->buttons & BT_BRAKE)) // Rubber-burn turn
|| (player->kartstuff[k_respawn]) // Respawning
|| (player->spectator || objectplacing)) // Not a physical player
*lang += (cmd->angleturn<<16);
cmd->angleturn = (INT16)(*lang >> 16);
cmd->latency = modeattacking ? 0 : (leveltime & 0xFF); // Send leveltime when this tic was generated to the server for control lag calculations
if (!hu_stopped)
{
*lang += (cmd->angleturn<<16);
}
@ -1165,7 +1175,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
LUAh_PlayerCmd(player, cmd);
//Reset away view if a command is given.
if ((cmd->forwardmove || cmd->sidemove || cmd->buttons)
if ((cmd->forwardmove || cmd->buttons)
&& !r_splitscreen && displayplayers[0] != consoleplayer && ssplayer == 1)
{
// Call ViewpointSwitch hooks here.
@ -1252,14 +1262,6 @@ void G_DoLoadLevel(boolean resetplayer)
P_FindEmerald();
g_localplayers[0] = consoleplayer; // view the guy you are playing
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
if (i > 0 && r_splitscreen < i)
g_localplayers[i] = consoleplayer;
}
gameaction = ga_nothing;
#ifdef PARANOIA
Z_CheckHeap(-2);
@ -1856,30 +1858,19 @@ void G_Ticker(boolean run)
if (gamestate == GS_LEVEL)
{
// Or, alternatively, retry.
if (!(netgame || multiplayer) && G_GetRetryFlag())
if (G_GetRetryFlag())
{
G_ClearRetryFlag();
if (modeattacking)
for (i = 0; i < MAXPLAYERS; i++)
{
pausedelay = INT32_MIN;
M_ModeAttackRetry(0);
}
/*
else
{
// Costs a life to retry ... unless the player in question is dead already, or you haven't even touched the first starpost in marathon run.
if (marathonmode && gamemap == spmarathon_start && !players[consoleplayer].starposttime)
if (playeringame[i])
{
marathonmode |= MA_INIT;
marathontime = 0;
K_PlayerLoseLife(&players[i]);
}
else if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE && players[consoleplayer].lives != INFLIVES)
players[consoleplayer].lives -= 1;
G_DoReborn(consoleplayer);
}
*/
D_MapChange(gamemap, gametype, (cv_kartencore.value == 1), false, 1, false, false);
}
for (i = 0; i < MAXPLAYERS; i++)
@ -1911,16 +1902,18 @@ void G_Ticker(boolean run)
if (playeringame[i])
{
if (K_PlayerUsesBotMovement(&players[i]))
G_CopyTiccmd(cmd, &netcmds[buf][i], 1);
// Use the leveltime sent in the player's ticcmd to determine control lag
if (modeattacking || K_PlayerUsesBotMovement(&players[i]))
{
K_BuildBotTiccmd(&players[i], cmd);
// Never has lag
cmd->latency = 0;
}
else
{
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
//@TODO add a cvar to allow setting this max
cmd->latency = min(((leveltime & 0xFF) - cmd->latency) & 0xFF, MAXPREDICTTICS-1);
}
players[i].angleturn += players[i].cmd.angleturn - players[i].oldrelangleturn;
@ -1934,7 +1927,7 @@ void G_Ticker(boolean run)
switch (gamestate)
{
case GS_LEVEL:
if (titledemo)
if (demo.title)
F_TitleDemoTicker();
P_Ticker(run); // tic the game
ST_Ticker(run);
@ -2058,15 +2051,11 @@ static inline void G_PlayerFinishLevel(INT32 player)
memset(p->kartstuff, 0, sizeof (p->kartstuff)); // SRB2kart
p->ringweapons = 0;
p->mo->flags2 &= ~MF2_SHADOW; // cancel invisibility
p->mo->drawflags &= ~(MFD_TRANSMASK|MFD_BRIGHTMASK); // cancel invisibility
P_FlashPal(p, 0, 0); // Resets
p->starpostscale = 0;
p->starpostangle = 0;
p->starposttime = 0;
p->starpostx = 0;
p->starposty = 0;
p->starpostz = 0;
p->starpostnum = 0;
memset(&p->respawn, 0, sizeof (p->respawn));
// SRB2kart: Increment the "matches played" counter.
if (player == consoleplayer)
@ -2092,10 +2081,17 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
player_t *p;
INT32 score, marescore;
INT32 lives;
boolean lostlife;
INT32 continues;
UINT8 kartspeed;
UINT8 kartweight;
boolean followerready;
INT32 followerskin;
UINT8 followercolor;
mobj_t *follower; // old follower, will probably be removed by the time we're dead but you never know.
INT32 charflags;
UINT32 followitem;
@ -2103,14 +2099,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
INT32 ctfteam;
INT32 starposttime;
INT16 starpostx;
INT16 starposty;
INT16 starpostz;
INT32 starpostnum;
INT32 starpostangle;
fixed_t starpostscale;
INT32 exiting;
tic_t dashmode;
INT16 numboxes;
@ -2133,7 +2122,13 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
INT16 playerangleturn;
INT16 oldrelangleturn;
UINT8 botdiffincrease;
boolean botrival;
SINT8 xtralife;
// SRB2kart
respawnvars_t respawn;
INT32 itemtype;
INT32 itemamount;
INT32 itemroulette;
@ -2143,12 +2138,12 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
INT32 comebackpoints;
INT32 wanted;
INT32 rings;
INT32 respawnflip;
boolean songcredit = false;
score = players[player].score;
marescore = players[player].marescore;
lives = players[player].lives;
lostlife = players[player].lostlife;
continues = players[player].continues;
ctfteam = players[player].ctfteam;
exiting = players[player].exiting;
@ -2184,25 +2179,27 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
kartspeed = players[player].kartspeed;
kartweight = players[player].kartweight;
follower = players[player].follower;
followerready = players[player].followerready;
followercolor = players[player].followercolor;
followerskin = players[player].followerskin;
availabilities = players[player].availabilities;
charflags = players[player].charflags;
starposttime = players[player].starposttime;
starpostx = players[player].starpostx;
starposty = players[player].starposty;
starpostz = players[player].starpostz;
starpostnum = players[player].starpostnum;
respawnflip = players[player].kartstuff[k_starpostflip]; //SRB2KART
starpostangle = players[player].starpostangle;
starpostscale = players[player].starpostscale;
followitem = players[player].followitem;
mare = players[player].mare;
bot = players[player].bot;
botdifficulty = players[player].botvars.difficulty;
botdiffincrease = players[player].botvars.diffincrease;
botrival = players[player].botvars.rival;
xtralife = players[player].xtralife;
// SRB2kart
if (betweenmaps || leveltime < starttime)
{
@ -2244,12 +2241,18 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
wanted = players[player].kartstuff[k_wanted];
}
// Obliterate follower from existence
P_SetTarget(&players[player].follower, NULL);
memcpy(&respawn, &players[player].respawn, sizeof (respawn));
p = &players[player];
memset(p, 0, sizeof (*p));
p->score = score;
p->marescore = marescore;
p->lives = lives;
p->lostlife = lostlife;
p->continues = continues;
p->pflags = pflags;
p->ctfteam = ctfteam;
@ -2270,14 +2273,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->availabilities = availabilities;
p->followitem = followitem;
p->starposttime = starposttime;
p->starpostx = starpostx;
p->starposty = starposty;
p->starpostz = starpostz;
p->starpostnum = starpostnum;
p->starpostangle = starpostangle;
p->starpostscale = starpostscale;
p->exiting = exiting;
p->dashmode = dashmode;
@ -2290,6 +2286,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->bot = bot;
p->botvars.difficulty = botdifficulty;
p->rings = rings;
p->botvars.diffincrease = botdiffincrease;
p->botvars.rival = botrival;
p->xtralife = xtralife;
// SRB2kart
p->kartstuff[k_itemroulette] = itemroulette;
@ -2304,7 +2303,18 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->kartstuff[k_wanted] = wanted;
p->kartstuff[k_eggmanblame] = -1;
p->kartstuff[k_lastdraft] = -1;
p->kartstuff[k_starpostflip] = respawnflip;
memcpy(&p->respawn, &respawn, sizeof (p->respawn));
if (follower)
P_RemoveMobj(follower);
p->followerready = followerready;
p->followerskin = followerskin;
p->followercolor = followercolor;
//p->follower = NULL; // respawn a new one with you, it looks better.
// ^ Not necessary anyway since it will be respawned regardless considering it doesn't exist anymore.
// Don't do anything immediately
p->pflags |= PF_USEDOWN;
@ -2362,7 +2372,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
S_ShowMusicCredit();
if (leveltime > (starttime + (TICRATE/2)) && !p->spectator)
p->kartstuff[k_respawn] = 48; // Respawn effect
{
K_DoIngameRespawn(p);
}
}
//
@ -2778,10 +2790,7 @@ void G_AddPlayer(INT32 playernum)
p->playerstate = PST_REBORN;
demo_extradata[playernum] |= DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN; // Set everything
if (G_GametypeUsesLives())
p->lives = 3;
demo_extradata[playernum] |= DXD_PLAYSTATE|DXD_COLOR|DXD_NAME|DXD_SKIN|DXD_FOLLOWER; // Set everything
if ((countplayers && !notexiting) || G_IsSpecialStage(gamemap))
P_DoPlayerExit(p);
@ -2791,6 +2800,47 @@ void G_ExitLevel(void)
{
if (gamestate == GS_LEVEL)
{
if (grandprixinfo.gp == true && grandprixinfo.wonround != true)
{
UINT8 i;
// You didn't win...
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator && !players[i].bot)
{
if (players[i].lives > 0)
{
break;
}
}
}
if (i == MAXPLAYERS)
{
// GAME OVER, try again from the start!
if (netgame)
{
; // restart cup here if we do online GP
}
else
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
}
}
else
{
// Go redo this course.
G_SetRetryFlag();
}
return;
}
gameaction = ga_completed;
lastdraw = true;
@ -3073,11 +3123,13 @@ boolean G_IsSpecialStage(INT32 mapnum)
//
boolean G_GametypeUsesLives(void)
{
if ((gametyperules & GTR_LIVES)
&& !(modeattacking || metalrecording) // No lives in Time Attack
&& !battlecapsules // No lives in bonus game
&& !G_IsSpecialStage(gamemap)) // No lives in special stage
if ((grandprixinfo.gp == true) // In Grand Prix
&& (gametype == GT_RACE) // NOT in bonus round
&& !G_IsSpecialStage(gamemap) // NOT in special stage
&& !(modeattacking || metalrecording)) // NOT in Record Attack
{
return true;
}
return false;
}
@ -3460,11 +3512,7 @@ static void G_HandleSaveLevel(void)
static void G_DoCompleted(void)
{
INT32 i, j = 0;
boolean gottoken = false;
SINT8 powertype = PWRLV_DISABLED;
boolean spec = G_IsSpecialStage(gamemap);
tokenlist = 0; // Reset the list
SINT8 powertype = K_UsingPowerLevels();
if (modeattacking && pausedelay)
pausedelay = 0;
@ -3482,10 +3530,21 @@ static void G_DoCompleted(void)
// SRB2Kart: exitlevel shouldn't get you the points
if (!players[i].exiting && !(players[i].pflags & PF_TIMEOVER))
{
players[i].pflags |= PF_TIMEOVER;
if (P_IsLocalPlayer(&players[i]))
j++;
if (players[i].bot)
{
K_FakeBotResults(&players[i]);
}
else
{
players[i].pflags |= PF_TIMEOVER;
if (P_IsLocalPlayer(&players[i]))
{
j++;
}
}
}
G_PlayerFinishLevel(i); // take away cards and stuff
}
@ -3505,11 +3564,30 @@ static void G_DoCompleted(void)
// go to next level
// nextmap is 0-based, unlike gamemap
if (nextmapoverride != 0)
{
nextmap = (INT16)(nextmapoverride-1);
else if (marathonmode && mapheaderinfo[gamemap-1]->marathonnext)
nextmap = (INT16)(mapheaderinfo[gamemap-1]->marathonnext-1);
else if (mapheaderinfo[gamemap-1]->nextlevel == 1101) // SRB2Kart: !!! WHENEVER WE GET GRAND PRIX, GO TO AWARDS MAP INSTEAD !!!
nextmap = (INT16)(mapheaderinfo[gamemap] ? gamemap : (spstage_start-1)); // (gamemap-1)+1 == gamemap :V
else if (grandprixinfo.gp == true)
{
if (grandprixinfo.roundnum == 0 || grandprixinfo.cup == NULL) // Single session
{
nextmap = prevmap; // Same map
}
else
{
if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map
{
nextmap = 1101; // ceremonymap
}
else
{
// Proceed to next map
nextmap = grandprixinfo.cup->levellist[grandprixinfo.roundnum];
grandprixinfo.roundnum++;
}
}
}
else
{
nextmap = (INT16)(mapheaderinfo[gamemap-1]->nextlevel-1);
@ -3517,11 +3595,15 @@ static void G_DoCompleted(void)
nextmap = 1100-1; // No infinite loop for you
}
// Remember last map for when you come out of the special stage.
if (!G_IsSpecialStage(gamemap))
lastmap = nextmap;
// If nextmap is actually going to get used, make sure it points to
// a map of the proper gametype -- skip levels that don't support
// the current gametype. (Helps avoid playing boss levels in Race,
// for instance).
if (!spec)
if (!modeattacking && grandprixinfo.gp == false && (nextmap >= 0 && nextmap < NUMMAPS))
{
if (nextmap >= 0 && nextmap < NUMMAPS)
{
@ -3576,35 +3658,18 @@ static void G_DoCompleted(void)
lastmap = nextmap; // Remember last map for when you come out of the special stage.
}
if ((gottoken = ((gametyperules & GTR_SPECIALSTAGES) && token)))
{
token--;
for (i = 0; i < 7; i++)
if (!(emeralds & (1<<i)))
{
nextmap = ((netgame || multiplayer) ? smpstage_start : sstage_start) + i - 1; // to special stage!
break;
}
if (i == 7)
{
gottoken = false;
token = 0;
}
}
if (spec && !gottoken)
nextmap = lastmap; // Exiting from a special stage? Go back to the game. Tails 08-11-2001
automapactive = false;
if (!(gametyperules & GTR_CAMPAIGN))
{
if (cv_advancemap.value == 0) // Stay on same map.
{
nextmap = prevmap;
}
else if (cv_advancemap.value == 2) // Go to random map.
{
nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, false, 0, false, NULL);
}
}
// We are committed to this map now.
@ -3614,14 +3679,6 @@ static void G_DoCompleted(void)
P_AllocMapHeader(nextmap);
// Set up power level gametype scrambles
if (netgame && cv_kartusepwrlv.value)
{
if ((gametyperules & GTR_CIRCUIT))
powertype = PWRLV_RACE;
else if ((gametyperules & GTR_BUMPERS))
powertype = PWRLV_BATTLE;
}
K_SetPowerLevelScrambles(powertype);
demointermission:
@ -3702,7 +3759,7 @@ void G_NextLevel(void)
{
if (gamestate != GS_VOTING)
{
if ((cv_advancemap.value == 3) && !modeattacking && !skipstats && (multiplayer || netgame))
if ((cv_advancemap.value == 3) && grandprixinfo.gp == false && !modeattacking && !skipstats && (multiplayer || netgame))
{
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
@ -3803,7 +3860,7 @@ static void G_DoContinued(void)
G_SaveGameOver((UINT32)cursaveslot, true);
// Reset # of lives
pl->lives = (ultimatemode) ? 1 : startinglivesbalance[numgameovers];
pl->lives = 3;
D_MapChange(gamemap, gametype, false, false, 0, false, false);
@ -4382,6 +4439,7 @@ void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar
{
INT32 i;
UINT16 color = SKINCOLOR_NONE;
paused = false;
if (demo.playback)
@ -4395,11 +4453,7 @@ void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar
// this leave the actual game if needed
SV_StartSinglePlayerServer();
if (savedata.lives > 0)
{
color = savedata.skincolor;
}
else if (splitscreen != ssplayers)
if (splitscreen != ssplayers)
{
splitscreen = ssplayers;
SplitScreen_OnChange();
@ -4444,62 +4498,40 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool
if (!demo.playback && !netgame) // Netgame sets random seed elsewhere, demo playback sets seed just before us!
P_SetRandSeed(M_RandomizedSeed()); // Use a more "Random" random seed
//SRB2Kart - Score is literally the only thing you SHOULDN'T reset at all times
//if (resetplayer)
// Clear a bunch of variables
redscore = bluescore = lastmap = 0;
racecountdown = exitcountdown = mapreset = exitfadestarted = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
// Clear a bunch of variables
numgameovers = tokenlist = token = sstimer = redscore = bluescore = lastmap = 0;
racecountdown = exitcountdown = mapreset = exitfadestarted = 0;
players[i].playerstate = PST_REBORN;
players[i].starpostnum = 0;
memset(&players[i].respawn, 0, sizeof (players[i].respawn));
for (i = 0; i < MAXPLAYERS; i++)
// The latter two should clear by themselves, but just in case
players[i].pflags &= ~(PF_GAMETYPEOVER|PF_FULLSTASIS);
// Clear cheatcodes too, just in case.
players[i].pflags &= ~(PF_GODMODE|PF_NOCLIP|PF_INVIS);
players[i].marescore = 0;
if (resetplayer && !(multiplayer && demo.playback)) // SRB2Kart
{
players[i].playerstate = PST_REBORN;
players[i].starpostscale = players[i].starpostangle = players[i].starpostnum = players[i].starposttime = 0;
players[i].starpostx = players[i].starposty = players[i].starpostz = 0;
#if 0
if (netgame || multiplayer)
{
if (!FLS || (players[i].lives < 1))
players[i].lives = cv_startinglives.value;
players[i].continues = 0;
}
else
{
players[i].lives = (pultmode) ? 1 : startinglivesbalance[0];
players[i].continues = (pultmode) ? 0 : 1;
}
players[i].lives = 3;
players[i].xtralife = 0;
#else
players[i].lives = 1; // SRB2Kart
#endif
if (!((netgame || multiplayer) && (FLS)))
players[i].score = 0;
// The latter two should clear by themselves, but just in case
players[i].pflags &= ~(PF_TAGIT|PF_GAMETYPEOVER|PF_FULLSTASIS);
// Clear cheatcodes too, just in case.
players[i].pflags &= ~(PF_GODMODE|PF_NOCLIP|PF_INVIS);
players[i].marescore = 0;
if (resetplayer && !(multiplayer && demo.playback)) // SRB2Kart
{
players[i].score = 0;
}
players[i].totalring = 0;
players[i].score = 0;
}
// Reset unlockable triggers
unlocktriggers = 0;
// clear itemfinder, just in case
if (!dedicated) // except in dedicated servers, where it is not registered and can actually I_Error debug builds
CV_StealthSetValue(&cv_itemfinder, 0);
}
// Reset unlockable triggers
unlocktriggers = 0;
// clear itemfinder, just in case
if (!dedicated) // except in dedicated servers, where it is not registered and can actually I_Error debug builds
CV_StealthSetValue(&cv_itemfinder, 0);
// internal game map
// well this check is useless because it is done before (d_netcmd.c::command_map_f)
// but in case of for demos....

View file

@ -187,7 +187,6 @@ void G_UpdateGametypeSelections(void);
void G_AddTOL(UINT32 newtol, const char *tolname);
void G_AddGametypeTOL(INT16 gtype, UINT32 newtol);
void G_SetGametypeDescription(INT16 gtype, char *descriptiontext, UINT8 leftcolor, UINT8 rightcolor);
INT32 G_GetGametypeByName(const char *gametypestr);
boolean G_IsSpecialStage(INT32 mapnum);
boolean G_GametypeUsesLives(void);

View file

@ -30,6 +30,7 @@
#include "../st_stuff.h"
#include "../p_local.h" // stplyr
#include "../g_game.h" // players
#include "../k_hud.h"
#include <fcntl.h>
#include "../i_video.h" // for rendermode != render_glide
@ -199,80 +200,6 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t
cy -= offsety;
}
if (option & V_SPLITSCREEN)
cy += FIXED_TO_FLOAT((BASEVIDHEIGHT/2)<<FRACBITS);
if (option & V_HORZSCREEN)
cx += FIXED_TO_FLOAT((BASEVIDWIDTH/2)<<FRACBITS);
if (splitscreen && (option & V_PERPLAYER))
{
float adjusty = ((option & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)/2.0f;
fscaleh /= 2;
cy /= 2;
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
float adjustx = ((option & V_NOSCALESTART) ? vid.width : BASEVIDWIDTH)/2.0f;
fscalew /= 2;
cx /= 2;
if (stplyr == &players[displayplayers[0]])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
option &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
}
else if (stplyr == &players[displayplayers[1]])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
cx += adjustx;
option &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
else if (stplyr == &players[displayplayers[2]])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
cy += adjusty;
option &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
else //if (stplyr == &players[displayplayers[3]])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(option & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
cx += adjustx;
cy += adjusty;
option &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
}
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayers[0]])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle = 1;
option &= ~V_SNAPTOBOTTOM;
}
else //if (stplyr == &players[displayplayers[1]])
{
if (!(option & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle = 2;
cy += adjusty;
option &= ~V_SNAPTOTOP;
}
}
}
if (!(option & V_NOSCALESTART))
{
cx = cx * dupx;
@ -280,44 +207,12 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t
if (!(option & V_SCALEPATCHMASK))
{
// if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT)
// cx and cy are possibly *slightly* off from float maths
// This is done before here compared to software because we directly alter cx and cy to centre
if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT)
{
// Need to temporarily cache the real patch to get the colour of the top left pixel
patch_t *realpatch = W_CacheSoftwarePatchNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0]));
if (!column->topdelta)
{
const UINT8 *source = (const UINT8 *)(column) + 3;
HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0]));
}
Z_Free(realpatch);
}
// centre screen
if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
{
if (option & V_SNAPTORIGHT)
cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
else if (!(option & V_SNAPTOLEFT))
cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2;
if (perplayershuffle & 4)
cx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/4;
else if (perplayershuffle & 8)
cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/4;
}
if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
{
if (option & V_SNAPTOBOTTOM)
cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
else if (!(option & V_SNAPTOTOP))
cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/2;
if (perplayershuffle & 1)
cy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/4;
else if (perplayershuffle & 2)
cy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy))/4;
}
INT32 intx, inty;
intx = (INT32)cx;
inty = (INT32)cy;
K_AdjustXYWithSnap(&intx, &inty, option, dupx, dupy);
cx = (float)intx;
cy = (float)inty;
}
}
@ -1263,40 +1158,18 @@ void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32
if (!(color & V_NOSCALESTART))
{
float dupx = (float)vid.dupx, dupy = (float)vid.dupy;
INT32 intx, inty;
fx *= dupx;
fy *= dupy;
fw *= dupx;
fh *= dupy;
if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
{
if (color & V_SNAPTORIGHT)
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
else if (!(color & V_SNAPTOLEFT))
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2;
if (perplayershuffle & 4)
fx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
else if (perplayershuffle & 8)
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
}
if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
{
// same thing here
if (color & V_SNAPTOBOTTOM)
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
else if (!(color & V_SNAPTOTOP))
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2;
if (perplayershuffle & 1)
fy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
else if (perplayershuffle & 2)
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
}
if (options & V_SPLITSCREEN)
fy += ((float)BASEVIDHEIGHT * dupy)/2;
if (options & V_HORZSCREEN)
fx += ((float)BASEVIDWIDTH * dupx)/2;
intx = (INT32)fx;
inty = (INT32)fy;
K_AdjustXYWithSnap(&intx, &inty, options, dupx, dupy);
fx = (float)intx;
fy = (float)inty;
}
if (fx >= vid.width || fy >= vid.height)
@ -1434,6 +1307,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
if (!(color & V_NOSCALESTART))
{
float dupx = (float)vid.dupx, dupy = (float)vid.dupy;
INT32 intx, inty;
if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
{
@ -1452,34 +1326,11 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
fw *= dupx;
fh *= dupy;
if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f)
{
if (color & V_SNAPTORIGHT)
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx));
else if (!(color & V_SNAPTOLEFT))
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2;
if (perplayershuffle & 4)
fx -= ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
else if (perplayershuffle & 8)
fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 4;
}
if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f)
{
// same thing here
if (color & V_SNAPTOBOTTOM)
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy));
else if (!(color & V_SNAPTOTOP))
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 2;
if (perplayershuffle & 1)
fy -= ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
else if (perplayershuffle & 2)
fy += ((float)vid.height - ((float)BASEVIDHEIGHT * dupy)) / 4;
}
if (color & V_SPLITSCREEN)
fy += ((float)BASEVIDHEIGHT * dupy)/2;
if (color & V_HORZSCREEN)
fx += ((float)BASEVIDWIDTH * dupx)/2;
intx = (INT32)fx;
inty = (INT32)fy;
K_AdjustXYWithSnap(&intx, &inty, color, dupx, dupy);
fx = (float)intx;
fy = (float)inty;
}
if (fx >= vid.width || fy >= vid.height)

View file

@ -3571,8 +3571,6 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
groundz = R_GetShadowZ(thing, &groundslope);
//if (abs(groundz - gl_viewz) / tz > 4) return; // Prevent stretchy shadows and possible crashes
floordiff = abs((flip < 0 ? thing->height : 0) + thingzpos - groundz);
alpha = floordiff / (4*FRACUNIT) + 75;
@ -3700,6 +3698,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
FBITFIELD occlusion;
boolean use_linkdraw_hack = false;
UINT8 alpha;
UINT8 brightmode = 0;
INT32 i;
float realtop, realbot, top, bot;
@ -3799,17 +3798,8 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
else
occlusion = PF_Occlude;
if (!cv_translucency.value) // translucency disabled
{
Surf.PolyColor.s.alpha = 0xFF;
blend = PF_Translucent|occlusion;
if (!occlusion) use_linkdraw_hack = true;
}
else if (spr->mobj->flags2 & MF2_SHADOW)
{
Surf.PolyColor.s.alpha = 0x40;
blend = PF_Translucent;
}
if (spr->mobj->drawflags & MFD_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf);
else if (spr->mobj->frame & FF_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
else
@ -3825,31 +3815,44 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
alpha = Surf.PolyColor.s.alpha;
if (spr->mobj->drawflags & MFD_BRIGHTMASK)
{
if (spr->mobj->drawflags & MFD_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->drawflags & MFD_SEMIBRIGHT)
brightmode = 2;
}
else
{
if (spr->mobj->frame & FF_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->frame & FF_SEMIBRIGHT)
brightmode = 2;
}
// Start with the lightlevel and colormap from the top of the sprite
lightlevel = *list[sector->numlights - 1].lightlevel;
colormap = *list[sector->numlights - 1].extra_colormap;
i = 0;
temp = FLOAT_TO_FIXED(realtop);
if (spr->mobj->frame & FF_FULLBRIGHT)
lightlevel = 255;
if (brightmode != 1)
lightlevel = *list[sector->numlights - 1].lightlevel;
for (i = 1; i < sector->numlights; i++)
{
fixed_t h = P_GetLightZAt(&sector->lightlist[i], spr->mobj->x, spr->mobj->y);
if (h <= temp)
{
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = *list[i-1].lightlevel > 255 ? 255 : *list[i-1].lightlevel;
if (spr->mobj->frame & FF_SEMIBRIGHT)
lightlevel = 128 + (lightlevel>>1);
if (brightmode != 1)
lightlevel = *list[i-1].lightlevel;
colormap = *list[i-1].extra_colormap;
break;
}
}
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
for (i = 0; i < sector->numlights; i++)
{
if (endtop < endrealbot && top < realbot)
@ -3858,13 +3861,13 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
// even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite
if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES))
{
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = *list[i].lightlevel > 255 ? 255 : *list[i].lightlevel;
if (spr->mobj->frame & FF_SEMIBRIGHT)
lightlevel = 128 + (lightlevel>>1);
colormap = *list[i].extra_colormap;
if (brightmode != 1)
{
lightlevel = *list[i].lightlevel;
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
}
colormap = list[i].extra_colormap;
}
if (i + 1 < sector->numlights)
@ -4076,12 +4079,28 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
{
sector_t *sector = spr->mobj->subsector->sector;
UINT8 lightlevel = 255;
UINT8 brightmode = 0;
extracolormap_t *colormap = sector->extra_colormap;
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
if (spr->mobj->drawflags & MFD_BRIGHTMASK)
{
if (spr->mobj->drawflags & MFD_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->drawflags & MFD_SEMIBRIGHT)
brightmode = 2;
}
else
{
if (spr->mobj->frame & FF_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->frame & FF_SEMIBRIGHT)
brightmode = 2;
}
if (spr->mobj->frame & FF_SEMIBRIGHT)
if (brightmode != 1)
lightlevel = sector->lightlevel;
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
HWR_Lighting(&Surf, lightlevel, colormap);
@ -4099,17 +4118,8 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
else
occlusion = PF_Occlude;
if (!cv_translucency.value) // translucency disabled
{
Surf.PolyColor.s.alpha = 0xFF;
blend = PF_Translucent|occlusion;
if (!occlusion) use_linkdraw_hack = true;
}
else if (spr->mobj->flags2 & MF2_SHADOW)
{
Surf.PolyColor.s.alpha = 0x40;
blend = PF_Translucent;
}
if (spr->mobj->drawflags & MFD_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf);
else if (spr->mobj->frame & FF_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
else
@ -4182,43 +4192,53 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
{
sector_t *sector = spr->mobj->subsector->sector;
UINT8 lightlevel = 255;
UINT8 brightmode = 0;
extracolormap_t *colormap = sector->extra_colormap;
if (spr->mobj->drawflags & MFD_BRIGHTMASK)
{
if (spr->mobj->drawflags & MFD_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->drawflags & MFD_SEMIBRIGHT)
brightmode = 2;
}
else
{
if (spr->mobj->frame & FF_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->frame & FF_SEMIBRIGHT)
brightmode = 2;
}
if (sector->numlights)
{
INT32 light;
light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel;
if (spr->mobj->frame & FF_SEMIBRIGHT)
lightlevel = 128 + (lightlevel>>1);
if (brightmode != 1)
lightlevel = *sector->lightlist[light].lightlevel;
if (*sector->lightlist[light].extra_colormap)
colormap = *sector->lightlist[light].extra_colormap;
}
else
{
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
if (spr->mobj->frame & FF_SEMIBRIGHT)
lightlevel = 128 + (lightlevel>>1);
if (brightmode != 1)
lightlevel = sector->lightlevel;
if (sector->extra_colormap)
colormap = sector->extra_colormap;
}
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
HWR_Lighting(&Surf, lightlevel, colormap);
}
if (spr->mobj->flags2 & MF2_SHADOW)
{
Surf.PolyColor.s.alpha = 0x40;
blend = PF_Translucent;
}
if (spr->mobj->drawflags & MFD_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf);
else if (spr->mobj->frame & FF_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
else
@ -4259,6 +4279,12 @@ static int CompareVisSprites(const void *p1, const void *p2)
int transparency1;
int transparency2;
int drawflags1;
int drawflags2;
int frame1;
int frame2;
// check for precip first, because then sprX->mobj is actually a precipmobj_t and does not have flags2 or tracer
int linkdraw1 = !spr1->precip && (spr1->mobj->flags2 & MF2_LINKDRAW) && spr1->mobj->tracer;
int linkdraw2 = !spr2->precip && (spr2->mobj->flags2 & MF2_LINKDRAW) && spr2->mobj->tracer;
@ -4271,34 +4297,48 @@ static int CompareVisSprites(const void *p1, const void *p2)
if (linkdraw1)
{
tz1 = spr1->tracertz;
transparency1 = (spr1->mobj->tracer->flags2 & MF2_SHADOW) || (spr1->mobj->tracer->frame & FF_TRANSMASK);
drawflags1 = spr1->mobj->tracer->drawflags;
frame1 = spr1->mobj->tracer->frame;
}
else
{
tz1 = spr1->tz;
transparency1 = (!spr1->precip && (spr1->mobj->flags2 & MF2_SHADOW)) || (spr1->mobj->frame & FF_TRANSMASK);
drawflags1 = (spr1->precip ? 0 : spr1->mobj->drawflags);
frame1 = spr1->mobj->frame;
}
if (linkdraw2)
{
tz2 = spr2->tracertz;
transparency2 = (spr2->mobj->tracer->flags2 & MF2_SHADOW) || (spr2->mobj->tracer->frame & FF_TRANSMASK);
drawflags2 = spr2->mobj->tracer->drawflags;
frame2 = spr2->mobj->tracer->frame;
}
else
{
tz2 = spr2->tz;
transparency2 = (!spr2->precip && (spr2->mobj->flags2 & MF2_SHADOW)) || (spr2->mobj->frame & FF_TRANSMASK);
drawflags2 = (spr2->precip ? 0 : spr2->mobj->drawflags);
frame2 = spr2->mobj->frame;
}
}
else
{
tz1 = spr1->tz;
transparency1 = (!spr1->precip && (spr1->mobj->flags2 & MF2_SHADOW)) || (spr1->mobj->frame & FF_TRANSMASK);
drawflags1 = (spr1->precip ? 0 : spr1->mobj->drawflags);
frame1 = spr1->mobj->frame;
tz2 = spr2->tz;
transparency2 = (!spr2->precip && (spr2->mobj->flags2 & MF2_SHADOW)) || (spr2->mobj->frame & FF_TRANSMASK);
drawflags2 = (spr2->precip ? 0 : spr2->mobj->drawflags);
frame2 = spr2->mobj->frame;
}
// first compare transparency flags, then compare tz, then compare dispoffset
transparency1 = (drawflags1 & FF_TRANSMASK) ?
((drawflags1 & FF_TRANSMASK)>>MFD_TRANSSHIFT) :
((frame1 & FF_TRANSMASK)>>FF_TRANSSHIFT);
transparency2 = (drawflags2 & FF_TRANSMASK) ?
((drawflags2 & FF_TRANSMASK)>>MFD_TRANSSHIFT) :
((frame2 & FF_TRANSMASK)>>FF_TRANSSHIFT);
idiff = transparency1 - transparency2;
if (idiff != 0) return idiff;

View file

@ -1260,6 +1260,23 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
sector_t *sector = spr->mobj->subsector->sector;
UINT8 lightlevel = 255;
extracolormap_t *colormap = NULL;
UINT8 brightmode = 0;
if (spr->mobj->drawflags & MFD_BRIGHTMASK)
{
if (spr->mobj->drawflags & MFD_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->drawflags & MFD_SEMIBRIGHT)
brightmode = 2;
}
else
{
if (spr->mobj->frame & FF_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->frame & FF_SEMIBRIGHT)
brightmode = 2;
}
if (sector->numlights)
{
@ -1267,21 +1284,24 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel;
if (brightmode != 1)
lightlevel = *sector->lightlist[light].lightlevel;
if (*sector->lightlist[light].extra_colormap)
colormap = *sector->lightlist[light].extra_colormap;
}
else
{
if (!(spr->mobj->frame & FF_FULLBRIGHT))
lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
if (brightmode != 1)
lightlevel = sector->lightlevel;
if (sector->extra_colormap)
colormap = sector->extra_colormap;
}
if (brightmode == 2)
lightlevel = 128 + (lightlevel>>1);
HWR_Lighting(&Surf, lightlevel, colormap);
}
else
@ -1311,8 +1331,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
//if (tics > durs)
//durs = tics;
if (spr->mobj->flags2 & MF2_SHADOW)
Surf.PolyColor.s.alpha = 0x40;
if (spr->mobj->drawflags & MFD_TRANSMASK)
HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf);
else if (spr->mobj->frame & FF_TRANSMASK)
HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
else

View file

@ -140,7 +140,7 @@ static const GLfloat byte2float[256] = {
// -----------------+
#ifdef DEBUG_TO_FILE
FILE *gllogstream;
FILE *gllogstream = NULL;
#endif
FUNCPRINTF void GL_DBG_Printf(const char *format, ...)
@ -149,14 +149,14 @@ FUNCPRINTF void GL_DBG_Printf(const char *format, ...)
char str[4096] = "";
va_list arglist;
if (!gllogstream)
gllogstream = fopen("ogllog.txt", "w");
if (gllogstream)
{
va_start(arglist, format);
vsnprintf(str, 4096, format, arglist);
va_end(arglist);
va_start(arglist, format);
vsnprintf(str, 4096, format, arglist);
va_end(arglist);
fwrite(str, strlen(str), 1, gllogstream);
fwrite(str, strlen(str), 1, gllogstream);
}
#else
(void)format;
#endif

View file

@ -14,6 +14,7 @@
#include "doomdef.h"
#include "byteptr.h"
#include "hu_stuff.h"
#include "font.h"
#include "m_menu.h" // gametype_cons_t
#include "m_cond.h" // emblems
@ -52,6 +53,7 @@
#include "s_sound.h" // song credits
#include "k_kart.h"
#include "k_color.h"
// coords are scaled
#define HU_INPUTX 0
@ -63,24 +65,9 @@
//-------------------------------------------
// heads up font
//-------------------------------------------
patch_t *hu_font[HU_FONTSIZE];
patch_t *kart_font[KART_FONTSIZE]; // SRB2kart
patch_t *tny_font[HU_FONTSIZE];
patch_t *tallnum[10]; // 0-9
patch_t *nightsnum[10]; // 0-9
// Level title and credits fonts
patch_t *lt_font[LT_FONTSIZE];
patch_t *cred_font[CRED_FONTSIZE];
patch_t *ttlnum[10]; // act numbers (0-9)
// Name tag fonts
patch_t *ntb_font[NT_FONTSIZE];
patch_t *nto_font[NT_FONTSIZE];
// ping font
// Note: I'd like to adress that at this point we might *REALLY* want to work towards a common drawString function that can take any font we want because this is really turning into a MESS. :V -Lat'
patch_t *pingnum[10];
patch_t *pinggfx[5]; // small ping graphic
patch_t *mping[5]; // smaller ping graphic
@ -193,128 +180,25 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum);
void HU_LoadGraphics(void)
{
char buffer[9];
INT32 i, j;
INT32 i;
if (dedicated)
return;
j = HU_FONTSTART;
for (i = 0; i < HU_FONTSIZE; i++, j++)
{
// cache the heads-up font for entire game execution
sprintf(buffer, "STCFN%.3d", j);
if (W_CheckNumForName(buffer) == LUMPERROR)
hu_font[i] = NULL;
else
hu_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
// tiny version of the heads-up font
sprintf(buffer, "TNYFN%.3d", j);
if (W_CheckNumForName(buffer) == LUMPERROR)
tny_font[i] = NULL;
else
tny_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
// SRB2kart
j = KART_FONTSTART;
for (i = 0; i < KART_FONTSIZE; i++, j++)
{
// cache the heads-up font for entire game execution
sprintf(buffer, "MKFNT%.3d", j);
if (W_CheckNumForName(buffer) == LUMPERROR)
kart_font[i] = NULL;
else
kart_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
//
j = LT_FONTSTART;
for (i = 0; i < LT_FONTSIZE; i++)
{
sprintf(buffer, "LTFNT%.3d", j);
j++;
if (W_CheckNumForName(buffer) == LUMPERROR)
lt_font[i] = NULL;
else
lt_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
// cache the credits font for entire game execution (why not?)
j = CRED_FONTSTART;
for (i = 0; i < CRED_FONTSIZE; i++)
{
sprintf(buffer, "CRFNT%.3d", j);
j++;
if (W_CheckNumForName(buffer) == LUMPERROR)
cred_font[i] = NULL;
else
cred_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
//cache numbers too!
for (i = 0; i < 10; i++)
{
sprintf(buffer, "STTNUM%d", i);
tallnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
sprintf(buffer, "NGTNUM%d", i);
nightsnum[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
sprintf(buffer, "PINGN%d", i);
pingnum[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
}
Font_Load();
// minus for negative tallnums
tallminus = (patch_t *)W_CachePatchName("STTMINUS", PU_HUDGFX);
tallinfin = (patch_t *)W_CachePatchName("STTINFIN", PU_HUDGFX);
// cache act numbers for level titles
for (i = 0; i < 10; i++)
{
sprintf(buffer, "TTL%.2d", i);
ttlnum[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
// cache the base name tag font for entire game execution
j = NT_FONTSTART;
for (i = 0; i < NT_FONTSIZE; i++)
{
sprintf(buffer, "NTFNT%.3d", j);
j++;
if (W_CheckNumForName(buffer) == LUMPERROR)
ntb_font[i] = NULL;
else
ntb_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
// cache the outline name tag font for entire game execution
j = NT_FONTSTART;
for (i = 0; i < NT_FONTSIZE; i++)
{
sprintf(buffer, "NTFNO%.3d", j);
j++;
if (W_CheckNumForName(buffer) == LUMPERROR)
nto_font[i] = NULL;
else
nto_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
tallminus = HU_CachePatch("STTMINUS");
// cache the crosshairs, don't bother to know which one is being used,
// just cache all 3, they're so small anyway.
for (i = 0; i < HU_CROSSHAIRS; i++)
{
sprintf(buffer, "CROSHAI%c", '1'+i);
crosshair[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
crosshair[i] = HU_CachePatch("CROSHAI%c", '1'+i);
}
emblemicon = W_CachePatchName("EMBLICON", PU_HUDGFX);
tokenicon = W_CachePatchName("TOKNICON", PU_HUDGFX);
exiticon = W_CachePatchName("EXITICON", PU_HUDGFX);
emblemicon = HU_CachePatch("EMBLICON");
tokenicon = HU_CachePatch("TOKNICON");
emeraldpics[0][0] = W_CachePatchName("CHAOS1", PU_HUDGFX);
emeraldpics[0][1] = W_CachePatchName("CHAOS2", PU_HUDGFX);
@ -343,20 +227,18 @@ void HU_LoadGraphics(void)
emeraldpics[2][6] = W_CachePatchName("EMBOX7", PU_HUDGFX);
//emeraldpics[2][7] = W_CachePatchName("EMBOX8", PU_HUDGFX); -- unused
songcreditbg = W_CachePatchName("K_SONGCR", PU_HUDGFX);
songcreditbg = HU_CachePatch("K_SONGCR");
// cache ping gfx:
for (i = 0; i < 5; i++)
{
sprintf(buffer, "PINGGFX%d", i+1);
pinggfx[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
sprintf(buffer, "MPING%d", i+1);
mping[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
pinggfx[i] = HU_CachePatch("PINGGFX%d", i+1);
mping[i] = HU_CachePatch("MPING%d", i+1);
}
// fps stuff
framecounter = W_CachePatchName("FRAMER", PU_HUDGFX);
frameslash = W_CachePatchName("FRAMESL", PU_HUDGFX);;
framecounter = HU_CachePatch("FRAMER");
frameslash = HU_CachePatch("FRAMESL");;
}
// Initialise Heads up
@ -364,6 +246,8 @@ void HU_LoadGraphics(void)
//
void HU_Init(void)
{
font_t font;
#ifndef NONET
COM_AddCommand("say", Command_Say_f);
COM_AddCommand("sayto", Command_Sayto_f);
@ -375,9 +259,78 @@ void HU_Init(void)
// set shift translation table
shiftxform = english_shiftxform;
/*
Setup fonts
*/
if (!dedicated)
{
#define DIM( s, n ) ( font.start = s, font.size = n )
#define ADIM( name ) DIM (name ## _FONTSTART, name ## _FONTSIZE)
#define PR( s ) strcpy(font.prefix, s)
#define DIG( n ) ( font.digits = n )
#define REG Font_DumbRegister(&font)
DIG (3);
ADIM (HU);
PR ("STCFN");
REG;
PR ("TNYFN");
REG;
ADIM (KART);
PR ("MKFNT");
REG;
ADIM (LT);
PR ("LTFNT");
REG;
ADIM (CRED);
PR ("CRFNT");
REG;
DIG (1);
DIM (0, 10);
PR ("STTNUM");
REG;
PR ("NGTNUM");
REG;
PR ("PINGN");
REG;
#undef REG
#undef DIG
#undef PR
#undef ADMIN
#undef DIM
}
HU_LoadGraphics();
}
patch_t *HU_CachePatch(const char *format, ...)
{
va_list ap;
char buffer[9];
va_start (ap, format);
vsprintf(buffer, format, ap);
va_end (ap);
if (W_CheckNumForName(buffer) == LUMPERROR)
return NULL;
else
return (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
}
static inline void HU_Stop(void)
{
headsupactive = false;
@ -780,62 +733,40 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
{
const char *prefix = "", *cstart = "", *cend = "", *adminchar = "\x82~\x83", *remotechar = "\x82@\x83", *fmt2, *textcolor = "\x80";
char *tempchar = NULL;
char color_prefix[2];
// player is a spectator?
if (players[playernum].spectator)
if (players[playernum].spectator)
{
cstart = "\x86"; // grey name
textcolor = "\x86";
// grey text
cstart = textcolor = "\x86";
}
else if (target == -1) // say team
{
if (players[playernum].ctfteam == 1) // red
if (players[playernum].ctfteam == 1)
{
cstart = "\x85";
textcolor = "\x85";
// red text
cstart = textcolor = "\x85";
}
else // blue
else
{
cstart = "\x84";
textcolor = "\x84";
// blue text
cstart = textcolor = "\x84";
}
}
else
{
UINT16 chatcolor = skincolors[players[playernum].skincolor].chatcolor;
if (!chatcolor || chatcolor%0x1000 || chatcolor>V_TANMAP)
cstart = "\x80";
else if (chatcolor == V_PURPLEMAP)
cstart = "\x81";
else if (chatcolor == V_YELLOWMAP)
cstart = "\x82";
else if (chatcolor == V_GREENMAP)
cstart = "\x83";
else if (chatcolor == V_BLUEMAP)
cstart = "\x84";
else if (chatcolor == V_REDMAP)
cstart = "\x85";
else if (chatcolor == V_GRAYMAP)
cstart = "\x86";
else if (chatcolor == V_ORANGEMAP)
cstart = "\x87";
else if (chatcolor == V_SKYMAP)
cstart = "\x88";
else if (chatcolor == V_LAVENDERMAP)
cstart = "\x89";
else if (chatcolor == V_GOLDMAP)
cstart = "\x8a";
else if (chatcolor == V_AQUAMAP)
cstart = "\x8b";
else if (chatcolor == V_MAGENTAMAP)
cstart = "\x8c";
else if (chatcolor == V_PINKMAP)
cstart = "\x8d";
else if (chatcolor == V_BROWNMAP)
cstart = "\x8e";
else if (chatcolor == V_TANMAP)
cstart = "\x8f";
if (chatcolor > V_TANMAP)
{
sprintf(color_prefix, "%c", '\x80');
}
else
{
sprintf(color_prefix, "%c", '\x80' + (chatcolor >> V_CHARCOLORSHIFT));
}
cstart = color_prefix;
}
prefix = cstart;
@ -844,6 +775,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
tempchar = (char *)Z_Calloc(strlen(cstart) + strlen(adminchar) + 1, PU_STATIC, NULL);
else if (IsPlayerAdmin(playernum))
tempchar = (char *)Z_Calloc(strlen(cstart) + strlen(remotechar) + 1, PU_STATIC, NULL);
if (tempchar)
{
if (playernum == serverplayer)
@ -911,7 +843,7 @@ static inline boolean HU_keyInChatString(char *s, char ch)
{
size_t l;
if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART])
if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && fontv[HU_FONT].font[ch-HU_FONTSTART])
|| ch == ' ') // Allow spaces, of course
{
l = strlen(s);
@ -1353,7 +1285,7 @@ static char *CHAT_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
c = toupper(c);
c -= HU_FONTSTART;
if (c < 0 || c >= HU_FONTSIZE || !hu_font[c])
if (c < 0 || c >= HU_FONTSIZE || !fontv[HU_FONT].font[c])
{
chw = spacewidth;
lastusablespace = i;
@ -2309,11 +2241,17 @@ void
HU_drawMiniPing (INT32 x, INT32 y, UINT32 ping, INT32 flags)
{
patch_t *patch;
INT32 w = BASEVIDWIDTH;
if (r_splitscreen > 1)
{
w /= 2;
}
patch = mping[Ping_gfx_num(ping)];
if (( flags & V_SNAPTORIGHT ))
x += ( BASEVIDWIDTH - SHORT (patch->width) );
x += ( w - SHORT (patch->width) );
V_DrawScaledPatch(x, y, flags, patch);
}

View file

@ -17,6 +17,7 @@
#include "d_event.h"
#include "w_wad.h"
#include "r_defs.h"
#include "font.h"
//------------------------------------
// heads up font
@ -42,11 +43,22 @@
#define CRED_FONTEND 'Z' // the last font character
#define CRED_FONTSIZE (CRED_FONTEND - CRED_FONTSTART + 1)
// Name tag font
// Used by base and outline font set
#define NT_FONTSTART '!' // the first font character
#define NT_FONTEND 'Z' // the last font character
#define NT_FONTSIZE (NT_FONTEND - NT_FONTSTART + 1)
#define X( name ) name ## _FONT
/* fonts */
enum
{
X (HU),
X (TINY),
X (KART),
X (LT),
X (CRED),
X (TALLNUM),
X (NIGHTSNUM),
X (PINGNUM),
};
#undef X
#define HU_CROSSHAIRS 3 // maximum of 9 - see HU_Init();
@ -84,19 +96,10 @@ void HU_AddChatText(const char *text, boolean playsound);
// set true when entering a chat message
extern boolean chat_on;
extern patch_t *hu_font[HU_FONTSIZE], *kart_font[KART_FONTSIZE], *tny_font[HU_FONTSIZE]; // SRB2kart
extern patch_t *tallnum[10];
extern patch_t *pingnum[10];
extern patch_t *pinggfx[5];
extern patch_t *nightsnum[10];
extern patch_t *framecounter;
extern patch_t *frameslash;
extern patch_t *lt_font[LT_FONTSIZE];
extern patch_t *cred_font[CRED_FONTSIZE];
extern patch_t *ntb_font[NT_FONTSIZE];
extern patch_t *nto_font[NT_FONTSIZE];
extern patch_t *ttlnum[10];
extern patch_t *emeraldpics[3][8];
extern patch_t *rflagico;
extern patch_t *bflagico;
extern patch_t *rmatcico;
@ -114,6 +117,9 @@ void HU_Init(void);
void HU_LoadGraphics(void);
// Load a HUDGFX patch or NULL.
patch_t *HU_CachePatch(const char *format, ...);
// reset heads up when consoleplayer respawns.
void HU_Start(void);

View file

@ -532,7 +532,9 @@ char sprnames[NUMSPRITES + 1][5] =
"ICEB","CNDL","DOCH","DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS",
"ZTCH","MKMA","MKMP","RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH",
"BFRT","OFRT","RFRT","PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN",
"FWRK","MXCL","RGSP","DRAF","GRES","OTFG","DBOS","XMS4","XMS5","VIEW"
"FWRK","MXCL","RGSP","DRAF","GRES","OTFG","DBOS","EGOO","WTRL","XMS4",
"XMS5","FBUB","GCHA","CHEZ","VIEW","DBCL","DBNC","DBST",
};
char spr2names[NUMPLAYERSPRITES][5] =
@ -3849,10 +3851,42 @@ state_t states[NUMSTATES] =
{SPR_DSHR, FF_PAPERSPRITE|5, 1, {NULL}, 0, 0, S_FASTDUST7}, // S_FASTDUST6
{SPR_DSHR, FF_PAPERSPRITE|6, 1, {NULL}, 0, 0, S_NULL}, // S_FASTDUST7
{SPR_DBOS, FF_FULLBRIGHT, 2, {NULL}, 6, 1, S_DRIFTEXPLODE2}, // S_DRIFTEXPLODE1
{SPR_DBOS, FF_FULLBRIGHT|1, 2, {NULL}, 6, 1, S_DRIFTEXPLODE3}, // S_DRIFTEXPLODE2
{SPR_DBOS, FF_FULLBRIGHT|2, 2, {NULL}, 6, 1, S_DRIFTEXPLODE4}, // S_DRIFTEXPLODE3
{SPR_DBOS, FF_FULLBRIGHT|3, 2, {NULL}, 6, 1, S_DRIFTEXPLODE1}, // S_DRIFTEXPLODE4
{SPR_DBOS, FF_FULLBRIGHT, 1, {NULL}, 6, 1, S_DRIFTEXPLODE2}, // S_DRIFTEXPLODE1
{SPR_DBST, FF_PAPERSPRITE|FF_FULLBRIGHT, 1, {NULL}, 6, 1, S_DRIFTEXPLODE3}, // S_DRIFTEXPLODE2
{SPR_DBOS, FF_FULLBRIGHT|1, 1, {NULL}, 6, 1, S_DRIFTEXPLODE4}, // S_DRIFTEXPLODE3
{SPR_DBST, FF_PAPERSPRITE|FF_FULLBRIGHT|1, 1, {NULL}, 6, 1, S_DRIFTEXPLODE5}, // S_DRIFTEXPLODE4
{SPR_DBOS, FF_FULLBRIGHT|2, 1, {NULL}, 6, 1, S_DRIFTEXPLODE6}, // S_DRIFTEXPLODE5
{SPR_DBST, FF_PAPERSPRITE|FF_FULLBRIGHT|2, 1, {NULL}, 6, 1, S_DRIFTEXPLODE7}, // S_DRIFTEXPLODE6
{SPR_DBOS, FF_FULLBRIGHT|3, 1, {NULL}, 6, 1, S_DRIFTEXPLODE8}, // S_DRIFTEXPLODE7
{SPR_DBST, FF_PAPERSPRITE|FF_FULLBRIGHT|3, 1, {NULL}, 6, 1, S_DRIFTEXPLODE1}, // S_DRIFTEXPLODE8
{SPR_DBCL, FF_FULLBRIGHT|0x0, 1, {NULL}, 6, 1, S_DRIFTCLIPA2}, // S_DRIFTCLIPA1
{SPR_DBCL, FF_FULLBRIGHT|0x8, 1, {NULL}, 6, 1, S_DRIFTCLIPA3}, // S_DRIFTCLIPA2
{SPR_DBCL, FF_FULLBRIGHT|0x1, 1, {NULL}, 6, 1, S_DRIFTCLIPA4}, // S_DRIFTCLIPA3
{SPR_DBCL, FF_FULLBRIGHT|0x9, 1, {NULL}, 6, 1, S_DRIFTCLIPA5}, // S_DRIFTCLIPA4
{SPR_DBCL, FF_FULLBRIGHT|0x2, 1, {NULL}, 6, 1, S_DRIFTCLIPA6}, // S_DRIFTCLIPA5
{SPR_DBCL, FF_FULLBRIGHT|0xA, 1, {NULL}, 6, 1, S_DRIFTCLIPA7}, // S_DRIFTCLIPA6
{SPR_DBCL, FF_FULLBRIGHT|0x3, 1, {NULL}, 6, 1, S_DRIFTCLIPA8}, // S_DRIFTCLIPA7
{SPR_DBCL, FF_FULLBRIGHT|0xB, 1, {NULL}, 6, 1, S_DRIFTCLIPA9}, // S_DRIFTCLIPA8
{SPR_DBCL, FF_FULLBRIGHT|0x4, 1, {NULL}, 6, 1, S_DRIFTCLIPA10}, // S_DRIFTCLIPA9
{SPR_DBCL, FF_FULLBRIGHT|0xC, 1, {NULL}, 6, 1, S_DRIFTCLIPA11}, // S_DRIFTCLIPA10
{SPR_DBCL, FF_FULLBRIGHT|0x5, 1, {NULL}, 6, 1, S_DRIFTCLIPA12}, // S_DRIFTCLIPA11
{SPR_DBCL, FF_FULLBRIGHT|0xD, 1, {NULL}, 6, 1, S_DRIFTCLIPA13}, // S_DRIFTCLIPA12
{SPR_DBCL, FF_FULLBRIGHT|0x6, 1, {NULL}, 6, 1, S_DRIFTCLIPA14}, // S_DRIFTCLIPA13
{SPR_DBCL, FF_FULLBRIGHT|0xE, 1, {NULL}, 6, 1, S_DRIFTCLIPA15}, // S_DRIFTCLIPA14
{SPR_DBCL, FF_FULLBRIGHT|0x7, 1, {NULL}, 6, 1, S_DRIFTCLIPA16}, // S_DRIFTCLIPA15
{SPR_DBCL, FF_FULLBRIGHT|0xF, 1, {NULL}, 6, 1, S_DRIFTCLIPB1}, // S_DRIFTCLIPA16
{SPR_DBCL, FF_FULLBRIGHT, 2, {NULL}, 6, 1, S_DRIFTCLIPB2}, // S_DRIFTCLIPB1
{SPR_DBCL, FF_FULLBRIGHT|1, 2, {NULL}, 6, 1, S_DRIFTCLIPB3}, // S_DRIFTCLIPB2
{SPR_DBCL, FF_FULLBRIGHT|2, 2, {NULL}, 6, 1, S_DRIFTCLIPB4}, // S_DRIFTCLIPB3
{SPR_DBCL, FF_FULLBRIGHT|3, 2, {NULL}, 6, 1, S_DRIFTCLIPB5}, // S_DRIFTCLIPB4
{SPR_DBCL, FF_FULLBRIGHT|4, 2, {NULL}, 6, 1, S_DRIFTCLIPB6}, // S_DRIFTCLIPB5
{SPR_DBCL, FF_FULLBRIGHT|5, 2, {NULL}, 6, 1, S_DRIFTCLIPB7}, // S_DRIFTCLIPB6
{SPR_DBCL, FF_FULLBRIGHT|6, 2, {NULL}, 6, 1, S_DRIFTCLIPB8}, // S_DRIFTCLIPB7
{SPR_DBCL, FF_FULLBRIGHT|7, 2, {NULL}, 6, 1, S_DRIFTCLIPB1}, // S_DRIFTCLIPB8
{SPR_DBNC, FF_FULLBRIGHT|FF_ANIMATE, 14, {NULL}, 6, 1, S_NULL}, // S_DRIFTCLIPSPARK
{SPR_BOST, FF_FULLBRIGHT|FF_ANIMATE, TICRATE, {NULL}, 6, 1, S_BOOSTSMOKESPAWNER}, // S_BOOSTFLAME
{SPR_NULL, 0, TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_BOOSTSMOKESPAWNER
@ -4752,6 +4786,37 @@ state_t states[NUMSTATES] =
{SPR_SMOK, 3, 7, {NULL}, 0, 0, S_OPAQUESMOKE5}, // S_OPAQUESMOKE4
{SPR_SMOK, 4, 8, {NULL}, 0, 0, S_NULL}, // S_OPAQUESMOKE5
// followers:
// bubble
{SPR_FBUB, 11|FF_ANIMATE|FF_TRANS70|FF_FULLBRIGHT, -1, {NULL}, 10, 3, S_FOLLOWERBUBBLE_FRONT}, // S_FOLLOWERBUBBLE_FRONT
{SPR_FBUB, FF_ANIMATE|0|FF_FULLBRIGHT, -1, {NULL}, 10, 3, S_FOLLOWERBUBBLE_BACK}, // S_FOLLOWERBUBBLE_BACK
// generic chao:
{SPR_GCHA, FF_ANIMATE, -1, {NULL}, 1, 4, S_GCHAOIDLE}, //S_GCHAOIDLE
{SPR_GCHA, 2|FF_ANIMATE, -1, {NULL}, 1, 2, S_GCHAOFLY}, //S_GCHAOFLY
{SPR_GCHA, 7, 5, {NULL}, 0, 0, S_GCHAOSAD2}, //S_GCHAOSAD1
{SPR_GCHA, 8, 3, {NULL}, 0, 0, S_GCHAOSAD3}, //S_GCHAOSAD2
{SPR_GCHA, 9, 6, {NULL}, 0, 0, S_GCHAOSAD4}, //S_GCHAOSAD3
{SPR_GCHA, 8, 3, {NULL}, 0, 0, S_GCHAOSAD1}, //S_GCHAOSAD4
{SPR_GCHA, 4, 8, {NULL}, 0, 0, S_GCHAOHAPPY2}, //S_GCHAOHAPPY1
{SPR_GCHA, 5, 4, {NULL}, 0, 0, S_GCHAOHAPPY3}, //S_GCHAOHAPPY2
{SPR_GCHA, 6, 8, {NULL}, 0, 0, S_GCHAOHAPPY4}, //S_GCHAOHAPPY3
{SPR_GCHA, 5, 4, {NULL}, 0, 0, S_GCHAOHAPPY1}, //S_GCHAOHAPPY4
// cheese:
{SPR_CHEZ, FF_ANIMATE, -1, {NULL}, 1, 4, S_CHEESEIDLE}, //S_CHEESEIDLE
{SPR_CHEZ, 2|FF_ANIMATE, -1, {NULL}, 1, 2, S_CHEESEFLY}, //S_CHEESEFLY
{SPR_CHEZ, 7, 5, {NULL}, 0, 0, S_CHEESESAD2}, //S_CHEESESAD1
{SPR_CHEZ, 8, 3, {NULL}, 0, 0, S_CHEESESAD3}, //S_CHEESESAD2
{SPR_CHEZ, 9, 6, {NULL}, 0, 0, S_CHEESESAD4}, //S_CHEESESAD3
{SPR_CHEZ, 8, 3, {NULL}, 0, 0, S_CHEESESAD1}, //S_CHEESESAD4
{SPR_CHEZ, 4, 8, {NULL}, 0, 0, S_CHEESEHAPPY2}, //S_CHEESEHAPPY1
{SPR_CHEZ, 5, 4, {NULL}, 0, 0, S_CHEESEHAPPY3}, //S_CHEESEHAPPY2
{SPR_CHEZ, 6, 8, {NULL}, 0, 0, S_CHEESEHAPPY4}, //S_CHEESEHAPPY3
{SPR_CHEZ, 5, 4, {NULL}, 0, 0, S_CHEESEHAPPY1}, //S_CHEESEHAPPY4
{SPR_MXCL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_RINGDEBT
{SPR_RGSP, FF_PAPERSPRITE|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_RINGSPARKS2}, // S_RINGSPARKS1
@ -4789,6 +4854,26 @@ state_t states[NUMSTATES] =
{SPR_CAPS, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SUPPORT
{SPR_CAPS, FF_ANIMATE|5, -1, {NULL}, 3, 1, S_NULL}, // S_BATTLECAPSULE_SUPPORTFLY
{SPR_EGOO, 0, 1, {NULL}, 0, 0, S_NULL}, // S_EGOORB
// Water Trail
{SPR_WTRL, FF_PAPERSPRITE , 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL1
{SPR_WTRL, FF_PAPERSPRITE|1, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL2
{SPR_WTRL, FF_PAPERSPRITE|2, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL3
{SPR_WTRL, FF_PAPERSPRITE|3, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL4
{SPR_WTRL, FF_PAPERSPRITE|4, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL5
{SPR_WTRL, FF_PAPERSPRITE|5, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL6
{SPR_WTRL, FF_PAPERSPRITE|6, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL7
{SPR_WTRL, FF_PAPERSPRITE|7, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL8
{SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|8, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY1
{SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|9, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY2
{SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|10, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY3
{SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|11, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY4
{SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|12, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY5
{SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|13, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY6
{SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|14, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY7
{SPR_WTRL, FF_TRANS50|FF_PAPERSPRITE|15, 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAILUNDERLAY8
#ifdef SEENAMES
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
#endif
@ -22706,6 +22791,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_DRIFTCLIP
-1, // doomednum
S_DRIFTCLIPA1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
105, // speed
32*FRACUNIT, // radius
64*FRACUNIT, // height
1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_DONTENCOREMAP|MF_GRENADEBOUNCE|MF_BOUNCE, // flags
S_NULL // raisestate
},
{ // MT_DRIFTCLIPSPARK
-1, // doomednum
S_DRIFTCLIPSPARK, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
8, // speed
32*FRACUNIT, // radius
64*FRACUNIT, // height
1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_BOOSTFLAME
-1, // doomednum
S_BOOSTFLAME, // spawnstate
@ -27946,6 +28085,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_RINGSPARKS
-1, // doomednum
S_RINGSPARKS1, // spawnstate
@ -28189,6 +28329,144 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_FOLLOWER
-1, // doomednum
S_INVISIBLE, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
8<<FRACBITS, // radius
16<<FRACBITS, // height
1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
S_NULL, // raisestate
},
{ // MT_FOLLOWERBUBBLE_FRONT
-1, // doomednum
S_FOLLOWERBUBBLE_FRONT, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
8<<FRACBITS, // radius
16<<FRACBITS, // height
2, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
S_NULL, // raisestate
},
{ // MT_FOLLOWERBUBBLE_BACK
-1, // doomednum
S_FOLLOWERBUBBLE_BACK, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
8<<FRACBITS, // radius
16<<FRACBITS, // height
-2, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOCLIPTHING|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
S_NULL, // raisestate
},
{ // MT_WATERTRAIL
-1, // doomednum
S_WATERTRAIL1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
48*FRACUNIT, // radius
32*FRACUNIT, // height
1, // display offset
100, // mass
1, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_WATERTRAILUNDERLAY
-1, // doomednum
S_WATERTRAILUNDERLAY1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
48*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
1, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
// ============================================================================================================================//
#ifdef SEENAMES

View file

@ -999,9 +999,21 @@ typedef enum sprite
SPR_DBOS, // Drift boost flame
SPR_EGOO,
SPR_WTRL, // Water Trail
SPR_FBUB, // follower bubble
SPR_GCHA, // follower: generic chao
SPR_CHEZ, // follower: cheese
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
SPR_VIEW,
SPR_DBCL, // Drift boost clip
SPR_DBNC, // Drift boost clip's sparks
SPR_DBST, // Drift boost plume
SPR_FIRSTFREESLOT,
SPR_LASTFREESLOT = SPR_FIRSTFREESLOT + NUMSPRITEFREESLOTS - 1,
NUMSPRITES
@ -4153,6 +4165,39 @@ typedef enum state
S_DRIFTEXPLODE2,
S_DRIFTEXPLODE3,
S_DRIFTEXPLODE4,
S_DRIFTEXPLODE5,
S_DRIFTEXPLODE6,
S_DRIFTEXPLODE7,
S_DRIFTEXPLODE8,
// Drift boost clip
S_DRIFTCLIPA1,
S_DRIFTCLIPA2,
S_DRIFTCLIPA3,
S_DRIFTCLIPA4,
S_DRIFTCLIPA5,
S_DRIFTCLIPA6,
S_DRIFTCLIPA7,
S_DRIFTCLIPA8,
S_DRIFTCLIPA9,
S_DRIFTCLIPA10,
S_DRIFTCLIPA11,
S_DRIFTCLIPA12,
S_DRIFTCLIPA13,
S_DRIFTCLIPA14,
S_DRIFTCLIPA15,
S_DRIFTCLIPA16,
S_DRIFTCLIPB1,
S_DRIFTCLIPB2,
S_DRIFTCLIPB3,
S_DRIFTCLIPB4,
S_DRIFTCLIPB5,
S_DRIFTCLIPB6,
S_DRIFTCLIPB7,
S_DRIFTCLIPB8,
// Drift boost clip sparks
S_DRIFTCLIPSPARK,
// Sneaker boost effect
S_BOOSTFLAME,
@ -5057,6 +5102,36 @@ typedef enum state
S_OPAQUESMOKE4,
S_OPAQUESMOKE5,
// followers:
// bubble:
S_FOLLOWERBUBBLE_FRONT,
S_FOLLOWERBUBBLE_BACK,
// generic chao:
S_GCHAOIDLE,
S_GCHAOFLY,
S_GCHAOSAD1,
S_GCHAOSAD2,
S_GCHAOSAD3,
S_GCHAOSAD4,
S_GCHAOHAPPY1,
S_GCHAOHAPPY2,
S_GCHAOHAPPY3,
S_GCHAOHAPPY4,
// cheese:
S_CHEESEIDLE,
S_CHEESEFLY,
S_CHEESESAD1,
S_CHEESESAD2,
S_CHEESESAD3,
S_CHEESESAD4,
S_CHEESEHAPPY1,
S_CHEESEHAPPY2,
S_CHEESEHAPPY3,
S_CHEESEHAPPY4,
S_RINGDEBT,
S_RINGSPARKS1,
S_RINGSPARKS2,
@ -5093,6 +5168,25 @@ typedef enum state
S_BATTLECAPSULE_SUPPORT,
S_BATTLECAPSULE_SUPPORTFLY,
S_EGOORB,
S_WATERTRAIL1,
S_WATERTRAIL2,
S_WATERTRAIL3,
S_WATERTRAIL4,
S_WATERTRAIL5,
S_WATERTRAIL6,
S_WATERTRAIL7,
S_WATERTRAIL8,
S_WATERTRAILUNDERLAY1,
S_WATERTRAILUNDERLAY2,
S_WATERTRAILUNDERLAY3,
S_WATERTRAILUNDERLAY4,
S_WATERTRAILUNDERLAY5,
S_WATERTRAILUNDERLAY6,
S_WATERTRAILUNDERLAY7,
S_WATERTRAILUNDERLAY8,
#ifdef SEENAMES
S_NAMECHECK,
#endif
@ -5910,6 +6004,8 @@ typedef enum mobj_type
MT_FASTLINE,
MT_FASTDUST,
MT_DRIFTEXPLODE,
MT_DRIFTCLIP,
MT_DRIFTCLIPSPARK,
MT_BOOSTFLAME,
MT_BOOSTSMOKE,
MT_SNEAKERTRAIL,
@ -6186,6 +6282,13 @@ typedef enum mobj_type
MT_BATTLECAPSULE,
MT_BATTLECAPSULE_PIECE,
MT_FOLLOWER,
MT_FOLLOWERBUBBLE_FRONT,
MT_FOLLOWERBUBBLE_BACK,
MT_WATERTRAIL,
MT_WATERTRAILUNDERLAY,
#ifdef SEENAMES
MT_NAMECHECK,
#endif

View file

@ -256,7 +256,6 @@ void K_CheckBumpers(void)
for (i = 0; i < MAXPLAYERS; i++)
{
players[i].pflags |= PF_TIMEOVER;
//players[i].lives = 0;
P_DoPlayerExit(&players[i]);
}
}
@ -397,7 +396,7 @@ static void K_SpawnOvertimeParticles(fixed_t x, fixed_t y, fixed_t scale, mobjty
//mo->destscale = mo->scale/4;
mo->frame += ((leveltime/4) % 8);
/*if (battleovertime.enabled < 10*TICRATE)
mo->flags2 |= MF2_SHADOW;*/
mo->drawflags |= MFD_SHADOW;*/
mo->angle = R_PointToAngle2(mo->x, mo->y, battleovertime.x, battleovertime.y) + ANGLE_90;
mo->z += P_RandomRange(0,48) * mo->scale;
break;

View file

@ -469,6 +469,10 @@ boolean K_BHeapPop(bheap_t *const heap, bheapitem_t *const returnitemstorage)
heap->array[0] = heap->array[heap->count];
heap->array[0].heapindex = 0U;
memset(&heap->array[heap->count], 0x00, sizeof(bheapitem_t));
if (heap->array[0].indexchanged != NULL)
{
heap->array[0].indexchanged(heap->array[0].data, heap->array[0].heapindex);
}
K_BHeapSortDown(heap, &heap->array[0]);
popsuccess = true;

View file

@ -1,5 +1,6 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
//
// This program is free software distributed under the
@ -295,11 +296,17 @@ boolean K_BotCanTakeCut(player_t *player)
--------------------------------------------------*/
static UINT32 K_BotRubberbandDistance(player_t *player)
{
const UINT32 spacing = 2048;
const UINT32 spacing = FixedDiv(512 * FRACUNIT, K_GetKartGameSpeedScalar(gamespeed)) / FRACUNIT;
const UINT8 portpriority = player - players;
UINT8 pos = 0;
UINT8 i;
if (player->botvars.rival)
{
// The rival should always try to be the front runner for the race.
return 0;
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (i == portpriority)
@ -312,15 +319,15 @@ static UINT32 K_BotRubberbandDistance(player_t *player)
// First check difficulty levels, then score, then settle it with port priority!
if (player->botvars.difficulty < players[i].botvars.difficulty)
{
pos++;
pos += 3;
}
else if (player->score < players[i].score)
{
pos++;
pos += 2;
}
else if (i < portpriority)
{
pos++;
pos += 1;
}
}
}
@ -336,11 +343,13 @@ static UINT32 K_BotRubberbandDistance(player_t *player)
fixed_t K_BotRubberband(player_t *player)
{
fixed_t rubberband = FRACUNIT;
fixed_t max, min;
player_t *firstplace = NULL;
UINT8 i;
if (player->exiting)
{
// You're done, we don't need to rubberband anymore.
return FRACUNIT;
}
@ -372,8 +381,8 @@ fixed_t K_BotRubberband(player_t *player)
if (wanteddist > player->distancetofinish)
{
// Whoa, you're too far ahead!
rubberband += (MAXBOTDIFFICULTY - player->botvars.difficulty) * distdiff;
// Whoa, you're too far ahead! Slow back down a little.
rubberband += (MAXBOTDIFFICULTY - player->botvars.difficulty) * (distdiff / 3);
}
else
{
@ -382,13 +391,23 @@ fixed_t K_BotRubberband(player_t *player)
}
}
if (rubberband > 2*FRACUNIT)
// Lv. 1: x1.0 max
// Lv. 5: x1.5 max
// Lv. 9: x2.0 max
max = FRACUNIT + ((FRACUNIT * (player->botvars.difficulty - 1)) / (MAXBOTDIFFICULTY - 1));
// Lv. 1: x0.75 min
// Lv. 5: x0.875 min
// Lv. 9: x1.0 min
min = FRACUNIT - (((FRACUNIT/4) * (MAXBOTDIFFICULTY - player->botvars.difficulty)) / (MAXBOTDIFFICULTY - 1));
if (rubberband > max)
{
rubberband = 2*FRACUNIT;
rubberband = max;
}
else if (rubberband < 7*FRACUNIT/8)
else if (rubberband < min)
{
rubberband = 7*FRACUNIT/8;
rubberband = min;
}
return rubberband;
@ -447,6 +466,32 @@ fixed_t K_BotTopSpeedRubberband(player_t *player)
return rubberband;
}
/*--------------------------------------------------
fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict)
See header file for description.
--------------------------------------------------*/
fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict)
{
fixed_t rubberband = K_BotRubberband(player) - FRACUNIT;
fixed_t newfrict;
if (rubberband <= 0)
{
// Never get stronger than normal friction
return frict;
}
newfrict = FixedDiv(frict, FRACUNIT + (rubberband / 2));
if (newfrict < 0)
newfrict = 0;
if (newfrict > FRACUNIT)
newfrict = FRACUNIT;
return newfrict;
}
/*--------------------------------------------------
fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y, fixed_t cx, fixed_t cy)
@ -637,7 +682,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
// Remove any existing controls
memset(cmd, 0, sizeof(ticcmd_t));
cmd->angleturn = (player->mo->angle >> 16) | TICCMD_RECEIVED;
cmd->angleturn = (player->mo->angle >> 16);
if (gamestate != GS_LEVEL)
{
@ -658,13 +703,16 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
// Start boost handler
if (leveltime <= starttime)
{
tic_t boosthold = starttime - TICRATE;
tic_t length = (TICRATE/6);
tic_t boosthold = starttime - K_GetSpindashChargeTime(player);
boosthold -= (MAXBOTDIFFICULTY - player->botvars.difficulty);
cmd->buttons |= BT_EBRAKEMASK;
boosthold -= (MAXBOTDIFFICULTY - player->botvars.difficulty) * length;
if (leveltime >= boosthold)
{
cmd->buttons |= BT_ACCELERATE;
cmd->buttons |= BT_DRIFT;
}
return;
@ -701,7 +749,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
if (anglediff > 90)
{
// Wrong way!
cmd->forwardmove = -25;
cmd->forwardmove = -MAXPLMOVE;
cmd->buttons |= BT_BRAKE;
}
else
@ -735,7 +783,7 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
cmd->buttons |= BT_ACCELERATE;
// Full speed ahead!
cmd->forwardmove = 50;
cmd->forwardmove = MAXPLMOVE;
if (dirdist <= rad)
{

View file

@ -1,5 +1,6 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
//
// This program is free software distributed under the
@ -95,6 +96,23 @@ fixed_t K_BotRubberband(player_t *player);
fixed_t K_BotTopSpeedRubberband(player_t *player);
/*--------------------------------------------------
fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict);
Gives a multiplier for a bot's rubberbanding.
Adjusted from K_BotRubberband to be used for friction.
Input Arguments:-
player - Player to check.
frict - Friction value to adjust.
Return:-
The new friction value.
--------------------------------------------------*/
fixed_t K_BotFrictionRubberband(player_t *player, fixed_t frict);
/*--------------------------------------------------
fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y, fixed_t cx, fixed_t cy);
@ -228,5 +246,4 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd);
void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt);
#endif

View file

@ -1,5 +1,6 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
//
// This program is free software distributed under the

View file

@ -1,5 +1,6 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
//
// This program is free software distributed under the

View file

@ -22,7 +22,6 @@
See header file for description.
--------------------------------------------------*/
UINT8 K_ColorRelativeLuminance(UINT8 r, UINT8 g, UINT8 b)
{
UINT32 redweight = 1063 * r;
@ -48,7 +47,6 @@ UINT16 K_RainbowColor(tic_t time)
See header file for description.
--------------------------------------------------*/
void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor)
{
INT32 i;
@ -92,14 +90,11 @@ void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor)
}
}
/** \brief Generates a translation colormap for Kart, to replace R_GenerateTranslationColormap in r_draw.c
/*--------------------------------------------------
void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color)
\param dest_colormap colormap to populate
\param skinnum number of skin, TC_DEFAULT or TC_BOSS
\param color translation color
\return void
*/
See header file for description.
--------------------------------------------------*/
void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color)
{
INT32 i;

View file

@ -19,6 +19,21 @@
#define DEFAULT_STARTTRANSCOLOR 96
#define NUM_PALETTE_ENTRIES 256
/*--------------------------------------------------
INT32 K_SkincolorToTextColor(UINT8 skincolor);
Gives you the "text" color (V_ constants) from a skincolor (SKINCOLOR_ constants).
Used primarily by the chat system.
Input Arguments:-
skincolor - SKINCOLOR_ constant
Return:-
V_ constant for font coloring
--------------------------------------------------*/
INT32 K_SkincolorToTextColor(UINT8 skincolor);
/*--------------------------------------------------
UINT8 K_ColorRelativeLuminance(UINT8 r, UINT8 g, UINT8 b);

605
src/k_grandprix.c Normal file
View file

@ -0,0 +1,605 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_grandprix.c
/// \brief Grand Prix mode game logic & bot behaviors
#include "k_grandprix.h"
#include "doomdef.h"
#include "d_player.h"
#include "g_game.h"
#include "k_bot.h"
#include "k_kart.h"
#include "m_random.h"
#include "r_things.h"
struct grandprixinfo grandprixinfo;
/*--------------------------------------------------
UINT8 K_BotStartingDifficulty(SINT8 value)
See header file for description.
--------------------------------------------------*/
UINT8 K_BotStartingDifficulty(SINT8 value)
{
// startingdifficulty: Easy = 3, Normal = 6, Hard = 9
SINT8 difficulty = (value + 1) * 3;
if (difficulty > MAXBOTDIFFICULTY)
{
difficulty = MAXBOTDIFFICULTY;
}
else if (difficulty < 1)
{
difficulty = 1;
}
return difficulty;
}
/*--------------------------------------------------
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
See header file for description.
--------------------------------------------------*/
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
{
INT16 points;
if (position >= numplayers || position == 0)
{
// Invalid position, no points
return 0;
}
points = numplayers - position;
// Give bonus to high-ranking players, depending on player count
// This rounds out the point gain when you get 1st every race,
// and gives bots able to catch up in points if a player gets an early lead.
// The maximum points you can get in a cup is: ((number of players - 1) + (max extra points)) * (number of races)
// 8P: (7 + 5) * 5 = 60 maximum points
// 12P: (11 + 5) * 5 = 80 maximum points
// 16P: (15 + 5) * 5 = 100 maximum points
switch (numplayers)
{
case 0: case 1: case 2: // 1v1
break; // No bonus needed.
case 3: case 4: // 3-4P
if (position == 1) { points += 1; } // 1st gets +1 extra point
break;
case 5: case 6: // 5-6P
if (position == 1) { points += 3; } // 1st gets +3 extra points
else if (position == 2) { points += 1; } // 2nd gets +1 extra point
break;
default: // Normal matches
if (position == 1) { points += 5; } // 1st gets +5 extra points
else if (position == 2) { points += 3; } // 2nd gets +3 extra points
else if (position == 3) { points += 1; } // 3rd gets +1 extra point
break;
}
// somehow underflowed?
if (points < 0)
{
points = 0;
}
return points;
}
/*--------------------------------------------------
void K_InitGrandPrixBots(void)
See header file for description.
--------------------------------------------------*/
void K_InitGrandPrixBots(void)
{
const char *defaultbotskinname = "eggrobo";
SINT8 defaultbotskin = R_SkinAvailable(defaultbotskinname);
const UINT8 startingdifficulty = K_BotStartingDifficulty(grandprixinfo.gamespeed);
UINT8 difficultylevels[MAXPLAYERS];
UINT8 playercount = 8;
UINT8 wantedbots = 0;
UINT8 numplayers = 0;
UINT8 competitors[MAXSPLITSCREENPLAYERS];
boolean skinusable[MAXSKINS];
UINT8 botskinlist[MAXPLAYERS];
UINT8 botskinlistpos = 0;
UINT8 newplayernum = 0;
UINT8 i, j;
if (defaultbotskin == -1)
{
// This shouldn't happen, but just in case
defaultbotskin = 0;
}
memset(competitors, MAXPLAYERS, sizeof (competitors));
memset(botskinlist, defaultbotskin, sizeof (botskinlist));
// init usable bot skins list
for (i = 0; i < MAXSKINS; i++)
{
if (i < numskins)
{
skinusable[i] = true;
}
else
{
skinusable[i] = false;
}
}
#if MAXPLAYERS != 16
I_Error("GP bot difficulty levels need rebalacned for the new player count!\n");
#endif
if (grandprixinfo.masterbots)
{
// Everyone is max difficulty!!
memset(difficultylevels, MAXBOTDIFFICULTY, sizeof (difficultylevels));
}
else
{
// init difficulty levels list
difficultylevels[0] = max(1, startingdifficulty);
difficultylevels[1] = max(1, startingdifficulty-1);
difficultylevels[2] = max(1, startingdifficulty-2);
difficultylevels[3] = max(1, startingdifficulty-3);
difficultylevels[4] = max(1, startingdifficulty-3);
difficultylevels[5] = max(1, startingdifficulty-4);
difficultylevels[6] = max(1, startingdifficulty-4);
difficultylevels[7] = max(1, startingdifficulty-4);
difficultylevels[8] = max(1, startingdifficulty-5);
difficultylevels[9] = max(1, startingdifficulty-5);
difficultylevels[10] = max(1, startingdifficulty-5);
difficultylevels[11] = max(1, startingdifficulty-6);
difficultylevels[12] = max(1, startingdifficulty-6);
difficultylevels[13] = max(1, startingdifficulty-6);
difficultylevels[14] = max(1, startingdifficulty-7);
difficultylevels[15] = max(1, startingdifficulty-7);
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
{
if (numplayers < MAXSPLITSCREENPLAYERS && !players[i].spectator)
{
competitors[numplayers] = i;
skinusable[players[i].skin] = false;
numplayers++;
}
else
{
players[i].spectator = true; // force spectate for all other players, if they happen to exist?
}
}
}
if (numplayers > 2)
{
// Add 3 bots per player beyond 2P
playercount += (numplayers-2) * 3;
}
wantedbots = playercount - numplayers;
// Create rival list
if (numplayers > 0)
{
for (i = 0; i < SKINRIVALS; i++)
{
for (j = 0; j < numplayers; j++)
{
player_t *p = &players[competitors[j]];
char *rivalname = skins[p->skin].rivals[i];
SINT8 rivalnum = R_SkinAvailable(rivalname);
if (rivalnum != -1 && skinusable[rivalnum])
{
botskinlist[botskinlistpos] = rivalnum;
skinusable[rivalnum] = false;
botskinlistpos++;
}
}
}
}
// Pad the remaining list with random skins if we need to
if (botskinlistpos < wantedbots)
{
for (i = botskinlistpos; i < wantedbots; i++)
{
UINT8 val = M_RandomKey(numskins);
UINT8 loops = 0;
while (!skinusable[val])
{
if (loops >= numskins)
{
// no more skins
break;
}
val++;
if (val >= numskins)
{
val = 0;
}
loops++;
}
if (loops >= numskins)
{
// leave the rest of the table as the default skin
break;
}
botskinlist[i] = val;
skinusable[val] = false;
}
}
for (i = 0; i < wantedbots; i++)
{
if (!K_AddBot(botskinlist[i], difficultylevels[i], &newplayernum))
{
break;
}
}
}
/*--------------------------------------------------
static INT16 K_RivalScore(player_t *bot)
Creates a "rival score" for a bot, used to determine which bot is the
most deserving of the rival status.
Input Arguments:-
bot - Player to check.
Return:-
"Rival score" value.
--------------------------------------------------*/
static INT16 K_RivalScore(player_t *bot)
{
const UINT16 difficulty = bot->botvars.difficulty;
const UINT16 score = bot->score;
SINT8 roundnum = 1, roundsleft = 1;
UINT16 lowestscore = UINT16_MAX;
UINT8 lowestdifficulty = MAXBOTDIFFICULTY;
UINT8 i;
if (grandprixinfo.cup != NULL)
{
roundnum = grandprixinfo.roundnum;
roundsleft = grandprixinfo.cup->numlevels - grandprixinfo.roundnum;
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
{
continue;
}
if (players[i].score < lowestscore)
{
lowestscore = players[i].score;
}
if (players[i].bot == true && players[i].botvars.difficulty < lowestdifficulty)
{
lowestdifficulty = players[i].botvars.difficulty;
}
}
// In the early game, difficulty is more important.
// This will try to influence the higher difficulty bots to get rival more often & get even more points.
// However, when we're running low on matches left, we need to focus more on raw score!
return ((difficulty - lowestdifficulty) * roundsleft) + ((score - lowestscore) * roundnum);
}
/*--------------------------------------------------
void K_UpdateGrandPrixBots(void)
See header file for description.
--------------------------------------------------*/
void K_UpdateGrandPrixBots(void)
{
player_t *oldrival = NULL;
player_t *newrival = NULL;
UINT16 newrivalscore = 0;
UINT8 i;
// Find the rival.
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || !players[i].bot)
{
continue;
}
if (players[i].botvars.diffincrease)
{
players[i].botvars.difficulty += players[i].botvars.diffincrease;
if (players[i].botvars.difficulty > MAXBOTDIFFICULTY)
{
players[i].botvars.difficulty = MAXBOTDIFFICULTY;
}
players[i].botvars.diffincrease = 0;
}
if (players[i].botvars.rival)
{
if (oldrival == NULL)
{
// Record the old rival to compare with our calculated new rival
oldrival = &players[i];
}
else
{
// Somehow 2 rivals were set?!
// Let's quietly fix our mess...
players[i].botvars.rival = false;
}
}
}
// Find the bot with the best average of score & difficulty.
for (i = 0; i < MAXPLAYERS; i++)
{
UINT16 ns = 0;
if (!playeringame[i] || players[i].spectator || !players[i].bot)
{
continue;
}
ns = K_RivalScore(&players[i]);
if (ns > newrivalscore)
{
newrival = &players[i];
newrivalscore = ns;
}
}
// Even if there's a new rival, we want to make sure that they're a better fit than the current one.
if (oldrival != newrival)
{
if (oldrival != NULL)
{
UINT16 os = K_RivalScore(oldrival);
if (newrivalscore < os + 5)
{
// This rival's only *slightly* better, no need to fire the old one.
// Our current rival's just fine, thank you very much.
return;
}
// Hand over your badge.
oldrival->botvars.rival = false;
}
// Set our new rival!
newrival->botvars.rival = true;
}
}
/*--------------------------------------------------
static UINT8 K_BotExpectedStanding(player_t *bot)
Predicts what placement a bot was expected to be in.
Used for determining if a bot's difficulty should raise.
Input Arguments:-
bot - Player to check.
Return:-
Position number the bot was expected to be in.
--------------------------------------------------*/
static UINT8 K_BotExpectedStanding(player_t *bot)
{
UINT8 pos = 1;
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (i == (bot - players))
{
continue;
}
if (playeringame[i] && !players[i].spectator)
{
if (players[i].bot)
{
if (players[i].botvars.difficulty > bot->botvars.difficulty)
{
pos++;
}
else if (players[i].score > bot->score)
{
pos++;
}
}
else
{
// Human player, always increment
pos++;
}
}
}
return pos;
}
/*--------------------------------------------------
void K_IncreaseBotDifficulty(player_t *bot)
See header file for description.
--------------------------------------------------*/
void K_IncreaseBotDifficulty(player_t *bot)
{
UINT8 expectedstanding;
INT16 standingdiff;
if (bot->botvars.difficulty >= MAXBOTDIFFICULTY)
{
// Already at max difficulty, don't need to increase
return;
}
// Increment bot difficulty based on what position you were meant to come in!
expectedstanding = K_BotExpectedStanding(bot);
standingdiff = expectedstanding - bot->kartstuff[k_position];
if (standingdiff >= -2)
{
UINT8 increase;
if (standingdiff > 5)
{
increase = 3;
}
else if (standingdiff > 2)
{
increase = 2;
}
else
{
increase = 1;
}
bot->botvars.diffincrease = increase;
}
else
{
bot->botvars.diffincrease = 0;
}
}
/*--------------------------------------------------
void K_FakeBotResults(player_t *bot)
See header file for description.
--------------------------------------------------*/
void K_FakeBotResults(player_t *bot)
{
const UINT32 distfactor = FixedMul(32 * bot->mo->scale, K_GetKartGameSpeedScalar(gamespeed)) / FRACUNIT;
UINT32 worstdist = 0;
tic_t besttime = UINT32_MAX;
UINT8 numplayers = 0;
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator)
{
numplayers++;
if (players[i].exiting && players[i].realtime < besttime)
{
besttime = players[i].realtime;
}
if (players[i].distancetofinish > worstdist)
{
worstdist = players[i].distancetofinish;
}
}
}
if (besttime == UINT32_MAX // No one finished, so you don't finish either.
|| bot->distancetofinish >= worstdist) // Last place, you aren't going to finish.
{
bot->pflags |= PF_TIMEOVER;
return;
}
// hey, you "won"
bot->exiting = 2;
bot->realtime += (bot->distancetofinish / distfactor);
bot->distancetofinish = 0;
K_IncreaseBotDifficulty(bot);
}
/*--------------------------------------------------
void K_PlayerLoseLife(player_t *player)
See header file for description.
--------------------------------------------------*/
void K_PlayerLoseLife(player_t *player)
{
if (!G_GametypeUsesLives())
{
return;
}
if (player->spectator || player->exiting || player->bot || player->lostlife)
{
return;
}
player->lives--;
player->lostlife = true;
#if 0
if (player->lives <= 0)
{
if (P_IsLocalPlayer(player))
{
S_StopMusic();
S_ChangeMusicInternal("gmover", false);
}
}
#endif
}
/*--------------------------------------------------
boolean K_CanChangeRules(void)
See header file for description.
--------------------------------------------------*/
boolean K_CanChangeRules(void)
{
if (demo.playback)
{
// We've already got our important settings!
return false;
}
if (grandprixinfo.gp == true && grandprixinfo.roundnum > 0)
{
// Don't cheat the rules of the GP!
return false;
}
if (modeattacking == true)
{
// Don't cheat the rules of Time Trials!
return false;
}
return true;
}

144
src/k_grandprix.h Normal file
View file

@ -0,0 +1,144 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2018-2020 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_grandprix.h
/// \brief Grand Prix mode game logic & bot behaviors
#ifndef __K_GRANDPRIX__
#define __K_GRANDPRIX__
#include "doomdef.h"
#include "doomstat.h"
extern struct grandprixinfo
{
boolean gp; ///< If true, then we are in a Grand Prix.
UINT8 roundnum; ///< Round number. If 0, this is a single session from the warp command.
cupheader_t *cup; ///< Which cup are we playing?
UINT8 gamespeed; ///< Copy of gamespeed, just to make sure you can't cheat it with cvars
boolean encore; ///< Ditto, but for encore mode
boolean masterbots; ///< If true, all bots should be max difficulty (Master Mode)
boolean initalize; ///< If true, we need to initialize a new session.
boolean wonround; ///< If false, then we retry the map instead of going to the next.
} grandprixinfo;
/*--------------------------------------------------
UINT8 K_BotStartingDifficulty(SINT8 value);
Determines the starting difficulty of the bots
for a specific game speed.
Input Arguments:-
value - Game speed value to use.
Return:-
Bot difficulty level.
--------------------------------------------------*/
UINT8 K_BotStartingDifficulty(SINT8 value);
/*--------------------------------------------------
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
Calculates the number of points that a player would
recieve if they won the round.
Input Arguments:-
position - Finishing position.
numplayers - Number of players in the game.
Return:-
Number of points to give.
--------------------------------------------------*/
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
/*--------------------------------------------------
void K_InitGrandPrixBots(void);
Spawns bots specifically tailored for Grand Prix mode.
--------------------------------------------------*/
void K_InitGrandPrixBots(void);
/*--------------------------------------------------
void K_UpdateGrandPrixBots(void);
Updates bot settings based on the the results of the race.
--------------------------------------------------*/
void K_UpdateGrandPrixBots(void);
/*--------------------------------------------------
void K_IncreaseBotDifficulty(player_t *bot);
Increases the difficulty of this bot when they finish the race.
Input Arguments:-
bot - Player to do this for.
Return:-
None
--------------------------------------------------*/
void K_IncreaseBotDifficulty(player_t *bot);
/*--------------------------------------------------
void K_FakeBotResults(player_t *bot);
Fakes the results of the race, when all human players have
already finished and only bots were remaining.
Input Arguments:-
bot - Player to do this for.
Return:-
None
--------------------------------------------------*/
void K_FakeBotResults(player_t *bot);
/*--------------------------------------------------
void K_PlayerLoseLife(player_t *player);
Removes a life from a human player.
Input Arguments:-
player - Player to do this for.
Return:-
None
--------------------------------------------------*/
void K_PlayerLoseLife(player_t *player);
/*--------------------------------------------------
boolean K_CanChangeRules(void);
Returns whenver or not the server is allowed
to change the game rules.
Input Arguments:-
None
Return:-
None
--------------------------------------------------*/
boolean K_CanChangeRules(void);
#endif

4122
src/k_hud.c Normal file

File diff suppressed because it is too large Load diff

28
src/k_hud.h Normal file
View file

@ -0,0 +1,28 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_hud.h
/// \brief HUD drawing functions exclusive to Kart
#include "doomtype.h"
#include "doomstat.h"
#ifndef __K_HUD__
#define __K_HUD__
#define RINGANIM_NUMFRAMES 10
#define RINGANIM_DELAYMAX 5
void K_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 dupy);
const char *K_GetItemPatch(UINT8 item, boolean tiny);
void K_LoadKartHUDGraphics(void);
void K_drawKartHUD(void);
void K_drawKartFreePlay(UINT32 flashtime);
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode);
#endif

File diff suppressed because it is too large Load diff

View file

@ -13,22 +13,28 @@
#define KART_FULLTURN 800
player_t *K_GetItemBoxPlayer(mobj_t *mobj);
angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t yourspeed);
void K_RegisterKartStuff(void);
UINT16 K_GetPlayerDontDrawFlag(player_t *player);
boolean K_IsPlayerLosing(player_t *player);
fixed_t K_GetKartGameSpeedScalar(SINT8 value);
extern consvar_t *KartItemCVars[NUMKARTRESULTS-1];
UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush);
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush, boolean bot, boolean rival);
INT32 K_GetShieldFromItem(INT32 item);
fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against);
void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid);
void K_KartPainEnergyFling(player_t *player);
void K_FlipFromObject(mobj_t *mo, mobj_t *master);
void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master);
void K_DoIngameRespawn(player_t *player);
void K_RespawnChecker(player_t *player);
void K_GenericExtraFlagsNoZAdjust(mobj_t *mo, mobj_t *master);
void K_SpawnDashDustRelease(player_t *player);
void K_SpawnDriftBoostClip(player_t *player);
void K_SpawnDriftBoostClipSpark(mobj_t *clip);
void K_KartMoveAnimation(player_t *player);
void K_KartPlayerHUDUpdate(player_t *player);
void K_KartPlayerThink(player_t *player, ticcmd_t *cmd);
@ -59,17 +65,23 @@ void K_UpdateDistanceFromFinishLine(player_t *const player);
boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y);
INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue);
INT32 K_GetKartDriftSparkValue(player_t *player);
void K_SpawnDriftBoostExplosion(player_t *player, int stage);
void K_KartUpdatePosition(player_t *player);
void K_DropItems(player_t *player);
void K_DropRocketSneaker(player_t *player);
void K_StripItems(player_t *player);
void K_StripOther(player_t *player);
void K_MomentumToFacing(player_t *player);
boolean K_ApplyOffroad(player_t *player);
tic_t K_GetSpindashChargeTime(player_t *player);
fixed_t K_GetSpindashChargeSpeed(player_t *player);
fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed);
fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower);
fixed_t K_GetKartAccel(player_t *player);
UINT16 K_GetKartFlashing(player_t *player);
fixed_t K_3dKartMovement(player_t *player, boolean onground, fixed_t forwardmove);
SINT8 K_GetForwardMove(player_t *player);
fixed_t K_3dKartMovement(player_t *player, boolean onground);
boolean K_PlayerEBrake(player_t *player);
void K_MoveKartPlayer(player_t *player, boolean onground);
void K_CheckSpectateStatus(void);
@ -81,12 +93,5 @@ void K_PlayPainSound(mobj_t *source);
void K_PlayHitEmSound(mobj_t *source);
void K_PlayPowerGloatSound(mobj_t *source);
const char *K_GetItemPatch(UINT8 item, boolean tiny);
INT32 K_calcSplitFlags(INT32 snapflags);
void K_LoadKartHUDGraphics(void);
void K_drawKartHUD(void);
void K_drawKartFreePlay(UINT32 flashtime);
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode);
// =========================================================================
#endif // __K_KART__

View file

@ -472,13 +472,44 @@ boolean K_PathfindAStar(path_t *const path, pathfindsetup_t *const pathfindsetup
// Reallocate nodesarray if it's full
if (nodesarraycount >= pathfindsetup->nodesarraycapacity)
{
pathfindnode_t *nodesarrayrealloc = NULL;
pathfindsetup->nodesarraycapacity = pathfindsetup->nodesarraycapacity * 2;
nodesarray = Z_Realloc(nodesarray, pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
nodesarrayrealloc = Z_Realloc(nodesarray, pathfindsetup->nodesarraycapacity * sizeof(pathfindnode_t), PU_STATIC, NULL);
if (nodesarray == NULL)
if (nodesarrayrealloc == NULL)
{
I_Error("K_PathfindAStar: Out of memory reallocating nodes array.");
}
// Need to update pointers in closedset, openset, and node "camefrom" if nodesarray moved.
if (nodesarray != nodesarrayrealloc)
{
size_t j = 0U;
size_t arrayindex = 0U;
for (j = 0U; j < closedsetcount; j++)
{
arrayindex = closedset[j] - nodesarray;
closedset[j] = &nodesarrayrealloc[arrayindex];
}
for (j = 0U; j < openset.count; j++)
{
arrayindex = ((pathfindnode_t *)(openset.array[j].data)) - nodesarray;
openset.array[j].data = &nodesarrayrealloc[arrayindex];
}
for (j = 0U; j < nodesarraycount; j++)
{
if (nodesarrayrealloc[j].camefrom != NULL)
{
arrayindex = nodesarrayrealloc[j].camefrom - nodesarray;
nodesarrayrealloc[j].camefrom = &nodesarrayrealloc[arrayindex];
}
}
arrayindex = currentnode - nodesarray;
currentnode = &nodesarrayrealloc[arrayindex];
}
nodesarray = nodesarrayrealloc;
}
// Create the new node and add it to the nodes array and open set

View file

@ -8,6 +8,7 @@
#include "m_random.h"
#include "m_cond.h" // M_UpdateUnlockablesAndExtraEmblems
#include "p_tick.h" // leveltime
#include "k_grandprix.h"
// Online rankings for the main gametypes.
// This array is saved to the gamedata.
@ -25,6 +26,27 @@ INT16 nospectategrief[MAXPLAYERS];
SINT8 speedscramble = -1;
SINT8 encorescramble = -1;
SINT8 K_UsingPowerLevels(void)
{
SINT8 pt = PWRLV_DISABLED;
if (!cv_kartusepwrlv.value || !netgame || grandprixinfo.gp == true)
{
return PWRLV_DISABLED;
}
if (G_RaceGametype())
{
pt = PWRLV_RACE;
}
else if (G_BattleGametype())
{
pt = PWRLV_BATTLE;
}
return pt;
}
void K_ClearClientPowerLevels(void)
{
UINT8 i, j;

View file

@ -21,6 +21,7 @@ extern UINT16 vspowerlevel[PWRLV_NUMTYPES];
extern UINT16 clientpowerlevels[MAXPLAYERS][PWRLV_NUMTYPES];
extern INT16 nospectategrief[MAXPLAYERS];
SINT8 K_UsingPowerLevels(void);
void K_ClearClientPowerLevels(void);
INT16 K_CalculatePowerLevelInc(INT16 diff);
INT16 K_CalculatePowerLevelAvg(void);

752
src/k_respawn.c Normal file
View file

@ -0,0 +1,752 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_respawn.c
/// \brief Respawning logic
#include "k_respawn.h"
#include "doomdef.h"
#include "d_player.h"
#include "k_kart.h"
#include "k_battle.h"
#include "g_game.h"
#include "p_local.h"
#include "p_tick.h"
#include "p_setup.h"
#include "r_main.h"
#include "s_sound.h"
#include "p_slopes.h"
#include "r_defs.h"
/*--------------------------------------------------
fixed_t K_RespawnOffset(player_t *player, boolean flip)
See header file for description.
--------------------------------------------------*/
fixed_t K_RespawnOffset(player_t *player, boolean flip)
{
fixed_t z = 0;
if (flip == true)
{
// Lat 24/7/20: Okay so before we even think about applying this flag, check if the sector we're in doesn't already have reverse gravity for that.
// Otherwise, we would reverse the reverse gravity and cancel it out. Yes, this is absolutely fucking dumb.
// I'm honestly not sure if this flag is even necessary anymore but we'll keep it just in case.
if (P_GetMobjGravity(player->mo) < 0)
player->mo->flags2 |= MF2_OBJECTFLIP;
player->mo->eflags |= MFE_VERTICALFLIP;
z -= ((128 * mapobjectscale) + (player->mo->height));
}
else
{
player->mo->flags2 &= ~MF2_OBJECTFLIP;
player->mo->eflags &= ~MFE_VERTICALFLIP;
z += (128 * mapobjectscale);
}
return z;
}
/*--------------------------------------------------
static void K_RespawnAtWaypoint(player_t *player, waypoint_t *waypoint)
Updates a player's respawn variables to go to the provided waypoint.
Input Arguments:-
player - Player to preform for.
waypoint - Waypoint to respawn to.
Return:-
None
--------------------------------------------------*/
static void K_RespawnAtWaypoint(player_t *player, waypoint_t *waypoint)
{
if (player == NULL || player->mo == NULL || P_MobjWasRemoved(player->mo))
{
return;
}
if (waypoint == NULL || waypoint->mobj == NULL || P_MobjWasRemoved(waypoint->mobj))
{
return;
}
player->respawn.pointx = waypoint->mobj->x;
player->respawn.pointy = waypoint->mobj->y;
player->respawn.pointz = waypoint->mobj->z;
player->respawn.flip = (waypoint->mobj->flags2 & MF2_OBJECTFLIP) ? true : false; // K_RespawnOffset wants a boolean!
player->respawn.pointz += K_RespawnOffset(player, player->respawn.flip);
}
/*--------------------------------------------------
void K_DoIngameRespawn(player_t *player)
See header file for description.
--------------------------------------------------*/
void K_DoIngameRespawn(player_t *player)
{
if (!player->mo || P_MobjWasRemoved(player->mo))
{
return;
}
if (player->respawn.state != RESPAWNST_NONE)
{
return;
}
if (leveltime < introtime)
{
return;
}
if (leveltime < starttime) // FAULT
{
player->powers[pw_nocontrol] = (starttime - leveltime) + 50;
player->pflags |= PF_SKIDDOWN; // cheeky pflag reuse
S_StartSound(player->mo, sfx_s3k83);
player->karthud[khud_fault] = 1;
}
player->kartstuff[k_ringboost] = 0;
player->kartstuff[k_driftboost] = 0;
player->kartstuff[k_drift] = 0;
player->kartstuff[k_driftcharge] = 0;
player->kartstuff[k_pogospring] = 0;
// Set up respawn position if invalid
if (player->respawn.wp != NULL && leveltime >= starttime)
{
const UINT32 dist = RESPAWN_DIST + (player->airtime * 48);
player->respawn.distanceleft = (dist * mapobjectscale) / FRACUNIT;
K_RespawnAtWaypoint(player, player->respawn.wp);
}
else
{
UINT32 bestdist = UINT32_MAX;
mapthing_t *beststart = NULL;
UINT8 numstarts = 0;
if (G_RaceGametype())
{
numstarts = numcoopstarts;
}
else if (G_BattleGametype())
{
numstarts = numdmstarts;
}
if (numstarts > 0)
{
UINT8 i = 0;
for (i = 0; i < numstarts; i++)
{
UINT32 dist = UINT32_MAX;
mapthing_t *checkstart = NULL;
if (G_RaceGametype())
{
checkstart = playerstarts[i];
}
else if (G_BattleGametype())
{
checkstart = deathmatchstarts[i];
}
else
{
break;
}
dist = (UINT32)P_AproxDistance((player->mo->x >> FRACBITS) - checkstart->x,
(player->mo->y >> FRACBITS) - checkstart->y);
if (dist < bestdist)
{
beststart = checkstart;
bestdist = dist;
}
}
}
if (beststart == NULL)
{
CONS_Alert(CONS_WARNING, "No respawn points!\n");
player->respawn.pointx = 0;
player->respawn.pointy = 0;
player->respawn.pointz = 0;
player->respawn.flip = false;
}
else
{
sector_t *s;
fixed_t z = (beststart->options >> ZSHIFT) * FRACUNIT;
player->respawn.pointx = beststart->x << FRACBITS;
player->respawn.pointy = beststart->y << FRACBITS;
s = R_PointInSubsector(beststart->x << FRACBITS, beststart->y << FRACBITS)->sector;
player->respawn.flip = (beststart->options & MTF_OBJECTFLIP);
if (player->respawn.flip == true)
{
player->respawn.pointz = (
#ifdef ESLOPE
s->c_slope ? P_GetZAt(s->c_slope, player->respawn.pointx, player->respawn.pointy) :
#endif
s->ceilingheight);
if (z != 0)
{
player->respawn.pointz -= z;
}
}
else
{
player->respawn.pointz = (
#ifdef ESLOPE
s->f_slope ? P_GetZAt(s->f_slope, player->respawn.pointx, player->respawn.pointy) :
#endif
s->floorheight);
if (z)
{
player->respawn.pointz += z;
}
}
}
player->respawn.pointz += K_RespawnOffset(player, player->respawn.flip);
player->respawn.distanceleft = 0;
}
player->respawn.timer = RESPAWN_TIME;
player->respawn.state = RESPAWNST_MOVE;
}
/*--------------------------------------------------
static size_t K_NextRespawnWaypointIndex(waypoint_t *waypoint)
Returns the index for the next respawn waypoint.
Input Arguments:-
waypoint - Waypoint to look after.
Return:-
An table index for waypoint_t -> nextwaypoints.
--------------------------------------------------*/
static size_t K_NextRespawnWaypointIndex(waypoint_t *waypoint)
{
size_t i = 0U;
size_t newwaypoint = SIZE_MAX;
// Set to the first valid nextwaypoint, for simplicity's sake.
// If we reach the last waypoint and it's still not valid, just use it anyway. Someone needs to fix their map!
for (i = 0U; i < waypoint->numnextwaypoints; i++)
{
newwaypoint = i;
if ((i == waypoint->numnextwaypoints - 1U)
|| ((K_GetWaypointIsEnabled(waypoint->nextwaypoints[newwaypoint]) == true)
&& (K_GetWaypointIsSpawnpoint(waypoint->nextwaypoints[newwaypoint]) == true)))
{
break;
}
}
return newwaypoint;
}
/*--------------------------------------------------
static void K_MovePlayerToRespawnPoint(player_t *player)
Handles the movement state of the respawn animation.
Input Arguments:-
player - Player to preform for.
Return:-
None
--------------------------------------------------*/
static void K_MovePlayerToRespawnPoint(player_t *player)
{
const fixed_t realstepamt = (64 * mapobjectscale);
fixed_t stepamt = realstepamt;
vertex_t dest, step, laser;
angle_t stepha, stepva;
fixed_t dist, fulldist;
UINT8 lasersteps = 4;
UINT32 laserdist;
waypoint_t *laserwp;
boolean laserflip;
player->mo->momx = player->mo->momy = player->mo->momz = 0;
player->powers[pw_flashing] = 2;
player->powers[pw_nocontrol] = max(2, player->powers[pw_nocontrol]);
if (leveltime % 8 == 0 && !mapreset)
{
S_StartSound(player->mo, sfx_s3kcas);
}
dest.x = player->respawn.pointx;
dest.y = player->respawn.pointy;
dest.z = player->respawn.pointz;
dist = P_AproxDistance(P_AproxDistance(
player->mo->x - dest.x,
player->mo->y - dest.y),
player->mo->z - dest.z
);
if (dist <= stepamt)
{
// Reduce by the amount we needed to get to this waypoint
stepamt -= dist;
// We've reached the destination point,
P_UnsetThingPosition(player->mo);
player->mo->x = dest.x;
player->mo->y = dest.y;
player->mo->z = dest.z;
P_SetThingPosition(player->mo);
// Find the next waypoint to head towards
if (player->respawn.wp != NULL)
{
size_t nwp = K_NextRespawnWaypointIndex(player->respawn.wp);
if (nwp == SIZE_MAX)
{
player->respawn.state = RESPAWNST_DROP;
return;
}
// Set angle, regardless of if we're done or not
player->frameangle = R_PointToAngle2(
player->mo->x, player->mo->y,
dest.x, dest.y
);
if ((player->respawn.distanceleft == 0 && K_GetWaypointIsSpawnpoint(player->respawn.wp) == true)
|| (player->respawn.wp == K_GetFinishLineWaypoint()
|| player->respawn.wp->nextwaypoints[nwp] == K_GetFinishLineWaypoint())) // Try not to allow you to pass the finish line while respawning, because it's janky
{
// Alright buddy, that's the end of the ride.
player->respawn.state = RESPAWNST_DROP;
return;
}
if (player->respawn.distanceleft > player->respawn.wp->nextwaypointdistances[nwp])
{
player->respawn.distanceleft -= player->respawn.wp->nextwaypointdistances[nwp];
}
else
{
player->respawn.distanceleft = 0;
}
player->respawn.wp = player->respawn.wp->nextwaypoints[nwp];
K_RespawnAtWaypoint(player, player->respawn.wp);
dest.x = player->respawn.pointx;
dest.y = player->respawn.pointy;
dest.z = player->respawn.pointz;
}
else
{
// We can now drop!
player->respawn.state = RESPAWNST_DROP;
return;
}
}
stepha = R_PointToAngle2(
player->mo->x, player->mo->y,
dest.x, dest.y
);
stepva = R_PointToAngle2(
0, player->mo->z,
P_AproxDistance(player->mo->x - dest.x, player->mo->y - dest.y), dest.z
);
// Move toward the respawn point
player->frameangle = stepha;
step.x = FixedMul(FixedMul(FINECOSINE(stepha >> ANGLETOFINESHIFT), stepamt), FINECOSINE(stepva >> ANGLETOFINESHIFT));
step.y = FixedMul(FixedMul(FINESINE(stepha >> ANGLETOFINESHIFT), stepamt), FINECOSINE(stepva >> ANGLETOFINESHIFT));
step.z = FixedMul(FINESINE(stepva >> ANGLETOFINESHIFT), 2*stepamt);
if (stepamt > 0)
{
player->mo->momx = step.x;
player->mo->momy = step.y;
player->mo->momz = step.z;
}
// NOW THEN, time for loads of dumb duplication!
// "Emulate" the rest of the path, that way we can spawn a particle a certain distance ahead of you.
if (stepamt != realstepamt)
{
// Reset back to default
stepamt = realstepamt;
step.x = FixedMul(FixedMul(FINECOSINE(stepha >> ANGLETOFINESHIFT), stepamt), FINECOSINE(stepva >> ANGLETOFINESHIFT));
step.y = FixedMul(FixedMul(FINESINE(stepha >> ANGLETOFINESHIFT), stepamt), FINECOSINE(stepva >> ANGLETOFINESHIFT));
step.z = FixedMul(FINESINE(stepva >> ANGLETOFINESHIFT), 2*stepamt);
}
laserdist = player->respawn.distanceleft;
laserwp = player->respawn.wp;
laserflip = player->respawn.flip;
laser.x = player->mo->x + (step.x / 2);
laser.y = player->mo->y + (step.y / 2);
laser.z = player->mo->z + (step.z / 2);
dist = P_AproxDistance(P_AproxDistance(
laser.x - dest.x,
laser.y - dest.y),
laser.z - dest.z
);
fulldist = dist + (laserdist * FRACUNIT);
while (lasersteps > 0)
{
if (fulldist <= stepamt)
{
break;
}
if (dist <= stepamt)
{
size_t lnwp;
laser.x = dest.x;
laser.y = dest.y;
laser.z = dest.z;
if (laserdist <= 0)
{
break;
}
lnwp = K_NextRespawnWaypointIndex(laserwp);
if (lnwp == SIZE_MAX)
{
break;
}
if (laserdist > laserwp->nextwaypointdistances[lnwp])
{
laserdist -= laserwp->nextwaypointdistances[lnwp];
}
else
{
laserdist = 0;
}
laserwp = laserwp->nextwaypoints[lnwp];
dest.x = laserwp->mobj->x;
dest.y = laserwp->mobj->y;
dest.z = laserwp->mobj->z;
laserflip = (laserwp->mobj->flags2 & MF2_OBJECTFLIP);
if (laserflip == true)
{
dest.z -= (128 * mapobjectscale) - (player->mo->height);
}
else
{
dest.z += (128 * mapobjectscale);
}
stepamt -= dist;
stepha = R_PointToAngle2(laser.x, laser.y, dest.x, dest.y);
stepva = R_PointToAngle2(0, laser.z, P_AproxDistance(laser.x - dest.x, laser.y - dest.y), dest.z);
step.x = FixedMul(FixedMul(FINECOSINE(stepha >> ANGLETOFINESHIFT), stepamt), FINECOSINE(stepva >> ANGLETOFINESHIFT));
step.y = FixedMul(FixedMul(FINESINE(stepha >> ANGLETOFINESHIFT), stepamt), FINECOSINE(stepva >> ANGLETOFINESHIFT));
step.z = FixedMul(FINESINE(stepva >> ANGLETOFINESHIFT), 2*stepamt);
}
else if (stepamt != realstepamt)
{
// Reset back to default
stepamt = realstepamt;
step.x = FixedMul(FixedMul(FINECOSINE(stepha >> ANGLETOFINESHIFT), stepamt), FINECOSINE(stepva >> ANGLETOFINESHIFT));
step.y = FixedMul(FixedMul(FINESINE(stepha >> ANGLETOFINESHIFT), stepamt), FINECOSINE(stepva >> ANGLETOFINESHIFT));
step.z = FixedMul(FINESINE(stepva >> ANGLETOFINESHIFT), 2*stepamt);
}
if (stepamt > 0)
{
laser.x += step.x;
laser.y += step.y;
laser.z += step.z;
}
dist = P_AproxDistance(P_AproxDistance(
laser.x - dest.x,
laser.y - dest.y),
laser.z - dest.z
);
fulldist = dist + (laserdist * FRACUNIT);
lasersteps--;
}
if (lasersteps == 0) // Don't spawn them beyond the respawn point.
{
mobj_t *lasermo = P_SpawnMobj(laser.x, laser.y, laser.z + (player->mo->height / 2), MT_DEZLASER);
if (lasermo && !P_MobjWasRemoved(lasermo))
{
P_SetMobjState(lasermo, S_DEZLASER_TRAIL1);
if (player->mo->eflags & MFE_VERTICALFLIP)
{
lasermo->eflags |= MFE_VERTICALFLIP;
}
P_SetTarget(&lasermo->target, player->mo);
lasermo->angle = stepha + ANGLE_90;
P_SetScale(lasermo, (lasermo->destscale = player->mo->scale));
}
}
}
/*--------------------------------------------------
static void K_HandleDropDash(player_t *player)
Handles the visuals for the waiting period,
before you're allowed to Drop Dash.
Input Arguments:-
player - Player to preform for.
Return:-
None
--------------------------------------------------*/
static void K_DropDashWait(player_t *player)
{
if (player->powers[pw_nocontrol] == 0)
player->respawn.timer--;
if (leveltime % 8 == 0)
{
const UINT8 ns = 8;
const angle_t sidediff = FixedAngle((360 / ns) * FRACUNIT);
UINT8 i;
if (!mapreset)
{
S_StartSound(player->mo, sfx_s3kcas);
}
for (i = 0; i < ns; i++)
{
const angle_t newangle = sidediff * i;
vertex_t spawn;
mobj_t *laser;
spawn.x = player->mo->x + P_ReturnThrustX(player->mo, newangle, 31 * player->mo->scale);
spawn.y = player->mo->y + P_ReturnThrustY(player->mo, newangle, 31 * player->mo->scale);
if (player->mo->eflags & MFE_VERTICALFLIP)
{
spawn.z = player->mo->z + player->mo->height;
}
else
{
spawn.z = player->mo->z;
}
laser = P_SpawnMobj(spawn.x, spawn.y, spawn.z, MT_DEZLASER);
if (laser && !P_MobjWasRemoved(laser))
{
if (player->mo->eflags & MFE_VERTICALFLIP)
{
laser->eflags |= MFE_VERTICALFLIP;
}
P_SetTarget(&laser->target, player->mo);
laser->angle = newangle + ANGLE_90;
laser->momz = (8 * player->mo->scale) * P_MobjFlip(player->mo);
P_SetScale(laser, (laser->destscale = player->mo->scale));
}
}
}
}
/*--------------------------------------------------
static void K_HandleDropDash(player_t *player)
Handles input for the Drop Dash maneuver.
Input Arguments:-
player - Player to preform for.
Return:-
None
--------------------------------------------------*/
static void K_HandleDropDash(player_t *player)
{
ticcmd_t *cmd = &player->cmd;
if (player->kartstuff[k_growshrinktimer] < 0)
{
player->mo->scalespeed = mapobjectscale/TICRATE;
player->mo->destscale = (6*mapobjectscale)/8;
if (cv_kartdebugshrink.value && !modeattacking && !player->bot)
{
player->mo->destscale = (6*player->mo->destscale)/8;
}
}
if (!P_IsObjectOnGround(player->mo))
{
if (mapreset)
{
return;
}
player->powers[pw_flashing] = K_GetKartFlashing(player);
// The old behavior was stupid and prone to accidental usage.
// Let's rip off Mania instead, and turn this into a Drop Dash!
if ((cmd->buttons & BT_ACCELERATE) && !player->kartstuff[k_spinouttimer]) // Since we're letting players spin out on respawn, don't let them charge a dropdash in this state. (It wouldn't work anyway)
{
player->respawn.dropdash++;
}
else
{
player->respawn.dropdash = 0;
}
if (player->respawn.dropdash == TICRATE/4)
{
S_StartSound(player->mo, sfx_ddash);
}
if ((player->respawn.dropdash >= TICRATE/4) && (player->respawn.dropdash & 1))
{
player->mo->colorized = true;
}
else
{
player->mo->colorized = false;
}
}
else
{
if ((cmd->buttons & BT_ACCELERATE) && (player->respawn.dropdash >= TICRATE/4))
{
S_StartSound(player->mo, sfx_s23c);
player->kartstuff[k_startboost] = 50;
K_SpawnDashDustRelease(player);
}
player->mo->colorized = false;
player->respawn.dropdash = 0;
//P_PlayRinglossSound(player->mo);
P_PlayerRingBurst(player, 3);
if (G_BattleGametype())
{
if (player->kartstuff[k_bumper] > 0)
{
if (player->kartstuff[k_bumper] == 1)
{
mobj_t *karmahitbox = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_KARMAHITBOX); // Player hitbox is too small!!
P_SetTarget(&karmahitbox->target, player->mo);
karmahitbox->destscale = player->mo->scale;
P_SetScale(karmahitbox, player->mo->scale);
CONS_Printf(M_GetText("%s lost all of their bumpers!\n"), player_names[player-players]);
}
player->kartstuff[k_bumper]--;
if (K_IsPlayerWanted(player))
K_CalculateBattleWanted();
}
if (!player->kartstuff[k_bumper])
{
player->kartstuff[k_comebacktimer] = comebacktime;
if (player->kartstuff[k_comebackmode] == 2)
{
mobj_t *poof = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EXPLODE);
S_StartSound(poof, mobjinfo[MT_KARMAHITBOX].seesound);
player->kartstuff[k_comebackmode] = 0;
}
}
K_CheckBumpers();
}
player->respawn.state = RESPAWNST_NONE;
}
}
/*--------------------------------------------------
void K_RespawnChecker(player_t *player)
See header file for description.
--------------------------------------------------*/
void K_RespawnChecker(player_t *player)
{
if (player->respawn.state == RESPAWNST_NONE)
{
return;
}
if (player->spectator)
{
player->respawn.state = RESPAWNST_NONE;
return;
}
switch (player->respawn.state)
{
case RESPAWNST_MOVE:
player->mo->momx = player->mo->momy = player->mo->momz = 0;
K_MovePlayerToRespawnPoint(player);
return;
case RESPAWNST_DROP:
player->mo->momx = player->mo->momy = 0;
if (player->respawn.timer > 0)
{
player->mo->momz = 0;
K_DropDashWait(player);
}
else
{
K_HandleDropDash(player);
}
return;
default:
player->respawn.state = RESPAWNST_NONE;
return;
}
}

71
src/k_respawn.h Normal file
View file

@ -0,0 +1,71 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2020 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_respawn.h
/// \brief Respawning logic
#ifndef __K_RESPAWN__
#define __K_RESPAWN__
#include "k_waypoint.h"
#include "d_player.h"
#define RESPAWN_DIST 1024
#define RESPAWN_TIME 48
#define RESPAWNST_NONE 0
#define RESPAWNST_MOVE 1
#define RESPAWNST_DROP 2
/*--------------------------------------------------
fixed_t K_RespawnOffset(player_t *player, boolean flip);
Updates the player's flip flags, and returns a
Z offset for respawning.
Input Arguments:-
player - Player to preform this for.
flip - false for normal, true for gravity flip.
Return:-
Z position offset.
--------------------------------------------------*/
fixed_t K_RespawnOffset(player_t *player, boolean flip);
/*--------------------------------------------------
void K_DoIngameRespawn(player_t *player);
Starts the respawning animation for the specified player,
updating their respawn variables in preparation.
Input Arguments:-
player - Player to preform this for.
Return:-
None
--------------------------------------------------*/
void K_DoIngameRespawn(player_t *player);
/*--------------------------------------------------
void K_RespawnChecker(player_t *player);
Thinker for the respawning animation.
Input Arguments:-
player - Player to preform this for.
Return:-
None
--------------------------------------------------*/
void K_RespawnChecker(player_t *player);
#endif

View file

@ -474,7 +474,7 @@ static void K_DebugWaypointsSpawnLine(waypoint_t *const waypoint1, waypoint_t *c
spawnedmobj->state->tics = 1;
spawnedmobj->frame = spawnedmobj->frame & ~FF_TRANSMASK;
spawnedmobj->color = linkcolours[linkcolour];
spawnedmobj->scale = FixedMul(FRACUNIT/4, FixedDiv((15 - ((leveltime + n) % 16))*FRACUNIT, 15*FRACUNIT));
spawnedmobj->scale = FixedMul(spawnedmobj->scale, FixedMul(FRACUNIT/4, FixedDiv((15 - ((leveltime + n) % 16))*FRACUNIT, 15*FRACUNIT)));
}
x += stepx;
@ -483,6 +483,48 @@ static void K_DebugWaypointsSpawnLine(waypoint_t *const waypoint1, waypoint_t *c
} while (n--);
}
/*--------------------------------------------------
void K_DebugWaypointDrawRadius(waypoint_t *const waypoint)
Draw a debugging circle to represent a waypoint's radius
Input Arguments:-
waypoint - A waypoint to draw the radius of
--------------------------------------------------*/
static void K_DebugWaypointDrawRadius(waypoint_t *const waypoint)
{
mobj_t *radiusOrb;
mobj_t *waypointmobj;
const INT32 numRadiusMobjs = 64;
INT32 i = 0;
angle_t spawnAngle = 0U;
fixed_t spawnX= 0;
fixed_t spawnY= 0;
fixed_t spawnZ= 0;
I_Assert(waypoint != NULL);
I_Assert(waypoint->mobj != NULL);
waypointmobj = waypoint->mobj;
for (i = 0; i < numRadiusMobjs; i++)
{
spawnAngle = (ANGLE_MAX / numRadiusMobjs) * i;
spawnZ = waypointmobj->z;
spawnX = waypointmobj->x + P_ReturnThrustX(waypointmobj, spawnAngle, waypointmobj->radius);
spawnY = waypointmobj->y + P_ReturnThrustY(waypointmobj, spawnAngle, waypointmobj->radius);
radiusOrb = P_SpawnMobj(spawnX, spawnY, spawnZ, MT_SPARK);
P_SetMobjState(radiusOrb, S_THOK);
radiusOrb->state->nextstate = S_NULL;
radiusOrb->state->tics = 1;
radiusOrb->frame = radiusOrb->frame & ~FF_TRANSMASK;
radiusOrb->color = SKINCOLOR_PURPLE;
radiusOrb->scale = radiusOrb->scale / 4;
}
}
/*--------------------------------------------------
void K_DebugWaypointsVisualise(void)
@ -523,15 +565,20 @@ void K_DebugWaypointsVisualise(void)
{
if (waypoint->numnextwaypoints == 0 && waypoint->numprevwaypoints == 0)
{
P_SetMobjState(debugmobj, S_EGOORB);
debugmobj->color = SKINCOLOR_RED;
debugmobj->colorized = true;
}
else if (waypoint->numnextwaypoints == 0 || waypoint->numprevwaypoints == 0)
{
P_SetMobjState(debugmobj, S_EGOORB);
debugmobj->color = SKINCOLOR_YELLOW;
debugmobj->colorized = true;
}
else if (waypoint == players[displayplayers[0]].nextwaypoint)
{
debugmobj->color = SKINCOLOR_GREEN;
K_DebugWaypointDrawRadius(waypoint);
}
else
{

View file

@ -29,6 +29,7 @@
#include "k_kart.h" // SRB2Kart
#include "k_battle.h"
#include "k_color.h"
#include "k_hud.h"
#include "d_netcmd.h" // IsPlayerAdmin
#include "m_menu.h" // Player Setup menu color stuff

View file

@ -19,6 +19,7 @@ enum hud {
hud_minimap,
hud_item,
hud_position,
hud_names, // online nametags
hud_check, // "CHECK" f-zero indicator
hud_minirankings, // Rankings to the left
hud_battlebumpers, // mini rankings battle bumpers.

View file

@ -23,6 +23,7 @@
#include "v_video.h"
#include "w_wad.h"
#include "z_zone.h"
#include "hu_stuff.h"
#include "lua_script.h"
#include "lua_libs.h"

View file

@ -56,6 +56,7 @@ enum mobj_e {
mobj_flags,
mobj_flags2,
mobj_eflags,
mobj_drawflags,
mobj_skin,
mobj_color,
mobj_bnext,
@ -129,6 +130,7 @@ static const char *const mobj_opt[] = {
"flags",
"flags2",
"eflags",
"drawflags",
"skin",
"color",
"bnext",
@ -285,6 +287,9 @@ static int mobj_get(lua_State *L)
case mobj_eflags:
lua_pushinteger(L, mo->eflags);
break;
case mobj_drawflags:
lua_pushinteger(L, mo->drawflags);
break;
case mobj_skin: // skin name or nil, not struct
if (!mo->skin)
return 0;
@ -599,7 +604,10 @@ static int mobj_set(lua_State *L)
mo->flags2 = (UINT32)luaL_checkinteger(L, 3);
break;
case mobj_eflags:
mo->eflags = (UINT32)luaL_checkinteger(L, 3);
mo->eflags = (UINT16)luaL_checkinteger(L, 3);
break;
case mobj_drawflags:
mo->drawflags = (UINT16)luaL_checkinteger(L, 3);
break;
case mobj_skin: // set skin by name
{

View file

@ -118,7 +118,7 @@ static int lib_iterateDisplayplayers(lua_State *L)
for (i++; i < MAXSPLITSCREENPLAYERS; i++)
{
if (!playeringame[displayplayers[i]] || i > splitscreen)
if (i > splitscreen || !playeringame[displayplayers[i]])
return 0; // Stop! There are no more players for us to go through. There will never be a player gap in displayplayers.
if (!players[displayplayers[i]].mo)
@ -139,6 +139,8 @@ static int lib_getDisplayplayers(lua_State *L)
lua_Integer i = luaL_checkinteger(L, 2);
if (i < 0 || i >= MAXSPLITSCREENPLAYERS)
return luaL_error(L, "displayplayers[] index %d out of range (0 - %d)", i, MAXSPLITSCREENPLAYERS-1);
if (i > splitscreen)
return 0;
if (!playeringame[displayplayers[i]])
return 0;
if (!players[displayplayers[i]].mo)
@ -217,6 +219,8 @@ static int player_get(lua_State *L)
LUA_PushUserdata(L, plr->kartstuff, META_KARTSTUFF);
else if (fastcmp(field,"frameangle"))
lua_pushangle(L, plr->frameangle);
else if (fastcmp(field,"airtime"))
lua_pushinteger(L, plr->airtime);
else if (fastcmp(field,"pflags"))
lua_pushinteger(L, plr->pflags);
else if (fastcmp(field,"panim"))
@ -238,6 +242,14 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->kartspeed);
else if (fastcmp(field,"kartweight"))
lua_pushinteger(L, plr->kartweight);
else if (fastcmp(field,"followerskin"))
lua_pushinteger(L, plr->followerskin);
else if (fastcmp(field,"followerready"))
lua_pushboolean(L, plr->followerready);
else if (fastcmp(field,"followercolor"))
lua_pushinteger(L, plr->followercolor);
else if (fastcmp(field,"follower"))
LUA_PushUserdata(L, plr->follower, META_MOBJ);
//
else if (fastcmp(field,"charflags"))
lua_pushinteger(L, plr->charflags);
@ -247,6 +259,8 @@ static int player_get(lua_State *L)
LUA_PushUserdata(L, plr->followmobj, META_MOBJ);
else if (fastcmp(field,"lives"))
lua_pushinteger(L, plr->lives);
else if (fastcmp(field,"lostlife"))
lua_pushboolean(L, plr->lostlife);
else if (fastcmp(field,"continues"))
lua_pushinteger(L, plr->continues);
else if (fastcmp(field,"xtralife"))
@ -299,20 +313,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->weapondelay);
else if (fastcmp(field,"tossdelay"))
lua_pushinteger(L, plr->tossdelay);
else if (fastcmp(field,"starpostx"))
lua_pushinteger(L, plr->starpostx);
else if (fastcmp(field,"starposty"))
lua_pushinteger(L, plr->starposty);
else if (fastcmp(field,"starpostz"))
lua_pushinteger(L, plr->starpostz);
else if (fastcmp(field,"starpostnum"))
lua_pushinteger(L, plr->starpostnum);
else if (fastcmp(field,"starposttime"))
lua_pushinteger(L, plr->starposttime);
else if (fastcmp(field,"starpostangle"))
lua_pushangle(L, plr->starpostangle);
else if (fastcmp(field,"starpostscale"))
lua_pushfixed(L, plr->starpostscale);
else if (fastcmp(field,"angle_pos"))
lua_pushangle(L, plr->angle_pos);
else if (fastcmp(field,"old_angle_pos"))
@ -405,6 +407,7 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->awayviewtics);
else if (fastcmp(field,"awayviewaiming"))
lua_pushangle(L, plr->awayviewaiming);
else if (fastcmp(field,"spectator"))
lua_pushboolean(L, plr->spectator);
else if (fastcmp(field,"bot"))
@ -514,10 +517,20 @@ static int player_set(lua_State *L)
return NOSET;
else if (fastcmp(field,"frameangle"))
plr->frameangle = luaL_checkangle(L, 3);
else if (fastcmp(field,"airtime"))
plr->airtime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"kartspeed"))
plr->kartspeed = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"kartweight"))
plr->kartweight = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"followerskin"))
plr->followerskin = luaL_checkinteger(L, 3);
else if (fastcmp(field,"followercolor"))
plr->followercolor = luaL_checkinteger(L, 3);
else if (fastcmp(field,"followerready"))
plr->followerready = luaL_checkboolean(L, 3);
else if (fastcmp(field,"follower")) // it's probably best we don't allow the follower mobj to change.
return NOSET;
//
else if (fastcmp(field,"charflags"))
plr->charflags = (UINT32)luaL_checkinteger(L, 3);
@ -532,6 +545,8 @@ static int player_set(lua_State *L)
}
else if (fastcmp(field,"lives"))
plr->lives = (SINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"lostlife"))
plr->lostlife = luaL_checkboolean(L, 3);
else if (fastcmp(field,"continues"))
plr->continues = (SINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"xtralife"))
@ -584,20 +599,8 @@ static int player_set(lua_State *L)
plr->weapondelay = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"tossdelay"))
plr->tossdelay = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"starpostx"))
plr->starpostx = (INT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"starposty"))
plr->starposty = (INT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"starpostz"))
plr->starpostz = (INT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"starpostnum"))
plr->starpostnum = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"starposttime"))
plr->starposttime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"starpostangle"))
plr->starpostangle = luaL_checkangle(L, 3);
else if (fastcmp(field,"starpostscale"))
plr->starpostscale = luaL_checkfixed(L, 3);
else if (fastcmp(field,"angle_pos"))
plr->angle_pos = luaL_checkangle(L, 3);
else if (fastcmp(field,"old_angle_pos"))
@ -843,8 +846,6 @@ static int ticcmd_get(lua_State *L)
if (fastcmp(field,"forwardmove"))
lua_pushinteger(L, cmd->forwardmove);
else if (fastcmp(field,"sidemove"))
lua_pushinteger(L, cmd->sidemove);
else if (fastcmp(field,"angleturn"))
lua_pushinteger(L, cmd->angleturn);
else if (fastcmp(field,"aiming"))
@ -873,8 +874,6 @@ static int ticcmd_set(lua_State *L)
if (fastcmp(field,"forwardmove"))
cmd->forwardmove = (SINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"sidemove"))
cmd->sidemove = (SINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"angleturn"))
cmd->angleturn = (INT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"aiming"))

View file

@ -833,19 +833,11 @@ void Command_Savecheckpoint_f(void)
REQUIRE_INLEVEL;
REQUIRE_SINGLEPLAYER;
players[consoleplayer].starposttime = players[consoleplayer].realtime;
players[consoleplayer].starpostx = players[consoleplayer].mo->x>>FRACBITS;
players[consoleplayer].starposty = players[consoleplayer].mo->y>>FRACBITS;
players[consoleplayer].starpostz = players[consoleplayer].mo->floorz>>FRACBITS;
players[consoleplayer].starpostangle = players[consoleplayer].mo->angle;
players[consoleplayer].starpostscale = players[consoleplayer].mo->destscale;
if (players[consoleplayer].mo->flags2 & MF2_OBJECTFLIP)
{
players[consoleplayer].starpostscale *= -1;
players[consoleplayer].starpostz += players[consoleplayer].mo->height;
}
players[consoleplayer].respawn.pointx = players[consoleplayer].mo->x;
players[consoleplayer].respawn.pointy = players[consoleplayer].mo->y;
players[consoleplayer].respawn.pointz = players[consoleplayer].mo->floorz;
CONS_Printf(M_GetText("Temporary checkpoint created at %d, %d, %d\n"), players[consoleplayer].starpostx, players[consoleplayer].starposty, players[consoleplayer].starpostz);
CONS_Printf(M_GetText("Temporary checkpoint created at %d, %d, %d\n"), players[consoleplayer].respawn.pointx, players[consoleplayer].respawn.pointy, players[consoleplayer].respawn.pointz);
}
// Like M_GetAllEmeralds() but for console devmode junkies.

View file

@ -32,6 +32,7 @@
#include "sounds.h"
#include "s_sound.h"
#include "i_system.h"
#include "i_threads.h"
// Addfile
#include "filesrch.h"
@ -126,6 +127,12 @@ typedef enum
NUM_QUITMESSAGES
} text_enum;
#ifdef HAVE_THREADS
I_mutex m_menu_mutex;
#endif
M_waiting_mode_t m_waiting_mode = M_NOT_WAITING;
const char *quitmsg[NUM_QUITMESSAGES];
// Stuff for customizing the player select screen Tails 09-22-2003
@ -1073,7 +1080,7 @@ enum
FIRSTSERVERLINE
};
static menuitem_t MP_RoomMenu[] =
menuitem_t MP_RoomMenu[] =
{
{IT_STRING | IT_CALL, NULL, "<Offline Mode>", M_ChooseRoom, 9},
{IT_DISABLED, NULL, "", M_ChooseRoom, 18},
@ -2893,7 +2900,6 @@ boolean M_Responder(event_t *ev)
//make sure the game doesn't still think we're in a netgame.
if (!Playing() && netgame && multiplayer)
{
MSCloseUDPSocket(); // Clean up so we can re-open the connection later.
netgame = false;
multiplayer = false;
}
@ -3305,6 +3311,30 @@ void M_SetupNextMenu(menu_t *menudef)
{
INT16 i;
#ifdef HAVE_THREADS
if (currentMenu == &MP_RoomDef || currentMenu == &MP_ConnectDef)
{
I_lock_mutex(&ms_QueryId_mutex);
{
ms_QueryId++;
}
I_unlock_mutex(ms_QueryId_mutex);
}
if (currentMenu == &MP_ConnectDef)
{
I_lock_mutex(&ms_ServerList_mutex);
{
if (ms_ServerList)
{
free(ms_ServerList);
ms_ServerList = NULL;
}
}
I_unlock_mutex(ms_ServerList_mutex);
}
#endif/*HAVE_THREADS*/
if (currentMenu->quitroutine)
{
// If you're going from a menu to itself, why are you running the quitroutine? You're not quitting it! -SH
@ -3364,6 +3394,19 @@ void M_Ticker(void)
if (--vidm_testingmode == 0)
setmodeneeded = vidm_previousmode + 1;
}
#ifdef HAVE_THREADS
I_lock_mutex(&ms_ServerList_mutex);
{
if (ms_ServerList)
{
CL_QueryServerList(ms_ServerList);
free(ms_ServerList);
ms_ServerList = NULL;
}
}
I_unlock_mutex(ms_ServerList_mutex);
#endif
}
//
@ -4844,7 +4887,7 @@ static boolean M_AddonsRefresh(void)
else if (majormods && !prevmajormods)
{
S_StartSound(NULL, sfx_s221);
message = va("%c%s\x80\nGameplay has now been modified.\nIf you wish to play Record Attack mode, restart the game to clear existing addons.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname);
message = va("%c%s\x80\nYou've loaded a gameplay-modifying addon.\n\nRecord Attack has been disabled, but you\ncan still play alone in local Multiplayer.\n\nIf you wish to play Record Attack mode, restart the game to disable loaded addons.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), refreshdirname);
prevmajormods = majormods;
}
@ -8455,22 +8498,65 @@ static INT32 menuRoomIndex = 0;
static void M_DrawRoomMenu(void)
{
static int frame = -12;
int dot_frame;
char text[4];
const char *rmotd;
const char *waiting_message;
int dots;
if (m_waiting_mode)
{
dot_frame = frame / 4;
dots = dot_frame + 3;
strcpy(text, " ");
if (dots > 0)
{
if (dot_frame < 0)
dot_frame = 0;
strncpy(&text[dot_frame], "...", min(dots, 3 - dot_frame));
}
if (++frame == 12)
frame = -12;
currentMenu->menuitems[0].text = text;
}
// use generic drawer for cursor, items and title
M_DrawGenericMenu();
V_DrawString(currentMenu->x - 16, currentMenu->y, highlightflags, M_GetText("Select a room"));
M_DrawTextBox(144, 24, 20, 20);
if (m_waiting_mode == M_NOT_WAITING)
{
M_DrawTextBox(144, 24, 20, 20);
if (itemOn == 0)
rmotd = M_GetText("Don't connect to the Master Server.");
else
rmotd = room_list[itemOn-1].motd;
if (itemOn == 0)
rmotd = M_GetText("Don't connect to the Master Server.");
else
rmotd = room_list[itemOn-1].motd;
rmotd = V_WordWrap(0, 20*8, 0, rmotd);
V_DrawString(144+8, 32, V_ALLOWLOWERCASE|V_RETURN8, rmotd);
rmotd = V_WordWrap(0, 20*8, 0, rmotd);
V_DrawString(144+8, 32, V_ALLOWLOWERCASE|V_RETURN8, rmotd);
}
if (m_waiting_mode)
{
// Display a little "please wait" message.
M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
if (m_waiting_mode == M_WAITING_VERSION)
waiting_message = "Checking for updates...";
else
waiting_message = "Fetching room info...";
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, waiting_message);
V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
}
}
static void M_DrawConnectMenu(void)
@ -8550,6 +8636,14 @@ static void M_DrawConnectMenu(void)
localservercount = serverlistcount;
M_DrawGenericMenu();
if (m_waiting_mode)
{
// Display a little "please wait" message.
M_DrawTextBox(52, BASEVIDHEIGHT/2-10, 25, 3);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2, 0, "Searching for servers...");
V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2)+12, 0, "Please wait.");
}
}
static boolean M_CancelConnect(void)
@ -8631,10 +8725,10 @@ void M_SortServerList(void)
#ifndef NONET
#ifdef UPDATE_ALERT
static boolean M_CheckMODVersion(void)
static boolean M_CheckMODVersion(int id)
{
char updatestring[500];
const char *updatecheck = GetMODVersion();
const char *updatecheck = GetMODVersion(id);
if(updatecheck)
{
sprintf(updatestring, UPDATE_ALERT_STRING, VERSIONSTRING, updatecheck);
@ -8643,7 +8737,62 @@ static boolean M_CheckMODVersion(void)
} else
return true;
}
#endif
#ifdef HAVE_THREADS
static void
Check_new_version_thread (int *id)
{
int hosting;
int okay;
okay = 0;
if (M_CheckMODVersion(*id))
{
I_lock_mutex(&ms_QueryId_mutex);
{
okay = ( *id == ms_QueryId );
}
I_unlock_mutex(ms_QueryId_mutex);
if (okay)
{
I_lock_mutex(&m_menu_mutex);
{
m_waiting_mode = M_WAITING_ROOMS;
hosting = ( currentMenu->prevMenu == &MP_ServerDef );
}
I_unlock_mutex(m_menu_mutex);
GetRoomsList(hosting, *id);
}
}
else
{
I_lock_mutex(&ms_QueryId_mutex);
{
okay = ( *id == ms_QueryId );
}
I_unlock_mutex(ms_QueryId_mutex);
}
if (okay)
{
I_lock_mutex(&m_menu_mutex);
{
if (m_waiting_mode)
{
m_waiting_mode = M_NOT_WAITING;
MP_RoomMenu[0].text = "<Offline Mode>";
}
}
I_unlock_mutex(m_menu_mutex);
}
free(id);
}
#endif/*HAVE_THREADS*/
#endif/*UPDATE_ALERT*/
static void M_ConnectMenu(INT32 choice)
{
@ -8672,18 +8821,21 @@ static void M_ConnectMenuModChecks(INT32 choice)
if (modifiedgame)
{
M_StartMessage(M_GetText("Addons are currently loaded.\n\nYou will only be able to join a server if\nit has the same ones loaded in the same order, which may be unlikely.\n\nIf you wish to play on other servers,\nrestart the game to clear existing addons.\n\n(Press a key)\n"),M_ConnectMenu,MM_EVENTHANDLER);
M_StartMessage(M_GetText("You have addons loaded.\nYou won't be able to join netgames!\n\nTo play online, restart the game\nand don't load any addons.\nSRB2Kart will automatically add\neverything you need when you join.\n\n(Press a key)\n"),M_ConnectMenu,MM_EVENTHANDLER);
return;
}
M_ConnectMenu(-1);
}
static UINT32 roomIds[NUM_LIST_ROOMS];
UINT32 roomIds[NUM_LIST_ROOMS];
static void M_RoomMenu(INT32 choice)
{
INT32 i;
#ifdef HAVE_THREADS
int *id;
#endif
(void)choice;
@ -8696,34 +8848,47 @@ static void M_RoomMenu(INT32 choice)
if (rendermode == render_soft)
I_FinishUpdate(); // page flip or blit buffer
if (GetRoomsList(currentMenu == &MP_ServerDef) < 0)
return;
#ifdef UPDATE_ALERT
if (!M_CheckMODVersion())
return;
#endif
for (i = 1; i < NUM_LIST_ROOMS+1; ++i)
MP_RoomMenu[i].status = IT_DISABLED;
memset(roomIds, 0, sizeof(roomIds));
for (i = 0; room_list[i].header.buffer[0]; i++)
{
if(*room_list[i].name != '\0')
{
MP_RoomMenu[i+1].text = room_list[i].name;
roomIds[i] = room_list[i].id;
MP_RoomMenu[i+1].status = IT_STRING|IT_CALL;
}
}
MP_RoomDef.prevMenu = currentMenu;
M_SetupNextMenu(&MP_RoomDef);
#ifdef UPDATE_ALERT
#ifdef HAVE_THREADS
m_waiting_mode = M_WAITING_VERSION;
MP_RoomMenu[0].text = "";
id = malloc(sizeof *id);
I_lock_mutex(&ms_QueryId_mutex);
{
*id = ms_QueryId;
}
I_unlock_mutex(ms_QueryId_mutex);
I_spawn_thread("check-new-version",
(I_thread_fn)Check_new_version_thread, id);
#else/*HAVE_THREADS*/
if (M_CheckMODVersion(0))
{
GetRoomsList(currentMenu->prevMenu == &MP_ServerDef, 0);
}
#endif/*HAVE_THREADS*/
#endif/*UPDATE_ALERT*/
}
static void M_ChooseRoom(INT32 choice)
{
#ifdef HAVE_THREADS
I_lock_mutex(&ms_QueryId_mutex);
{
ms_QueryId++;
}
I_unlock_mutex(ms_QueryId_mutex);
#endif
if (choice == 0)
ms_RoomId = -1;
else

View file

@ -21,7 +21,7 @@
#include "f_finale.h" // for ttmode_enum
#include "i_threads.h"
#include "mserv.h"
#include "r_things.h" // for SKINNAMESIZE
#include "r_skins.h" // for SKINNAMESIZE
// Compatibility with old-style named NiGHTS replay files.
#define OLDNREPLAYNAME
@ -339,6 +339,9 @@ typedef struct menuitem_s
extern menuitem_t MP_RoomMenu[];
extern UINT32 roomIds[NUM_LIST_ROOMS];
extern menuitem_t MP_RoomMenu[];
extern UINT32 roomIds[NUM_LIST_ROOMS];
typedef struct menu_s
{
UINT32 menuid; // ID to encode menu type and hierarchy

View file

@ -28,6 +28,7 @@
#include "k_kart.h" // SRB2kart
#include "k_waypoint.h"
#include "k_battle.h"
#include "k_respawn.h"
#ifdef HW3SOUND
#include "hardware/hw3sound.h"
@ -943,10 +944,10 @@ void A_Look(mobj_t *actor)
if (LUA_CallAction("A_Look", actor))
return;
if (!P_LookForPlayers(actor, locvar1 & 65535, false , FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale)))
if (leveltime < starttime) // SRB2kart - no looking before race starts
return;
if (leveltime < starttime) // SRB2kart - no looking before race starts
if (!P_LookForPlayers(actor, locvar1 & 65535, false , FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale)))
return;
// go into chase state
@ -4478,10 +4479,10 @@ void A_BubbleSpawn(mobj_t *actor)
if (!(actor->eflags & MFE_UNDERWATER))
{
// Don't draw or spawn bubbles above water
actor->flags2 |= MF2_DONTDRAW;
actor->drawflags |= MFD_DONTDRAW;
return;
}
actor->flags2 &= ~MF2_DONTDRAW;
actor->drawflags &= ~MFD_DONTDRAW;
if (!(actor->flags2 & MF2_AMBUSH))
{
@ -4611,9 +4612,9 @@ void A_BubbleCheck(mobj_t *actor)
return;
if (actor->eflags & MFE_UNDERWATER)
actor->flags2 &= ~MF2_DONTDRAW; // underwater so draw
actor->drawflags &= ~MFD_DONTDRAW; // underwater so draw
else
actor->flags2 |= MF2_DONTDRAW; // above water so don't draw
actor->drawflags |= MFD_DONTDRAW; // above water so don't draw
}
// Function: A_AttractChase
@ -4716,9 +4717,9 @@ void A_AttractChase(mobj_t *actor)
// Rings flicker before disappearing
if (actor->fuse && actor->fuse < 5*TICRATE && (leveltime & 1))
actor->flags2 |= MF2_DONTDRAW;
actor->drawflags |= MFD_DONTDRAW;
else
actor->flags2 &= ~MF2_DONTDRAW;
actor->drawflags &= ~MFD_DONTDRAW;
// spilled rings have ghost trails and get capped to a certain speed
if (actor->type == (mobjtype_t)actor->info->reactiontime)
@ -4952,9 +4953,9 @@ void A_ThrownRing(mobj_t *actor)
// spilled rings (and thrown bounce) flicker before disappearing
if (leveltime & 1 && actor->fuse > 0 && actor->fuse < 2*TICRATE
&& actor->type != MT_THROWNGRENADE)
actor->flags2 |= MF2_DONTDRAW;
actor->drawflags |= MFD_DONTDRAW;
else
actor->flags2 &= ~MF2_DONTDRAW;
actor->drawflags &= ~MFD_DONTDRAW;
if (actor->tracer && actor->tracer->health <= 0)
P_SetTarget(&actor->tracer, NULL);
@ -6665,11 +6666,8 @@ void A_MixUp(mobj_t *actor)
INT32 transspeed; //player speed
// Starpost stuff
INT16 starpostx, starposty, starpostz;
fixed_t starpostx, starposty, starpostz;
INT32 starpostnum;
tic_t starposttime;
angle_t starpostangle;
fixed_t starpostscale;
INT32 mflags2;
@ -6713,24 +6711,21 @@ void A_MixUp(mobj_t *actor)
angle = players[one].mo->angle;
drawangle = players[one].drawangle;
starpostx = players[one].starpostx;
starposty = players[one].starposty;
starpostz = players[one].starpostz;
starpostangle = players[one].starpostangle;
starpostscale = players[one].starpostscale;
starpostx = players[one].respawn.pointx;
starposty = players[one].respawn.pointy;
starpostz = players[one].respawn.pointz;
starpostnum = players[one].starpostnum;
starposttime = players[one].starposttime;
mflags2 = players[one].mo->flags2;
P_MixUp(players[one].mo, players[two].mo->x, players[two].mo->y, players[two].mo->z, players[two].mo->angle,
players[two].starpostx, players[two].starposty, players[two].starpostz,
players[two].starpostnum, players[two].starposttime, players[two].starpostangle,
players[two].starpostscale, players[two].drawangle, players[two].mo->flags2);
players[two].respawn.pointx, players[two].respawn.pointy, players[two].respawn.pointz,
players[two].starpostnum, 0, 0,
FRACUNIT, players[two].drawangle, players[two].mo->flags2);
P_MixUp(players[two].mo, x, y, z, angle, starpostx, starposty, starpostz,
starpostnum, starposttime, starpostangle,
starpostscale, drawangle, mflags2);
starpostnum, 0, 0,
FRACUNIT, drawangle, mflags2);
//carry set after mixup. Stupid P_ResetPlayer() takes away some of the stuff we look for...
//but not all of it! So we need to make sure they aren't set wrong or anything.
@ -6753,11 +6748,8 @@ void A_MixUp(mobj_t *actor)
INT32 transspeed[MAXPLAYERS]; //player speed
// Star post stuff
INT16 spposition[MAXPLAYERS][3];
fixed_t spposition[MAXPLAYERS][3];
INT32 starpostnum[MAXPLAYERS];
tic_t starposttime[MAXPLAYERS];
angle_t starpostangle[MAXPLAYERS];
fixed_t starpostscale[MAXPLAYERS];
INT32 flags2[MAXPLAYERS];
@ -6789,13 +6781,10 @@ void A_MixUp(mobj_t *actor)
transspeed[counter] = players[i].speed;
transtracer[counter] = players[i].mo->tracer;
spposition[counter][0] = players[i].starpostx;
spposition[counter][1] = players[i].starposty;
spposition[counter][2] = players[i].starpostz;
spposition[counter][0] = players[i].respawn.pointx;
spposition[counter][1] = players[i].respawn.pointy;
spposition[counter][2] = players[i].respawn.pointz;
starpostnum[counter] = players[i].starpostnum;
starposttime[counter] = players[i].starposttime;
starpostangle[counter] = players[i].starpostangle;
starpostscale[counter] = players[i].starpostscale;
flags2[counter] = players[i].mo->flags2;
@ -6835,8 +6824,8 @@ void A_MixUp(mobj_t *actor)
P_MixUp(players[i].mo, position[teleportfrom][0], position[teleportfrom][1], position[teleportfrom][2], anglepos[teleportfrom][0],
spposition[teleportfrom][0], spposition[teleportfrom][1], spposition[teleportfrom][2],
starpostnum[teleportfrom], starposttime[teleportfrom], starpostangle[teleportfrom],
starpostscale[teleportfrom], anglepos[teleportfrom][1], flags2[teleportfrom]);
starpostnum[teleportfrom], 0, 0,
FRACUNIT, anglepos[teleportfrom][1], flags2[teleportfrom]);
//...carry after. same reasoning.
players[i].powers[pw_carry] = transcarry[teleportfrom];
@ -9812,7 +9801,7 @@ void A_SPBChase(mobj_t *actor)
if (players[i].mo->health <= 0)
continue; // dead
if (players[i].kartstuff[k_respawn])
if (players[i].respawn.state != RESPAWNST_NONE)
continue;*/ // respawning
if (players[i].kartstuff[k_position] < bestrank)
@ -9989,7 +9978,7 @@ void A_SPBChase(mobj_t *actor)
actor->lastlook = -1; // Just make sure this is reset
if (!player || !player->mo || player->mo->health <= 0 || player->kartstuff[k_respawn])
if (!player || !player->mo || player->mo->health <= 0 || (player->respawn.state != RESPAWNST_NONE))
{
// No one there? Completely STOP.
actor->momx = actor->momy = actor->momz = 0;
@ -10274,7 +10263,7 @@ void A_RandomShadowFrame(mobj_t *actor)
fake->destscale = FRACUNIT*3/2;
fake->angle = actor->angle;
fake->tics = -1;
actor->flags2 |= MF2_DONTDRAW;
actor->drawflags |= MFD_DONTDRAW;
actor->extravalue1 = 1;
}

View file

@ -33,6 +33,7 @@
#include "k_kart.h"
#include "k_battle.h"
#include "k_pwrlv.h"
#include "k_grandprix.h"
// CTF player names
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
@ -902,71 +903,146 @@ void P_CheckPointLimit(void)
// Checks whether or not to end a race netgame.
boolean P_CheckRacers(void)
{
INT32 i, j, numplayersingame = 0, numexiting = 0;
UINT8 i;
UINT8 numplayersingame = 0;
UINT8 numexiting = 0;
boolean eliminatelast = cv_karteliminatelast.value;
boolean everyonedone = true;
boolean eliminatebots = false;
boolean griefed = false;
// Check if all the players in the race have finished. If so, end the level.
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].exiting || players[i].bot || !players[i].lives)
continue;
if (nospectategrief[i] != -1) // prevent spectate griefing
{
griefed = true;
}
break;
if (!playeringame[i] || players[i].spectator || players[i].lives <= 0) // Not playing
{
// Y'all aren't even playing
continue;
}
numplayersingame++;
if (players[i].exiting || (players[i].pflags & PF_TIMEOVER))
{
numexiting++;
}
else
{
if (players[i].bot)
{
// Isn't a human, thus doesn't matter. (Sorry, robots.)
// Set this so that we can check for bots that need to get eliminated, though!
eliminatebots = true;
continue;
}
everyonedone = false;
}
}
if (i == MAXPLAYERS) // finished
// If we returned here with bots left, then the last place bot may have a chance to finish the map and NOT get time over.
// Not that it affects anything, they didn't make the map take longer or even get any points from it. But... it's a bit inconsistent!
// So if there's any bots, we'll let the game skip this, continue onto calculating eliminatelast, THEN we return true anyway.
if (everyonedone && !eliminatebots)
{
// Everyone's finished, we're done here!
racecountdown = exitcountdown = 0;
return true;
}
for (j = 0; j < MAXPLAYERS; j++)
if (numplayersingame <= 1)
{
if (nospectategrief[j] != -1) // prevent spectate griefing
griefed = true;
if (!playeringame[j] || players[j].spectator)
continue;
numplayersingame++;
if (players[j].exiting)
numexiting++;
// Never do this without enough players.
eliminatelast = false;
}
else
{
if (grandprixinfo.gp == true)
{
// Always do this in GP
eliminatelast = true;
}
else if (griefed)
{
// Don't do this if someone spectated
eliminatelast = false;
}
}
if (cv_karteliminatelast.value && numplayersingame > 1 && !griefed)
if (eliminatelast == true && (numplayersingame <= numexiting-1))
{
// check if we just got unlucky and there was only one guy who was a problem
for (j = i+1; j < MAXPLAYERS; j++)
// Everyone's done playing but one guy apparently.
// Just kill everyone who is still playing.
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[j] || players[j].spectator || players[j].exiting || !players[j].lives)
if (!playeringame[i] || players[i].spectator || players[i].lives <= 0) // Not playing
{
// Y'all aren't even playing
continue;
break;
}
if (players[i].exiting || (players[i].pflags & PF_TIMEOVER))
{
// You're done, you're free to go.
continue;
}
P_DoTimeOver(&players[i]);
}
if (j == MAXPLAYERS) // finish anyways, force a time over
{
P_DoTimeOver(&players[i]);
racecountdown = exitcountdown = 0;
return true;
}
// Everyone should be done playing at this point now.
racecountdown = exitcountdown = 0;
return true;
}
if (!racecountdown) // Check to see if the winners have finished, to set countdown.
if (everyonedone)
{
// See above: there might be bots that are still going, but all players are done, so we can exit now.
racecountdown = exitcountdown = 0;
return true;
}
// SO, we're not done playing.
// Let's see if it's time to start the death counter!
if (!racecountdown)
{
// If the winners are all done, then start the death timer.
UINT8 winningpos = 1;
winningpos = max(1, numplayersingame/2);
if (numplayersingame % 2) // any remainder?
{
winningpos++;
}
if (numexiting >= winningpos)
racecountdown = (((netgame || multiplayer) ? cv_countdowntime.value : 30)*TICRATE) + 1; // 30 seconds to finish, get going!
{
tic_t countdown = 30*TICRATE; // 30 seconds left to finish, get going!
if (netgame)
{
// Custom timer
countdown = cv_countdowntime.value * TICRATE;
}
racecountdown = countdown + 1;
}
}
if (numplayersingame < 2) // reset nospectategrief in free play
// We're still playing, but no one else is, so we need to reset spectator griefing.
if (numplayersingame <= 1)
{
for (j = 0; j < MAXPLAYERS; j++)
nospectategrief[j] = -1;
memset(nospectategrief, -1, sizeof (nospectategrief));
}
// Turns out we're still having a good time & playing the game, we didn't have to do anything :)
return false;
}
@ -1068,7 +1144,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
{
if (metalrecording) // Ack! Metal Sonic shouldn't die! Cut the tape, end recording!
G_StopMetalRecording(true);
target->flags2 &= ~MF2_DONTDRAW;
target->drawflags &= ~MFD_DONTDRAW;
}
// if killed by a player
@ -1076,12 +1153,28 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
{
if (target->flags & MF_MONITOR || target->type == MT_RANDOMITEM)
{
UINT8 i;
P_SetTarget(&target->target, source);
source->player->numboxes++;
if (cv_itemrespawn.value && (netgame || multiplayer))
for (i = 0; i < MAXPLAYERS; i++)
{
target->fuse = cv_itemrespawntime.value*TICRATE + 2; // Random box generation
if (&players[i] == source->player)
{
continue;
}
if (playeringame[i] && !players[i].spectator && players[i].lives != 0)
{
break;
}
}
if (i < MAXPLAYERS)
{
// Respawn items in multiplayer, don't respawn them when alone
target->fuse = 2*TICRATE + 2;
}
}
}
@ -1096,44 +1189,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
target->standingslope = NULL;
target->pmomz = 0;
if (!target->player->bot && !G_IsSpecialStage(gamemap) && G_GametypeUsesLives())
{
if (!(target->player->pflags & PF_FINISHED))
target->player->lives -= 1; // Lose a life Tails 03-11-2000
if (target->player->lives <= 0) // Tails 03-14-2000
{
boolean gameovermus = false;
if ((netgame || multiplayer) && G_GametypeUsesCoopLives() && (cv_cooplives.value != 1))
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (players[i].lives > 0)
break;
}
if (i == MAXPLAYERS)
gameovermus = true;
}
else if (P_IsLocalPlayer(target->player))
gameovermus = true;
if (gameovermus) // Yousa dead now, Okieday? Tails 03-14-2000
S_ChangeMusicEx("_gover", 0, 0, 0, (2*MUSICRATE) - (MUSICRATE/25), 0); // 1.96 seconds
//P_PlayJingle(target->player, JT_GOVER); // can't be used because incompatible with track fadeout
if (!(netgame || multiplayer || demo.playback || demo.recording || metalrecording || modeattacking) && numgameovers < maxgameovers)
{
numgameovers++;
if ((!modifiedgame || savemoddata) && cursaveslot > 0)
G_SaveGameOver((UINT32)cursaveslot, (target->player->continues <= 0));
}
}
}
target->player->playerstate = PST_DEAD;
if (target->player == &players[consoleplayer])
@ -1619,7 +1674,7 @@ static void P_KillPlayer(player_t *player, mobj_t *source, INT32 damage)
{
mobj_t *boom;
player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP);
player->mo->flags2 |= MF2_DONTDRAW;
player->mo->drawflags |= MFD_DONTDRAW;
boom = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_FZEROBOOM);
boom->scale = player->mo->scale;
boom->angle = player->mo->angle;
@ -1783,6 +1838,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|| inflictor->type == MT_SMK_THWOMP || inflictor->player))
{
player->kartstuff[k_sneakertimer] = 0;
player->kartstuff[k_numsneakers] = 0;
K_SpinPlayer(player, source, 1, inflictor, false);
K_KartPainEnergyFling(player);

View file

@ -26,6 +26,7 @@
#include "w_wad.h"
#include "k_kart.h" // SRB2kart 011617
#include "k_collide.h"
#include "k_respawn.h"
#include "hu_stuff.h" // SRB2kart
#include "i_system.h" // SRB2kart
@ -329,39 +330,10 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
// 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;
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;
finalAngle = K_ReflectAngle(
R_PointToAngle2(0, 0, savemomx, savemomy), finalAngle,
objectSpeed, finalSpeed
);
}
}
@ -2823,6 +2795,100 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y)
return true;
}
//
// PTR_GetSpecialLines
//
static boolean PTR_GetSpecialLines(intercept_t *in)
{
line_t *ld;
I_Assert(in->isaline);
ld = in->d.line;
if (!ld->backsector)
{
return true;
}
if (P_SpecialIsLinedefCrossType(ld->special))
{
add_spechit(ld);
}
return true;
}
//
// P_HitSpecialLines
// Finds all special lines in the provided path and tries to cross them.
// For zoom tubes and respawning, which noclip but need to cross finish lines.
//
void P_HitSpecialLines(mobj_t *thing, fixed_t x, fixed_t y, fixed_t momx, fixed_t momy)
{
fixed_t leadx, leady;
fixed_t trailx, traily;
line_t *ld = NULL;
INT32 side = 0, oldside = 0;
I_Assert(thing != NULL);
#ifdef PARANOIA
if (P_MobjWasRemoved(thing))
I_Error("Previously-removed Thing of type %u crashes P_CheckPosition!", thing->type);
#endif
// reset special lines
numspechitint = 0U;
numspechit = 0U;
// trace along the three leading corners
if (momx > 0)
{
leadx = x + thing->radius;
trailx = x - thing->radius;
}
else
{
leadx = x - thing->radius;
trailx = x + thing->radius;
}
if (momy > 0)
{
leady = y + thing->radius;
traily = y - thing->radius;
}
else
{
leady = y - thing->radius;
traily = y + thing->radius;
}
P_PathTraverse(leadx, leady, leadx + momx, leady + momy, PT_ADDLINES, PTR_GetSpecialLines);
P_PathTraverse(trailx, leady, trailx + momx, leady + momy, PT_ADDLINES, PTR_GetSpecialLines);
P_PathTraverse(leadx, traily, leadx + momx, traily + momy, PT_ADDLINES, PTR_GetSpecialLines);
spechitint_copyinto();
// remove any duplicates that may be in spechitint
spechitint_removedups();
// handle any of the special lines that were crossed
while (numspechitint--)
{
ld = &lines[spechitint[numspechitint]];
side = P_PointOnLineSide(x + momx, y + momy, ld);
oldside = P_PointOnLineSide(x, y, ld);
if (side != oldside)
{
if (ld->special)
{
P_CrossSpecialLine(ld, oldside, thing);
}
}
}
}
//
// P_ThingHeightClip
// Takes a valid thing and adjusts the thing->floorz,

View file

@ -53,6 +53,7 @@ void P_UnsetPrecipThingPosition(precipmobj_t *thing);
void P_SetPrecipitationThingPosition(precipmobj_t *thing);
void P_CreatePrecipSecNodeList(precipmobj_t *thing, fixed_t x,fixed_t y);
boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y);
void P_HitSpecialLines(mobj_t *thing, fixed_t x, fixed_t y, fixed_t momx, fixed_t momy);
extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
extern pslope_t *opentopslope, *openbottomslope;

View file

@ -38,6 +38,7 @@
#include "k_kart.h"
#include "k_battle.h"
#include "k_color.h"
#include "k_respawn.h"
#include "k_bot.h"
static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}};
@ -1278,8 +1279,8 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
player = mo->player;
if (player) // valid only if player avatar
{
if (FixedHypot(player->rmomx, player->rmomy) < FixedMul(STOPSPEED, mo->scale) && player->cmd.forwardmove == 0
&& !(player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && (abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)))
if (FixedHypot(player->rmomx, player->rmomy) < FixedMul(STOPSPEED, mo->scale) && K_GetForwardMove(player) == 0
&& !(player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) /*&& (abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)*/))
{
// if in a walking frame, stop moving
if (player->panim == PA_WALK)
@ -1292,16 +1293,8 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
}
else if (!(mo->eflags & MFE_SPRUNG))
{
if (oldx == mo->x && oldy == mo->y) // didn't go anywhere
{
mo->momx = FixedMul(mo->momx, ORIG_FRICTION);
mo->momy = FixedMul(mo->momy, ORIG_FRICTION);
}
else
{
mo->momx = FixedMul(mo->momx, mo->friction);
mo->momy = FixedMul(mo->momy, mo->friction);
}
mo->momx = FixedMul(mo->momx, mo->friction);
mo->momy = FixedMul(mo->momy, mo->friction);
mo->friction = ORIG_FRICTION;
}
@ -1785,7 +1778,7 @@ void P_XYMovement(mobj_t *mo)
if (mo->type == MT_FLINGRING || mo->type == MT_BALLHOG || mo->type == MT_BUBBLESHIELDTRAP)
return;
if (mo->player && (mo->player->kartstuff[k_spinouttimer] && !mo->player->kartstuff[k_wipeoutslow]) && mo->player->speed <= K_GetKartSpeed(mo->player, false)/2)
if (player && (player->kartstuff[k_spinouttimer] && !player->kartstuff[k_wipeoutslow]) && player->speed <= FixedDiv(20*mapobjectscale, player->kartstuff[k_offroad] + FRACUNIT))
return;
//}
@ -2293,6 +2286,17 @@ boolean P_ZMovement(mobj_t *mo)
mom.z = P_MobjFlip(mo)*FixedMul(5*FRACUNIT, mo->scale);
else if (mo->type == MT_SPINFIRE) // elemental shield fire is another exception here
;
else if (mo->type == MT_DRIFTCLIP)
{
mom.z = -mom.z/2;
if (abs(mom.z) > 4 * mo->scale / 3)
{
K_SpawnDriftBoostClipSpark(mo);
S_StartSound(mo, sfx_tink);
}
else
mo->flags2 ^= MFD_DONTDRAW;
}
else if (mo->flags & MF_MISSILE)
{
if (!(mo->flags & MF_NOCLIP))
@ -2673,7 +2677,6 @@ void P_PlayerZMovement(mobj_t *mo)
boolean clipmomz = !(P_CheckDeathPitCollide(mo));
mo->pmomz = 0; // We're on a new floor, don't keep doing platform movement.
mo->eflags |= MFE_JUSTHITFLOOR; // Spin Attack
clipmomz = P_PlayerHitFloor(mo->player, true);
@ -3503,14 +3506,12 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
// momentum movement
mobj->eflags &= ~MFE_JUSTSTEPPEDDOWN;
if (mobj->state-states == S_PLAY_BOUNCE_LANDING)
goto animonly; // no need for checkposition - doesn't move at ALL
// Zoom tube
if (mobj->tracer)
if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer))
{
if (mobj->player->powers[pw_carry] == CR_ZOOMTUBE || mobj->player->powers[pw_carry] == CR_ROPEHANG)
if (mobj->player->powers[pw_carry] == CR_ZOOMTUBE || mobj->player->respawn.state == RESPAWNST_MOVE)
{
P_HitSpecialLines(mobj, mobj->x, mobj->y, mobj->momx, mobj->momy);
P_UnsetThingPosition(mobj);
mobj->x += mobj->momx;
mobj->y += mobj->momy;
@ -3521,13 +3522,6 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
mobj->ceilingz = tmceilingz;
goto animonly;
}
else if (mobj->player->powers[pw_carry] == CR_MACESPIN)
{
P_CheckPosition(mobj, mobj->x, mobj->y);
mobj->floorz = tmfloorz;
mobj->ceilingz = tmceilingz;
goto animonly;
}
}
// Needed for gravity boots
@ -3703,16 +3697,16 @@ static void P_RingThinker(mobj_t *mobj)
if (mobj->fuse < TICRATE*3)
{
if (leveltime & 1)
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
else
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
}
if (!mobj->fuse)
{
if (!LUAh_MobjFuse(mobj))
{
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
spark = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SIGNSPARKLE); // Spawn a fancy sparkle
K_MatchGenericExtraFlags(spark, mobj);
spark->colorized = true;
@ -7606,6 +7600,26 @@ static void P_MobjSceneryThink(mobj_t *mobj)
if (mobj->tics > 0)
mobj->flags2 ^= MF2_DONTDRAW;
break;
case MT_FOLLOWER:
// small thinker for follower:
// We cleanse ourselves from existence if our target player doesn't exist for whatever reason. (generally players leaving)
if (!mobj->target || P_MobjWasRemoved(mobj->target) || !mobj->target->player || mobj->target->player->spectator || mobj->target->player->followerskin < 0)
{
// Remove possible hnext list (bubble)
mobj_t *bub = mobj->hnext;
mobj_t *tmp;
while (bub && !P_MobjWasRemoved(bub))
{
tmp = bub->hnext;
P_RemoveMobj(bub);
bub = tmp;
}
P_RemoveMobj(mobj);
}
return;
case MT_VWREF:
case MT_VWREB:
{
@ -11425,13 +11439,13 @@ void P_SceneryThinker(mobj_t *mobj)
&& mobj->extravalue1 > 0 && mobj->extravalue2 >= 2)
{
if (mobj->extravalue2 == 2) // I don't know why the normal logic doesn't work for this.
mobj->flags2 ^= MF2_DONTDRAW;
mobj->drawflags ^= MFD_DONTDRAW;
else
{
if (mobj->fuse == mobj->extravalue2)
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->drawflags &= ~MFD_DONTDRAW;
else
mobj->flags2 |= MF2_DONTDRAW;
mobj->drawflags |= MFD_DONTDRAW;
}
}
@ -11564,6 +11578,9 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
case MT_FLOATINGITEM:
thing->shadowscale = FRACUNIT/2;
break;
case MT_DRIFTCLIP:
thing->shadowscale = FRACUNIT/3;
break;
default:
if (thing->flags & (MF_ENEMY|MF_BOSS))
thing->shadowscale = FRACUNIT;
@ -12633,18 +12650,20 @@ void P_RespawnSpecials(void)
return;
else if (pcount > 1)
{
time = (180 - (pcount * 10))*TICRATE;
time = (120 - ((pcount-2) * 10))*TICRATE;
// If the map is longer or shorter than 3 laps, then adjust ring respawn to account for this.
// 5 lap courses would have more retreaded ground, while 2 lap courses would have less.
if ((mapheaderinfo[gamemap-1]->numlaps != 3)
&& !(mapheaderinfo[gamemap-1]->levelflags & LF_SECTIONRACE))
time = (time * 3) / max(1, mapheaderinfo[gamemap-1]->numlaps);
}
// only respawn items when cv_itemrespawn is on
//if (!cv_itemrespawn.value) // TODO: remove this cvar
//return;
if (time < 10*TICRATE)
{
// Ensure it doesn't go into absurdly low values
time = 10*TICRATE;
}
}
// nothing left to respawn?
if (iquehead == iquetail)
@ -12801,6 +12820,8 @@ void P_SpawnPlayer(INT32 playernum)
p->awayviewmobj = NULL;
p->awayviewtics = 0;
P_SetTarget(&p->follower, NULL); // cleanse follower from existence
// set the scale to the mobj's destscale so settings get correctly set. if we don't, they sometimes don't.
if (cv_kartdebugshrink.value && !modeattacking && !p->bot)
mobj->destscale = 6*mobj->destscale/8;
@ -12824,14 +12845,11 @@ void P_SpawnPlayer(INT32 playernum)
p->nightstime = sstimer;
}
if (p->kartstuff[k_respawn] != 0)
p->mo->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY;
if ((gametyperules & GTR_BUMPERS)) // SRB2kart
{
mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height + 16*FRACUNIT, MT_PLAYERARROW);
P_SetTarget(&overheadarrow->target, mobj);
overheadarrow->flags2 |= MF2_DONTDRAW;
overheadarrow->drawflags |= MFD_DONTDRAW;
P_SetScale(overheadarrow, mobj->destscale);
if (p->spectator && pcount > 1) // HEY! No being cheap...
@ -12857,10 +12875,10 @@ void P_SpawnPlayer(INT32 playernum)
P_SetTarget(&mo->target, mobj);
mo->angle = (diff * (i-1));
mo->color = mobj->color;
if (mobj->flags2 & MF2_DONTDRAW)
mo->flags2 |= MF2_DONTDRAW;
if (mobj->drawflags & MFD_DONTDRAW)
mo->drawflags |= MFD_DONTDRAW;
else
mo->flags2 &= ~MF2_DONTDRAW;
mo->drawflags &= ~MFD_DONTDRAW;
}
}
}
@ -12970,6 +12988,11 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing)
else
z = floor;
if (p->respawn.state != RESPAWNST_NONE)
{
z += K_RespawnOffset(p, (mthing->options & MTF_OBJECTFLIP));
}
if (z < floor)
z = floor;
else if (z > ceilingspawn)
@ -13007,18 +13030,18 @@ void P_MovePlayerToStarpost(INT32 playernum)
mobj_t *mobj = p->mo;
I_Assert(mobj != NULL);
K_DoIngameRespawn(p);
P_UnsetThingPosition(mobj);
mobj->x = p->starpostx << FRACBITS;
mobj->y = p->starposty << FRACBITS;
mobj->x = p->respawn.pointx;
mobj->y = p->respawn.pointy;
P_SetThingPosition(mobj);
sector = R_PointInSubsector(mobj->x, mobj->y)->sector;
floor = P_GetSectorFloorZAt (sector, mobj->x, mobj->y);
ceiling = P_GetSectorCeilingZAt(sector, mobj->x, mobj->y);
z = p->starpostz << FRACBITS;
P_SetScale(mobj, (mobj->destscale = abs(p->starpostscale)));
z = p->respawn.pointz;
if (p->starpostscale < 0)
{
@ -13041,12 +13064,7 @@ void P_MovePlayerToStarpost(INT32 playernum)
mobj->z = z;
mobj->angle = p->starpostangle;
P_AfterPlayerSpawn(playernum);
if (!(netgame || multiplayer))
leveltime = p->starposttime;
}
fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale)

View file

@ -108,7 +108,7 @@ typedef enum
// Don't use the blocklinks (inert but displayable)
MF_NOBLOCKMAP = 1<<4,
// Thin, paper-like collision bound (for visual equivalent, see FF_PAPERSPRITE)
MF_PAPERCOLLISION = 1<<5,
MF_PAPERCOLLISION = 1<<5,
// You can push this object. It can activate switches and things by pushing it on top.
MF_PUSHABLE = 1<<6,
// Object is a boss.
@ -159,7 +159,7 @@ typedef enum
MF_GRENADEBOUNCE = 1<<28,
// Run the action thinker on spawn.
MF_RUNSPAWNFUNC = 1<<29,
// Don't remap in Encore mode.
// Don't remap in Encore mode. (Not a drawflag so that it's settable by mobjinfo.)
MF_DONTENCOREMAP = 1<<30,
// free: 1<<31
} mobjflag_t;
@ -169,7 +169,7 @@ typedef enum
MF2_AXIS = 1, // It's a NiGHTS axis! (For faster checking)
MF2_TWOD = 1<<1, // Moves like it's in a 2D level
MF2_DONTRESPAWN = 1<<2, // Don't respawn this object!
MF2_DONTDRAW = 1<<3, // Don't generate a vissprite
// free: 1<<3
MF2_AUTOMATIC = 1<<4, // Thrown ring has automatic properties
MF2_RAILRING = 1<<5, // Thrown ring has rail properties
MF2_BOUNCERING = 1<<6, // Thrown ring has bounce properties
@ -185,7 +185,7 @@ typedef enum
MF2_JUSTATTACKED = 1<<16, // can be pushed by other moving mobjs
MF2_FIRING = 1<<17, // turret fire
MF2_SUPERFIRE = 1<<18, // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
MF2_SHADOW = 1<<19, // Fuzzy draw, makes targeting harder.
// free: 1<<19
MF2_STRONGBOX = 1<<20, // Flag used for "strong" random monitors.
MF2_OBJECTFLIP = 1<<21, // Flag for objects that always have flipped gravity.
MF2_SKULLFLY = 1<<22, // Special handling: skull in flight.
@ -248,14 +248,43 @@ typedef enum
MFE_TRACERANGLE = 1<<11,
// SRB2Kart: The mobj just hit & bounced off a wall, this is cleared on next frame
MFE_JUSTBOUNCEDWALL = 1<<12,
// SRB2Kart: Splitscreen sprite display; very wasteful but I couldn't think of another way to do it...
MFE_DRAWONLYFORP1 = 1<<13,
MFE_DRAWONLYFORP2 = 1<<14,
MFE_DRAWONLYFORP3 = 1<<15,
MFE_DRAWONLYFORP4 = 1<<15, // WELP, just merge drawflags later so this isn't a problem :V
// free: to and including 1<<15
} mobjeflag_t;
//
// Mobj drawing flags
// Set by hex, to make masking shenanigans easier to keep track of.
//
typedef enum
{
// Don't generate a vissprite for individual screens
MFD_DONTDRAWP1 = 0x0001,
MFD_DONTDRAWP2 = 0x0002,
MFD_DONTDRAWP3 = 0x0004,
MFD_DONTDRAWP4 = 0x0008,
// Transparency override flags
MFD_TRANS10 = 0x0010,
MFD_TRANS20 = 0x0020,
MFD_TRANS30 = 0x0030,
MFD_TRANS40 = 0x0040,
MFD_TRANS50 = 0x0050,
MFD_TRANS60 = 0x0060,
MFD_TRANS70 = 0x0070,
MFD_TRANS80 = 0x0080,
MFD_TRANS90 = 0x0090,
MFD_TRANSMASK = 0x00F0,
// Brightness override flags
MFD_FULLBRIGHT = 0x0100,
MFD_SEMIBRIGHT = 0x0200,
MFD_NOBRIGHT = 0x0300,
MFD_BRIGHTMASK = 0x0F00,
// Shortcuts
MFD_DONTDRAW = MFD_DONTDRAWP1|MFD_DONTDRAWP2|MFD_DONTDRAWP3|MFD_DONTDRAWP4,
MFD_SHADOW = MFD_TRANS80|MFD_FULLBRIGHT,
MFD_TRANSSHIFT = 4,
// free: to and including 0x8000
} mobjdflag_t;
//
// PRECIPITATION flags ?! ?! ?!
//
@ -315,6 +344,7 @@ typedef struct mobj_s
UINT32 flags; // flags from mobjinfo tables
UINT32 flags2; // MF2_ flags
UINT16 eflags; // extra flags
UINT16 drawflags; // Rendering-related flags. These should not be used for game logic.
void *skin; // overrides 'sprite' when non-NULL (for player bodies to 'remember' the skin)
// Player and mobj sprites in multiplayer modes are modified

View file

@ -54,14 +54,9 @@ UINT8 *save_p;
// than an UINT16
typedef enum
{
// RFLAGPOINT = 0x01,
// BFLAGPOINT = 0x02,
CAPSULE = 0x04,
AWAYVIEW = 0x08,
FIRSTAXIS = 0x10,
SECONDAXIS = 0x20,
FOLLOW = 0x40,
DRONE = 0x80,
AWAYVIEW = 0x01,
FOLLOWITEM = 0x02,
FOLLOWER = 0x04,
} player_saveflags;
static inline void P_ArchivePlayer(void)
@ -119,10 +114,6 @@ static void P_NetArchivePlayers(void)
for (j = 0; j < NUMPOWERS; j++)
WRITEUINT16(save_p, players[i].powers[j]);
for (j = 0; j < NUMKARTSTUFF; j++)
WRITEINT32(save_p, players[i].kartstuff[j]);
WRITEANGLE(save_p, players[i].frameangle);
WRITEUINT8(save_p, players[i].playerstate);
WRITEUINT32(save_p, players[i].pflags);
@ -135,6 +126,7 @@ static void P_NetArchivePlayers(void)
WRITEUINT32(save_p, players[i].score);
WRITEFIXED(save_p, players[i].dashspeed);
WRITESINT8(save_p, players[i].lives);
WRITEUINT8(save_p, players[i].lostlife);
WRITESINT8(save_p, players[i].continues);
WRITESINT8(save_p, players[i].xtralife);
WRITEUINT8(save_p, players[i].gotcontinue);
@ -165,6 +157,7 @@ static void P_NetArchivePlayers(void)
WRITEINT16(save_p, players[i].totalring);
WRITEUINT32(save_p, players[i].realtime);
WRITEUINT8(save_p, players[i].laps);
WRITEINT32(save_p, players[i].starpostnum);
////////////////////
// CTF Mode Stuff //
@ -172,17 +165,6 @@ static void P_NetArchivePlayers(void)
WRITEINT32(save_p, players[i].ctfteam);
WRITEUINT16(save_p, players[i].gotflag);
WRITEINT32(save_p, players[i].weapondelay);
WRITEINT32(save_p, players[i].tossdelay);
WRITEUINT32(save_p, players[i].starposttime);
WRITEINT16(save_p, players[i].starpostx);
WRITEINT16(save_p, players[i].starposty);
WRITEINT16(save_p, players[i].starpostz);
WRITEINT32(save_p, players[i].starpostnum);
WRITEANGLE(save_p, players[i].starpostangle);
WRITEFIXED(save_p, players[i].starpostscale);
WRITEANGLE(save_p, players[i].angle_pos);
WRITEANGLE(save_p, players[i].old_angle_pos);
@ -219,23 +201,14 @@ static void P_NetArchivePlayers(void)
WRITEUINT8(save_p, players[i].texttimer);
WRITEUINT8(save_p, players[i].textvar);
if (players[i].capsule)
flags |= CAPSULE;
if (players[i].awayviewmobj)
flags |= AWAYVIEW;
if (players[i].axis1)
flags |= FIRSTAXIS;
if (players[i].axis2)
flags |= SECONDAXIS;
if (players[i].followmobj)
flags |= FOLLOW;
flags |= FOLLOWITEM;
if (players[i].drone)
flags |= DRONE;
if (players[i].follower)
flags |= FOLLOWER;
WRITEINT16(save_p, players[i].lastsidehit);
WRITEINT16(save_p, players[i].lastlinehit);
@ -269,18 +242,45 @@ static void P_NetArchivePlayers(void)
// SRB2kart
WRITEUINT8(save_p, players[i].kartspeed);
WRITEUINT8(save_p, players[i].kartweight);
WRITEUINT8(save_p, players[i].followerskin);
WRITEUINT8(save_p, players[i].followerready); // booleans are really just numbers eh??
WRITEUINT8(save_p, players[i].followercolor);
if (flags & FOLLOWER)
WRITEUINT32(save_p, players[i].follower->mobjnum);
//
for (j = 0; j < NUMKARTSTUFF; j++)
WRITEINT32(save_p, players[i].kartstuff[j]);
for (j = 0; j < MAXPREDICTTICS; j++)
{
WRITEINT16(save_p, players[i].lturn_max[j]);
WRITEINT16(save_p, players[i].rturn_max[j]);
}
WRITEANGLE(save_p, players[i].frameangle);
WRITEUINT32(save_p, players[i].distancetofinish);
WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].nextwaypoint));
WRITEUINT32(save_p, players[i].airtime);
// respawnvars_t
WRITEUINT8(save_p, players[i].respawn.state);
WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].respawn.wp));
WRITEFIXED(save_p, players[i].respawn.pointx);
WRITEFIXED(save_p, players[i].respawn.pointy);
WRITEFIXED(save_p, players[i].respawn.pointz);
WRITEUINT8(save_p, players[i].respawn.flip);
WRITEUINT32(save_p, players[i].respawn.timer);
WRITEUINT32(save_p, players[i].respawn.distanceleft);
WRITEUINT32(save_p, players[i].respawn.dropdash);
// botvars_t
WRITEUINT8(save_p, players[i].botvars.difficulty);
WRITEUINT8(save_p, players[i].botvars.diffincrease);
WRITEUINT8(save_p, players[i].botvars.rival);
WRITEUINT32(save_p, players[i].botvars.itemdelay);
WRITEUINT32(save_p, players[i].botvars.itemconfirm);
WRITESINT8(save_p, players[i].botvars.turnconfirm);
@ -323,10 +323,6 @@ static void P_NetUnArchivePlayers(void)
for (j = 0; j < NUMPOWERS; j++)
players[i].powers[j] = READUINT16(save_p);
for (j = 0; j < NUMKARTSTUFF; j++)
players[i].kartstuff[j] = READINT32(save_p);
players[i].frameangle = READANGLE(save_p);
players[i].playerstate = READUINT8(save_p);
players[i].pflags = READUINT32(save_p);
@ -339,6 +335,7 @@ static void P_NetUnArchivePlayers(void)
players[i].score = READUINT32(save_p);
players[i].dashspeed = READFIXED(save_p); // dashing speed
players[i].lives = READSINT8(save_p);
players[i].lostlife = (boolean)READUINT8(save_p);
players[i].continues = READSINT8(save_p); // continues that player has acquired
players[i].xtralife = READSINT8(save_p); // Ring Extra Life counter
players[i].gotcontinue = READUINT8(save_p); // got continue from stage
@ -369,6 +366,7 @@ static void P_NetUnArchivePlayers(void)
players[i].totalring = READINT16(save_p); // Total number of rings obtained for Race Mode
players[i].realtime = READUINT32(save_p); // integer replacement for leveltime
players[i].laps = READUINT8(save_p); // Number of laps (optional)
players[i].starpostnum = READINT32(save_p);
////////////////////
// CTF Mode Stuff //
@ -379,14 +377,6 @@ static void P_NetUnArchivePlayers(void)
players[i].weapondelay = READINT32(save_p);
players[i].tossdelay = READINT32(save_p);
players[i].starposttime = READUINT32(save_p);
players[i].starpostx = READINT16(save_p);
players[i].starposty = READINT16(save_p);
players[i].starpostz = READINT16(save_p);
players[i].starpostnum = READINT32(save_p);
players[i].starpostangle = READANGLE(save_p);
players[i].starpostscale = READFIXED(save_p);
players[i].angle_pos = READANGLE(save_p);
players[i].old_angle_pos = READANGLE(save_p);
@ -465,18 +455,44 @@ static void P_NetUnArchivePlayers(void)
// SRB2kart
players[i].kartspeed = READUINT8(save_p);
players[i].kartweight = READUINT8(save_p);
players[i].followerskin = READUINT8(save_p);
players[i].followerready = READUINT8(save_p);
players[i].followercolor = READUINT8(save_p);
if (flags & FOLLOWER)
players[i].follower = (mobj_t *)(size_t)READUINT32(save_p);
//
for (j = 0; j < NUMKARTSTUFF; j++)
players[i].kartstuff[j] = READINT32(save_p);
for (j = 0; j < MAXPREDICTTICS; j++)
{
players[i].lturn_max[j] = READINT16(save_p);
players[i].rturn_max[j] = READINT16(save_p);
}
players[i].frameangle = READANGLE(save_p);
players[i].distancetofinish = READUINT32(save_p);
players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save_p);
players[i].airtime = READUINT32(save_p);
// respawnvars_t
players[i].respawn.state = READUINT8(save_p);
players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save_p);
players[i].respawn.pointx = READFIXED(save_p);
players[i].respawn.pointy = READFIXED(save_p);
players[i].respawn.pointz = READFIXED(save_p);
players[i].respawn.flip = (boolean)READUINT8(save_p);
players[i].respawn.timer = READUINT32(save_p);
players[i].respawn.distanceleft = READUINT32(save_p);
players[i].respawn.dropdash = READUINT32(save_p);
// botvars_t
players[i].botvars.difficulty = READUINT8(save_p);
players[i].botvars.diffincrease = READUINT8(save_p);
players[i].botvars.rival = (boolean)READUINT8(save_p);
players[i].botvars.itemdelay = READUINT32(save_p);
players[i].botvars.itemconfirm = READUINT32(save_p);
players[i].botvars.turnconfirm = READSINT8(save_p);
@ -1391,9 +1407,10 @@ typedef enum
MD2_MIRRORED = 1<<13,
MD2_ROLLANGLE = 1<<14,
MD2_SHADOWSCALE = 1<<15,
MD2_WAYPOINTCAP = 1<<16,
MD2_KITEMCAP = 1<<17,
MD2_ITNEXT = 1<<18,
MD2_DRAWFLAGS = 1<<16,
MD2_WAYPOINTCAP = 1<<17,
MD2_KITEMCAP = 1<<18,
MD2_ITNEXT = 1<<19,
} mobj_diff2_t;
typedef enum
@ -1606,6 +1623,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
diff2 |= MD2_ROLLANGLE;
if (mobj->shadowscale)
diff2 |= MD2_SHADOWSCALE;
if (mobj->drawflags)
diff2 |= MD2_DRAWFLAGS;
if (mobj == waypointcap)
diff2 |= MD2_WAYPOINTCAP;
if (mobj == kitemcap)
@ -1755,7 +1774,21 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
if (diff2 & MD2_ROLLANGLE)
WRITEANGLE(save_p, mobj->rollangle);
if (diff2 & MD2_SHADOWSCALE)
{
WRITEFIXED(save_p, mobj->shadowscale);
WRITEUINT8(save_p, mobj->whiteshadow);
}
if (diff2 & MD2_DRAWFLAGS)
{
UINT16 df = mobj->drawflags;
if ((mobj->drawflags & MFD_DONTDRAW) != MFD_DONTDRAW)
{
df = (mobj->drawflags & ~MFD_DONTDRAW);
}
WRITEUINT16(save_p, df);
}
WRITEUINT32(save_p, mobj->mobjnum);
}
@ -2814,7 +2847,12 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
if (diff2 & MD2_ROLLANGLE)
mobj->rollangle = READANGLE(save_p);
if (diff2 & MD2_SHADOWSCALE)
{
mobj->shadowscale = READFIXED(save_p);
mobj->whiteshadow = READUINT8(save_p);
}
if (diff2 & MD2_DRAWFLAGS)
mobj->drawflags = READUINT16(save_p);
if (diff & MD_REDFLAG)
{
@ -3843,56 +3881,47 @@ static void P_RelinkPointers(void)
if (!(mobj->itnext = P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "itnext not found on %d\n", mobj->type);
}
if (mobj->player && mobj->player->capsule)
if (mobj->player)
{
temp = (UINT32)(size_t)mobj->player->capsule;
mobj->player->capsule = NULL;
if (!P_SetTarget(&mobj->player->capsule, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "capsule not found on %d\n", mobj->type);
}
if (mobj->player && mobj->player->axis1)
{
temp = (UINT32)(size_t)mobj->player->axis1;
mobj->player->axis1 = NULL;
if (!P_SetTarget(&mobj->player->axis1, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "axis1 not found on %d\n", mobj->type);
}
if (mobj->player && mobj->player->axis2)
{
temp = (UINT32)(size_t)mobj->player->axis2;
mobj->player->axis2 = NULL;
if (!P_SetTarget(&mobj->player->axis2, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "axis2 not found on %d\n", mobj->type);
}
if (mobj->player && mobj->player->awayviewmobj)
{
temp = (UINT32)(size_t)mobj->player->awayviewmobj;
mobj->player->awayviewmobj = NULL;
if (!P_SetTarget(&mobj->player->awayviewmobj, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "awayviewmobj not found on %d\n", mobj->type);
}
if (mobj->player && mobj->player->nextwaypoint)
{
temp = (UINT32)(size_t)mobj->player->nextwaypoint;
mobj->player->nextwaypoint = K_GetWaypointFromIndex(temp);
if (mobj->player->nextwaypoint == NULL)
if ( mobj->player->awayviewmobj)
{
CONS_Debug(DBG_GAMELOGIC, "nextwaypoint not found on %d\n", mobj->type);
temp = (UINT32)(size_t)mobj->player->awayviewmobj;
mobj->player->awayviewmobj = NULL;
if (!P_SetTarget(&mobj->player->awayviewmobj, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "awayviewmobj not found on %d\n", mobj->type);
}
if (mobj->player->followmobj)
{
temp = (UINT32)(size_t)mobj->player->followmobj;
mobj->player->followmobj = NULL;
if (!P_SetTarget(&mobj->player->followmobj, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "followmobj not found on %d\n", mobj->type);
}
if (mobj->player->follower)
{
temp = (UINT32)(size_t)mobj->player->follower;
mobj->player->follower = NULL;
if (!P_SetTarget(&mobj->player->follower, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "follower not found on %d\n", mobj->type);
}
if (mobj->player->nextwaypoint)
{
temp = (UINT32)(size_t)mobj->player->nextwaypoint;
mobj->player->nextwaypoint = K_GetWaypointFromIndex(temp);
if (mobj->player->nextwaypoint == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "nextwaypoint not found on %d\n", mobj->type);
}
}
if (mobj->player->respawn.wp)
{
temp = (UINT32)(size_t)mobj->player->respawn.wp;
mobj->player->respawn.wp = K_GetWaypointFromIndex(temp);
if (mobj->player->respawn.wp == NULL)
{
CONS_Debug(DBG_GAMELOGIC, "respawn.wp not found on %d\n", mobj->type);
}
}
}
if (mobj->player && mobj->player->followmobj)
{
temp = (UINT32)(size_t)mobj->player->followmobj;
mobj->player->followmobj = NULL;
if (!P_SetTarget(&mobj->player->followmobj, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "followmobj not found on %d\n", mobj->type);
}
if (mobj->player && mobj->player->drone)
{
temp = (UINT32)(size_t)mobj->player->drone;
mobj->player->drone = NULL;
if (!P_SetTarget(&mobj->player->drone, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "drone not found on %d\n", mobj->type);
}
}
}
@ -4144,6 +4173,10 @@ static void P_NetArchiveMisc(void)
WRITEUINT8(save_p, thwompsactive);
WRITESINT8(save_p, spbplace);
WRITEUINT8(save_p, rainbowstartavailable);
WRITEUINT32(save_p, introtime);
WRITEUINT32(save_p, starttime);
// Is it paused?
if (paused)
@ -4274,6 +4307,10 @@ static inline boolean P_NetUnArchiveMisc(void)
thwompsactive = (boolean)READUINT8(save_p);
spbplace = READSINT8(save_p);
rainbowstartavailable = (boolean)READUINT8(save_p);
introtime = READUINT32(save_p);
starttime = READUINT32(save_p);
// Is it paused?
if (READUINT8(save_p) == 0x2f)

View file

@ -87,6 +87,7 @@
#include "k_pwrlv.h"
#include "k_waypoint.h"
#include "k_bot.h"
#include "k_grandprix.h"
//
// Map MD5, calculated on level load.
@ -3294,7 +3295,7 @@ lumpnum_t lastloadedmaplumpnum; // for comparative savegame
static void P_InitLevelSettings(void)
{
INT32 i;
boolean canresetlives = true;
UINT8 p = 0;
leveltime = 0;
@ -3355,14 +3356,24 @@ static void P_InitLevelSettings(void)
for (i = 0; i < MAXPLAYERS; i++)
{
players[i].lives = 1; // SRB2Kart
if (playeringame[i] && !players[i].spectator)
p++;
if (grandprixinfo.gp == false)
{
players[i].lives = 3;
players[i].xtralife = 0;
players[i].totalring = 0;
}
players[i].realtime = racecountdown = exitcountdown = 0;
curlap = bestlap = 0; // SRB2Kart
players[i].lostlife = false;
players[i].gotcontinue = false;
players[i].xtralife = players[i].deadtimer = players[i].numboxes = players[i].totalring = players[i].laps = 0;
players[i].deadtimer = players[i].numboxes = players[i].laps = 0;
players[i].health = 1;
players[i].aiming = 0;
players[i].pflags &= ~PF_TIMEOVER;
}
@ -3388,11 +3399,52 @@ static void P_InitLevelSettings(void)
// hit these too
players[i].pflags &= ~(PF_GAMETYPEOVER);
// Wipe follower from existence to avoid crashes
players[i].follower = NULL;
}
// SRB2Kart: map load variables
if (modeattacking) // Just play it safe and set everything
rainbowstartavailable = false;
if (p >= 2)
rainbowstartavailable = true;
if (p <= 2)
{
introtime = 0; // No intro in Record Attack / 1v1
}
else
{
introtime = (108) + 5; // 108 for rotation, + 5 for white fade
}
numbulbs = 5;
if (p > 2)
{
numbulbs += (p-2);
}
starttime = (introtime + (3*TICRATE)) + ((2*TICRATE) + (numbulbs * bulbtime)); // Start countdown time, + buffer time
// SRB2Kart: map load variables
if (grandprixinfo.gp == true)
{
if (G_BattleGametype())
{
gamespeed = KARTSPEED_EASY;
}
else
{
gamespeed = grandprixinfo.gamespeed;
}
franticitems = false;
comeback = true;
}
else if (modeattacking)
{
// Just play it safe and set everything
gamespeed = KARTSPEED_HARD;
franticitems = false;
comeback = true;
@ -3417,11 +3469,6 @@ static void P_InitLevelSettings(void)
memset(&battleovertime, 0, sizeof(struct battleovertime));
speedscramble = encorescramble = -1;
if (!modeattacking)
{
K_UpdateMatchRaceBots();
}
}
// Respawns all the mapthings and mobjs in the map from the already loaded map data.
@ -4195,6 +4242,17 @@ boolean P_LoadLevel(boolean fromnetsave)
// clear special respawning que
iquehead = iquetail = 0;
// Fab : 19-07-98 : start cd music for this level (note: can be remapped)
I_PlayCD((UINT8)(gamemap), false);
// preload graphics
#ifdef HWRENDER // not win32 only 19990829 by Kin
if (rendermode != render_soft && rendermode != render_none)
{
HWR_PrepLevelCache(numtextures);
}
#endif
P_MapEnd();
// Remove the loading shit from the screen
@ -4247,6 +4305,25 @@ boolean P_LoadLevel(boolean fromnetsave)
// NOW you can try to spawn in the Battle capsules, if there's not enough players for a match
K_SpawnBattleCapsules();
if (grandprixinfo.gp == true)
{
if (grandprixinfo.initalize == true)
{
K_InitGrandPrixBots();
grandprixinfo.initalize = false;
}
else if (grandprixinfo.wonround == true)
{
K_UpdateGrandPrixBots();
grandprixinfo.wonround = false;
}
}
else if (!modeattacking)
{
// We're in a Match Race, use simplistic randomized bots.
K_UpdateMatchRaceBots();
}
// No render mode, stop here.
if (rendermode == render_none)
return true;

View file

@ -22,6 +22,7 @@
#include "r_main.h"
#include "p_maputl.h"
#include "w_wad.h"
#include "k_kart.h" // K_PlayerEBrake
pslope_t *slopelist = NULL;
UINT16 slopecount = 0;
@ -883,6 +884,10 @@ 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) {
// SRB2Kart - spindash negates slopes
if (K_PlayerEBrake(mo->player))
return;
// 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

View file

@ -40,6 +40,7 @@
#include "k_kart.h" // SRB2kart
#include "console.h" // CON_LogMessage
#include "k_respawn.h"
#ifdef HW3SOUND
#include "hardware/hw3sound.h"
@ -2071,7 +2072,12 @@ static void K_HandleLapIncrement(player_t *player)
{
if (player)
{
if ((player->starpostnum == numstarposts) || (player->laps == 0))
if (leveltime < starttime)
{
// Will fault the player
K_DoIngameRespawn(player);
}
else if ((player->starpostnum == numstarposts) || (player->laps == 0))
{
size_t i = 0;
UINT8 nump = 0;
@ -2106,6 +2112,14 @@ static void K_HandleLapIncrement(player_t *player)
player->karthud[khud_lapanimation] = 80;
}
if (rainbowstartavailable == true)
{
S_StartSound(player->mo, sfx_s23c);
player->kartstuff[k_startboost] = 125;
K_SpawnDriftBoostExplosion(player, 3);
rainbowstartavailable = false;
}
if (netgame && player->laps >= (UINT8)cv_numlaps.value)
CON_LogMessage(va(M_GetText("%s has finished the race.\n"), player_names[player-players]));
@ -2117,7 +2131,6 @@ static void K_HandleLapIncrement(player_t *player)
curlap = 0;
}
player->starposttime = player->realtime;
player->starpostnum = 0;
if (P_IsDisplayPlayer(player))
@ -4715,19 +4728,19 @@ DoneSection2:
break;
case 5: // Speed pad
if (player->kartstuff[k_dashpadcooldown] != 0)
if (player->kartstuff[k_floorboost] != 0)
{
player->kartstuff[k_floorboost] = 2;
break;
}
i = P_FindSpecialLineFromTag(4, sector->tag, -1);
if (i != -1)
{
angle_t lineangle;
fixed_t linespeed;
fixed_t sfxnum;
lineangle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y);
linespeed = sides[lines[i].sidenum[0]].textureoffset;
angle_t lineangle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y);
fixed_t linespeed = P_AproxDistance(lines[i].v2->x-lines[i].v1->x, lines[i].v2->y-lines[i].v1->y);
fixed_t playerspeed = P_AproxDistance(player->mo->momx, player->mo->momy);
if (linespeed == 0)
{
@ -4738,36 +4751,21 @@ DoneSection2:
// SRB2Kart: Scale the speed you get from them!
// This is scaled differently from other horizontal speed boosts from stuff like springs, because of how this is used for some ramp jumps.
if (player->mo->scale > mapobjectscale)
linespeed = FixedMul(linespeed, mapobjectscale + (player->mo->scale - mapobjectscale));
if (!(lines[i].flags & ML_EFFECT4))
{
P_UnsetThingPosition(player->mo);
if (roversector) // make FOF speed pads work
{
player->mo->x = roversector->soundorg.x;
player->mo->y = roversector->soundorg.y;
}
else
{
player->mo->x = sector->soundorg.x;
player->mo->y = sector->soundorg.y;
}
P_SetThingPosition(player->mo);
linespeed = FixedMul(linespeed, mapobjectscale + (player->mo->scale - mapobjectscale));
}
P_InstaThrust(player->mo, lineangle, linespeed);
lineangle = K_ReflectAngle(
R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy), lineangle,
playerspeed, linespeed
);
P_InstaThrust(player->mo, lineangle, max(linespeed, 2*playerspeed));
player->kartstuff[k_dashpadcooldown] = TICRATE/3;
player->kartstuff[k_pogospring] = 0;
S_StartSound(player->mo, sfx_spdpad);
{
sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons
if (cv_kartvoices.value)
S_StartSound(player->mo, sfx_kbost1+pick);
//K_TauntVoiceTimers(player);
}
player->kartstuff[k_floorboost] = 2;
S_StartSound(player->mo, sfx_cdfm62);
}
break;

View file

@ -38,6 +38,9 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
const INT32 takeflags2 = MF2_TWOD|MF2_OBJECTFLIP;
UINT8 i;
(void)starposttime;
(void)starpostangle;
// the move is ok,
// so link the thing into its new position
P_UnsetThingPosition(thing);
@ -80,12 +83,9 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
thing->player->speed = 0;
// Starpost information
thing->player->starpostx = starpostx;
thing->player->starposty = starposty;
thing->player->starpostz = starpostz;
thing->player->starposttime = starposttime;
thing->player->starpostangle = starpostangle;
thing->player->starpostscale = starpostscale;
thing->player->respawn.pointx = starpostx;
thing->player->respawn.pointy = starposty;
thing->player->respawn.pointz = starpostz;
thing->player->starpostnum = starpostnum;
thing->player->drawangle = drawangle;

View file

@ -641,9 +641,9 @@ void P_Ticker(boolean run)
if (exitcountdown > 1)
exitcountdown--;
if (indirectitemcooldown > 1)
if (indirectitemcooldown > 0)
indirectitemcooldown--;
if (hyubgone > 1)
if (hyubgone > 0)
hyubgone--;
if ((gametyperules & GTR_BUMPERS))

File diff suppressed because it is too large Load diff

View file

@ -93,6 +93,7 @@ extern INT16 color8to16[256]; // remap color index to highcolor
extern INT16 *hicolormaps; // remap high colors to high colors..
extern CV_PossibleValue_t Color_cons_t[];
extern CV_PossibleValue_t Followercolor_cons_t[]; // follower colours table, not a duplicate because of the "Match" option.
// Load TEXTURES definitions, create lookup tables
void R_LoadTextures(void);

View file

@ -148,6 +148,7 @@ static UINT8** translationtablecache[TT_CACHE_SIZE] = {NULL};
UINT8 skincolor_modified[MAXSKINCOLORS];
CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1];
CV_PossibleValue_t Followercolor_cons_t[MAXSKINCOLORS+3]; // +3 to account for "Match", "Opposite" & NULL
/** \brief The R_InitTranslationTables

View file

@ -166,10 +166,6 @@ static void ChaseCam_OnChange(void);
static void ChaseCam2_OnChange(void);
static void ChaseCam3_OnChange(void);
static void ChaseCam4_OnChange(void);
static void FlipCam_OnChange(void);
static void FlipCam2_OnChange(void);
static void FlipCam3_OnChange(void);
static void FlipCam4_OnChange(void);
void SendWeaponPref(void);
void SendWeaponPref2(void);
void SendWeaponPref3(void);
@ -180,10 +176,6 @@ consvar_t cv_chasecam = {"chasecam", "On", CV_CALL, CV_OnOff, ChaseCam_OnChange,
consvar_t cv_chasecam2 = {"chasecam2", "On", CV_CALL, CV_OnOff, ChaseCam2_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_chasecam3 = {"chasecam3", "On", CV_CALL, CV_OnOff, ChaseCam3_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_chasecam4 = {"chasecam4", "On", CV_CALL, CV_OnOff, ChaseCam4_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_flipcam = {"flipcam", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_flipcam2 = {"flipcam2", "No", CV_SAVE|CV_CALL|CV_NOINIT, CV_YesNo, FlipCam2_OnChange, 0, NULL, NULL, 0, 0, NULL};
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", "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};
@ -191,8 +183,6 @@ consvar_t cv_allowmlook = {"allowmlook", "Yes", CV_NETVAR, CV_YesNo, NULL, 0, NU
consvar_t cv_showhud = {"showhud", "Yes", CV_CALL, CV_YesNo, R_SetViewSize, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_translucenthud = {"translucenthud", "10", CV_SAVE, translucenthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_translucency = {"translucency", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_drawdist = {"drawdist", "8192", CV_SAVE, drawdist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_drawdist_precip = {"drawdist_precip", "1024", CV_SAVE, drawdist_precip_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_fov = {"fov", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange, 0, NULL, NULL, 0, 0, NULL};
@ -284,26 +274,6 @@ static void ChaseCam4_OnChange(void)
;
}
static void FlipCam_OnChange(void)
{
SendWeaponPref();
}
static void FlipCam2_OnChange(void)
{
SendWeaponPref2();
}
static void FlipCam3_OnChange(void)
{
SendWeaponPref3();
}
static void FlipCam4_OnChange(void)
{
SendWeaponPref4();
}
//
// R_PointOnSide
// Traverse BSP (sub) tree,
@ -1675,16 +1645,10 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_tailspickup);
CV_RegisterVar(&cv_allowmlook);
CV_RegisterVar(&cv_homremoval);
CV_RegisterVar(&cv_flipcam);
CV_RegisterVar(&cv_flipcam2);
CV_RegisterVar(&cv_flipcam3);
CV_RegisterVar(&cv_flipcam4);
// Enough for dedicated server
if (dedicated)
return;
CV_RegisterVar(&cv_translucency);
CV_RegisterVar(&cv_drawdist);
CV_RegisterVar(&cv_drawdist_precip);
CV_RegisterVar(&cv_fov);

View file

@ -101,7 +101,6 @@ extern consvar_t cv_chasecam[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_flipcam[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_shadow;
extern consvar_t cv_translucency;
extern consvar_t cv_drawdist, v_drawdist_precip;
extern consvar_t cv_fov;
extern consvar_t cv_skybox;

View file

@ -319,7 +319,7 @@ static visplane_t *new_visplane(unsigned hash)
visplane_t *check = freetail;
if (!check)
{
check = calloc(2, sizeof (*check));
check = calloc(1, sizeof (*check));
if (check == NULL) I_Error("%s: Out of memory", "new_visplane"); // FIXME: ugly
}
else

View file

@ -176,14 +176,8 @@ static void R_DrawWallSplats(void)
colfunc = colfuncs[BASEDRAWFUNC];
break;
case SPLATDRAWMODE_TRANS:
if (!cv_translucency.value)
colfunc = colfuncs[BASEDRAWFUNC];
else
{
dc_transmap = transtables + ((tr_trans50 - 1)<<FF_TRANSSHIFT);
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
}
dc_transmap = transtables + ((tr_trans50 - 1)<<FF_TRANSSHIFT);
colfunc = fuzzcolfunc;
break;
case SPLATDRAWMODE_SHADE:
colfunc = colfuncs[COLDRAWFUNC_SHADE];

View file

@ -1150,6 +1150,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope)
continue;
z = isflipped ? P_GetFFloorBottomZAt(rover, thing->x, thing->y) : P_GetFFloorTopZAt(rover, thing->x, thing->y);
if CHECKZ
{
groundz = z;
@ -1227,8 +1228,9 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope)
if (shadowslope != NULL)
*shadowslope = groundslope;
return groundz;
#undef CHECKZ
return groundz;
}
static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, fixed_t tx, fixed_t tz)
@ -1865,19 +1867,27 @@ static void R_ProjectSprite(mobj_t *thing)
vis->transmap = NULL;
// specific translucency
if (!cv_translucency.value)
; // no translucency
else if (oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility)
vis->transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT); // because now the translucency is set through FF_TRANSMASK
else if (oldthing->frame & FF_TRANSMASK)
vis->transmap = transtables + (oldthing->frame & FF_TRANSMASK) - 0x10000;
if (thing->drawflags & MFD_TRANSMASK) // Object is forcing transparency to a specific value
vis->transmap = transtables + ((((thing->drawflags & MFD_TRANSMASK) - MFD_TRANS10) >> MFD_TRANSSHIFT) << FF_TRANSSHIFT);
else if (thing->frame & FF_TRANSMASK)
vis->transmap = transtables + ((thing->frame & FF_TRANSMASK) - FF_TRANS10);
if (oldthing->frame & FF_FULLBRIGHT || oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW)
vis->cut |= SC_FULLBRIGHT;
else if (oldthing->frame & FF_SEMIBRIGHT)
vis->cut |= SC_SEMIBRIGHT;
if (thing->drawflags & MFD_BRIGHTMASK)
{
if (thing->drawflags & MFD_FULLBRIGHT)
vis->cut |= SC_FULLBRIGHT;
else if (thing->drawflags & MFD_SEMIBRIGHT)
vis->cut |= SC_SEMIBRIGHT;
}
else
{
if (thing->frame & FF_FULLBRIGHT)
vis->cut |= SC_FULLBRIGHT;
else if (thing->frame & FF_SEMIBRIGHT)
vis->cut |= SC_SEMIBRIGHT;
}
if (vis->cut & SC_FULLBRIGHT
if ((vis->cut & SC_FULLBRIGHT)
&& (!vis->extra_colormap || !(vis->extra_colormap->flags & CMF_FADEFULLBRIGHTSPRITES)))
{
// full bright: goggles
@ -2047,8 +2057,9 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
vis->patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
// specific translucency
// (no draw flags)
if (thing->frame & FF_TRANSMASK)
vis->transmap = (thing->frame & FF_TRANSMASK) - 0x10000 + transtables;
vis->transmap = ((thing->frame & FF_TRANSMASK) - FF_TRANS10) + transtables;
else
vis->transmap = NULL;
@ -2078,7 +2089,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
mobj_t *thing;
precipmobj_t *precipthing; // Tails 08-25-2002
INT32 lightnum;
fixed_t limit_dist, hoop_limit_dist;
fixed_t limit_dist;
if (rendermode != render_soft)
return;
@ -2809,37 +2820,19 @@ void R_ClipSprites(drawseg_t* dsstart, portal_t* portal)
/* Check if thing may be drawn from our current view. */
boolean R_ThingVisible (mobj_t *thing)
{
boolean split_drawsprite = true;
UINT16 splitflags = 0;
if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW
|| (r_viewmobj && (thing == r_viewmobj || (r_viewmobj->player && r_viewmobj->player->followmobj == thing))))
if (thing->sprite == SPR_NULL)
return false;
splitflags = thing->eflags & (MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
if (r_viewmobj && (thing == r_viewmobj || (r_viewmobj->player && r_viewmobj->player->followmobj == thing)))
return false;
if (r_splitscreen && splitflags)
{
split_drawsprite = false;
if ((viewssnum == 0 && (thing->drawflags & MFD_DONTDRAWP1))
|| (viewssnum == 1 && (thing->drawflags & MFD_DONTDRAWP2))
|| (viewssnum == 2 && (thing->drawflags & MFD_DONTDRAWP3))
|| (viewssnum == 3 && (thing->drawflags & MFD_DONTDRAWP4)))
return false;
if (thing->eflags & MFE_DRAWONLYFORP1)
if (viewssnum == 0)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP2)
if (viewssnum == 1)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1)
if (viewssnum == 2)
split_drawsprite = true;
if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2)
if (viewssnum == 3)
split_drawsprite = true;
}
return split_drawsprite;
return true;
}
boolean R_ThingVisibleWithinDist (mobj_t *thing,

View file

@ -161,7 +161,7 @@ typedef struct vissprite_s
lighttable_t *colormap; // for color translation and shadow draw
// maxbright frames as well
UINT8 *transmap; // for MF2_SHADOW sprites, which translucency table to use
UINT8 *transmap; // which translucency table to use
INT32 mobjflags;

View file

@ -93,6 +93,11 @@ ifndef NOTHREADS
OBJS+=$(OBJDIR)/i_threads.o
endif
ifndef NOTHREADS
OPTS+=-DHAVE_THREADS
OBJS+=$(OBJDIR)/i_threads.o
endif
ifdef SDL_TTF
OPTS+=-DHAVE_TTF
SDL_LDFLAGS+=-lSDL2_ttf -lfreetype -lz

View file

@ -234,6 +234,7 @@
<ClInclude Include="..\hardware\hw_md3load.h" />
<ClInclude Include="..\hardware\hw_model.h" />
<ClInclude Include="..\hardware\u_list.h" />
<ClInclude Include="..\font.h" />
<ClInclude Include="..\hu_stuff.h" />
<ClInclude Include="..\info.h" />
<ClInclude Include="..\i_addrinfo.h" />
@ -252,6 +253,7 @@
<ClInclude Include="..\lzf.h" />
<ClInclude Include="..\md5.h" />
<ClInclude Include="..\mserv.h" />
<ClInclude Include="..\http-mserv.h" />
<ClInclude Include="..\m_aatree.h" />
<ClInclude Include="..\m_anigif.h" />
<ClInclude Include="..\m_argv.h" />
@ -384,6 +386,7 @@
<ClCompile Include="..\hardware\hw_model.c" />
<ClCompile Include="..\hardware\r_opengl\r_opengl.c" />
<ClCompile Include="..\hardware\u_list.c" />
<ClCompile Include="..\font.c" />
<ClCompile Include="..\hu_stuff.c" />
<ClCompile Include="..\info.c" />
<ClCompile Include="..\i_addrinfo.c">
@ -407,6 +410,7 @@
<ClCompile Include="..\lzf.c" />
<ClCompile Include="..\md5.c" />
<ClCompile Include="..\mserv.c" />
<ClCompile Include="..\http-mserv.c" />
<ClCompile Include="..\m_aatree.c" />
<ClCompile Include="..\m_anigif.c" />
<ClCompile Include="..\m_argv.c" />

View file

@ -297,6 +297,9 @@
<ClInclude Include="..\mserv.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\http-mserv.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\lua_hook.h">
<Filter>LUA</Filter>
</ClInclude>
@ -693,6 +696,9 @@
<ClCompile Include="..\mserv.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\http-mserv.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\lua_baselib.c">
<Filter>LUA</Filter>
</ClCompile>

View file

@ -2090,6 +2090,50 @@
RelativePath="..\console.h"
>
</File>
<File
RelativePath="..\font.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File
RelativePath="..\font.h"
>
</File>
<File
RelativePath="..\hu_stuff.c"
>
@ -2742,6 +2786,50 @@
RelativePath="..\mserv.h"
>
</File>
<File
RelativePath="..\http-mserv.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File
RelativePath="..\http-mserv.h"
>
</File>
</Filter>
<Filter
Name="M_Misc"

View file

@ -1412,6 +1412,8 @@ static inline boolean I_SkipFrame(void)
//
void I_FinishUpdate(void)
{
int player;
if (rendermode == render_none)
return; //Alam: No software or OpenGl surface
@ -1426,7 +1428,25 @@ void I_FinishUpdate(void)
if (cv_showping.value && netgame &&
( consoleplayer != serverplayer || ! server_lagless ))
{
SCR_DisplayLocalPing();
if (server_lagless)
{
if (consoleplayer != serverplayer)
SCR_DisplayLocalPing();
}
else
{
for (
player = 1;
player < MAXPLAYERS;
player++
){
if (D_IsPlayerHumanAndGaming(player))
{
SCR_DisplayLocalPing();
break;
}
}
}
}
}

View file

@ -34,6 +34,7 @@
#endif
#include "../doomdef.h"
#include "../d_main.h"
#ifdef HWRENDER
#include "../hardware/r_opengl/r_opengl.h"
@ -155,11 +156,26 @@ boolean OglSdlSurface(INT32 w, INT32 h)
{
INT32 cbpp = cv_scr_depth.value < 16 ? 16 : cv_scr_depth.value;
static boolean first_init = false;
const char *gllogdir = NULL;
oglflags = 0;
if (!first_init)
{
if (!gllogstream)
{
gllogdir = D_Home();
#ifdef DEBUG_TO_FILE
#ifdef DEFAULTDIR
if (gllogdir)
gllogstream = fopen(va("%s/"DEFAULTDIR"/ogllog.txt",gllogdir), "wt");
else
#endif
gllogstream = fopen("./ogllog.txt", "wt");
#endif
}
gl_version = pglGetString(GL_VERSION);
gl_renderer = pglGetString(GL_RENDERER);
gl_extensions = pglGetString(GL_EXTENSIONS);

View file

@ -655,6 +655,16 @@
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\font.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ClCompile Include="..\hu_stuff.c">
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -1366,6 +1376,7 @@
<ClInclude Include="..\am_map.h" />
<ClInclude Include="..\command.h" />
<ClInclude Include="..\console.h" />
<ClInclude Include="..\font.h" />
<ClInclude Include="..\hu_stuff.h" />
<ClInclude Include="..\st_stuff.h" />
<ClInclude Include="..\y_inter.h" />

View file

@ -2090,6 +2090,50 @@
RelativePath="..\console.h"
>
</File>
<File
RelativePath="..\font.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File
RelativePath="..\font.h"
>
</File>
<File
RelativePath="..\hu_stuff.c"
>

View file

@ -877,8 +877,8 @@ sfxinfo_t S_sfx[NUMSFX] =
{"bfare", false, 128, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Pleasure Castle fanfare
{"merry", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Pleasure Castle merry-go-round ambient
{"bowlh", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Pleasure Castle pins
{"tppop", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},// Pleasure Castle bombs
{"hsdoor", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},// Red Barrage Area door
{"tppop", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Pleasure Castle bombs
{"hsdoor", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Red Barrage Area door
{"hstrn", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Red Barrage Area train
{"aspkb", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Red Barrage Area spikeballs
{"wind1", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Midnight Channel monsters
@ -891,6 +891,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"sploss", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Down to yellow sparks
{"itfree", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // :shitsfree:
{"dbgsal", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Debug notification
{"cock", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Hammer cocks, bang bang
// SRB2Kart - Engine sounds
// Engine class A

View file

@ -954,6 +954,7 @@ typedef enum
sfx_sploss,
sfx_itfree,
sfx_dbgsal,
sfx_cock,
// Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy...
// Engine class A - Low Speed, Low Weight

View file

@ -31,7 +31,7 @@
#include "m_misc.h" // moviemode
#include "m_anigif.h" // cv_gif_downscale
#include "p_setup.h" // NiGHTS grading
#include "k_kart.h" // SRB2kart
#include "k_hud.h" // SRB2kart
//random index
#include "m_random.h"
@ -884,11 +884,11 @@ static void ST_overlayDrawer(void)
INT32 y = (stplyr == &players[displayplayers[0]]) ? 4 : BASEVIDHEIGHT/2-12;
sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]);
V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT), name);
V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_ALLOWLOWERCASE|V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN, name);
}
else if (r_splitscreen)
{
V_DrawCenteredThinString((vid.width/vid.dupx)/4, BASEVIDHEIGHT/2 - 12, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT), player_names[stplyr-players]);
V_DrawCenteredThinString((vid.width/vid.dupx)/4, BASEVIDHEIGHT/2 - 12, V_HUDTRANSHALF|V_ALLOWLOWERCASE|V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN, player_names[stplyr-players]);
}
}
}
@ -933,16 +933,15 @@ static void ST_overlayDrawer(void)
// SRB2kart: changed positions & text
if (r_splitscreen)
{
INT32 splitflags = K_calcSplitFlags(0);
V_DrawThinString(2, (BASEVIDHEIGHT/2)-20, V_YELLOWMAP|V_HUDTRANSHALF|splitflags, M_GetText("- SPECTATING -"));
V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|splitflags, itemtxt);
V_DrawThinString(2, (BASEVIDHEIGHT/2)-20, V_YELLOWMAP|V_HUDTRANSHALF|V_SPLITSCREEN, M_GetText("- SPECTATING -"));
V_DrawThinString(2, (BASEVIDHEIGHT/2)-10, V_HUDTRANSHALF|V_SPLITSCREEN, itemtxt);
}
else
{
V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF|V_YELLOWMAP, M_GetText("- SPECTATING -"));
V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF, itemtxt);
V_DrawString(2, BASEVIDHEIGHT-20, V_HUDTRANSHALF, M_GetText("Accelerate - Float"));
V_DrawString(2, BASEVIDHEIGHT-10, V_HUDTRANSHALF, M_GetText("Brake - Sink"));
V_DrawString(2, BASEVIDHEIGHT-40, V_HUDTRANSHALF|V_SPLITSCREEN|V_YELLOWMAP, M_GetText("- SPECTATING -"));
V_DrawString(2, BASEVIDHEIGHT-30, V_HUDTRANSHALF|V_SPLITSCREEN, itemtxt);
V_DrawString(2, BASEVIDHEIGHT-20, V_HUDTRANSHALF|V_SPLITSCREEN, M_GetText("Accelerate - Float"));
V_DrawString(2, BASEVIDHEIGHT-10, V_HUDTRANSHALF|V_SPLITSCREEN, M_GetText("Brake - Sink"));
}
}
}

View file

@ -74,7 +74,6 @@ extern INT32 st_translucency;
extern lumpnum_t st_borderpatchnum;
// patches, also used in intermission
extern patch_t *tallnum[10];
extern patch_t *sboscore;
extern patch_t *sbotime;
extern patch_t *sbocolon;

File diff suppressed because it is too large Load diff

View file

@ -135,9 +135,9 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue);
#define V_WRAPX 0x08000000 // Don't clamp texture on X (for HW mode)
#define V_WRAPY 0x10000000 // Don't clamp texture on Y (for HW mode)
#define V_NOSCALESTART 0x20000000 // don't scale x, y, start coords
#define V_SPLITSCREEN 0x40000000
#define V_HORZSCREEN 0x80000000
#define V_NOSCALESTART 0x20000000 // don't scale x, y, start coords
#define V_SPLITSCREEN 0x40000000 // Add half of screen width or height automatically depending on player number
#define V_SLIDEIN 0x80000000 // Slide in from the sides on level load, depending on snap flags
// defines for old functions
#define V_DrawPatch(x,y,s,p) V_DrawFixedPatch((x)<<FRACBITS, (y)<<FRACBITS, FRACUNIT, s|V_NOSCALESTART|V_NOSCALEPATCH, p, NULL)
@ -187,6 +187,12 @@ void V_EncoreInvertScreen(void);
void V_DrawPromptBack(INT32 boxheight, INT32 color);
/* Convenience macros for leagacy string function macros. */
#define V__DrawOneScaleString( x,y,scale,option,font,string ) \
V_DrawStringScaled(x,y,scale,FRACUNIT,FRACUNIT,option,font,string)
#define V__DrawDupxString( x,y,scale,option,font,string )\
V__DrawOneScaleString ((x)<<FRACBITS,(y)<<FRACBITS,scale,option,font,string)
// draw a single character
void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);
// draw a single character, but for the chat
@ -194,51 +200,48 @@ void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UI
UINT8 *V_GetStringColormap(INT32 colorflags);
void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string);
#define V_DrawLevelTitle( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,LT_FONT,string)
// wordwrap a string using the hu_font
char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string);
// draw a string using a font
void V_DrawStringScaled(
fixed_t x,
fixed_t y,
fixed_t scale,
fixed_t space_scale,
fixed_t linefeed_scale,
INT32 flags,
int font,
const char *text);
// draw a string using the hu_font
void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawKartString(INT32 x, INT32 y, INT32 option, const char *string); // SRB2kart
#define V_DrawString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,HU_FONT,string)
#define V_DrawKartString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,KART_FONT,string)
void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string);
// draw a string using the hu_font, 0.5x scale
void V_DrawSmallString(INT32 x, INT32 y, INT32 option, const char *string);
#define V_DrawSmallString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT>>1,option,HU_FONT,string)
void V_DrawCenteredSmallString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedSmallString(INT32 x, INT32 y, INT32 option, const char *string);
// draw a string using the tny_font
void V_DrawThinString(INT32 x, INT32 y, INT32 option, const char *string);
#define V_DrawThinString( x,y,option,string ) \
V__DrawDupxString (x,y,FRACUNIT,option,TINY_FONT,string)
void V_DrawCenteredThinString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedThinString(INT32 x, INT32 y, INT32 option, const char *string);
// draw a string using the tny_font, 0.5x scale
void V_DrawSmallThinString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawCenteredSmallThinString(INT32 x, INT32 y, INT32 option, const char *string);
void V_DrawRightAlignedSmallThinString(INT32 x, INT32 y, INT32 option, const char *string);
#define V_DrawStringAtFixed( x,y,option,string ) \
V__DrawOneScaleString (x,y,FRACUNIT,option,HU_FONT,string)
// draw a string using the hu_font at fixed_t coordinates
void V_DrawStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawCenteredStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawRightAlignedStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
// draw a string using the hu_font at fixed_t coordinates, 0.5x scale
void V_DrawSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawCenteredSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawRightAlignedSmallStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
// draw a string using the tny_font at fixed_t coordinates
void V_DrawThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawCenteredThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawRightAlignedThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
// draw a string using the tny_font at fixed_t coordinates, 0.5x scale
void V_DrawSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawCenteredSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
void V_DrawRightAlignedSmallThinStringAtFixed(fixed_t x, fixed_t y, INT32 option, const char *string);
#define V_DrawThinStringAtFixed( x,y,option,string ) \
V__DrawOneScaleString (x,y,FRACUNIT,option,TINY_FONT,string)
// Draw tall nums, used for menu, HUD, intermission
void V_DrawTallNum(INT32 x, INT32 y, INT32 flags, INT32 num);
@ -254,7 +257,8 @@ INT32 V_LevelNameWidth(const char *string);
INT32 V_LevelNameHeight(const char *string);
INT16 V_LevelActNumWidth(UINT8 num); // act number width
void V_DrawCreditString(fixed_t x, fixed_t y, INT32 option, const char *string);
#define V_DrawCreditString( x,y,option,string ) \
V__DrawOneScaleString (x,y,FRACUNIT,option,CRED_FONT,string)
INT32 V_CreditStringWidth(const char *string);
// Draw a string using the nt_font

View file

@ -1473,7 +1473,6 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
size = 0;
zerr(zErr);
}
(void)inflateEnd(&strm);
}
else

View file

@ -235,6 +235,7 @@
<ClCompile Include="..\hardware\hw_md3load.c" />
<ClCompile Include="..\hardware\hw_model.c" />
<ClCompile Include="..\hardware\u_list.c" />
<ClCompile Include="..\font.c" />
<ClCompile Include="..\hu_stuff.c" />
<ClCompile Include="..\info.c" />
<ClCompile Include="..\i_addrinfo.c">
@ -406,6 +407,7 @@
<ClInclude Include="..\hardware\hw_md3load.h" />
<ClInclude Include="..\hardware\hw_model.h" />
<ClInclude Include="..\hardware\u_list.h" />
<ClInclude Include="..\font.h" />
<ClInclude Include="..\hu_stuff.h" />
<ClInclude Include="..\info.h" />
<ClInclude Include="..\i_addrinfo.h" />

View file

@ -1831,6 +1831,50 @@
RelativePath="..\console.h"
>
</File>
<File
RelativePath="..\font.c"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File
RelativePath="..\font.h"
>
</File>
<File
RelativePath="..\hu_stuff.c"
>

View file

@ -45,6 +45,7 @@
#include "k_pwrlv.h"
#include "console.h" // cons_menuhighlight
#include "lua_hook.h" // IntermissionThinker hook
#include "k_grandprix.h"
#ifdef HWRENDER
#include "hardware/hw_main.h"
@ -197,7 +198,12 @@ static void Y_CompareScore(INT32 i)
static void Y_CompareRank(INT32 i)
{
INT16 increase = ((data.match.increase[i] == INT16_MIN) ? 0 : data.match.increase[i]);
UINT32 score = (powertype != -1 ? clientpowerlevels[i][powertype] : players[i].score);
UINT32 score = players[i].score;
if (powertype != PWRLV_DISABLED)
{
score = clientpowerlevels[i][powertype];
}
if (!(data.match.val[data.match.numplayers] == UINT32_MAX || (score - increase) > data.match.val[data.match.numplayers]))
return;
@ -301,18 +307,26 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
data.match.name[data.match.numplayers] = player_names[i];
if (data.match.numplayers && (data.match.val[data.match.numplayers] == data.match.val[data.match.numplayers-1]))
data.match.pos[data.match.numplayers] = data.match.pos[data.match.numplayers-1];
else
data.match.pos[data.match.numplayers] = data.match.numplayers+1;
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] = (numplayersingame + numgriefers) - data.match.pos[data.match.numplayers];
data.match.pos[data.match.numplayers] = data.match.pos[data.match.numplayers-1];
}
else
{
data.match.pos[data.match.numplayers] = data.match.numplayers+1;
}
if ((powertype == PWRLV_DISABLED)
&& (!rankingsmode)
&& !(players[i].pflags & PF_TIMEOVER)
&& (data.match.pos[data.match.numplayers] < (numplayersingame + numgriefers)))
{
// Online rank is handled further below in this file.
data.match.increase[i] = K_CalculateGPRankPoints(data.match.pos[data.match.numplayers], numplayersingame + numgriefers);
players[i].score += data.match.increase[i];
}
if (demo.recording && !rankingsmode)
{
G_WriteStanding(
data.match.pos[data.match.numplayers],
data.match.name[data.match.numplayers],
@ -320,6 +334,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
*data.match.color[data.match.numplayers],
data.match.val[data.match.numplayers]
);
}
data.match.numplayers++;
}
@ -507,9 +522,36 @@ dontdrawbg:
int y2;
if (data.match.rankingsmode)
timeheader = (powertype != -1 ? "PWR.LV" : "RANK");
{
if (powertype == PWRLV_DISABLED)
{
timeheader = "RANK";
}
else
{
timeheader = "PWR.LV";
}
}
else
timeheader = ((intertype == int_race || (intertype == int_battle && battlecapsules)) ? "TIME" : "SCORE");
{
switch (intertype)
{
default:
case int_race:
timeheader = "TIME";
break;
case int_battle:
if (battlecapsules)
{
timeheader = "TIME";
}
else
{
timeheader = "SCORE";
}
break;
}
}
// draw the level name
V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 12, 0, data.match.levelstring);
@ -600,8 +642,11 @@ dontdrawbg:
if (data.match.rankingsmode)
{
if (powertype != -1 && !clientpowerlevels[data.match.num[i]][powertype]) // No power level (splitscreen guests)
if (powertype != PWRLV_DISABLED && !clientpowerlevels[data.match.num[i]][powertype])
{
// No power level (splitscreen guests)
STRBUFCPY(strtime, "----");
}
else
{
if (data.match.increase[data.match.num[i]] != INT16_MIN)
@ -670,7 +715,7 @@ skiptallydrawer:
if (!LUA_HudEnabled(hud_intermissionmessages))
return;
if (timer)
if (timer && grandprixinfo.gp == false)
{
char *string;
INT32 tickdown = (timer+1)/TICRATE;
@ -774,74 +819,73 @@ void Y_Ticker(void)
if (intertype == int_race || intertype == int_battle)
{
if (netgame || multiplayer)
if (!(multiplayer && demo.playback)) // Don't advance to rankings in replays
{
if (sorttic == -1)
sorttic = intertic + max((cv_inttime.value/2)-2, 2)*TICRATE; // 8 second pause after match results
else if (!(multiplayer && demo.playback)) // Don't advance to rankings in replays
if (!data.match.rankingsmode && (intertic >= sorttic + 8))
{
if (!data.match.rankingsmode && (intertic >= sorttic + 8))
Y_CalculateMatchData(1, Y_CompareRank);
Y_CalculateMatchData(1, Y_CompareRank);
}
if (data.match.rankingsmode && intertic > sorttic+16+(2*TICRATE))
if (data.match.rankingsmode && intertic > sorttic+16+(2*TICRATE))
{
INT32 q=0,r=0;
boolean kaching = true;
for (q = 0; q < data.match.numplayers; q++)
{
INT32 q=0,r=0;
boolean kaching = true;
for (q = 0; q < data.match.numplayers; q++)
{
if (data.match.num[q] == MAXPLAYERS
if (data.match.num[q] == MAXPLAYERS
|| !data.match.increase[data.match.num[q]]
|| data.match.increase[data.match.num[q]] == INT16_MIN)
continue;
{
continue;
}
r++;
data.match.jitter[data.match.num[q]] = 1;
r++;
data.match.jitter[data.match.num[q]] = 1;
if (powertype != -1)
if (powertype != PWRLV_DISABLED)
{
// Power Levels
if (abs(data.match.increase[data.match.num[q]]) < 10)
{
// 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;
}
// Not a lot of point increase left, just set to 0 instantly
data.match.increase[data.match.num[q]] = 0;
}
else
{
// Basic bitch points
if (data.match.increase[data.match.num[q]])
{
if (--data.match.increase[data.match.num[q]])
kaching = false;
}
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;
}
}
if (r)
{
S_StartSound(NULL, (kaching ? sfx_chchng : sfx_ptally));
Y_CalculateMatchData(2, Y_CompareRank);
}
else
endtic = intertic + 3*TICRATE; // 3 second pause after end of tally
{
// Basic bitch points
if (data.match.increase[data.match.num[q]])
{
if (--data.match.increase[data.match.num[q]])
kaching = false;
}
}
}
if (r)
{
S_StartSound(NULL, (kaching ? sfx_chchng : sfx_ptally));
Y_CalculateMatchData(2, Y_CompareRank);
}
else
endtic = intertic + 3*TICRATE; // 3 second pause after end of tally
}
}
else if (!(intertic & 1))
@ -1159,19 +1203,11 @@ void Y_StartIntermission(void)
#endif
// set player Power Level type
powertype = PWRLV_DISABLED;
if (netgame && cv_kartusepwrlv.value)
{
if ((gametyperules & GTR_CIRCUIT))
powertype = PWRLV_RACE;
else if ((gametyperules & GTR_BUMPERS))
powertype = PWRLV_BATTLE;
}
powertype = K_UsingPowerLevels();
if (!multiplayer)
{
timer = 0;
timer = 20*TICRATE;
if (!majormods && !multiplayer && !demo.playback) // move this once we have a proper time attack screen
{
@ -1190,7 +1226,7 @@ void Y_StartIntermission(void)
}
else
{
if (cv_inttime.value == 0 && ((intertype == int_coop) || (intertype == int_spec)))
if (cv_inttime.value == 0)
timer = 0;
else if (demo.playback) // Override inttime (which is pulled from the replay anyway
timer = 10*TICRATE;
@ -1205,10 +1241,8 @@ void Y_StartIntermission(void)
if (intermissiontypes[gametype] != int_none)
intertype = intermissiontypes[gametype];
else if (gametype == GT_RACE)
intertype = int_race;
else if (gametype == GT_BATTLE)
intertype = int_battle;
sorttic = max((timer/2) - 2*TICRATE, 2*TICRATE); // 8 second pause after match results
// We couldn't display the intermission even if we wanted to.
// But we still need to give the players their score bonuses, dummy.
@ -1250,7 +1284,9 @@ void Y_StartIntermission(void)
}
if (powertype != PWRLV_DISABLED)
{
K_UpdatePowerLevels();
}
//if (intertype == int_race || intertype == int_battle)
{