Merge branch 'master' into big-large-map-markers

# Conflicts:
#	src/d_netcmd.c
This commit is contained in:
SteelT 2021-01-09 15:52:34 -05:00
commit 29b5f38347
83 changed files with 4702 additions and 2212 deletions

View file

@ -453,8 +453,9 @@ if(${SRB2_CONFIG_HAVE_DISCORDRPC})
if(${DISCORDRPC_FOUND})
set(SRB2_HAVE_DISCORDRPC ON)
add_definitions(-DHAVE_DISCORDRPC)
set(SRB2_DISCORDRPC_SOURCES discord.c)
set(SRB2_DISCORDRPC_HEADERS discord.h)
add_definitions(-DUSE_STUN)
set(SRB2_DISCORDRPC_SOURCES discord.c stun.c)
set(SRB2_DISCORDRPC_HEADERS discord.h stun.h)
prepend_sources(SRB2_DISCORDRPC_SOURCES)
prepend_sources(SRB2_DISCORDRPC_HEADERS)
source_group("Discord Rich Presence" FILES ${SRB2_DISCORDRPC_SOURCES} ${SRB2_DISCORDRPC_HEADERS})

View file

@ -393,8 +393,8 @@ endif
ifdef HAVE_DISCORDRPC
LIBS+=-ldiscord-rpc
CFLAGS+=-DHAVE_DISCORDRPC
OBJS+=$(OBJDIR)/discord.o
CFLAGS+=-DHAVE_DISCORDRPC -DUSE_STUN
OBJS+=$(OBJDIR)/discord.o $(OBJDIR)/stun.o
endif
include blua/Makefile.cfg

View file

@ -35,7 +35,7 @@ enum
/* Command buffer flags. */
enum
{
COM_SAFE = 1,
COM_SAFE = 0x01,
};
typedef void (*com_func_t)(void);

View file

@ -546,6 +546,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
// Score is resynched in the rspfirm resync packet
rsp->rings = SHORT(players[i].rings);
rsp->spheres = SHORT(players[i].spheres);
rsp->lives = players[i].lives;
rsp->lostlife = players[i].lostlife;
rsp->continues = players[i].continues;
@ -615,6 +616,19 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->kartstuff[j] = LONG(players[i].kartstuff[j]);
rsp->airtime = (tic_t)LONG(players[i].airtime);
rsp->trickpanel = (UINT8)players[i].trickpanel;
rsp->trickdelay = (boolean)players[i].trickdelay;
rsp->trickmomx = (fixed_t)LONG(players[i].trickmomx);
rsp->trickmomy = (fixed_t)LONG(players[i].trickmomy);
rsp->trickmomz = (fixed_t)LONG(players[i].trickmomz);
rsp->bumpers = players[i].bumpers;
rsp->karmadelay = SHORT(players[i].karmadelay);
rsp->eliminated = players[i].eliminated;
rsp->tumbleBounces = players[i].tumbleBounces;
rsp->tumbleHeight = SHORT(players[i].tumbleHeight);
rsp->tumbleLastBounce = players[i].tumbleLastBounce;
// respawnvars_t
rsp->respawn_state = players[i].respawn.state;
@ -690,6 +704,7 @@ static void resynch_read_player(resynch_pak *rsp)
// Score is resynched in the rspfirm resync packet
players[i].rings = SHORT(rsp->rings);
players[i].spheres = SHORT(rsp->spheres);
players[i].lives = rsp->lives;
players[i].lostlife = rsp->lostlife;
players[i].continues = rsp->continues;
@ -758,6 +773,19 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].kartstuff[j] = LONG(rsp->kartstuff[j]);
players[i].airtime = (tic_t)LONG(rsp->airtime);
players[i].trickpanel = (UINT8)rsp->trickpanel;
players[i].trickdelay = (boolean)rsp->trickdelay;
players[i].trickmomx = (fixed_t)LONG(rsp->trickmomx);
players[i].trickmomy = (fixed_t)LONG(rsp->trickmomy);
players[i].trickmomz = (fixed_t)LONG(rsp->trickmomz);
players[i].bumpers = rsp->bumpers;
players[i].karmadelay = SHORT(rsp->karmadelay);
players[i].eliminated = rsp->eliminated;
players[i].tumbleBounces = rsp->tumbleBounces;
players[i].tumbleHeight = SHORT(rsp->tumbleHeight);
players[i].tumbleLastBounce = (boolean)rsp->tumbleLastBounce;
// respawnvars_t
players[i].respawn.state = rsp->respawn_state;
@ -1246,7 +1274,7 @@ static inline void CL_DrawConnectionStatus(void)
cltext = M_GetText("Server full, waiting for a slot...");
else
cltext = M_GetText("Requesting to join...");
break;
#ifdef HAVE_CURL
case CL_PREPAREHTTPFILES:
@ -1990,6 +2018,9 @@ static void SendAskInfo(INT32 node)
// now allowed traffic from the host to us in, so once the MS relays
// our address to the host, it'll be able to speak to us.
HSendPacket(node, false, 0, sizeof (askinfo_pak));
if (node != 0 && node != BROADCASTADDR)
I_NetRequestHolePunch();
}
serverelem_t serverlist[MAXSERVERLIST];
@ -2112,7 +2143,7 @@ void CL_UpdateServerList (void)
static void M_ConfirmConnect(event_t *ev)
{
#ifndef NONET
#ifndef NONET
if (ev->type == ev_keydown)
{
if (ev->data1 == ' ' || ev->data1 == 'y' || ev->data1 == KEY_ENTER || ev->data1 == gamecontrol[0][gc_accelerate][0] || ev->data1 == gamecontrol[0][gc_accelerate][1])
@ -2135,7 +2166,7 @@ static void M_ConfirmConnect(event_t *ev)
}
else
cl_mode = CL_LOADFILES;
M_ClearMenus(true);
}
else if (ev->data1 == 'n' || ev->data1 == KEY_ESCAPE|| ev->data1 == gamecontrol[0][gc_brake][0] || ev->data1 == gamecontrol[0][gc_brake][1])
@ -2346,7 +2377,10 @@ static boolean CL_ServerConnectionSearchTicker(tic_t *asksent)
cl_mode = CL_CHECKFILES;
}
else
{
cl_mode = CL_ASKJOIN; // files need not be checked for the server.
*asksent = 0;
}
return true;
}
@ -2380,7 +2414,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
{
boolean waitmore;
INT32 i;
#ifdef NONET
(void)tmpsave;
#endif
@ -2417,7 +2451,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
{
curl_transfers++;
}
cl_mode = CL_DOWNLOADHTTPFILES;
}
break;
@ -2982,9 +3016,7 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
}
}
if (K_IsPlayerWanted(&players[playernum]))
K_CalculateBattleWanted();
K_CalculateBattleWanted();
LUAh_PlayerQuit(&players[playernum], reason); // Lua hook for player quitting
// don't look through someone's view who isn't there
@ -3575,6 +3607,76 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
}
}
#ifdef HAVE_CURL
/** Add a login for HTTP downloads. If the
* user/password is missing, remove it.
*
* \sa Command_list_http_logins
*/
static void Command_set_http_login (void)
{
HTTP_login *login;
HTTP_login **prev_next;
if (COM_Argc() < 2)
{
CONS_Printf(
"set_http_login <URL> [user:password]: Set or remove a login to "
"authenticate HTTP downloads.\n"
);
return;
}
login = CURLGetLogin(COM_Argv(1), &prev_next);
if (COM_Argc() == 2)
{
if (login)
{
(*prev_next) = login->next;
CONS_Printf("Login for '%s' removed.\n", login->url);
Z_Free(login);
}
}
else
{
if (login)
Z_Free(login->auth);
else
{
login = ZZ_Alloc(sizeof *login);
login->url = Z_StrDup(COM_Argv(1));
}
login->auth = Z_StrDup(COM_Argv(2));
login->next = curl_logins;
curl_logins = login;
}
}
/** List logins for HTTP downloads.
*
* \sa Command_set_http_login
*/
static void Command_list_http_logins (void)
{
HTTP_login *login;
for (
login = curl_logins;
login;
login = login->next
){
CONS_Printf(
"'%s' -> '%s'\n",
login->url,
login->auth
);
}
}
#endif/*HAVE_CURL*/
static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}};
consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL);
@ -3650,6 +3752,10 @@ void D_ClientServerInit(void)
COM_AddCommand("reloadbans", Command_ReloadBan);
COM_AddCommand("connect", Command_connect);
COM_AddCommand("nodes", Command_Nodes);
#ifdef HAVE_CURL
COM_AddCommand("set_http_login", Command_set_http_login);
COM_AddCommand("list_http_logins", Command_list_http_logins);
#endif
#ifdef PACKETDROP
COM_AddCommand("drop", Command_Drop);
COM_AddCommand("droprate", Command_Droprate);
@ -5487,7 +5593,10 @@ static void CL_SendClientCmd(void)
boolean mis = false;
if (lowest_lag && ( gametic % lowest_lag ))
{
cl_packetmissed = true;
return;
}
netbuffer->packettype = PT_CLIENTCMD;
@ -6012,6 +6121,19 @@ static void UpdatePingTable(void)
}
}
static void RenewHolePunch(void)
{
static time_t past;
const time_t now = time(NULL);
if ((now - past) > 20)
{
I_NetRegisterHolePunch();
past = now;
}
}
// Handle timeouts to prevent definitive freezes from happenning
static void HandleNodeTimeouts(void)
{
@ -6050,6 +6172,11 @@ void NetKeepAlive(void)
MasterClient_Ticker();
#endif
if (netgame && serverrunning)
{
RenewHolePunch();
}
if (client)
{
// send keep alive
@ -6109,6 +6236,11 @@ void NetUpdate(void)
MasterClient_Ticker(); // Acking the Master Server
#endif
if (netgame && serverrunning)
{
RenewHolePunch();
}
if (client)
{
if (!resynch_local_inprogress)

View file

@ -37,7 +37,7 @@ applications may follow different packet versions.
// be transmitted.
// Networking and tick handling related.
#define BACKUPTICS 32
#define BACKUPTICS 1024
#define TICQUEUE 512 // more than enough for most timeouts....
#define MAXTEXTCMD 256
//
@ -214,6 +214,7 @@ typedef struct
// Score is resynched in the confirm resync packet
INT16 rings;
INT16 spheres;
SINT8 lives;
boolean lostlife;
SINT8 continues;
@ -280,6 +281,19 @@ typedef struct
// SRB2kart
INT32 kartstuff[NUMKARTSTUFF];
tic_t airtime;
UINT8 trickpanel;
boolean trickdelay;
fixed_t trickmomx;
fixed_t trickmomy;
fixed_t trickmomz;
UINT8 bumpers;
INT16 karmadelay;
boolean eliminated;
UINT8 tumbleBounces;
UINT16 tumbleHeight;
boolean tumbleLastBounce;
// respawnvars_t
UINT8 respawn_state;
@ -567,6 +581,7 @@ extern INT32 mapchangepending;
// Points inside doomcom
extern doomdata_t *netbuffer;
extern consvar_t cv_stunserver;
extern consvar_t cv_httpsource;
extern consvar_t cv_showjoinaddress;

View file

@ -1412,6 +1412,11 @@ void D_SRB2Main(void)
CON_Init();
memset(timelimits, 0, sizeof(timelimits));
memset(pointlimits, 0, sizeof(pointlimits));
timelimits[GT_BATTLE] = 2;
D_RegisterServerCommands();
D_RegisterClientCommands(); // be sure that this is called before D_CheckNetGame
R_RegisterEngineStuff();

View file

@ -49,6 +49,8 @@ tic_t connectiontimeout = (10*TICRATE);
doomcom_t *doomcom = NULL;
/// \brief network packet data, points inside doomcom
doomdata_t *netbuffer = NULL;
/// \brief hole punching packet, also points inside doomcom
holepunch_t *holepunchpacket = NULL;
#ifdef DEBUGFILE
FILE *debugfile = NULL; // put some net info in a file during the game
@ -72,6 +74,8 @@ boolean (*I_NetCanGet)(void) = NULL;
void (*I_NetCloseSocket)(void) = NULL;
void (*I_NetFreeNodenum)(INT32 nodenum) = NULL;
SINT8 (*I_NetMakeNodewPort)(const char *address, const char* port) = NULL;
void (*I_NetRequestHolePunch)(void) = NULL;
void (*I_NetRegisterHolePunch)(void) = NULL;
boolean (*I_NetOpenSocket)(void) = NULL;
boolean (*I_Ban) (INT32 node) = NULL;
void (*I_ClearBans)(void) = NULL;
@ -1347,6 +1351,7 @@ boolean D_CheckNetGame(void)
I_Error("Too many nodes (%d), max:%d", doomcom->numnodes, MAXNETNODES);
netbuffer = (doomdata_t *)(void *)&doomcom->data;
holepunchpacket = (holepunch_t *)(void *)&doomcom->data;
#ifdef DEBUGFILE
if (M_CheckParm("-debugfile"))

View file

@ -289,10 +289,10 @@ consvar_t cv_skin[MAXSPLITSCREENPLAYERS] = {
// player's followers. Also saved.
consvar_t cv_follower[MAXSPLITSCREENPLAYERS] = {
CVAR_INIT ("follower", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower_OnChange),
CVAR_INIT ("follower2", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower2_OnChange),
CVAR_INIT ("follower3", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower3_OnChange),
CVAR_INIT ("follower4", "-1", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower4_OnChange)
CVAR_INIT ("follower", "None", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower_OnChange),
CVAR_INIT ("follower2", "None", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower2_OnChange),
CVAR_INIT ("follower3", "None", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower3_OnChange),
CVAR_INIT ("follower4", "None", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Follower4_OnChange)
};
// player's follower colors... Also saved...
@ -351,6 +351,7 @@ consvar_t cv_eggmanmonitor = CVAR_INIT ("eggmanmonitor", "On", CV_NETVAR|CV_C
consvar_t cv_orbinaut = CVAR_INIT ("orbinaut", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_jawz = CVAR_INIT ("jawz", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_mine = CVAR_INIT ("mine", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_landmine = CVAR_INIT ("landmine", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_ballhog = CVAR_INIT ("ballhog", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_selfpropelledbomb = CVAR_INIT ("selfpropelledbomb", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_grow = CVAR_INIT ("grow", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
@ -453,8 +454,7 @@ consvar_t cv_scrambleonchange = CVAR_INIT ("scrambleonchange", "Off", CV_SAVE|CV
consvar_t cv_itemfinder = CVAR_INIT ("itemfinder", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, ItemFinder_OnChange);
// Scoring type options
static CV_PossibleValue_t overtime_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Super"}, {0, NULL}};
consvar_t cv_overtime = CVAR_INIT ("overtime", "Yes", CV_NETVAR|CV_CHEAT, overtime_cons_t, NULL);
consvar_t cv_overtime = CVAR_INIT ("overtime", "Yes", CV_NETVAR|CV_CHEAT, CV_YesNo, NULL);
consvar_t cv_rollingdemos = CVAR_INIT ("rollingdemos", "On", CV_SAVE, CV_OnOff, NULL);
@ -462,9 +462,9 @@ static CV_PossibleValue_t pointlimit_cons_t[] = {{1, "MIN"}, {MAXSCORE, "MAX"},
consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, pointlimit_cons_t, PointLimit_OnChange);
static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "None"}, {0, NULL}};
consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange);
static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, NULL}};
consvar_t cv_numlaps = CVAR_INIT ("numlaps", "4", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, NumLaps_OnChange);
static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {50, "MAX"}, {0, "Map default"}, {0, NULL}};
static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}};
consvar_t cv_numlaps = CVAR_INIT ("numlaps", "3", CV_NETVAR|CV_CALL|CV_NOINIT, numlaps_cons_t, NumLaps_OnChange);
static CV_PossibleValue_t basenumlaps_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, "Map default"}, {0, NULL}};
consvar_t cv_basenumlaps = CVAR_INIT ("basenumlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, basenumlaps_cons_t, BaseNumLaps_OnChange);
// Point and time limits for every gametype
@ -749,6 +749,10 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_dummyconsvar);
#ifdef USE_STUN
CV_RegisterVar(&cv_stunserver);
#endif
CV_RegisterVar(&cv_discordinvites);
RegisterNetXCmd(XD_DISCORD, Got_DiscordInfo);
}
@ -2852,13 +2856,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
memset(&luabanks, 0, sizeof(luabanks));
}
if (modeattacking)
{
SetPlayerSkinByNum(0, cv_chooseskin.value-1);
players[0].skincolor = skins[players[0].skin].prefcolor;
CV_StealthSetValue(&cv_playercolor[0], players[0].skincolor);
}
LUAh_MapChange(mapnumber);
demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING;
@ -3467,8 +3464,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
if (gametyperules & GTR_BUMPERS) // SRB2kart
{
players[playernum].marescore = 0;
if (K_IsPlayerWanted(&players[playernum]))
K_CalculateBattleWanted();
K_CalculateBattleWanted();
}
K_PlayerForfeit(playernum, true);
@ -4327,15 +4323,13 @@ static void TimeLimit_OnChange(void)
if (cv_timelimit.value != 0)
{
CONS_Printf(M_GetText("Levels will end after %d second%s.\n"),cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003
timelimitintics = cv_timelimit.value * TICRATE;
CONS_Printf(M_GetText("Rounds will end after %d minute%s.\n"),cv_timelimit.value,cv_timelimit.value == 1 ? "" : "s"); // Graue 11-17-2003
timelimitintics = cv_timelimit.value * (60*TICRATE);
// Note the deliberate absence of any code preventing
// pointlimit and timelimit from being set simultaneously.
// Some people might like to use them together. It works.
}
else if (netgame || multiplayer)
CONS_Printf(M_GetText("Time limit disabled\n"));
#ifdef HAVE_DISCORDRPC
DRPC_UpdatePresence();

View file

@ -66,7 +66,7 @@ extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_ingamecap, cv_res
// SRB2kart items
extern consvar_t cv_superring, cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana;
extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine;
extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine, cv_landmine;
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;

View file

@ -138,6 +138,7 @@ static UINT32 curl_origfilesize;
static UINT32 curl_origtotalfilesize;
static char *curl_realname = NULL;
fileneeded_t *curl_curfile = NULL;
HTTP_login *curl_logins;
#endif
luafiletransfer_t *luafiletransfers = NULL;
@ -476,10 +477,10 @@ INT32 CL_CheckFiles(void)
for (i = 0; i < fileneedednum; i++)
{
if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_FALLBACK)
if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK)
downloadrequired = true;
if (fileneeded[i].status == FS_FOUND || fileneeded[i].status == FS_NOTFOUND)
if (fileneeded[i].status != FS_OPEN)
filestoload++;
if (fileneeded[i].status != FS_NOTCHECKED) //since we're running this over multiple tics now, its possible for us to come across files checked in previous tics
@ -1646,6 +1647,8 @@ int curlprogress_callback(void *clientp, double dltotal, double dlnow, double ul
void CURLPrepareFile(const char* url, int dfilenum)
{
HTTP_login *login;
#ifdef PARANOIA
if (M_CheckParm("-nodownload"))
I_Error("Attempted to download files in -nodownload mode");
@ -1674,6 +1677,14 @@ void CURLPrepareFile(const char* url, int dfilenum)
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.
// Authenticate if the user so wishes
login = CURLGetLogin(url, NULL);
if (login)
{
curl_easy_setopt(http_handle, CURLOPT_USERPWD, login->auth);
}
// Follow a redirect request, if sent by the server.
curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1L);
@ -1775,4 +1786,27 @@ void CURLGetFile(void)
curl_global_cleanup();
}
}
HTTP_login *
CURLGetLogin (const char *url, HTTP_login ***return_prev_next)
{
HTTP_login * login;
HTTP_login ** prev_next;
for (
prev_next = &curl_logins;
( login = (*prev_next));
prev_next = &login->next
){
if (strcmp(login->url, url) == 0)
{
if (return_prev_next)
(*return_prev_next) = prev_next;
return login;
}
}
return NULL;
}
#endif

View file

@ -72,6 +72,16 @@ extern UINT32 totalfilesrequestedsize;
extern boolean curl_failedwebdownload;
extern boolean curl_running;
extern INT32 curl_transfers;
typedef struct HTTP_login HTTP_login;
extern struct HTTP_login
{
char * url;
char * auth;
HTTP_login * next;
}
*curl_logins;
#endif
UINT8 *PutFileNeeded(UINT16 firstfile);
@ -151,6 +161,7 @@ size_t nameonlylength(const char *s);
#ifdef HAVE_CURL
void CURLPrepareFile(const char* url, int dfilenum);
void CURLGetFile(void);
HTTP_login * CURLGetLogin (const char *url, HTTP_login ***return_prev_next);
#endif
#endif // __D_NETFIL__

View file

@ -245,17 +245,18 @@ Run this macro, then #undef FOREACH afterward
FOREACH (ORBINAUT, 6),\
FOREACH (JAWZ, 7),\
FOREACH (MINE, 8),\
FOREACH (BALLHOG, 9),\
FOREACH (SPB, 10),\
FOREACH (GROW, 11),\
FOREACH (SHRINK, 12),\
FOREACH (THUNDERSHIELD, 13),\
FOREACH (BUBBLESHIELD, 14),\
FOREACH (FLAMESHIELD, 15),\
FOREACH (HYUDORO, 16),\
FOREACH (POGOSPRING, 17),\
FOREACH (SUPERRING, 18),\
FOREACH (KITCHENSINK, 19)
FOREACH (LANDMINE, 9),\
FOREACH (BALLHOG, 10),\
FOREACH (SPB, 11),\
FOREACH (GROW, 12),\
FOREACH (SHRINK, 13),\
FOREACH (THUNDERSHIELD, 14),\
FOREACH (BUBBLESHIELD, 15),\
FOREACH (FLAMESHIELD, 16),\
FOREACH (HYUDORO, 17),\
FOREACH (POGOSPRING, 18),\
FOREACH (SUPERRING, 19),\
FOREACH (KITCHENSINK, 20)
typedef enum
{
@ -335,7 +336,7 @@ typedef enum
k_sparkleanim, // Angle offset for ring sparkle animation
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
@ -449,6 +450,10 @@ typedef enum
// QUICKLY GET RING TOTAL, INCLUDING RINGS CURRENTLY IN THE PICKUP ANIMATION
#define RINGTOTAL(p) (p->rings + p->kartstuff[k_pickuprings])
// CONSTANTS FOR TRICK PANELS
#define TRICKMOMZRAMP (30)
#define TRICKLAG (9)
//}
// player_t struct for all respawn variables
@ -512,6 +517,7 @@ typedef struct player_s
// player's ring count
INT16 rings;
INT16 spheres;
// Power ups. invinc and invis are tic counters.
UINT16 powers[NUMPOWERS];
@ -522,7 +528,18 @@ typedef struct player_s
UINT32 distancetofinish;
waypoint_t *nextwaypoint;
respawnvars_t respawn; // Respawn info
tic_t airtime; // Keep track of how long you've been in the air
tic_t airtime; // Keep track of how long you've been in the air
UINT8 trickpanel; // Trick panel state
boolean trickdelay; // Prevent tricks until control stick is neutral
fixed_t trickmomx;
fixed_t trickmomy;
fixed_t trickmomz; // Instead of stupid auxiliary variables let's... just make some ourselves.
UINT8 bumpers;
INT16 karmadelay;
boolean eliminated;
// Bit flags.
// See pflags_t, above.
@ -553,6 +570,10 @@ typedef struct player_s
UINT16 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)
UINT8 tumbleBounces;
UINT16 tumbleHeight;
boolean tumbleLastBounce;
//
UINT32 charflags; // Extra abilities/settings for skins (combinable stuff)

View file

@ -1271,8 +1271,6 @@ static void readspriteframe(MYFILE *f, spriteinfo_t *sprinfo, UINT8 frame)
sprinfo->pivot[frame].x = value;
else if (fastcmp(word, "YPIVOT"))
sprinfo->pivot[frame].y = value;
else if (fastcmp(word, "ROTAXIS"))
sprinfo->pivot[frame].rotaxis = value;
else
{
f->curpos = lastline;
@ -6116,10 +6114,43 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FASTRING11",
"S_FASTRING12",
// Blue Sphere for special stages
// Blue Sphere
"S_BLUESPHERE",
"S_BLUESPHEREBONUS",
"S_BLUESPHERESPARK",
"S_BLUESPHERE_SPAWN",
"S_BLUESPHERE_BOUNCE1",
"S_BLUESPHERE_BOUNCE2",
"S_BLUESPHERE_BOUNCE3",
"S_BLUESPHERE_BOUNCE4",
"S_BLUESPHERE_BOUNCE5",
"S_BLUESPHERE_BOUNCE6",
"S_BLUESPHERE_BOUNCE7",
"S_BLUESPHERE_BOUNCE8",
"S_BLUESPHERE_BOUNCE9",
"S_BLUESPHERE_BOUNCE10",
"S_BLUESPHERE_BOUNCE11",
"S_BLUESPHERE_BOUNCE12",
"S_BLUESPHERE_BOUNCE13",
"S_BLUESPHERE_BOUNCE14",
"S_BLUESPHERE_BOUNCE15",
"S_BLUESPHERE_BOUNCE16",
"S_BLUESPHERE_BOUNCE17",
"S_BLUESPHERE_BOUNCE18",
"S_BLUESPHERE_BOUNCE19",
"S_BLUESPHERE_BOUNCE20",
"S_BLUESPHERE_BOUNCE21",
"S_BLUESPHERE_BOUNCE22",
"S_BLUESPHERE_BOUNCE23",
"S_BLUESPHERE_BOUNCE24",
"S_BLUESPHERE_BOUNCE25",
"S_BLUESPHERE_BOUNCE26",
"S_BLUESPHERE_BOUNCE27",
"S_BLUESPHERE_BOUNCE28",
// Bomb Sphere
"S_BOMBSPHERE1",
@ -6178,13 +6209,17 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_EMBLEM26",
// Chaos Emeralds
"S_CEMG1",
"S_CEMG2",
"S_CEMG3",
"S_CEMG4",
"S_CEMG5",
"S_CEMG6",
"S_CEMG7",
"S_CHAOSEMERALD1",
"S_CHAOSEMERALD2",
"S_CHAOSEMERALD_UNDER",
"S_EMERALDSPARK1",
"S_EMERALDSPARK2",
"S_EMERALDSPARK3",
"S_EMERALDSPARK4",
"S_EMERALDSPARK5",
"S_EMERALDSPARK6",
"S_EMERALDSPARK7",
// Emerald hunt shards
"S_SHRD1",
@ -8462,6 +8497,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_SLOWBOOM9",
"S_SLOWBOOM10",
// Land Mine
"S_LANDMINE",
"S_LANDMINE_EXPLODE",
// Ballhog
"S_BALLHOG1",
"S_BALLHOG2",
@ -8629,6 +8668,44 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_BATTLEBUMPER2",
"S_BATTLEBUMPER3",
"S_BATTLEBUMPER_EXCRYSTALA1",
"S_BATTLEBUMPER_EXCRYSTALA2",
"S_BATTLEBUMPER_EXCRYSTALA3",
"S_BATTLEBUMPER_EXCRYSTALA4",
"S_BATTLEBUMPER_EXCRYSTALB1",
"S_BATTLEBUMPER_EXCRYSTALB2",
"S_BATTLEBUMPER_EXCRYSTALB3",
"S_BATTLEBUMPER_EXCRYSTALB4",
"S_BATTLEBUMPER_EXCRYSTALC1",
"S_BATTLEBUMPER_EXCRYSTALC2",
"S_BATTLEBUMPER_EXCRYSTALC3",
"S_BATTLEBUMPER_EXCRYSTALC4",
"S_BATTLEBUMPER_EXSHELLA1",
"S_BATTLEBUMPER_EXSHELLA2",
"S_BATTLEBUMPER_EXSHELLB1",
"S_BATTLEBUMPER_EXSHELLB2",
"S_BATTLEBUMPER_EXSHELLC1",
"S_BATTLEBUMPER_EXSHELLC2",
"S_BATTLEBUMPER_EXDEBRIS1",
"S_BATTLEBUMPER_EXDEBRIS2",
"S_BATTLEBUMPER_EXBLAST1",
"S_BATTLEBUMPER_EXBLAST2",
"S_BATTLEBUMPER_EXBLAST3",
"S_BATTLEBUMPER_EXBLAST4",
"S_BATTLEBUMPER_EXBLAST5",
"S_BATTLEBUMPER_EXBLAST6",
"S_BATTLEBUMPER_EXBLAST7",
"S_BATTLEBUMPER_EXBLAST8",
"S_BATTLEBUMPER_EXBLAST9",
"S_BATTLEBUMPER_EXBLAST10",
// DEZ respawn laser
"S_DEZLASER",
"S_DEZLASER_TRAIL1",
@ -9229,9 +9306,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_TIREGREASE",
"S_OVERTIMEFOG",
"S_OVERTIMEORB",
"S_OVERTIMEBEAM",
"S_OVERTIME_BULB1",
"S_OVERTIME_BULB2",
"S_OVERTIME_LASER",
"S_OVERTIME_CENTER",
"S_BATTLECAPSULE_SIDE1",
"S_BATTLECAPSULE_SIDE2",
@ -9259,6 +9337,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_WATERTRAILUNDERLAY7",
"S_WATERTRAILUNDERLAY8",
"S_SPINDASHDUST",
"S_SPINDASHWIND",
#ifdef SEENAMES
"S_NAMECHECK",
#endif
@ -9407,16 +9488,10 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_REDFLAG", // Red CTF Flag
"MT_BLUEFLAG", // Blue CTF Flag
"MT_EMBLEM",
"MT_EMERALD1",
"MT_EMERALD2",
"MT_EMERALD3",
"MT_EMERALD4",
"MT_EMERALD5",
"MT_EMERALD6",
"MT_EMERALD7",
"MT_EMERALD",
"MT_EMERALDSPARK",
"MT_EMERHUNT", // Emerald Hunt
"MT_EMERALDSPAWN", // Emerald spawner w/ delay
"MT_FLINGEMERALD", // Lost emerald
// Springs and others
"MT_FAN",
@ -10093,6 +10168,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BOOMEXPLODE",
"MT_BOOMPARTICLE",
"MT_LANDMINE", // Land Mine
"MT_BALLHOG", // Ballhog
"MT_BALLHOGBOOM",
@ -10111,6 +10188,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_SINKTRAIL",
"MT_BATTLEBUMPER", // Battle Mode bumper
"MT_BATTLEBUMPER_DEBRIS",
"MT_BATTLEBUMPER_BLAST",
"MT_DEZLASER",
@ -10325,9 +10404,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_SPBDUST",
"MT_TIREGREASE",
"MT_OVERTIMEFOG",
"MT_OVERTIMEORB",
"MT_OVERTIMEBEAM",
"MT_OVERTIME_PARTICLE",
"MT_OVERTIME_CENTER",
"MT_BATTLECAPSULE",
"MT_BATTLECAPSULE_PIECE",
@ -10339,6 +10417,11 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_WATERTRAIL",
"MT_WATERTRAILUNDERLAY",
"MT_SPINDASHDUST",
"MT_SPINDASHWIND",
"MT_PAPERITEMSPOT",
#ifdef SEENAMES
"MT_NAMECHECK",
#endif
@ -10659,67 +10742,67 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart.
// Special super colors
// Super Sonic Yellow
"SUPER1", // SKINCOLOR_SUPER1
"SUPER2", // SKINCOLOR_SUPER2,
"SUPER3", // SKINCOLOR_SUPER3,
"SUPER4", // SKINCOLOR_SUPER4,
"SUPER5", // SKINCOLOR_SUPER5,
"SUPERSILVER1",
"SUPERSILVER2",
"SUPERSILVER3",
"SUPERSILVER4",
"SUPERSILVER5",
// Super Tails Orange
"TSUPER1", // SKINCOLOR_TSUPER1,
"TSUPER2", // SKINCOLOR_TSUPER2,
"TSUPER3", // SKINCOLOR_TSUPER3,
"TSUPER4", // SKINCOLOR_TSUPER4,
"TSUPER5", // SKINCOLOR_TSUPER5,
"SUPERRED1",
"SUPERRED2",
"SUPERRED3",
"SUPERRED4",
"SUPERRED5",
// Super Knuckles Red
"KSUPER1", // SKINCOLOR_KSUPER1,
"KSUPER2", // SKINCOLOR_KSUPER2,
"KSUPER3", // SKINCOLOR_KSUPER3,
"KSUPER4", // SKINCOLOR_KSUPER4,
"KSUPER5", // SKINCOLOR_KSUPER5,
"SUPERORANGE1",
"SUPERORANGE2",
"SUPERORANGE3",
"SUPERORANGE4",
"SUPERORANGE5",
// Hyper Sonic Pink
"PSUPER1", // SKINCOLOR_PSUPER1,
"PSUPER2", // SKINCOLOR_PSUPER2,
"PSUPER3", // SKINCOLOR_PSUPER3,
"PSUPER4", // SKINCOLOR_PSUPER4,
"PSUPER5", // SKINCOLOR_PSUPER5,
"SUPERGOLD1",
"SUPERGOLD2",
"SUPERGOLD3",
"SUPERGOLD4",
"SUPERGOLD5",
// Hyper Sonic Blue
"BSUPER1", // SKINCOLOR_BSUPER1,
"BSUPER2", // SKINCOLOR_BSUPER2,
"BSUPER3", // SKINCOLOR_BSUPER3,
"BSUPER4", // SKINCOLOR_BSUPER4,
"BSUPER5", // SKINCOLOR_BSUPER5,
"SUPERPERIDOT1",
"SUPERPERIDOT2",
"SUPERPERIDOT3",
"SUPERPERIDOT4",
"SUPERPERIDOT5",
// Aqua Super
"ASUPER1", // SKINCOLOR_ASUPER1,
"ASUPER2", // SKINCOLOR_ASUPER2,
"ASUPER3", // SKINCOLOR_ASUPER3,
"ASUPER4", // SKINCOLOR_ASUPER4,
"ASUPER5", // SKINCOLOR_ASUPER5,
"SUPERSKY1",
"SUPERSKY2",
"SUPERSKY3",
"SUPERSKY4",
"SUPERSKY5",
// Hyper Sonic Green
"GSUPER1", // SKINCOLOR_GSUPER1,
"GSUPER2", // SKINCOLOR_GSUPER2,
"GSUPER3", // SKINCOLOR_GSUPER3,
"GSUPER4", // SKINCOLOR_GSUPER4,
"GSUPER5", // SKINCOLOR_GSUPER5,
"SUPERPURPLE1",
"SUPERPURPLE2",
"SUPERPURPLE3",
"SUPERPURPLE4",
"SUPERPURPLE5",
// Hyper Sonic White
"WSUPER1", // SKINCOLOR_WSUPER1,
"WSUPER2", // SKINCOLOR_WSUPER2,
"WSUPER3", // SKINCOLOR_WSUPER3,
"WSUPER4", // SKINCOLOR_WSUPER4,
"WSUPER5", // SKINCOLOR_WSUPER5,
"SUPERRUST1",
"SUPERRUST2",
"SUPERRUST3",
"SUPERRUST4",
"SUPERRUST5",
// Creamy Super (Shadow?)
"CSUPER1", // SKINCOLOR_CSUPER1,
"CSUPER2", // SKINCOLOR_CSUPER2,
"CSUPER3", // SKINCOLOR_CSUPER3,
"CSUPER4", // SKINCOLOR_CSUPER4,
"CSUPER5" // SKINCOLOR_CSUPER5,
"SUPERTAN1",
"SUPERTAN2",
"SUPERTAN3",
"SUPERTAN4",
"SUPERTAN5",
"CHAOSEMERALD1",
"CHAOSEMERALD2",
"CHAOSEMERALD3",
"CHAOSEMERALD4",
"CHAOSEMERALD5",
"CHAOSEMERALD6",
"CHAOSEMERALD7"
};
static const char *const POWERS_LIST[] = {
@ -10793,7 +10876,7 @@ static const char *const KARTSTUFF_LIST[] = {
"SPARKLEANIM",
"JMP",
"OFFROAD",
"POGOSPRING",
"BRAKESTOP",
"SPINDASH",
"SPINDASHSPEED",
"SPINDASHBOOST",
@ -11111,13 +11194,23 @@ struct {
{"LF2_VISITNEEDED",LF2_VISITNEEDED},
// Emeralds
{"EMERALD1",EMERALD1},
{"EMERALD2",EMERALD2},
{"EMERALD3",EMERALD3},
{"EMERALD4",EMERALD4},
{"EMERALD5",EMERALD5},
{"EMERALD6",EMERALD6},
{"EMERALD7",EMERALD7},
{"EMERALD_CHAOS1",EMERALD_CHAOS1},
{"EMERALD_CHAOS2",EMERALD_CHAOS2},
{"EMERALD_CHAOS3",EMERALD_CHAOS3},
{"EMERALD_CHAOS4",EMERALD_CHAOS4},
{"EMERALD_CHAOS5",EMERALD_CHAOS5},
{"EMERALD_CHAOS6",EMERALD_CHAOS6},
{"EMERALD_CHAOS7",EMERALD_CHAOS7},
{"EMERALD_ALLCHAOS",EMERALD_ALLCHAOS},
{"EMERALD_SUPER1",EMERALD_SUPER1},
{"EMERALD_SUPER2",EMERALD_SUPER2},
{"EMERALD_SUPER3",EMERALD_SUPER3},
{"EMERALD_SUPER4",EMERALD_SUPER4},
{"EMERALD_SUPER5",EMERALD_SUPER5},
{"EMERALD_SUPER6",EMERALD_SUPER6},
{"EMERALD_SUPER7",EMERALD_SUPER7},
{"EMERALD_ALLSUPER",EMERALD_ALLSUPER},
{"EMERALD_ALL",EMERALD_ALL},
// SKINCOLOR_ doesn't include these..!
{"MAXSKINCOLORS",MAXSKINCOLORS},
@ -11209,8 +11302,9 @@ struct {
{"DMG_NORMAL",DMG_NORMAL},
{"DMG_WIPEOUT",DMG_WIPEOUT},
{"DMG_EXPLODE",DMG_EXPLODE},
{"DMG_SQUISH",DMG_SQUISH},
{"DMG_TUMBLE",DMG_TUMBLE},
{"DMG_STING",DMG_STING},
{"DMG_KARMA",DMG_KARMA},
//// Death types
{"DMG_INSTAKILL",DMG_INSTAKILL},
{"DMG_DEATHPIT",DMG_DEATHPIT},
@ -11422,11 +11516,6 @@ struct {
{"DI_SOUTHEAST",DI_SOUTHEAST},
{"NUMDIRS",NUMDIRS},
// Sprite rotation axis (rotaxis_t)
{"ROTAXIS_X",ROTAXIS_X},
{"ROTAXIS_Y",ROTAXIS_Y},
{"ROTAXIS_Z",ROTAXIS_Z},
// Buttons (ticcmd_t) // SRB2kart
{"BT_ACCELERATE",BT_ACCELERATE},
{"BT_DRIFT",BT_DRIFT},

View file

@ -12,9 +12,7 @@
#ifdef HAVE_DISCORDRPC
#ifdef HAVE_CURL
#include <curl/curl.h>
#endif // HAVE_CURL
#include <time.h>
#include "i_system.h"
#include "d_clisrv.h"
@ -27,6 +25,8 @@
#include "mserv.h" // cv_advertise
#include "z_zone.h"
#include "byteptr.h"
#include "stun.h"
#include "i_tcp.h" // current_port
#include "discord.h"
#include "doomdef.h"
@ -45,16 +45,7 @@ struct discordInfo_s discordInfo;
discordRequest_t *discordRequestList = NULL;
#ifdef HAVE_CURL
struct SelfIPbuffer
{
CURL *curl;
char *pointer;
size_t length;
};
static char self_ip[IP_SIZE];
#endif // HAVE_CURL
/*--------------------------------------------------
static char *DRPC_XORIPString(const char *input)
@ -335,39 +326,23 @@ void DRPC_Init(void)
DRPC_UpdatePresence();
}
#ifdef HAVE_CURL
/*--------------------------------------------------
static size_t DRPC_WriteServerIP(char *s, size_t size, size_t n, void *userdata)
static void DRPC_GotServerIP(UINT32 address)
Writing function for use with curl. Only intended to be used with simple text.
Callback triggered by successful STUN response.
Input Arguments:-
s - Data to write
size - Always 1.
n - Length of data
userdata - Passed in from CURLOPT_WRITEDATA, intended to be SelfIPbuffer
address - IPv4 address of this machine, in network byte order.
Return:-
Number of bytes wrote in this pass.
None
--------------------------------------------------*/
static size_t DRPC_WriteServerIP(char *s, size_t size, size_t n, void *userdata)
static void DRPC_GotServerIP(UINT32 address)
{
struct SelfIPbuffer *buffer;
size_t newlength;
buffer = userdata;
newlength = buffer->length + size*n;
buffer->pointer = realloc(buffer->pointer, newlength+1);
memcpy(buffer->pointer + buffer->length, s, size*n);
buffer->pointer[newlength] = '\0';
buffer->length = newlength;
return size*n;
const unsigned char * p = (const unsigned char *)&address;
sprintf(self_ip, "%u.%u.%u.%u:%u", p[0], p[1], p[2], p[3], current_port);
DRPC_UpdatePresence();
}
#endif // HAVE_CURL
/*--------------------------------------------------
static const char *DRPC_GetServerIP(void)
@ -387,64 +362,21 @@ static const char *DRPC_GetServerIP(void)
{
// We're not the server, so we could successfully get the IP!
// No need to do anything else :)
return address;
sprintf(self_ip, "%s:%u", address, current_port);
return self_ip;
}
}
#ifdef HAVE_CURL
// This is a little bit goofy, but
// there's practically no good way to get your own public IP address,
// so we've gotta break out curl for this :V
if (!self_ip[0])
{
CURL *curl;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl)
{
// The API to get your public IP address from.
// Picked because it's stupid simple and it's been up for a long time.
const char *api = "http://ip4only.me/api/";
struct SelfIPbuffer buffer;
CURLcode success;
buffer.length = 0;
buffer.pointer = malloc(buffer.length+1);
buffer.pointer[0] = '\0';
curl_easy_setopt(curl, CURLOPT_URL, api);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DRPC_WriteServerIP);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
success = curl_easy_perform(curl);
if (success == CURLE_OK)
{
char *tmp;
tmp = strtok(buffer.pointer, ",");
if (!strcmp(tmp, "IPv4")) // ensure correct type of IP
{
tmp = strtok(NULL, ",");
strncpy(self_ip, tmp, IP_SIZE); // Yay, we have the IP :)
}
}
free(buffer.pointer);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}
if (self_ip[0])
{
return self_ip;
}
else
#endif // HAVE_CURL
return NULL; // Could not get your IP for whatever reason, so we cannot do Discord invites
{
// There happens to be a good way to get it after all! :D
STUN_bind(DRPC_GotServerIP);
return NULL;
}
}
/*--------------------------------------------------
@ -510,19 +442,6 @@ void DRPC_UpdatePresence(void)
// Server info
if (netgame)
{
if (cv_advertise.value)
{
discordPresence.state = "Public";
}
else
{
discordPresence.state = "Private";
}
discordPresence.partyId = server_context; // Thanks, whoever gave us Mumble support, for implementing the EXACT thing Discord wanted for this field!
discordPresence.partySize = D_NumPlayers(); // Players in server
discordPresence.partyMax = discordInfo.maxPlayers; // Max players
if (DRPC_InvitesAreAllowed() == true)
{
const char *join;
@ -536,7 +455,24 @@ void DRPC_UpdatePresence(void)
joinSecretSet = true;
}
else
{
return;
}
}
if (cv_advertise.value)
{
discordPresence.state = "Public";
}
else
{
discordPresence.state = "Private";
}
discordPresence.partyId = server_context; // Thanks, whoever gave us Mumble support, for implementing the EXACT thing Discord wanted for this field!
discordPresence.partySize = D_NumPlayers(); // Players in server
discordPresence.partyMax = discordInfo.maxPlayers; // Max players
}
else
{

View file

@ -386,6 +386,14 @@ typedef enum
SKINCOLOR_SUPERTAN4,
SKINCOLOR_SUPERTAN5,
SKINCOLOR_CHAOSEMERALD1,
SKINCOLOR_CHAOSEMERALD2,
SKINCOLOR_CHAOSEMERALD3,
SKINCOLOR_CHAOSEMERALD4,
SKINCOLOR_CHAOSEMERALD5,
SKINCOLOR_CHAOSEMERALD6,
SKINCOLOR_CHAOSEMERALD7,
SKINCOLOR_FIRSTFREESLOT,
SKINCOLOR_LASTFREESLOT = SKINCOLOR_FIRSTFREESLOT + NUMCOLORFREESLOTS - 1,
@ -661,10 +669,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// Render flats on walls
#define WALLFLATS
/// - SRB2Kart options -
/// Camera always has noclip.
#define NOCLIPCAM
/// Divide volume of music and sounds by this much (loudest sounds on earth)
#define VOLUME_DIVIDER 4
#define USER_VOLUME_SCALE 2
@ -682,4 +686,11 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
#undef UPDATE_ALERT
#endif
/// - SRB2Kart options -
/// Camera always has noclip.
#define NOCLIPCAM
/// Other karma comeback modes
//#define OTHERKARMAMODES
#endif // __DOOMDEF__

View file

@ -454,30 +454,31 @@ enum GameTypeRules
{
// Race rules
GTR_CIRCUIT = 1, // Enables the finish line, laps, and the waypoint system.
GTR_RINGS = 1<<1, // Rings will be spawned in this mode. (Don't get too cheeky, ring sting is still enabled :])
GTR_BOTS = 1<<2, // Allows bots in this gametype. Combine with BotTiccmd hooks to make bots support your gametype.
// Battle gametype rules
GTR_BUMPERS = 1<<3, // Enables the bumper health system
GTR_WANTED = 1<<4, // Enables the wanted anti-camping system
GTR_KARMA = 1<<5, // Enables the Karma system if you're out of bumpers
GTR_ITEMARROWS = 1<<6, // Show item box arrows above players
GTR_CAPSULES = 1<<7, // Enables the wanted anti-camping system
GTR_BATTLESTARTS = 1<<8, // Use Battle Mode start positions.
GTR_SPHERES = 1<<4, // Replaces rings with blue spheres
GTR_PAPERITEMS = 1<<5, // Replaces item boxes with paper item spawners
GTR_WANTED = 1<<6, // Enables the wanted anti-camping system
GTR_KARMA = 1<<7, // Enables the Karma system if you're out of bumpers
GTR_ITEMARROWS = 1<<8, // Show item box arrows above players
GTR_CAPSULES = 1<<9, // Enables the wanted anti-camping system
GTR_BATTLESTARTS = 1<<10, // Use Battle Mode start positions.
GTR_POINTLIMIT = 1<<9, // Reaching point limit ends the round
GTR_TIMELIMIT = 1<<10, // Reaching time limit ends the round
GTR_OVERTIME = 1<<11, // Allow overtime behavior
GTR_POINTLIMIT = 1<<11, // Reaching point limit ends the round
GTR_TIMELIMIT = 1<<12, // Reaching time limit ends the round
GTR_OVERTIME = 1<<13, // Allow overtime behavior
// Custom gametype rules
GTR_TEAMS = 1<<12, // Teams are forced on
GTR_NOTEAMS = 1<<13, // Teams are forced off
GTR_TEAMSTARTS = 1<<14, // Use team-based start positions
GTR_TEAMS = 1<<14, // Teams are forced on
GTR_NOTEAMS = 1<<15, // Teams are forced off
GTR_TEAMSTARTS = 1<<16, // Use team-based start positions
// Grand Prix rules
GTR_CAMPAIGN = 1<<15, // Handles cup-based progression
GTR_LIVES = 1<<16, // Lives system, players are forced to spectate during Game Over.
GTR_SPECIALBOTS = 1<<17, // Bot difficulty gets stronger between rounds, and the rival system is enabled.
GTR_CAMPAIGN = 1<<17, // Handles cup-based progression
GTR_LIVES = 1<<18, // Lives system, players are forced to spectate during Game Over.
GTR_SPECIALBOTS = 1<<19, // Bot difficulty gets stronger between rounds, and the rival system is enabled.
// free: to and including 1<<31
};
@ -519,15 +520,34 @@ extern UINT32 matchesplayed;
extern UINT8 stagefailed;
// Emeralds stored as bits to throw savegame hackers off.
typedef enum
{
EMERALD_CHAOS1 = 1,
EMERALD_CHAOS2 = 1<<1,
EMERALD_CHAOS3 = 1<<2,
EMERALD_CHAOS4 = 1<<3,
EMERALD_CHAOS5 = 1<<4,
EMERALD_CHAOS6 = 1<<5,
EMERALD_CHAOS7 = 1<<6,
EMERALD_ALLCHAOS = EMERALD_CHAOS1|EMERALD_CHAOS2|EMERALD_CHAOS3|EMERALD_CHAOS4|EMERALD_CHAOS5|EMERALD_CHAOS6|EMERALD_CHAOS7,
EMERALD_SUPER1 = 1<<7,
EMERALD_SUPER2 = 1<<8,
EMERALD_SUPER3 = 1<<9,
EMERALD_SUPER4 = 1<<10,
EMERALD_SUPER5 = 1<<11,
EMERALD_SUPER6 = 1<<12,
EMERALD_SUPER7 = 1<<13,
EMERALD_ALLSUPER = EMERALD_SUPER1|EMERALD_SUPER2|EMERALD_SUPER3|EMERALD_SUPER4|EMERALD_SUPER5|EMERALD_SUPER6|EMERALD_SUPER7,
EMERALD_ALL = EMERALD_ALLCHAOS|EMERALD_ALLSUPER
} emeraldflags_t;
extern UINT16 emeralds;
#define EMERALD1 1
#define EMERALD2 2
#define EMERALD3 4
#define EMERALD4 8
#define EMERALD5 16
#define EMERALD6 32
#define EMERALD7 64
#define ALL7EMERALDS(v) ((v & (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) == (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7))
#define ALLCHAOSEMERALDS(v) ((v & EMERALD_ALLCHAOS) == EMERALD_ALLCHAOS)
#define ALLSUPEREMERALDS(v) ((v & EMERALD_ALLSUPER) == EMERALD_ALLSUPER)
#define ALLEMERALDS(v) ((v & EMERALD_ALL) == EMERALD_ALL)
#define NUM_LUABANKS 16 // please only make this number go up between versions, never down. you'll break saves otherwise. also, must fit in UINT8
extern INT32 luabanks[NUM_LUABANKS];

View file

@ -889,7 +889,7 @@ void F_StartGameEvaluation(void)
// Just in case they're open ... somehow
M_ClearMenus(true);
goodending = (ALL7EMERALDS(emeralds));
goodending = (ALLCHAOSEMERALDS(emeralds));
gameaction = ga_nothing;
paused = false;
@ -1154,7 +1154,7 @@ static void F_CacheEnding(void)
endescp[4] = W_CachePatchName("ENDESCP4", PU_PATCH);
// so we only need to check once
if ((goodending = ALL7EMERALDS(emeralds)))
if ((goodending = ALLCHAOSEMERALDS(emeralds)))
{
endfwrk[0] = W_CachePatchName("ENDFWRK3", PU_PATCH);
endfwrk[1] = W_CachePatchName("ENDFWRK4", PU_PATCH);

View file

@ -104,7 +104,7 @@ demoghost *ghosts = NULL;
// DEMO RECORDING
//
#define DEMOVERSION 0x0004
#define DEMOVERSION 0x0007
#define DEMOHEADER "\xF0" "KartReplay" "\x0F"
#define DF_GHOST 0x01 // This demo contains ghost data too!
@ -112,7 +112,7 @@ demoghost *ghosts = NULL;
#define DF_BREAKTHECAPSULES 0x04 // This demo is from Break the Capsules and contains its final completion time!
#define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ???
#define DF_LUAVARS 0x20 // this demo contains extra lua vars; this is mostly used for backwards compability
#define DF_LUAVARS 0x20 // this demo contains extra lua vars
#define DF_ATTACKSHIFT 1
#define DF_ENCORE 0x40
@ -318,10 +318,6 @@ void G_ReadDemoExtraData(void)
playeringame[p] = true;
G_AddPlayer(p);
players[p].spectator = true;
// There's likely an off-by-one error in timing recording or playback of joins. This hacks around it so I don't have to find out where that is. \o/
if (oldcmd[p].forwardmove)
P_RandomByte();
}
else
{
@ -423,7 +419,10 @@ void G_WriteDemoExtraData(void)
{
// write follower
memset(name, 0, 16);
strncpy(name, followers[players[i].followerskin].skinname, 16);
if (players[i].followerskin == -1)
strncpy(name, "None", 16);
else
strncpy(name, followers[players[i].followerskin].skinname, 16);
M_Memcpy(demo_p, name, 16);
demo_p += 16;
@ -623,13 +622,21 @@ void G_WriteAllGhostTics(void)
counter++;
if (counter % cv_netdemosyncquality.value != 0) // Only write 1 in this many ghost datas per tic to cut down on multiplayer replay size.
if (multiplayer && ((counter % cv_netdemosyncquality.value) != 0)) // Only write 1 in this many ghost datas per tic to cut down on multiplayer replay size.
continue;
WRITEUINT8(demo_p, i);
G_WriteGhostTic(players[i].mo, i);
}
WRITEUINT8(demo_p, 0xFF);
// attention here for the ticcmd size!
// latest demos with mouse aiming byte in ticcmd
if (demo_p >= demoend - (13 + 9 + 9))
{
G_CheckDemoStatus(); // no more space
return;
}
}
void G_WriteGhostTic(mobj_t *ghost, INT32 playernum)
@ -726,26 +733,22 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum)
ghostext[playernum].flags |= EZT_SPRITE;
}
if (ghost->player && (
ghostext[playernum].kartitem != ghost->player->kartstuff[k_itemtype] ||
ghostext[playernum].kartamount != ghost->player->kartstuff[k_itemamount] ||
ghostext[playernum].kartbumpers != ghost->player->kartstuff[k_bumper]
))
{
ghostext[playernum].flags |= EZT_KART;
ghostext[playernum].kartitem = ghost->player->kartstuff[k_itemtype];
ghostext[playernum].kartamount = ghost->player->kartstuff[k_itemamount];
ghostext[playernum].kartbumpers = ghost->player->kartstuff[k_bumper];
}
if (ghostext[playernum].flags)
{
ziptic |= GZT_EXTRA;
if (ghost->player)
{
if (
ghostext[playernum].kartitem != ghost->player->kartstuff[k_itemtype] ||
ghostext[playernum].kartamount != ghost->player->kartstuff[k_itemamount] ||
ghostext[playernum].kartbumpers != ghost->player->kartstuff[k_bumper]
)
{
ghostext[playernum].flags |= EZT_KART;
ghostext[playernum].kartitem = ghost->player->kartstuff[k_itemtype];
ghostext[playernum].kartamount = ghost->player->kartstuff[k_itemamount];
ghostext[playernum].kartbumpers = ghost->player->kartstuff[k_bumper];
}
}
if (ghostext[playernum].color == ghostext[playernum].lastcolor)
ghostext[playernum].flags &= ~EZT_COLOR;
if (ghostext[playernum].scale == ghostext[playernum].lastscale)
@ -840,14 +843,6 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum)
oldghost[playernum].flags2 &= ~MF2_AMBUSH;
*ziptic_p = ziptic;
// attention here for the ticcmd size!
// latest demos with mouse aiming byte in ticcmd
if (demo_p >= demoend - (13 + 9 + 9))
{
G_CheckDemoStatus(); // no more space
return;
}
}
void G_ConsAllGhostTics(void)
@ -1071,16 +1066,18 @@ void G_GhostTicker(void)
if (ziptic & DXD_FOLLOWER)
g->p += 32; // ok (32 because there's both the skin and the colour)
if (ziptic & DXD_PLAYSTATE && READUINT8(g->p) != DXD_PST_PLAYING)
I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this
I_Error("Ghost is not a record attack ghost PLAYSTATE"); //@TODO lmao don't blow up like this
}
else if (ziptic == DW_RNG)
g->p += 4; // RNG seed
else
I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this
I_Error("Ghost is not a record attack ghost DXD"); //@TODO lmao don't blow up like this
ziptic = READUINT8(g->p);
}
ziptic = READUINT8(g->p);
if (ziptic & ZT_FWD)
g->p++;
if (ziptic & ZT_TURNING)
@ -1090,9 +1087,9 @@ void G_GhostTicker(void)
if (ziptic & ZT_AIMING)
g->p += 2;
if (ziptic & ZT_LATENCY)
g->p += 1;
g->p++;
if (ziptic & ZT_FLAGS)
g->p += 1;
g->p++;
// Grab ghost data.
ziptic = READUINT8(g->p);
@ -1100,7 +1097,7 @@ void G_GhostTicker(void)
if (ziptic == 0xFF)
goto skippedghosttic; // Didn't write ghost info this frame
else if (ziptic != 0)
I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this
I_Error("Ghost is not a record attack ghost ZIPTIC"); //@TODO lmao don't blow up like this
ziptic = READUINT8(g->p);
if (ziptic & GZT_XYZ)
@ -1113,17 +1110,17 @@ void G_GhostTicker(void)
{
if (ziptic & GZT_MOMXY)
{
g->oldmo.momx = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
g->oldmo.momy = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
g->oldmo.momx = READFIXED(g->p);
g->oldmo.momy = READFIXED(g->p);
}
if (ziptic & GZT_MOMZ)
g->oldmo.momz = (g->version < 0x000e) ? READINT16(g->p)<<8 : READFIXED(g->p);
g->oldmo.momz = READFIXED(g->p);
g->oldmo.x += g->oldmo.momx;
g->oldmo.y += g->oldmo.momy;
g->oldmo.z += g->oldmo.momz;
}
if (ziptic & GZT_ANGLE)
g->mo->angle = READUINT8(g->p)<<24;
g->oldmo.angle = READUINT8(g->p)<<24;
if (ziptic & GZT_FRAME)
g->oldmo.frame = READUINT8(g->p);
if (ziptic & GZT_SPR2)
@ -1209,30 +1206,6 @@ void G_GhostTicker(void)
g->p += 12; // kartitem, kartamount, kartbumpers
}
if (READUINT8(g->p) != 0xFF) // Make sure there isn't other ghost data here.
I_Error("Ghost is not a record attack ghost"); //@TODO lmao don't blow up like this
skippedghosttic:
// Tick ghost colors (Super and Mario Invincibility flashing)
switch(g->color)
{
case GHC_SUPER: // Super (P_DoSuperStuff)
if (g->mo->skin)
{
skin_t *skin = (skin_t *)g->mo->skin;
g->mo->color = skin->supercolor;
}
else
g->mo->color = SKINCOLOR_SUPERGOLD1;
g->mo->color += abs( ( (signed)( (unsigned)leveltime >> 1 ) % 9) - 4);
break;
case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer)
g->mo->color = (UINT16)(SKINCOLOR_RUBY + (leveltime % (FIRSTSUPERCOLOR - SKINCOLOR_RUBY))); // Passes through all saturated colours
break;
default:
break;
}
#define follow g->mo->tracer
if (ziptic & GZT_FOLLOW)
{ // Even more...
@ -1298,6 +1271,31 @@ skippedghosttic:
P_RemoveMobj(follow);
P_SetTarget(&follow, NULL);
}
skippedghosttic:
// Tick ghost colors (Super and Mario Invincibility flashing)
switch(g->color)
{
case GHC_SUPER: // Super (P_DoSuperStuff)
if (g->mo->skin)
{
skin_t *skin = (skin_t *)g->mo->skin;
g->mo->color = skin->supercolor;
}
else
g->mo->color = SKINCOLOR_SUPERGOLD1;
g->mo->color += abs( ( (signed)( (unsigned)leveltime >> 1 ) % 9) - 4);
break;
case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer)
g->mo->color = (UINT16)(SKINCOLOR_RUBY + (leveltime % (FIRSTSUPERCOLOR - SKINCOLOR_RUBY))); // Passes through all saturated colours
break;
default:
break;
}
if (READUINT8(g->p) != 0xFF) // Make sure there isn't other ghost data here.
I_Error("Ghost is not a record attack ghost GHOSTEND"); //@TODO lmao don't blow up like this
// Demo ends after ghost data.
if (*g->p == DEMOMARKER)
{
@ -1318,6 +1316,7 @@ skippedghosttic:
Z_Free(g);
continue;
}
p = g;
#undef follow
}
@ -1440,8 +1439,11 @@ void G_PreviewRewind(tic_t previewtime)
players[i].drawangle = info->playerinfo[i].player.drawangle + FixedMul((INT32) (next_info->playerinfo[i].player.drawangle - info->playerinfo[i].player.drawangle), tweenvalue);
players[i].mo->sprite = info->playerinfo[i].mobj.sprite;
players[i].mo->sprite2 = info->playerinfo[i].mobj.sprite2;
players[i].mo->frame = info->playerinfo[i].mobj.frame;
players[i].mo->hitlag = info->playerinfo[i].mobj.hitlag;
players[i].realtime = info->playerinfo[i].player.realtime;
for (j = 0; j < NUMKARTSTUFF; j++)
players[i].kartstuff[j] = info->playerinfo[i].player.kartstuff[j];
@ -1466,7 +1468,7 @@ void G_ConfirmRewind(tic_t rewindtime)
if (rewindtime <= starttime)
{
demo.rewinding = false;
demo.rewinding = true; // this doesn't APPEAR to cause any misery, and it allows us to prevent running all the wipes again
G_DoPlayDemo(NULL); // Restart the current demo
}
else
@ -1903,7 +1905,8 @@ void G_BeginRecording(void)
if (encoremode)
demoflags |= DF_ENCORE;
demoflags |= DF_LUAVARS;
if (multiplayer)
demoflags |= DF_LUAVARS;
// Setup header.
M_Memcpy(demo_p, DEMOHEADER, 12); demo_p += 12;
@ -2037,9 +2040,8 @@ void G_BeginRecording(void)
WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing
// player lua vars, always saved even if empty
LUA_Archive(&demo_p);
WRITEUINT32(demo_p,P_GetInitSeed());
if (demoflags & DF_LUAVARS)
LUA_Archive(&demo_p);
memset(&oldcmd,0,sizeof(oldcmd));
memset(&oldghost,0,sizeof(oldghost));
@ -2716,7 +2718,6 @@ void G_DoPlayDemo(char *defdemoname)
demo.version = READUINT16(demo_p);
switch(demo.version)
{
case 0x000d:
case DEMOVERSION: // latest always supported
break;
// too old, cannot support.
@ -3105,7 +3106,6 @@ void G_AddGhost(char *defdemoname)
ghostversion = READUINT16(p);
switch(ghostversion)
{
case 0x000d:
case DEMOVERSION: // latest always supported
break;
// too old, cannot support.
@ -3149,6 +3149,14 @@ void G_AddGhost(char *defdemoname)
return;
}
if (flags & DF_LUAVARS) // can't be arsed to add support for grinding away ported lua material
{
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Replay data contains luavars, cannot continue.\n"), pdemoname);
Z_Free(pdemoname);
Z_Free(buffer);
return;
}
p++; // gametype
G_SkipDemoExtraFiles(&p); // Don't wanna modify the file list for ghosts.
@ -3215,6 +3223,8 @@ void G_AddGhost(char *defdemoname)
kartspeed = READUINT8(p);
kartweight = READUINT8(p);
p += 4; // followitem (maybe change later)
if (READUINT8(p) != 0xFF)
{
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname);

View file

@ -1264,7 +1264,7 @@ void G_StartTitleCard(void)
{
// The title card has been disabled for this map.
// Oh well.
if (!G_IsTitleCardAvailable())
if (!G_IsTitleCardAvailable() || demo.rewinding)
{
WipeStageTitle = false;
return;
@ -1587,7 +1587,7 @@ boolean G_CouldView(INT32 playernum)
// I don't know if we want this actually, but I'll humor the suggestion anyway
if ((gametyperules & GTR_BUMPERS) && !demo.playback)
{
if (player->kartstuff[k_bumper] <= 0)
if (player->bumpers <= 0)
return false;
}
@ -2068,6 +2068,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
UINT8 botdifficulty;
INT16 rings;
INT16 spheres;
angle_t playerangleturn;
UINT8 botdiffincrease;
@ -2083,9 +2084,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
INT32 roulettetype;
INT32 growshrinktimer;
INT32 bumper;
INT32 comebackpoints;
INT32 wanted;
boolean songcredit = false;
boolean eliminated;
score = players[player].score;
marescore = players[player].marescore;
@ -2151,8 +2152,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
itemamount = 0;
growshrinktimer = 0;
bumper = ((gametyperules & GTR_BUMPERS) ? K_StartingBumperCount() : 0);
rings = ((gametyperules & GTR_RINGS) ? 5 : 0);
comebackpoints = 0;
rings = ((gametyperules & GTR_SPHERES) ? 0 : 5);
spheres = 0;
eliminated = false;
wanted = 0;
}
else
@ -2177,9 +2179,10 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
else
growshrinktimer = 0;
bumper = players[player].kartstuff[k_bumper];
bumper = players[player].bumpers;
rings = players[player].rings;
comebackpoints = players[player].kartstuff[k_comebackpoints];
spheres = players[player].spheres;
eliminated = players[player].eliminated;
wanted = players[player].kartstuff[k_wanted];
}
@ -2227,6 +2230,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->bot = bot;
p->botvars.difficulty = botdifficulty;
p->rings = rings;
p->spheres = spheres;
p->botvars.diffincrease = botdiffincrease;
p->botvars.rival = botrival;
p->xtralife = xtralife;
@ -2237,9 +2241,9 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->kartstuff[k_itemtype] = itemtype;
p->kartstuff[k_itemamount] = itemamount;
p->kartstuff[k_growshrinktimer] = growshrinktimer;
p->kartstuff[k_bumper] = bumper;
p->kartstuff[k_comebackpoints] = comebackpoints;
p->kartstuff[k_comebacktimer] = comebacktime;
p->bumpers = bumper;
p->karmadelay = comebacktime;
p->eliminated = eliminated;
p->kartstuff[k_wanted] = wanted;
p->kartstuff[k_eggmanblame] = -1;
p->kartstuff[k_lastdraft] = -1;
@ -2799,9 +2803,9 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] =
UINT32 gametypedefaultrules[NUMGAMETYPES] =
{
// Race
GTR_CIRCUIT|GTR_RINGS|GTR_BOTS,
GTR_CIRCUIT|GTR_BOTS,
// Battle
GTR_BUMPERS|GTR_WANTED|GTR_KARMA|GTR_ITEMARROWS|GTR_CAPSULES|GTR_BATTLESTARTS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME
GTR_SPHERES|GTR_BUMPERS|GTR_PAPERITEMS|GTR_WANTED|GTR_KARMA|GTR_ITEMARROWS|GTR_CAPSULES|GTR_BATTLESTARTS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME
};
//

View file

@ -101,21 +101,13 @@ typedef struct
//Hurdler: Transform (coords + angles)
//BP: transform order : scale(rotation_x(rotation_y(translation(v))))
// Kart features
//#define USE_FTRANSFORM_ANGLEZ
//#define USE_FTRANSFORM_MIRROR
// Vanilla features
#define USE_MODEL_NEXTFRAME
typedef struct
{
FLOAT x,y,z; // position
#ifdef USE_FTRANSFORM_ANGLEZ
FLOAT anglex,angley,anglez; // aimingangle / viewangle
#else
FLOAT anglex,angley; // aimingangle / viewangle
#endif
FLOAT scalex,scaley,scalez;
FLOAT fovxangle, fovyangle;
UINT8 splitscreen;
@ -123,13 +115,10 @@ typedef struct
boolean shearing; // 14042019
angle_t viewaiming; // 17052019
boolean roll;
SINT8 rollflip;
FLOAT rollangle; // done to not override USE_FTRANSFORM_ANGLEZ
UINT8 rotaxis;
FLOAT centerx, centery;
#ifdef USE_FTRANSFORM_MIRROR
FLOAT rollx, rollz;
boolean mirror; // SRB2Kart: Encore Mode
#endif
} FTransform;
// Transformed vector, as passed to HWR API

View file

@ -50,7 +50,7 @@ EXPORT void HWRAPI(ClearMipMapCache) (void);
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
//Hurdler: added for new development
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface, FBITFIELD blendmode);
EXPORT void HWRAPI(CreateModelVBOs) (model_t *model);
EXPORT void HWRAPI(SetTransform) (FTransform *stransform);
EXPORT INT32 HWRAPI(GetTextureUsed) (void);

View file

@ -3617,9 +3617,9 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v
static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
{
const fixed_t thingxpos = thing->x + thing->sprxoff;
const fixed_t thingypos = thing->y + thing->spryoff;
const fixed_t thingzpos = thing->z + thing->sprzoff;
fixed_t thingxpos = thing->x + thing->sprxoff;
fixed_t thingypos = thing->y + thing->spryoff;
fixed_t thingzpos = thing->z + thing->sprzoff;
GLPatch_t *gpatch;
FOutVector shadowVerts[4];
@ -3637,6 +3637,21 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
fixed_t slopez;
pslope_t *groundslope;
// hitlag vibrating
if (thing->hitlag > 0)
{
fixed_t mul = thing->hitlag * (FRACUNIT / 10);
if (leveltime & 1)
{
mul = -mul;
}
thingxpos += FixedMul(thing->momx, mul);
thingypos += FixedMul(thing->momy, mul);
thingzpos += FixedMul(thing->momz, mul);
}
groundz = R_GetShadowZ(thing, &groundslope);
floordiff = abs((flip < 0 ? thing->height : 0) + thingzpos - groundz);
@ -4263,20 +4278,10 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
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 (spr->mobj->frame & FF_FULLBRIGHT)
brightmode = 1;
else if (spr->mobj->frame & FF_SEMIBRIGHT)
brightmode = 2;
if (sector->numlights)
{
@ -4305,9 +4310,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr)
HWR_Lighting(&Surf, lightlevel, colormap);
}
if (spr->mobj->drawflags & MFD_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf);
else if (spr->mobj->frame & FF_TRANSMASK)
if (spr->mobj->frame & FF_TRANSMASK)
blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
else
{
@ -4867,9 +4870,9 @@ static void HWR_AddSprites(sector_t *sec)
// BP why not use xtoviexangle/viewangletox like in bsp ?....
static void HWR_ProjectSprite(mobj_t *thing)
{
const fixed_t thingxpos = thing->x + thing->sprxoff;
const fixed_t thingypos = thing->y + thing->spryoff;
const fixed_t thingzpos = thing->z + thing->sprzoff;
fixed_t thingxpos = thing->x + thing->sprxoff;
fixed_t thingypos = thing->y + thing->spryoff;
fixed_t thingzpos = thing->z + thing->sprzoff;
gl_vissprite_t *vis;
float tr_x, tr_y;
@ -4902,11 +4905,27 @@ static void HWR_ProjectSprite(mobj_t *thing)
#ifdef ROTSPRITE
patch_t *rotsprite = NULL;
INT32 rollangle = 0;
angle_t spriterotangle = 0;
#endif
if (!thing)
return;
// hitlag vibrating
if (thing->hitlag > 0)
{
fixed_t mul = thing->hitlag * (FRACUNIT / 10);
if (leveltime & 1)
{
mul = -mul;
}
thingxpos += FixedMul(thing->momx, mul);
thingypos += FixedMul(thing->momy, mul);
thingzpos += FixedMul(thing->momz, mul);
}
dispoffset = thing->info->dispoffset;
this_scale = FIXED_TO_FLOAT(thing->scale);
@ -5025,9 +5044,11 @@ static void HWR_ProjectSprite(mobj_t *thing)
spr_topoffset = spritecachedinfo[lumpoff].topoffset;
#ifdef ROTSPRITE
if (thing->rollangle)
spriterotangle = R_SpriteRotationAngle(thing);
if (spriterotangle != 0)
{
rollangle = R_GetRollAngle(thing->rollangle);
rollangle = R_GetRollAngle(spriterotangle);
if (!(sprframe->rotsprite.cached & (1<<rot)))
R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip);
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
@ -5508,6 +5529,8 @@ static void HWR_DrawSkyBackground(player_t *player)
fixed_t rol = AngleFixed(player->viewrollangle);
dometransform.rollangle = FIXED_TO_FLOAT(rol);
dometransform.roll = true;
dometransform.rollx = 1.0f;
dometransform.rollz = 0.0f;
}
dometransform.splitscreen = r_splitscreen;
@ -5786,6 +5809,8 @@ void HWR_RenderSkyboxView(player_t *player)
fixed_t rol = AngleFixed(player->viewrollangle);
atransform.rollangle = FIXED_TO_FLOAT(rol);
atransform.roll = true;
atransform.rollx = 1.0f;
atransform.rollz = 0.0f;
}
atransform.splitscreen = r_splitscreen;
@ -5987,6 +6012,8 @@ void HWR_RenderPlayerView(void)
fixed_t rol = AngleFixed(player->viewrollangle);
atransform.rollangle = FIXED_TO_FLOAT(rol);
atransform.roll = true;
atransform.rollx = 1.0f;
atransform.rollz = 0.0f;
}
atransform.splitscreen = r_splitscreen;

View file

@ -1340,9 +1340,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
// Look at HWR_ProjectSprite for more
{
const fixed_t thingxpos = spr->mobj->x + spr->mobj->sprxoff;
const fixed_t thingypos = spr->mobj->y + spr->mobj->spryoff;
const fixed_t thingzpos = spr->mobj->z + spr->mobj->sprzoff;
fixed_t thingxpos = spr->mobj->x + spr->mobj->sprxoff;
fixed_t thingypos = spr->mobj->y + spr->mobj->spryoff;
fixed_t thingzpos = spr->mobj->z + spr->mobj->sprzoff;
GLPatch_t *gpatch;
INT32 durs = spr->mobj->state->tics;
@ -1353,22 +1353,41 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !(spr->mobj->frame & FF_HORIZONTALFLIP));
spritedef_t *sprdef;
spriteframe_t *sprframe;
spriteinfo_t *sprinfo;
angle_t ang;
INT32 mod;
float finalscale;
FBITFIELD blendmode = PF_Masked;
// hitlag vibrating
if (spr->mobj->hitlag > 0)
{
fixed_t mul = spr->mobj->hitlag * (FRACUNIT / 10);
if (leveltime & 1)
{
mul = -mul;
}
thingxpos += FixedMul(spr->mobj->momx, mul);
thingypos += FixedMul(spr->mobj->momy, mul);
thingzpos += FixedMul(spr->mobj->momz, mul);
}
// Apparently people don't like jump frames like that, so back it goes
//if (tics > durs)
//durs = tics;
if (spr->mobj->drawflags & MFD_TRANSMASK)
HWR_TranstableToAlpha((spr->mobj->drawflags & MFD_TRANSMASK)>>MFD_TRANSSHIFT, &Surf);
blendmode = 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);
blendmode = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
else
Surf.PolyColor.s.alpha = 0xFF;
if (blendmode == PF_Masked)
{
blendmode |= PF_Occlude;
}
// dont forget to enabled the depth test because we can't do this like
// before: polygons models are not sorted
@ -1378,12 +1397,10 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
{
md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins];
md2->skin = (skin_t*)spr->mobj->skin-skins;
sprinfo = &((skin_t *)spr->mobj->skin)->sprinfo[spr->mobj->sprite2];
}
else
{
md2 = &md2_models[spr->mobj->sprite];
sprinfo = &spriteinfo[spr->mobj->sprite];
}
// texture loading before model init, so it knows if sprite graphics are used, which
@ -1578,60 +1595,35 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
}
p.rollangle = 0.0f;
p.rollflip = 1;
p.rotaxis = 0;
if (spr->mobj->rollangle)
{
fixed_t camAngleDiff = AngleFixed(viewangle) - FLOAT_TO_FIXED(p.angley); // dumb reconversion back, I know
fixed_t anglef = AngleFixed(spr->mobj->rollangle);
p.rollangle = FIXED_TO_FLOAT(anglef);
p.roll = true;
// rotation pivot
p.centerx = FIXED_TO_FLOAT(spr->mobj->radius/2);
p.centery = FIXED_TO_FLOAT(spr->mobj->height/(flip ? -2 : 2));
p.centerx = FIXED_TO_FLOAT(spr->mobj->radius / 2);
p.centery = FIXED_TO_FLOAT(spr->mobj->height / 2);
// rotation axis
if (sprinfo->available)
p.rotaxis = (UINT8)(sprinfo->pivot[(spr->mobj->frame & FF_FRAMEMASK)].rotaxis);
// for NiGHTS specifically but should work everywhere else
ang = R_PointToAngle (spr->mobj->x, spr->mobj->y) - (spr->mobj->player ? spr->mobj->player->drawangle : spr->mobj->angle);
if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
p.rollflip = 1;
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
p.rollflip = -1;
if (flip)
p.rollflip *= -1;
// rotation axes relative to camera
p.rollx = FIXED_TO_FLOAT(FINECOSINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT));
p.rollz = FIXED_TO_FLOAT(FINESINE(FixedAngle(camAngleDiff) >> ANGLETOFINESHIFT));
}
p.anglex = 0.0f;
#ifdef USE_FTRANSFORM_ANGLEZ
// Slope rotation from Kart
p.anglez = 0.0f;
if (spr->mobj->standingslope)
{
fixed_t tempz = spr->mobj->standingslope->normal.z;
fixed_t tempy = spr->mobj->standingslope->normal.y;
fixed_t tempx = spr->mobj->standingslope->normal.x;
fixed_t tempangle = AngleFixed(R_PointToAngle2(0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx));
p.anglez = FIXED_TO_FLOAT(tempangle);
tempangle = -AngleFixed(R_PointToAngle2(0, 0, tempz, tempy));
p.anglex = FIXED_TO_FLOAT(tempangle);
}
#endif
p.anglez = FIXED_TO_FLOAT(AngleFixed(spr->mobj->pitch));
p.anglex = FIXED_TO_FLOAT(AngleFixed(spr->mobj->roll));
// SRB2CBTODO: MD2 scaling support
finalscale *= FIXED_TO_FLOAT(spr->mobj->scale);
p.flip = atransform.flip;
#ifdef USE_FTRANSFORM_MIRROR
p.mirror = atransform.mirror; // from Kart
#endif
p.mirror = atransform.mirror;
HWD.pfnSetShader(SHADER_MODEL); // model shader
HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, hflip, &Surf);
HWD.pfnDrawModel(md2->model, frame, durs, tics, nextFrame, &p, finalscale, flip, hflip, &Surf, blendmode);
}
return true;

View file

@ -2513,7 +2513,7 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model)
#define BUFFER_OFFSET(i) ((void*)(i))
static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface, FBITFIELD blendmode)
{
static GLRGBAFloat poly = {0,0,0,0};
static GLRGBAFloat tint = {0,0,0,0};
@ -2593,7 +2593,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
else
pglColor4ubv((GLubyte*)&Surface->PolyColor.s);
SetBlend((poly.alpha < 1 ? PF_Translucent : (PF_Masked|PF_Occlude))|PF_Modulated);
SetBlend(blendmode|PF_Modulated);
tint.red = byte2float[Surface->TintColor.s.red];
tint.green = byte2float[Surface->TintColor.s.green];
@ -2610,7 +2610,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
pglEnable(GL_CULL_FACE);
pglEnable(GL_NORMALIZE);
#ifdef USE_FTRANSFORM_MIRROR
// flipped is if the object is vertically flipped
// hflipped is if the object is horizontally flipped
// pos->flip is if the screen is flipped vertically
@ -2623,17 +2622,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
else
pglCullFace(GL_BACK);
}
#else
// pos->flip is if the screen is flipped too
if (flipped ^ hflipped ^ pos->flip) // If one or three of these are active, but not two, invert the model's culling
{
pglCullFace(GL_FRONT);
}
else
{
pglCullFace(GL_BACK);
}
#endif
pglPushMatrix(); // should be the same as glLoadIdentity
//Hurdler: now it seems to work
@ -2643,22 +2631,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
if (hflipped)
scalez = -scalez;
#ifdef USE_FTRANSFORM_ANGLEZ
pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); // rotate by slope from Kart
#endif
pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f);
pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f);
pglRotatef(pos->anglex, 1.0f, 0.0f, 0.0f);
pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f);
if (pos->roll)
{
float roll = (1.0f * pos->rollflip);
pglTranslatef(pos->centerx, pos->centery, 0);
if (pos->rotaxis == 2) // Z
pglRotatef(pos->rollangle, 0.0f, 0.0f, roll);
else if (pos->rotaxis == 1) // Y
pglRotatef(pos->rollangle, 0.0f, roll, 0.0f);
else // X
pglRotatef(pos->rollangle, roll, 0.0f, 0.0f);
pglRotatef(pos->rollangle, pos->rollx, 0.0f, pos->rollz);
pglTranslatef(-pos->centerx, -pos->centery, 0);
}
@ -2812,9 +2792,9 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
// -----------------+
// HWRAPI DrawModel : Draw a model
// -----------------+
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface, FBITFIELD blendmode)
{
DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, hflipped, Surface);
DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, hflipped, Surface, blendmode);
}
// -----------------+
@ -2831,13 +2811,9 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform)
if (stransform)
{
used_fov = stransform->fovxangle;
#ifdef USE_FTRANSFORM_MIRROR
// mirroring from Kart
if (stransform->mirror)
pglScalef(-stransform->scalex, stransform->scaley, -stransform->scalez);
else
#endif
if (stransform->flip)
else if (stransform->flip)
pglScalef(stransform->scalex, -stransform->scaley, -stransform->scalez);
else
pglScalef(stransform->scalex, stransform->scaley, -stransform->scalez);

View file

@ -77,11 +77,19 @@ typedef struct
char data[MAXPACKETLENGTH];
} ATTRPACK doomcom_t;
typedef struct
{
INT32 magic;
INT32 addr;
INT16 port;
} ATTRPACK holepunch_t;
#if defined(_MSC_VER)
#pragma pack()
#endif
extern doomcom_t *doomcom;
extern holepunch_t *holepunchpacket;
/** \brief return packet in doomcom struct
*/
@ -140,6 +148,15 @@ extern boolean (*I_NetOpenSocket)(void);
extern void (*I_NetCloseSocket)(void);
/** \brief send a hole punching request
*/
extern void (*I_NetRequestHolePunch)(void);
/** \brief register this machine on the hole punching server
*/
extern void (*I_NetRegisterHolePunch)(void);
extern boolean (*I_Ban) (INT32 node);
extern void (*I_ClearBans)(void);
extern const char *(*I_GetNodeAddress) (INT32 node);

View file

@ -152,6 +152,7 @@ static UINT8 UPNP_support = TRUE;
#include "d_netfil.h"
#include "i_tcp.h"
#include "m_argv.h"
#include "stun.h"
#include "doomstat.h"
@ -203,6 +204,7 @@ static size_t broadcastaddresses = 0;
static boolean nodeconnected[MAXNETNODES+1];
static mysockaddr_t banned[MAXBANS];
static UINT8 bannedmask[MAXBANS];
static const INT32 hole_punch_magic = MSBF_LONG (0x52eb11);
#endif
static size_t numbans = 0;
@ -559,6 +561,27 @@ void Command_Numnodes(void)
#endif
#ifndef NONET
static boolean hole_punch(ssize_t c)
{
if (c == 10 && holepunchpacket->magic == hole_punch_magic)
{
mysockaddr_t addr;
addr.ip4.sin_family = AF_INET;
addr.ip4.sin_addr.s_addr = holepunchpacket->addr;
addr.ip4.sin_port = holepunchpacket->port;
sendto(mysockets[0], NULL, 0, 0, &addr.any, sizeof addr.ip4);
CONS_Debug(DBG_NETPLAY,
"hole punching request from %s\n", SOCK_AddrToStr(&addr));
return true;
}
else
{
return false;
}
}
// Returns true if a packet was received from a new node, false in all other cases
static boolean SOCK_Get(void)
{
@ -573,8 +596,20 @@ static boolean SOCK_Get(void)
fromlen = (socklen_t)sizeof(fromaddress);
c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0,
(void *)&fromaddress, &fromlen);
if (c != ERRSOCKET)
if (c > 0)
{
#ifdef USE_STUN
if (STUN_got_response(doomcom->data, c))
{
return false;
}
#endif
if (hole_punch(c))
{
return false;
}
// find remote node number
for (j = 1; j <= MAXNETNODES; j++) //include LAN
{
@ -1257,17 +1292,14 @@ void I_ShutdownTcpDriver(void)
}
#ifndef NONET
static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
static boolean SOCK_GetAddr(struct sockaddr_in *sin, const char *address, const char *port, boolean test)
{
SINT8 newnode = -1;
struct my_addrinfo *ai = NULL, *runp, hints;
int gaie;
if (!port || !port[0])
if (!port || !port[0])
port = DEFAULTPORT;
DEBFILE(va("Creating new node: %s@%s\n", address, port));
memset (&hints, 0x00, sizeof (hints));
hints.ai_flags = 0;
hints.ai_family = AF_UNSPEC;
@ -1275,30 +1307,91 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
hints.ai_protocol = IPPROTO_UDP;
gaie = I_getaddrinfo(address, port, &hints, &ai);
if (gaie == 0)
{
newnode = getfreenode();
}
if (newnode == -1)
if (gaie != 0)
{
I_freeaddrinfo(ai);
return -1;
return false;
}
runp = ai;
if (test)
{
while (runp != NULL)
{
if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0)
break;
runp = runp->ai_next;
}
}
if (runp != NULL)
memcpy(sin, runp->ai_addr, runp->ai_addrlen);
I_freeaddrinfo(ai);
return (runp != NULL);
}
static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
{
SINT8 newnode = getfreenode();
DEBFILE(va("Creating new node: %s@%s\n", address, port));
if (newnode != -1)
{
if (!SOCK_GetAddr(&clientaddress[newnode].ip4, address, port, true))
{
nodeconnected[newnode] = false;
return -1;
}
}
return newnode;
}
static void rendezvous(int size)
{
char *addrs = strdup(cv_rendezvousserver.string);
char *host = strtok(addrs, ":");
char *port = strtok(NULL, ":");
mysockaddr_t rzv;
if (SOCK_GetAddr(&rzv.ip4, host, (port ? port : "7777"), false))
{
holepunchpacket->magic = hole_punch_magic;
sendto(mysockets[0], doomcom->data, size, 0, &rzv.any, sizeof rzv.ip4);
}
else
runp = ai;
while (runp != NULL)
{
// find ip of the server
if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0)
{
memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen);
break;
}
runp = runp->ai_next;
CONS_Alert(CONS_ERROR, "Failed to contact rendezvous server (%s).\n",
cv_rendezvousserver.string);
}
I_freeaddrinfo(ai);
return newnode;
free(addrs);
}
static void SOCK_RequestHolePunch(void)
{
mysockaddr_t * addr = &clientaddress[doomcom->remotenode];
holepunchpacket->addr = addr->ip4.sin_addr.s_addr;
holepunchpacket->port = addr->ip4.sin_port;
CONS_Debug(DBG_NETPLAY,
"requesting hole punch to node %s\n", SOCK_AddrToStr(addr));
rendezvous(10);
}
static void SOCK_RegisterHolePunch(void)
{
rendezvous(4);
}
#endif
@ -1325,6 +1418,9 @@ static boolean SOCK_OpenSocket(void)
I_NetCanGet = SOCK_CanGet;
#endif
I_NetRequestHolePunch = SOCK_RequestHolePunch;
I_NetRegisterHolePunch = SOCK_RegisterHolePunch;
// build the socket but close it first
SOCK_CloseSocket();
return UDP_Socket();

View file

@ -135,11 +135,12 @@ char sprnames[NUMSPRITES + 1][5] =
"TOKE", // Special Stage Token
"RFLG", // Red CTF Flag
"BFLG", // Blue CTF Flag
//"SPHR", // Sphere
"BSPH", // Sphere
"NCHP", // NiGHTS chip
"NSTR", // NiGHTS star
"EMBM", // Emblem
"CEMG", // Chaos Emeralds
"EMRC", // Chaos Emeralds
"ESPK",
"SHRD", // Emerald Hunt
// Interactive Objects
@ -543,6 +544,7 @@ char sprnames[NUMSPRITES + 1][5] =
"JAWZ", // Jawz
"SSMN", // SS Mine
"KRBM", // SS Mine BOOM
"LNDM", // Land Mine
"BHOG", // Ballhog
"BHBM", // Ballhog BOOM
"SPBM", // Self-Propelled Bomb
@ -557,6 +559,10 @@ char sprnames[NUMSPRITES + 1][5] =
"SINK", // Kitchen Sink
"SITR", // Kitchen Sink Trail
"KBLN", // Battle Mode Bumper
"BEXC", // Battle Bumper Explosion: Crystal
"BEXS", // Battle Bumper Explosion: Shell
"BDEB", // Battle Bumper Explosion: Debris
"BEXB", // Battle Bumper Explosion: Blast
"DEZL", // DEZ Laser respawn
@ -713,7 +719,9 @@ char sprnames[NUMSPRITES + 1][5] =
"DRAF",
"GRES",
"OTFG",
"OTBU",
"OTLS",
"OTCP",
"DBOS", // Drift boost flame
@ -730,6 +738,9 @@ char sprnames[NUMSPRITES + 1][5] =
"DBCL", // Drift boost clip
"DBNC", // Drift boost clip's sparks
"DBST", // Drift boost plume
"SDDS", // Spindash dust
"SDWN", // Spindash wind
};
char spr2names[NUMPLAYERSPRITES][5] =
@ -1799,20 +1810,49 @@ state_t states[NUMSTATES] =
{SPR_RING, 20, 1, {NULL}, 0, 0, S_FASTRING12}, // S_FASTRING11
{SPR_RING, 22, 1, {NULL}, 0, 0, S_FASTRING1}, // S_FASTRING12
// Blue Sphere for special stages
{SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERE
{SPR_SPHR, FF_FULLBRIGHT
#ifdef MANIASPHERES
|FF_ANIMATE|FF_RANDOMANIM
#endif
, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS
{SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERESPARK
// Blue Sphere
{SPR_BSPH, FF_SEMIBRIGHT|2, TICRATE, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE1}, // S_BLUESPHERE
{SPR_BSPH, FF_SEMIBRIGHT|2, TICRATE, {A_SetRandomTics}, 1, TICRATE, S_BLUESPHERE_BOUNCE1}, // S_BLUESPHERE_SPAWN
{SPR_BSPH, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE2}, // S_BLUESPHERE_BOUNCE1
{SPR_BSPH, FF_SEMIBRIGHT|4, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE3}, // S_BLUESPHERE_BOUNCE2
{SPR_BSPH, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE4}, // S_BLUESPHERE_BOUNCE3
{SPR_BSPH, FF_SEMIBRIGHT|4, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE5}, // S_BLUESPHERE_BOUNCE4
{SPR_BSPH, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE6}, // S_BLUESPHERE_BOUNCE5
{SPR_BSPH, FF_SEMIBRIGHT|2, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE7}, // S_BLUESPHERE_BOUNCE6
{SPR_BSPH, FF_SEMIBRIGHT|4, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE8}, // S_BLUESPHERE_BOUNCE7
{SPR_BSPH, FF_SEMIBRIGHT|2, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE9}, // S_BLUESPHERE_BOUNCE8
{SPR_BSPH, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE10}, // S_BLUESPHERE_BOUNCE9
{SPR_BSPH, FF_SEMIBRIGHT|2, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE11}, // S_BLUESPHERE_BOUNCE10
{SPR_BSPH, FF_SEMIBRIGHT|4, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE12}, // S_BLUESPHERE_BOUNCE11
{SPR_BSPH, FF_SEMIBRIGHT|2, 1, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE13}, // S_BLUESPHERE_BOUNCE12
{SPR_BSPH, FF_SEMIBRIGHT, 2, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE14}, // S_BLUESPHERE_BOUNCE13
{SPR_BSPH, FF_SEMIBRIGHT|1, 2, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE15}, // S_BLUESPHERE_BOUNCE14
{SPR_BSPH, FF_SEMIBRIGHT|2, 2, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE16}, // S_BLUESPHERE_BOUNCE15
{SPR_BSPH, FF_SEMIBRIGHT|3, 2, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE17}, // S_BLUESPHERE_BOUNCE16
{SPR_BSPH, FF_SEMIBRIGHT|4, 2, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE18}, // S_BLUESPHERE_BOUNCE17
{SPR_BSPH, FF_SEMIBRIGHT|3, 4, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE19}, // S_BLUESPHERE_BOUNCE18
{SPR_BSPH, FF_SEMIBRIGHT|2, 4, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE20}, // S_BLUESPHERE_BOUNCE19
{SPR_BSPH, FF_SEMIBRIGHT|1, 4, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE21}, // S_BLUESPHERE_BOUNCE20
{SPR_BSPH, FF_SEMIBRIGHT, 6, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE22}, // S_BLUESPHERE_BOUNCE21
{SPR_BSPH, FF_SEMIBRIGHT|1, 6, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE23}, // S_BLUESPHERE_BOUNCE22
{SPR_BSPH, FF_SEMIBRIGHT|2, 6, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE24}, // S_BLUESPHERE_BOUNCE23
{SPR_BSPH, FF_SEMIBRIGHT|3, 9, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE25}, // S_BLUESPHERE_BOUNCE24
{SPR_BSPH, FF_SEMIBRIGHT|4, 9, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE26}, // S_BLUESPHERE_BOUNCE25
{SPR_BSPH, FF_SEMIBRIGHT|3, 9, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE27}, // S_BLUESPHERE_BOUNCE26
{SPR_BSPH, FF_SEMIBRIGHT|2, 9, {NULL}, 0, 0, S_BLUESPHERE_BOUNCE28}, // S_BLUESPHERE_BOUNCE27
{SPR_BSPH, FF_SEMIBRIGHT|1, 9, {NULL}, 0, 0, S_BLUESPHERE}, // S_BLUESPHERE_BOUNCE28
// Bomb Sphere
{SPR_SPHR, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2}, // S_BOMBSPHERE1
{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3}, // S_BOMBSPHERE2
{SPR_SPHR, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4}, // S_BOMBSPHERE3
{SPR_SPHR, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1}, // S_BOMBSPHERE4
{SPR_BSPH, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BOMBSPHERE2}, // S_BOMBSPHERE1
{SPR_BSPH, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE3}, // S_BOMBSPHERE2
{SPR_BSPH, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BOMBSPHERE4}, // S_BOMBSPHERE3
{SPR_BSPH, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BOMBSPHERE1}, // S_BOMBSPHERE4
// NiGHTS Chip
{SPR_NCHP, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 15, 2, S_NULL}, // S_NIGHTSCHIP
@ -1865,13 +1905,17 @@ state_t states[NUMSTATES] =
{SPR_EMBM, 25, -1, {NULL}, 0, 0, S_NULL}, // S_EMBLEM26
// Chaos Emeralds
{SPR_CEMG, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG1
{SPR_CEMG, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG2
{SPR_CEMG, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG3
{SPR_CEMG, FF_FULLBRIGHT|3, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG4
{SPR_CEMG, FF_FULLBRIGHT|4, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG5
{SPR_CEMG, FF_FULLBRIGHT|5, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG6
{SPR_CEMG, FF_FULLBRIGHT|6, -1, {NULL}, 0, 0, S_NULL}, // S_CEMG7
{SPR_EMRC, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_CHAOSEMERALD2}, // S_CHAOSEMERALD1
{SPR_EMRC, FF_FULLBRIGHT|FF_TRANSADD, 1, {NULL}, 0, 0, S_CHAOSEMERALD1}, // S_CHAOSEMERALD2
{SPR_EMRC, FF_FULLBRIGHT|1, -1, {NULL}, 1, 0, S_NULL}, // S_CHAOSEMERALD_UNDER
{SPR_ESPK, FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EMERALDSPARK2}, // S_EMERALDSPARK1
{SPR_ESPK, FF_FULLBRIGHT|1, 3, {NULL}, 0, 0, S_EMERALDSPARK3}, // S_EMERALDSPARK2
{SPR_ESPK, FF_FULLBRIGHT|2, 3, {NULL}, 0, 0, S_EMERALDSPARK4}, // S_EMERALDSPARK3
{SPR_ESPK, FF_FULLBRIGHT|3, 3, {NULL}, 0, 0, S_EMERALDSPARK5}, // S_EMERALDSPARK4
{SPR_ESPK, FF_FULLBRIGHT|4, 3, {NULL}, 0, 0, S_EMERALDSPARK6}, // S_EMERALDSPARK5
{SPR_ESPK, FF_FULLBRIGHT|5, 3, {NULL}, 0, 0, S_EMERALDSPARK7}, // S_EMERALDSPARK6
{SPR_ESPK, FF_FULLBRIGHT|6, 3, {NULL}, 0, 0, S_NULL}, // S_EMERALDSPARK7
// Emerald hunt shards
{SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD1
@ -3715,14 +3759,14 @@ state_t states[NUMSTATES] =
{SPR_CAPS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGCAPSULE
// Orbiting Chaos Emeralds/Ideya for NiGHTS
{SPR_CEMG, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM1}, // S_ORBITEM1
{SPR_CEMG, FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM2}, // S_ORBITEM2
{SPR_CEMG, FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM3}, // S_ORBITEM3
{SPR_CEMG, FF_FULLBRIGHT|3, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM4}, // S_ORBITEM4
{SPR_CEMG, FF_FULLBRIGHT|4, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM5}, // S_ORBITEM5
{SPR_CEMG, FF_FULLBRIGHT|5, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM6}, // S_ORBITEM6
{SPR_CEMG, FF_FULLBRIGHT|6, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM7}, // S_ORBITEM7
{SPR_CEMG, FF_FULLBRIGHT|7, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM8
{SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM1}, // S_ORBITEM1
{SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM2}, // S_ORBITEM2
{SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM3}, // S_ORBITEM3
{SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM4}, // S_ORBITEM4
{SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM5}, // S_ORBITEM5
{SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM6}, // S_ORBITEM6
{SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM7}, // S_ORBITEM7
{SPR_EMRC, FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBITEM8}, // S_ORBITEM8
{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA1}, // S_ORBIDYA1
{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|1, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA2}, // S_ORBIDYA2
{SPR_IDYA, FF_TRANS20|FF_FULLBRIGHT|2, 1, {A_OrbitNights}, ANG2*2, 0, S_ORBIDYA3}, // S_ORBIDYA3
@ -4206,6 +4250,9 @@ state_t states[NUMSTATES] =
{SPR_KRBM, FF_FULLBRIGHT|8, 5, {NULL}, 0, 0, S_SLOWBOOM10}, // S_SLOWBOOM9
{SPR_KRBM, FF_FULLBRIGHT|9, 5, {NULL}, 0, 0, S_NULL}, // S_SLOWBOOM10
{SPR_LNDM, 0, -1, {NULL}, 0, 0, S_LANDMINE}, // S_LANDMINE
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_LANDMINE_EXPLODE
{SPR_BHOG, 0, 3, {A_PlaySound}, sfx_s1bd, 1, S_BALLHOG2}, // S_BALLHOG1
{SPR_BHOG, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BALLHOG3}, // S_BALLHOG2
{SPR_BHOG, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_BALLHOG4}, // S_BALLHOG3
@ -4362,9 +4409,47 @@ state_t states[NUMSTATES] =
{SPR_SITR, 1, 5, {NULL}, 0, 0, S_SINKTRAIL3}, // S_SINKTRAIL2
{SPR_SITR, 2, 3, {NULL}, 0, 0, S_NULL}, // S_SINKTRAIL3
{SPR_KBLN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_BATTLEBUMPER1}, // S_BATTLEBUMPER1
{SPR_KBLN, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_BATTLEBUMPER2}, // S_BATTLEBUMPER2
{SPR_KBLN, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_BATTLEBUMPER3}, // S_BATTLEBUMPER3
{SPR_KBLN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEBUMPER1
{SPR_KBLN, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEBUMPER2
{SPR_KBLN, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEBUMPER3
{SPR_BEXC, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALA2}, // S_BATTLEBUMPER_EXCRYSTALA1
{SPR_BEXC, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALA3}, // S_BATTLEBUMPER_EXCRYSTALA2
{SPR_BEXC, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALA4}, // S_BATTLEBUMPER_EXCRYSTALA3
{SPR_BEXC, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALA1}, // S_BATTLEBUMPER_EXCRYSTALA4
{SPR_BEXC, FF_SEMIBRIGHT|3, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALB2}, // S_BATTLEBUMPER_EXCRYSTALB1
{SPR_BEXC, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALB3}, // S_BATTLEBUMPER_EXCRYSTALB2
{SPR_BEXC, FF_SEMIBRIGHT|3, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALB4}, // S_BATTLEBUMPER_EXCRYSTALB3
{SPR_BEXC, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALB1}, // S_BATTLEBUMPER_EXCRYSTALB4
{SPR_BEXC, FF_SEMIBRIGHT|6, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALC2}, // S_BATTLEBUMPER_EXCRYSTALC1
{SPR_BEXC, FF_FULLBRIGHT|7, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALC3}, // S_BATTLEBUMPER_EXCRYSTALC2
{SPR_BEXC, FF_SEMIBRIGHT|6, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALC4}, // S_BATTLEBUMPER_EXCRYSTALC3
{SPR_BEXC, FF_FULLBRIGHT|8, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXCRYSTALC1}, // S_BATTLEBUMPER_EXCRYSTALC4
{SPR_BEXS, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLA2}, // S_BATTLEBUMPER_EXSHELLA1
{SPR_BEXS, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLA1}, // S_BATTLEBUMPER_EXSHELLA2
{SPR_BEXS, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLB2}, // S_BATTLEBUMPER_EXSHELLB1
{SPR_BEXS, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLB1}, // S_BATTLEBUMPER_EXSHELLB2
{SPR_BEXS, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLC2}, // S_BATTLEBUMPER_EXSHELLC1
{SPR_BEXS, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_BATTLEBUMPER_EXSHELLC1}, // S_BATTLEBUMPER_EXSHELLC2
{SPR_BDEB, FF_FULLBRIGHT|FF_ANIMATE, 84, {NULL}, 13, 6, S_BATTLEBUMPER_EXDEBRIS2}, // S_BATTLEBUMPER_EXDEBRIS1
{SPR_BDEB, FF_FULLBRIGHT|13, 20, {NULL}, 0, 0, S_NULL}, // S_BATTLEBUMPER_EXDEBRIS2
{SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST2}, // S_BATTLEBUMPER_EXBLAST1
{SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS10, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST3}, // S_BATTLEBUMPER_EXBLAST2
{SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS20, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST4}, // S_BATTLEBUMPER_EXBLAST3
{SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS30, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST5}, // S_BATTLEBUMPER_EXBLAST4
{SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS40, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST6}, // S_BATTLEBUMPER_EXBLAST5
{SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS50, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST7}, // S_BATTLEBUMPER_EXBLAST6
{SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS60, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST8}, // S_BATTLEBUMPER_EXBLAST7
{SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS70, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST9}, // S_BATTLEBUMPER_EXBLAST8
{SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS80, 2, {NULL}, 0, 0, S_BATTLEBUMPER_EXBLAST10}, // S_BATTLEBUMPER_EXBLAST9
{SPR_BEXB, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_TRANS90, 2, {NULL}, 0, 0, S_NULL}, // S_BATTLEBUMPER_EXBLAST10
{SPR_DEZL, FF_FULLBRIGHT|FF_PAPERSPRITE, 8, {NULL}, 0, 0, S_NULL}, // S_DEZLASER
{SPR_DEZL, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_DEZLASER_TRAIL2}, // S_DEZLASER_TRAIL1
@ -4995,9 +5080,10 @@ state_t states[NUMSTATES] =
{SPR_GRES, FF_ANIMATE|FF_PAPERSPRITE, -1, {NULL}, 2, 4, S_NULL}, // S_TIREGREASE
{SPR_OTFG, FF_FULLBRIGHT|FF_TRANS50, TICRATE, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEFOG
{SPR_OTFG, 2|FF_FULLBRIGHT|FF_PAPERSPRITE, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEORB
{SPR_OTFG, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEBEAM
{SPR_OTBU, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIME_BULB1
{SPR_OTBU, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIME_BULB2
{SPR_OTLS, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIME_LASER
{SPR_OTCP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_OVERTIME_CENTER
{SPR_CAPS, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SIDE1
{SPR_CAPS, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SIDE2
@ -5026,6 +5112,9 @@ state_t states[NUMSTATES] =
{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
{SPR_SDDS, FF_ANIMATE, 9, {NULL}, 9, 1, S_NULL}, // S_SPINDASHDUST
{SPR_SDWN, FF_ANIMATE|FF_PAPERSPRITE, 18, {NULL}, 9, 2, S_NULL}, // S_SPINDASHWIND
#ifdef SEENAMES
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
#endif
@ -7923,35 +8012,35 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
},
{ // MT_BLUESPHERE
1706, // doomednum
S_BLUESPHERE, // spawnstate
-1, // doomednum
S_BLUESPHERE_SPAWN, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
MT_FLINGBLUESPHERE, // reactiontime
MT_FLINGBLUESPHERE, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_BLUESPHERESPARK, // deathstate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_s3k65, // deathsound
38*FRACUNIT, // speed
16*FRACUNIT, // radius
24*FRACUNIT, // height
48*FRACUNIT, // radius
48*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
S_BLUESPHEREBONUS // raisestate
MF_RUNSPAWNFUNC|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_FLINGBLUESPHERE
-1, // doomednum
S_BLUESPHERE, // spawnstate
S_BLUESPHERE_SPAWN, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
@ -7962,7 +8051,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_BLUESPHERESPARK, // deathstate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_s3k65, // deathsound
38*FRACUNIT, // speed
@ -7973,7 +8062,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // damage
sfx_None, // activesound
MF_SLIDEME|MF_SPECIAL, // flags
S_BLUESPHEREBONUS // raisestate
S_NULL // raisestate
},
{ // MT_BOMBSPHERE
@ -8165,9 +8254,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_EMERALD1
313, // doomednum
S_CEMG1, // spawnstate
{ // MT_EMERALD
-1, // doomednum
S_CHAOSEMERALD1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
@ -8178,22 +8267,23 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_SPRK1, // deathstate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_cgot, // deathsound
EMERALD1, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
sfx_s3k9c, // deathsound
0, // speed
72*FRACUNIT, // radius
72*FRACUNIT, // height
0, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // flags
MF_SPECIAL|MF_PICKUPFROMBELOW|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_EMERALD2
314, // doomednum
S_CEMG2, // spawnstate
{ // MT_EMERALDSPARK
-1, // doomednum
S_EMERALDSPARK1,// spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
@ -8204,147 +8294,17 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_SPRK1, // deathstate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_cgot, // deathsound
EMERALD2, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
sfx_None, // deathsound
0, // speed
8*FRACUNIT, // radius
8*FRACUNIT, // height
0, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // flags
S_NULL // raisestate
},
{ // MT_EMERALD3
315, // doomednum
S_CEMG3, // 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_SPRK1, // deathstate
S_NULL, // xdeathstate
sfx_cgot, // deathsound
EMERALD3, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // flags
S_NULL // raisestate
},
{ // MT_EMERALD4
316, // doomednum
S_CEMG4, // 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_SPRK1, // deathstate
S_NULL, // xdeathstate
sfx_cgot, // deathsound
EMERALD4, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // flags
S_NULL // raisestate
},
{ // MT_EMERALD5
317, // doomednum
S_CEMG5, // 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_SPRK1, // deathstate
S_NULL, // xdeathstate
sfx_cgot, // deathsound
EMERALD5, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // flags
S_NULL // raisestate
},
{ // MT_EMERALD6
318, // doomednum
S_CEMG6, // 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_SPRK1, // deathstate
S_NULL, // xdeathstate
sfx_cgot, // deathsound
EMERALD6, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // flags
S_NULL // raisestate
},
{ // MT_EMERALD7
319, // doomednum
S_CEMG7, // 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_SPRK1, // deathstate
S_NULL, // xdeathstate
sfx_cgot, // deathsound
EMERALD7, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_SPECIAL, // flags
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -8402,33 +8362,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_FLINGEMERALD
-1, // doomednum
S_CEMG1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_SPRK1, // deathstate
S_NULL, // xdeathstate
sfx_cgot, // deathsound
60*FRACUNIT, // speed
16*FRACUNIT, // radius
48*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_SLIDEME|MF_SPECIAL, // flags
S_NULL // raisestate
},
{ // MT_FAN
540, // doomednum
S_FAN, // spawnstate
@ -8560,7 +8493,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
25*FRACUNIT, // mass
0, // damage
sfx_None, // activesound
MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags
MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_YELLOWSPRING2 // raisestate
},
@ -8587,7 +8520,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
40*FRACUNIT, // mass
0, // damage
sfx_None, // activesound
MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags
MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_REDSPRING2 // raisestate
},
@ -8614,7 +8547,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
64*FRACUNIT, // mass
0, // damage
sfx_None, // activesound
MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags
MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_BLUESPRING2 // raisestate
},
@ -8641,7 +8574,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
15*FRACUNIT, // mass
0, // damage
sfx_None, // activesound
MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags
MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_GREYSPRING2 // raisestate
},
@ -8668,7 +8601,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
25*FRACUNIT, // mass
25*FRACUNIT, // damage
sfx_None, // activesound
MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags
MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_YDIAG2 // raisestate
},
@ -8695,7 +8628,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
40*FRACUNIT, // mass
40*FRACUNIT, // damage
sfx_None, // activesound
MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags
MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_RDIAG2 // raisestate
},
@ -8722,7 +8655,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
64*FRACUNIT, // mass
64*FRACUNIT, // damage
sfx_None, // activesound
MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags
MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_BDIAG2 // raisestate
},
@ -8749,7 +8682,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
15*FRACUNIT, // mass
15*FRACUNIT, // damage
sfx_None, // activesound
MF_SOLID|MF_SPRING|MF_DONTENCOREMAP, // flags
MF_SOLID|MF_SPRING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_GDIAG2 // raisestate
},
@ -18644,22 +18577,22 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_RAIN1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_rainin, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_SPLASH1, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
-72*FRACUNIT, // speed
1*FRACUNIT, // radius
8*FRACUNIT, // height
0, // display offset
4, // mass
80, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP, // flags
@ -18672,7 +18605,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
@ -18686,8 +18619,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
4*FRACUNIT, // radius
4*FRACUNIT, // height
0, // display offset
4, // mass
0, // damage
0, // mass
2, // damage
sfx_None, // activesound
MF_NOBLOCKMAP, // flags
S_NULL // raisestate
@ -19073,7 +19006,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_GOTEMERALD
-1, // doomednum
S_CEMG1, // spawnstate
S_CHAOSEMERALD1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
@ -22908,13 +22841,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate
sfx_itpick, // deathsound
0, // speed
32*FRACUNIT, // radius
32*FRACUNIT, // height
48*FRACUNIT, // radius
64*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_SLIDEME|MF_SPECIAL|MF_DONTENCOREMAP, // flags
MF_SLIDEME|MF_SPECIAL|MF_PICKUPFROMBELOW|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -23836,6 +23769,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_LANDMINE
-1, // doomednum
S_LANDMINE, // spawnstate
2, // spawnhealth
S_NULL, // seestate
sfx_tossed, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_LANDMINE_EXPLODE, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
24*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_s3k5c, // activesound
MF_SHOOTABLE|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_BALLHOG
-1, // doomednum
S_BALLHOG1, // spawnstate
@ -24200,7 +24160,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_BATTLEBUMPER1, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
4*FRACUNIT, // speed
@ -24214,6 +24174,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_BATTLEBUMPER_DEBRIS
-1, // doomednum
S_BATTLEBUMPER_EXDEBRIS1,// 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*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_BATTLEBUMPER_BLAST
-1, // doomednum
S_BATTLEBUMPER_EXBLAST1, // 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*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_DEZLASER
-1, // doomednum
S_DEZLASER, // spawnstate
@ -28402,9 +28416,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_OVERTIMEFOG
{ // MT_OVERTIME_PARTICLE
-1, // doomednum
S_OVERTIMEFOG, // spawnstate
S_NULL, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
@ -28420,8 +28434,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // deathsound
0, // speed
16<<FRACBITS, // radius
32<<FRACBITS, // height
-1, // display offset
24<<FRACBITS, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
@ -28429,9 +28443,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_OVERTIMEORB
-1, // doomednum
S_OVERTIMEORB, // spawnstate
{ // MT_OVERTIME_CENTER
3775, // doomednum
S_OVERTIME_CENTER, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
@ -28446,40 +28460,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
16<<FRACBITS, // radius
48<<FRACBITS, // height
-1, // display offset
12<<FRACBITS, // radius
72<<FRACBITS, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_OVERTIMEBEAM
-1, // doomednum
S_OVERTIMEBEAM, // 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<<FRACBITS, // radius
48<<FRACBITS, // height
-1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
MF_SOLID|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -28675,6 +28662,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_SPINDASHDUST
-1, // doomednum
S_SPINDASHDUST, // 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
12*FRACUNIT, // radius
24*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_SPINDASHWIND
-1, // doomednum
S_SPINDASHWIND, // 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
12*FRACUNIT, // radius
24*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_PAPERITEMSPOT
-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
48*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
1, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
// ============================================================================================================================//
#ifdef SEENAMES
@ -28864,7 +28932,15 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
{"Super Tan 2", {0x00, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5}, SKINCOLOR_BROWN, 13, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN2
{"Super Tan 3", {0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9}, SKINCOLOR_BROWN, 12, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN3
{"Super Tan 4", {0x51, 0x52, 0x52, 0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed}, SKINCOLOR_BROWN, 11, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN4
{"Super Tan 5", {0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed, 0xee, 0xef, 0xef}, SKINCOLOR_BROWN, 10, V_BROWNMAP, false} // SKINCOLOR_SUPERTAN5
{"Super Tan 5", {0x52, 0x52, 0x54, 0x54, 0x54, 0x55, 0x56, 0x57, 0xf5, 0xf7, 0xf9, 0xfb, 0xed, 0xee, 0xef, 0xef}, SKINCOLOR_BROWN, 10, V_BROWNMAP, false}, // SKINCOLOR_SUPERTAN5
{"Chaos Emerald 1", { 0, 88, 188, 98, 114, 116, 117, 119, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD1
{"Chaos Emerald 2", { 0, 80, 82, 74, 65, 52, 56, 60, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD2
{"Chaos Emerald 3", { 0, 252, 201, 179, 182, 183, 185, 187, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD3
{"Chaos Emerald 4", { 0, 144, 146, 147, 149, 165, 167, 169, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD4
{"Chaos Emerald 5", { 0, 1, 144, 4, 9, 170, 14, 21, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD5
{"Chaos Emerald 6", { 0, 208, 50, 32, 34, 37, 40, 44, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_CHAOSEMERALD6
{"Chaos Emerald 7", { 0, 120, 121, 140, 133, 135, 149, 156, 0, 0, 0, 0, 0, 0, 0, 0}, SKINCOLOR_NONE, 0, 0, false} // SKINCOLOR_CHAOSEMERALD7
};
/** Patches the mobjinfo, state, and skincolor tables.

View file

@ -406,11 +406,12 @@ typedef enum sprite
SPR_TOKE, // Special Stage Token
SPR_RFLG, // Red CTF Flag
SPR_BFLG, // Blue CTF Flag
//SPR_SPHR, // Sphere
SPR_BSPH, // Sphere
SPR_NCHP, // NiGHTS chip
SPR_NSTR, // NiGHTS star
SPR_EMBM, // Emblem
SPR_CEMG, // Chaos Emeralds
SPR_EMRC, // Chaos Emeralds
SPR_ESPK,
SPR_SHRD, // Emerald Hunt
// Interactive Objects
@ -814,6 +815,7 @@ typedef enum sprite
SPR_JAWZ, // Jawz
SPR_SSMN, // SS Mine
SPR_KRBM, // SS Mine BOOM
SPR_LNDM, // Land Mine
SPR_BHOG, // Ballhog
SPR_BHBM, // Ballhog BOOM
SPR_SPBM, // Self-Propelled Bomb
@ -828,6 +830,10 @@ typedef enum sprite
SPR_SINK, // Kitchen Sink
SPR_SITR, // Kitchen Sink Trail
SPR_KBLN, // Battle Mode Bumper
SPR_BEXC, // Battle Bumper Explosion: Crystal
SPR_BEXS, // Battle Bumper Explosion: Shell
SPR_BDEB, // Battle Bumper Explosion: Debris
SPR_BEXB, // Battle Bumper Explosion: Blast
SPR_DEZL, // DEZ Laser respawn
@ -984,7 +990,9 @@ typedef enum sprite
SPR_DRAF,
SPR_GRES,
SPR_OTFG,
SPR_OTBU,
SPR_OTLS,
SPR_OTCP,
SPR_DBOS, // Drift boost flame
@ -1002,6 +1010,9 @@ typedef enum sprite
SPR_DBNC, // Drift boost clip's sparks
SPR_DBST, // Drift boost plume
SPR_SDDS, // Spindash dust
SPR_SDWN, // Spindash wind
SPR_FIRSTFREESLOT,
SPR_LASTFREESLOT = SPR_FIRSTFREESLOT + NUMSPRITEFREESLOTS - 1,
NUMSPRITES
@ -2016,8 +2027,41 @@ typedef enum state
// Blue Sphere for special stages
S_BLUESPHERE,
S_BLUESPHEREBONUS,
S_BLUESPHERESPARK,
S_BLUESPHERE_SPAWN,
S_BLUESPHERE_BOUNCE1,
S_BLUESPHERE_BOUNCE2,
S_BLUESPHERE_BOUNCE3,
S_BLUESPHERE_BOUNCE4,
S_BLUESPHERE_BOUNCE5,
S_BLUESPHERE_BOUNCE6,
S_BLUESPHERE_BOUNCE7,
S_BLUESPHERE_BOUNCE8,
S_BLUESPHERE_BOUNCE9,
S_BLUESPHERE_BOUNCE10,
S_BLUESPHERE_BOUNCE11,
S_BLUESPHERE_BOUNCE12,
S_BLUESPHERE_BOUNCE13,
S_BLUESPHERE_BOUNCE14,
S_BLUESPHERE_BOUNCE15,
S_BLUESPHERE_BOUNCE16,
S_BLUESPHERE_BOUNCE17,
S_BLUESPHERE_BOUNCE18,
S_BLUESPHERE_BOUNCE19,
S_BLUESPHERE_BOUNCE20,
S_BLUESPHERE_BOUNCE21,
S_BLUESPHERE_BOUNCE22,
S_BLUESPHERE_BOUNCE23,
S_BLUESPHERE_BOUNCE24,
S_BLUESPHERE_BOUNCE25,
S_BLUESPHERE_BOUNCE26,
S_BLUESPHERE_BOUNCE27,
S_BLUESPHERE_BOUNCE28,
// Bomb Sphere
S_BOMBSPHERE1,
@ -2076,13 +2120,17 @@ typedef enum state
S_EMBLEM26,
// Chaos Emeralds
S_CEMG1,
S_CEMG2,
S_CEMG3,
S_CEMG4,
S_CEMG5,
S_CEMG6,
S_CEMG7,
S_CHAOSEMERALD1,
S_CHAOSEMERALD2,
S_CHAOSEMERALD_UNDER,
S_EMERALDSPARK1,
S_EMERALDSPARK2,
S_EMERALDSPARK3,
S_EMERALDSPARK4,
S_EMERALDSPARK5,
S_EMERALDSPARK6,
S_EMERALDSPARK7,
// Emerald hunt shards
S_SHRD1,
@ -4360,6 +4408,10 @@ typedef enum state
S_SLOWBOOM9,
S_SLOWBOOM10,
// Land mine
S_LANDMINE,
S_LANDMINE_EXPLODE,
// Ballhog
S_BALLHOG1,
S_BALLHOG2,
@ -4527,6 +4579,44 @@ typedef enum state
S_BATTLEBUMPER2,
S_BATTLEBUMPER3,
S_BATTLEBUMPER_EXCRYSTALA1,
S_BATTLEBUMPER_EXCRYSTALA2,
S_BATTLEBUMPER_EXCRYSTALA3,
S_BATTLEBUMPER_EXCRYSTALA4,
S_BATTLEBUMPER_EXCRYSTALB1,
S_BATTLEBUMPER_EXCRYSTALB2,
S_BATTLEBUMPER_EXCRYSTALB3,
S_BATTLEBUMPER_EXCRYSTALB4,
S_BATTLEBUMPER_EXCRYSTALC1,
S_BATTLEBUMPER_EXCRYSTALC2,
S_BATTLEBUMPER_EXCRYSTALC3,
S_BATTLEBUMPER_EXCRYSTALC4,
S_BATTLEBUMPER_EXSHELLA1,
S_BATTLEBUMPER_EXSHELLA2,
S_BATTLEBUMPER_EXSHELLB1,
S_BATTLEBUMPER_EXSHELLB2,
S_BATTLEBUMPER_EXSHELLC1,
S_BATTLEBUMPER_EXSHELLC2,
S_BATTLEBUMPER_EXDEBRIS1,
S_BATTLEBUMPER_EXDEBRIS2,
S_BATTLEBUMPER_EXBLAST1,
S_BATTLEBUMPER_EXBLAST2,
S_BATTLEBUMPER_EXBLAST3,
S_BATTLEBUMPER_EXBLAST4,
S_BATTLEBUMPER_EXBLAST5,
S_BATTLEBUMPER_EXBLAST6,
S_BATTLEBUMPER_EXBLAST7,
S_BATTLEBUMPER_EXBLAST8,
S_BATTLEBUMPER_EXBLAST9,
S_BATTLEBUMPER_EXBLAST10,
// DEZ Laser respawn
S_DEZLASER,
S_DEZLASER_TRAIL1,
@ -5147,9 +5237,10 @@ typedef enum state
S_TIREGREASE,
S_OVERTIMEFOG,
S_OVERTIMEORB,
S_OVERTIMEBEAM,
S_OVERTIME_BULB1,
S_OVERTIME_BULB2,
S_OVERTIME_LASER,
S_OVERTIME_CENTER,
S_BATTLECAPSULE_SIDE1,
S_BATTLECAPSULE_SIDE2,
@ -5177,6 +5268,9 @@ typedef enum state
S_WATERTRAILUNDERLAY7,
S_WATERTRAILUNDERLAY8,
S_SPINDASHDUST,
S_SPINDASHWIND,
#ifdef SEENAMES
S_NAMECHECK,
#endif
@ -5345,16 +5439,10 @@ typedef enum mobj_type
MT_REDFLAG, // Red CTF Flag
MT_BLUEFLAG, // Blue CTF Flag
MT_EMBLEM,
MT_EMERALD1,
MT_EMERALD2,
MT_EMERALD3,
MT_EMERALD4,
MT_EMERALD5,
MT_EMERALD6,
MT_EMERALD7,
MT_EMERALD,
MT_EMERALDSPARK,
MT_EMERHUNT, // Emerald Hunt
MT_EMERALDSPAWN, // Emerald spawner w/ delay
MT_FLINGEMERALD, // Lost emerald
// Springs and others
MT_FAN,
@ -6031,6 +6119,8 @@ typedef enum mobj_type
MT_BOOMEXPLODE,
MT_BOOMPARTICLE,
MT_LANDMINE, // Land Mine
MT_BALLHOG, // Ballhog
MT_BALLHOGBOOM,
@ -6049,6 +6139,8 @@ typedef enum mobj_type
MT_SINKTRAIL,
MT_BATTLEBUMPER, // Battle Mode bumpers
MT_BATTLEBUMPER_DEBRIS,
MT_BATTLEBUMPER_BLAST,
MT_DEZLASER,
@ -6263,9 +6355,8 @@ typedef enum mobj_type
MT_SPBDUST,
MT_TIREGREASE,
MT_OVERTIMEFOG,
MT_OVERTIMEORB,
MT_OVERTIMEBEAM,
MT_OVERTIME_PARTICLE,
MT_OVERTIME_CENTER,
MT_BATTLECAPSULE,
MT_BATTLECAPSULE_PIECE,
@ -6277,6 +6368,11 @@ typedef enum mobj_type
MT_WATERTRAIL,
MT_WATERTRAILUNDERLAY,
MT_SPINDASHDUST,
MT_SPINDASHWIND,
MT_PAPERITEMSPOT,
#ifdef SEENAMES
MT_NAMECHECK,
#endif

View file

@ -41,6 +41,9 @@ INT32 K_StartingBumperCount(void)
boolean K_IsPlayerWanted(player_t *player)
{
#if 1
return (player->kartstuff[k_position] == 1);
#else
UINT8 i;
if (!(gametyperules & GTR_WANTED))
@ -54,28 +57,26 @@ boolean K_IsPlayerWanted(player_t *player)
return true;
}
return false;
#endif
}
void K_CalculateBattleWanted(void)
{
UINT8 numingame = 0, numplaying = 0, numwanted = 0;
SINT8 bestbumperplayer = -1, bestbumper = -1;
UINT8 numingame = 0, numwanted = 0;
SINT8 camppos[MAXPLAYERS]; // who is the biggest camper
UINT8 ties = 0, nextcamppos = 0;
boolean setbumper = false;
UINT8 i, j;
#if 0
if (!(gametyperules & GTR_WANTED))
#endif
{
for (i = 0; i < 4; i++)
battlewanted[i] = -1;
memset(battlewanted, -1, sizeof (battlewanted));
return;
}
wantedcalcdelay = wantedfrequency;
for (i = 0; i < MAXPLAYERS; i++)
camppos[i] = -1; // initialize
memset(camppos, -1, sizeof (camppos)); // initialize
for (i = 0; i < MAXPLAYERS; i++)
{
@ -87,33 +88,38 @@ void K_CalculateBattleWanted(void)
if (players[i].exiting) // We're done, don't calculate.
return;
numplaying++;
if (players[i].kartstuff[k_bumper] <= 0) // Not alive, so don't do anything else
if (players[i].bumpers <= 0) // Not alive, so don't do anything else
continue;
numingame++;
if (bestbumper == -1 || players[i].kartstuff[k_bumper] > bestbumper)
{
bestbumper = players[i].kartstuff[k_bumper];
bestbumperplayer = i;
}
else if (players[i].kartstuff[k_bumper] == bestbumper)
bestbumperplayer = -1; // Tie, no one has best bumper.
for (j = 0; j < MAXPLAYERS; j++)
{
if (!playeringame[j] || players[j].spectator)
continue;
if (players[j].kartstuff[k_bumper] <= 0)
if (players[j].bumpers <= 0)
continue;
if (j == i)
continue;
if (players[j].kartstuff[k_wanted] == players[i].kartstuff[k_wanted] && players[j].marescore > players[i].marescore)
if (K_NumEmeralds(&players[j]) > K_NumEmeralds(&players[i]))
{
position++;
}
else if (players[j].bumpers > players[i].bumpers)
{
position++;
}
else if (players[j].marescore > players[i].marescore)
{
position++;
}
else if (players[j].kartstuff[k_wanted] > players[i].kartstuff[k_wanted])
{
position++;
}
}
position--; // Make zero based
@ -124,7 +130,7 @@ void K_CalculateBattleWanted(void)
camppos[position] = i;
}
if (numplaying <= 2 || (numingame <= 2 && bestbumper == 1)) // In 1v1s then there's no need for WANTED. In bigger netgames, don't show anyone as WANTED when they're equally matched.
if (numingame <= 2) // In 1v1s then there's no need for WANTED.
numwanted = 0;
else
numwanted = min(4, 1 + ((numingame-2) / 4));
@ -132,19 +138,11 @@ void K_CalculateBattleWanted(void)
for (i = 0; i < 4; i++)
{
if (i+1 > numwanted) // Not enough players for this slot to be wanted!
battlewanted[i] = -1;
else if (bestbumperplayer != -1 && !setbumper) // If there's a player who has an untied bumper lead over everyone else, they are the first to be wanted.
{
battlewanted[i] = bestbumperplayer;
setbumper = true; // Don't set twice
battlewanted[i] = -1;
}
else
{
// Don't accidentally set the same player, if the bestbumperplayer is also a huge camper.
while (bestbumperplayer != -1 && camppos[nextcamppos] != -1
&& bestbumperplayer == camppos[nextcamppos])
nextcamppos++;
// Do not add *any* more people if there's too many times that are tied with others.
// This could theoretically happen very easily if people don't hit each other for a while after the start of a match.
// (I will be sincerely impressed if more than 2 people tie after people start hitting each other though)
@ -230,7 +228,7 @@ void K_CheckBumpers(void)
numingame++;
winnerscoreadd += players[i].marescore;
if (players[i].kartstuff[k_bumper] <= 0) // if you don't have any bumpers, you're probably not a winner
if (players[i].bumpers <= 0) // if you don't have any bumpers, you're probably not a winner
{
nobumpers = true;
continue;
@ -277,125 +275,411 @@ void K_CheckBumpers(void)
P_DoPlayerExit(&players[i]);
}
#define MAXPLANESPERSECTOR (MAXFFLOORS+1)*2
static void K_SpawnOvertimeParticles(fixed_t x, fixed_t y, fixed_t scale, mobjtype_t type, boolean ceiling)
void K_CheckEmeralds(player_t *player)
{
UINT8 i;
fixed_t flatz[MAXPLANESPERSECTOR];
boolean flip[MAXPLANESPERSECTOR];
UINT8 numflats = 0;
mobj_t *mo;
subsector_t *ss = R_PointInSubsectorOrNull(x, y);
sector_t *sec;
if (!ss)
if (!ALLCHAOSEMERALDS(player->powers[pw_emeralds]))
{
return;
sec = ss->sector;
// convoluted stuff JUST to get all of the planes we need to draw orbs on :V
for (i = 0; i < MAXPLANESPERSECTOR; i++)
flip[i] = false;
if (sec->floorpic != skyflatnum)
{
flatz[numflats] = P_GetZAt(sec->f_slope, x, y, sec->floorheight);
numflats++;
}
if (sec->ceilingpic != skyflatnum && ceiling)
{
flatz[numflats] = P_GetZAt(sec->c_slope, x, y, sec->ceilingheight) - FixedMul(mobjinfo[type].height, scale);
flip[numflats] = true;
numflats++;
}
if (sec->ffloors)
player->marescore++; // lol
for (i = 0; i < MAXPLAYERS; i++)
{
ffloor_t *rover;
for (rover = sec->ffloors; rover; rover = rover->next)
if (!playeringame[i] || players[i].spectator)
{
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER))
continue;
if (*rover->toppic != skyflatnum)
{
flatz[numflats] = P_GetZAt(*rover->t_slope, x, y, *rover->topheight);
numflats++;
}
if (*rover->bottompic != skyflatnum && ceiling)
{
flatz[numflats] = P_GetZAt(*rover->b_slope, x, y, *rover->bottomheight);
flip[numflats] = true;
numflats++;
}
continue;
}
if (&players[i] == player)
{
continue;
}
players[i].bumpers = 0;
}
if (numflats <= 0) // no flats
return;
K_CheckBumpers();
}
for (i = 0; i < numflats; i++)
mobj_t *K_SpawnChaosEmerald(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT32 emeraldType)
{
boolean validEmerald = true;
mobj_t *emerald = P_SpawnMobj(x, y, z, MT_EMERALD);
mobj_t *overlay;
P_Thrust(emerald,
FixedAngle(P_RandomFixed() * 180) + angle,
32 * mapobjectscale);
emerald->momz = flip * 24 * mapobjectscale;
if (emerald->eflags & MFE_UNDERWATER)
emerald->momz = (117 * emerald->momz) / 200;
emerald->threshold = 10;
switch (emeraldType)
{
mo = P_SpawnMobj(x, y, flatz[i], type);
case EMERALD_CHAOS1:
emerald->color = SKINCOLOR_CHAOSEMERALD1;
break;
case EMERALD_CHAOS2:
emerald->color = SKINCOLOR_CHAOSEMERALD2;
break;
case EMERALD_CHAOS3:
emerald->color = SKINCOLOR_CHAOSEMERALD3;
break;
case EMERALD_CHAOS4:
emerald->color = SKINCOLOR_CHAOSEMERALD4;
break;
case EMERALD_CHAOS5:
emerald->color = SKINCOLOR_CHAOSEMERALD5;
break;
case EMERALD_CHAOS6:
emerald->color = SKINCOLOR_CHAOSEMERALD6;
break;
case EMERALD_CHAOS7:
emerald->color = SKINCOLOR_CHAOSEMERALD7;
break;
default:
CONS_Printf("Invalid emerald type %d\n", emeraldType);
validEmerald = false;
break;
}
// Lastly, if this can see the skybox mobj, then... we just wasted our time :V
if (skyboxmo[0] && !P_MobjWasRemoved(skyboxmo[0]))
if (validEmerald == true)
{
emerald->extravalue1 = emeraldType;
}
overlay = P_SpawnMobjFromMobj(emerald, 0, 0, 0, MT_OVERLAY);
P_SetTarget(&overlay->target, emerald);
P_SetMobjState(overlay, S_CHAOSEMERALD_UNDER);
overlay->color = emerald->color;
return emerald;
}
void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType)
{
UINT8 i;
SINT8 flip = P_MobjFlip(player->mo);
for (i = 0; i < 14; i++)
{
UINT32 emeraldFlag = (1 << i);
if ((player->powers[pw_emeralds] & emeraldFlag) && (emeraldFlag & emeraldType))
{
const fixed_t sbz = skyboxmo[0]->z;
fixed_t checkz = sec->floorheight;
mobj_t *emerald = K_SpawnChaosEmerald(player->mo->x, player->mo->y, player->mo->z, player->mo->angle - ANGLE_90, flip, emeraldFlag);
P_SetTarget(&emerald->target, player->mo);
while (checkz < sec->ceilingheight)
{
P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, checkz);
if (P_CheckSight(skyboxmo[0], mo))
{
P_RemoveMobj(mo);
break;
}
else
checkz += 32*mapobjectscale;
}
P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, sbz);
if (P_MobjWasRemoved(mo))
continue;
}
P_SetScale(mo, scale);
if (flip[i])
{
mo->flags2 |= MF2_OBJECTFLIP;
mo->eflags |= MFE_VERTICALFLIP;
}
switch(type)
{
case MT_OVERTIMEFOG:
mo->destscale = 8*mo->scale;
mo->momz = P_RandomRange(1,8)*mo->scale;
break;
case MT_OVERTIMEORB:
//mo->destscale = mo->scale/4;
mo->frame += ((leveltime/4) % 8);
/*if (battleovertime.enabled < 10*TICRATE)
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;
default:
break;
player->powers[pw_emeralds] &= ~emeraldFlag;
}
}
}
#undef MAXPLANESPERSECTOR
UINT8 K_NumEmeralds(player_t *player)
{
UINT8 i;
UINT8 num = 0;
for (i = 0; i < 14; i++)
{
UINT32 emeraldFlag = (1 << i);
if (player->powers[pw_emeralds] & emeraldFlag)
{
num++;
}
}
return num;
}
void K_RunPaperItemSpawners(void)
{
const boolean overtime = (battleovertime.enabled >= 10*TICRATE);
tic_t interval = 8*TICRATE;
UINT32 emeraldsSpawned = 0;
UINT32 firstUnspawnedEmerald = 0;
thinker_t *th;
mobj_t *mo;
UINT8 pcount = 0;
INT16 i;
if (leveltime < starttime)
{
// Round hasn't started yet!
return;
}
if (overtime == true)
{
if (battleovertime.radius < 512*mapobjectscale)
{
// Barrier has closed in too much
return;
}
// Double frequency of items
interval /= 2;
}
if (((leveltime - starttime) % interval) != 0)
{
return;
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
{
continue;
}
emeraldsSpawned |= players[i].powers[pw_emeralds];
if ((players[i].exiting > 0 || players[i].eliminated)
|| ((gametyperules & GTR_BUMPERS) && players[i].bumpers <= 0))
{
continue;
}
pcount++;
}
if (overtime == true)
{
SINT8 flip = 1;
// Just find emeralds, no paper spots
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)th;
if (mo->type == MT_EMERALD)
{
emeraldsSpawned |= mo->extravalue1;
}
}
for (i = 0; i < 7; i++)
{
UINT32 emeraldFlag = (1 << i);
if (!(emeraldsSpawned & emeraldFlag))
{
firstUnspawnedEmerald = emeraldFlag;
break;
}
}
if (firstUnspawnedEmerald != 0)
{
K_SpawnChaosEmerald(
battleovertime.x, battleovertime.y, battleovertime.z + (128 * mapobjectscale * flip),
FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip,
firstUnspawnedEmerald
);
}
else
{
K_CreatePaperItem(
battleovertime.x, battleovertime.y, battleovertime.z + (128 * mapobjectscale * flip),
FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip,
0, 0
);
}
}
else
{
if (pcount > 0)
{
#define MAXITEM 64
UINT8 item = 0;
mobj_t *spotList[MAXITEM];
boolean spotUsed[MAXITEM];
INT16 starti = 0;
memset(spotUsed, false, sizeof(spotUsed));
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)th;
if (mo->type == MT_PAPERITEMSPOT)
{
if (item >= MAXITEM)
continue;
spotList[item] = mo;
item++;
}
else if (mo->type == MT_EMERALD)
{
emeraldsSpawned |= mo->extravalue1;
}
}
if (item <= 0)
{
return;
}
for (i = 0; i < 7; i++)
{
UINT32 emeraldFlag = (1 << i);
if (!(emeraldsSpawned & emeraldFlag))
{
firstUnspawnedEmerald = emeraldFlag;
starti = -1;
break;
}
}
for (i = starti; i < min(item + starti, pcount); i++)
{
UINT8 r = P_RandomKey(item);
UINT8 recursion = 0;
mobj_t *drop = NULL;
SINT8 flip = 1;
while (spotUsed[r] == true)
{
r = P_RandomKey(item);
if ((recursion++) > MAXITEM)
{
// roll with it anyway I guess
break;
}
}
flip = P_MobjFlip(spotList[r]);
// When -1, we're spawning a Chaos Emerald.
if (i == -1)
{
drop = K_SpawnChaosEmerald(
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip,
firstUnspawnedEmerald
);
}
else
{
drop = K_CreatePaperItem(
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
FixedAngle(P_RandomRange(0, 359) * FRACUNIT), flip,
0, 0
);
}
K_FlipFromObject(drop, spotList[r]);
spotUsed[r] = true;
}
}
}
}
static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale)
{
UINT8 i, j;
for (i = 0; i <= r_splitscreen; i++)
{
player_t *player = &players[displayplayers[i]];
fixed_t zpos;
SINT8 flip;
if (player == NULL || player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
{
continue;
}
if (player->mo->eflags & MFE_VERTICALFLIP)
{
zpos = player->mo->z + player->mo->height;
}
else
{
zpos = player->mo->z;
}
flip = P_MobjFlip(player->mo);
for (j = 0; j < 3; j++)
{
mobj_t *mo = P_SpawnMobj(x, y, zpos, MT_OVERTIME_PARTICLE);
if (player->mo->eflags & MFE_VERTICALFLIP)
{
mo->flags2 |= MF2_OBJECTFLIP;
mo->eflags |= MFE_VERTICALFLIP;
}
mo->angle = R_PointToAngle2(mo->x, mo->y, battleovertime.x, battleovertime.y) + ANGLE_90;
mo->drawflags |= (MFD_DONTDRAW & ~(K_GetPlayerDontDrawFlag(player)));
P_SetScale(mo, scale);
switch (j)
{
case 0:
P_SetMobjState(mo, S_OVERTIME_BULB1);
if (leveltime & 1)
mo->frame += 1;
//P_SetScale(mo, mapobjectscale);
zpos += 35 * mo->scale * flip;
break;
case 1:
P_SetMobjState(mo, S_OVERTIME_LASER);
if (leveltime & 1)
mo->frame += 3;
else
mo->frame += (leveltime / 2) % 3;
//P_SetScale(mo, scale);
zpos += 346 * mo->scale * flip;
if (battleovertime.enabled < 10*TICRATE)
mo->drawflags |= MFD_TRANS50;
break;
case 2:
P_SetMobjState(mo, S_OVERTIME_BULB2);
if (leveltime & 1)
mo->frame += 1;
//P_SetScale(mo, mapobjectscale);
break;
default:
I_Error("Bruh moment has occured\n");
return;
}
}
}
}
void K_RunBattleOvertime(void)
{
UINT16 i, j;
if (battleovertime.enabled < 10*TICRATE)
{
battleovertime.enabled++;
@ -404,70 +688,37 @@ void K_RunBattleOvertime(void)
if (battleovertime.enabled == 10*TICRATE)
S_StartSound(NULL, sfx_kc40);
}
else
else if (battleovertime.radius > 0)
{
if (battleovertime.radius > battleovertime.minradius)
battleovertime.radius -= mapobjectscale;
if (battleovertime.radius > 2*mapobjectscale)
battleovertime.radius -= 2*mapobjectscale;
else
battleovertime.radius = battleovertime.minradius;
battleovertime.radius = 0;
}
if (leveltime & 1)
if (battleovertime.radius > 0)
{
UINT8 transparency = tr_trans50;
const fixed_t pi = (22 * FRACUNIT) / 7; // loose approximation, this doesn't need to be incredibly precise
const INT32 orbs = 32;
const angle_t angoff = ANGLE_MAX / orbs;
const UINT8 spriteSpacing = 128;
if (!splitscreen && players[displayplayers[0]].mo)
{
INT32 dist = P_AproxDistance(battleovertime.x-players[displayplayers[0]].mo->x, battleovertime.y-players[displayplayers[0]].mo->y);
transparency = max(0, NUMTRANSMAPS - ((256 + (dist>>FRACBITS)) / 256));
}
fixed_t circumference = FixedMul(pi, battleovertime.radius * 2);
fixed_t scale = max(circumference / spriteSpacing / orbs, mapobjectscale);
if (transparency < NUMTRANSMAPS)
{
mobj_t *beam = P_SpawnMobj(battleovertime.x, battleovertime.y, battleovertime.z + (mobjinfo[MT_RANDOMITEM].height/2), MT_OVERTIMEBEAM);
P_SetScale(beam, beam->scale*2);
if (transparency > 0)
beam->frame |= transparency<<FF_TRANSSHIFT;
}
}
fixed_t size = FixedMul(mobjinfo[MT_OVERTIME_PARTICLE].radius, scale);
fixed_t posOffset = max(battleovertime.radius - size, 0);
// 16 orbs at the normal minimum size of 512
{
const fixed_t pi = (22<<FRACBITS) / 7; // loose approximation, this doesn't need to be incredibly precise
fixed_t scale = mapobjectscale + (battleovertime.radius/2048);
fixed_t sprwidth = 32*scale;
fixed_t circumference = FixedMul(pi, battleovertime.radius<<1);
UINT16 orbs = circumference / sprwidth;
angle_t angoff = ANGLE_MAX / orbs;
INT32 i;
for (i = 0; i < orbs; i++)
{
angle_t ang = (i * angoff) + FixedAngle((leveltime/2)<<FRACBITS);
fixed_t x = battleovertime.x + P_ReturnThrustX(NULL, ang, battleovertime.radius - FixedMul(mobjinfo[MT_OVERTIMEORB].radius, scale));
fixed_t y = battleovertime.y + P_ReturnThrustY(NULL, ang, battleovertime.radius - FixedMul(mobjinfo[MT_OVERTIMEORB].radius, scale));
K_SpawnOvertimeParticles(x, y, scale, MT_OVERTIMEORB, false);
}
}
angle_t ang = (i * angoff) + FixedAngle((leveltime * FRACUNIT) / 4);
if (battleovertime.enabled < 10*TICRATE)
return;
fixed_t x = battleovertime.x + P_ReturnThrustX(NULL, ang, posOffset);
fixed_t y = battleovertime.y + P_ReturnThrustY(NULL, ang, posOffset);
/*if (!S_IdPlaying(sfx_s3kd4s)) // global ambience
S_StartSoundAtVolume(NULL, sfx_s3kd4s, min(255, ((4096*mapobjectscale) - battleovertime.radius)>>FRACBITS / 2));*/
for (i = 0; i < 16; i++)
{
j = 0;
while (j < 32) // max attempts
{
fixed_t x = battleovertime.x + ((P_RandomRange(-64,64) * 128)<<FRACBITS);
fixed_t y = battleovertime.y + ((P_RandomRange(-64,64) * 128)<<FRACBITS);
fixed_t closestdist = battleovertime.radius + (8*mobjinfo[MT_OVERTIMEFOG].radius);
j++;
if (P_AproxDistance(x-battleovertime.x, y-battleovertime.y) < closestdist)
continue;
K_SpawnOvertimeParticles(x, y, 4*mapobjectscale, MT_OVERTIMEFOG, false);
break;
K_SpawnOvertimeLaser(x, y, scale);
}
}
}

View file

@ -7,7 +7,7 @@
extern struct battleovertime
{
UINT16 enabled; ///< Has this been initalized yet?
fixed_t radius, minradius; ///< Radius of kill field
fixed_t radius; ///< Radius of kill field
fixed_t x, y, z; ///< Position to center on
} battleovertime;
@ -20,6 +20,11 @@ boolean K_IsPlayerWanted(player_t *player);
void K_CalculateBattleWanted(void);
void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount);
void K_CheckBumpers(void);
void K_CheckEmeralds(player_t *player);
mobj_t *K_SpawnChaosEmerald(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT32 emeraldType);
void K_DropEmeraldsFromPlayer(player_t *player, UINT32 emeraldType);
UINT8 K_NumEmeralds(player_t *player);
void K_RunPaperItemSpawners(void);
void K_RunBattleOvertime(void);
void K_SetupMovingCapsule(mapthing_t *mt, mobj_t *mobj);
void K_SpawnBattleCapsules(void);

View file

@ -1036,6 +1036,7 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
K_BotItemSneaker(player, cmd);
break;
case KITEM_BANANA:
case KITEM_LANDMINE:
if (!player->kartstuff[k_itemheld])
{
K_BotItemGenericTrapShield(player, cmd, turnamt, false);

View file

@ -589,6 +589,7 @@ static boolean K_BotSteerObjects(mobj_t *thing)
case MT_JAWZ_SHIELD:
case MT_SSMINE:
case MT_SSMINE_SHIELD:
case MT_LANDMINE:
case MT_BALLHOG:
case MT_SPB:
case MT_BUBBLESHIELDTRAP:

View file

@ -30,7 +30,7 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
if (t2->player)
{
if (t2->player->powers[pw_flashing]
if ((t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0)
&& !(t1->type == MT_ORBINAUT || t1->type == MT_JAWZ || t1->type == MT_JAWZ_DUD))
return true;
@ -58,11 +58,6 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|| t2->type == MT_BALLHOG)
{
// Other Item Damage
if (t2->eflags & MFE_VERTICALFLIP)
t2->z -= t2->height;
else
t2->z += t2->height;
S_StartSound(t2, t2->info->deathsound);
P_KillMobj(t2, t1, t1, DMG_NORMAL);
@ -73,7 +68,7 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
damageitem = true;
}
else if (t2->type == MT_SSMINE_SHIELD || t2->type == MT_SSMINE)
else if (t2->type == MT_SSMINE_SHIELD || t2->type == MT_SSMINE || t2->type == MT_LANDMINE)
{
damageitem = true;
// Bomb death
@ -94,11 +89,6 @@ boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
if (damageitem)
{
// This Item Damage
if (t1->eflags & MFE_VERTICALFLIP)
t1->z -= t1->height;
else
t1->z += t1->height;
S_StartSound(t1, t1->info->deathsound);
P_KillMobj(t1, t2, t2, DMG_NORMAL);
@ -133,7 +123,7 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2)
if (t2->player)
{
if (t2->player->powers[pw_flashing])
if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0)
return true;
// Banana snipe!
@ -147,7 +137,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2)
}
else
{
// Player Damage
P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL);
}
@ -159,11 +148,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2)
|| t2->type == MT_BALLHOG)
{
// Other Item Damage
if (t2->eflags & MFE_VERTICALFLIP)
t2->z -= t2->height;
else
t2->z += t2->height;
S_StartSound(t2, t2->info->deathsound);
P_KillMobj(t2, t1, t1, DMG_NORMAL);
@ -174,6 +158,12 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2)
damageitem = true;
}
else if (t2->type == MT_SSMINE_SHIELD || t2->type == MT_SSMINE || t2->type == MT_LANDMINE)
{
damageitem = true;
// Bomb death
P_KillMobj(t2, t1, t1, DMG_NORMAL);
}
else if (t2->flags & MF_SHOOTABLE)
{
// Shootable damage
@ -184,11 +174,6 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2)
if (damageitem)
{
// This Item Damage
if (t1->eflags & MFE_VERTICALFLIP)
t1->z -= t1->height;
else
t1->z += t1->height;
S_StartSound(t1, t1->info->deathsound);
P_KillMobj(t1, t2, t2, DMG_NORMAL);
@ -219,11 +204,15 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2)
if (!P_CanPickupItem(t2->player, 2))
return true;
if ((gametyperules & GTR_BUMPERS) && t2->player->kartstuff[k_bumper] <= 0)
if ((gametyperules & GTR_BUMPERS) && t2->player->bumpers <= 0)
{
if (t2->player->kartstuff[k_comebackmode] || t2->player->kartstuff[k_comebacktimer])
#ifdef OTHERKARMAMODES
if (t2->player->kartstuff[k_comebackmode] || t2->player->karmadelay)
return true;
t2->player->kartstuff[k_comebackmode] = 2;
#else
return true;
#endif
}
else
{
@ -253,7 +242,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2)
if (t1->target && t1->target->player)
{
if ((gametyperules & GTR_CIRCUIT) || t1->target->player->kartstuff[k_bumper] > 0)
if ((gametyperules & GTR_CIRCUIT) || t1->target->player->bumpers > 0)
t2->player->kartstuff[k_eggmanblame] = t1->target->player-players;
else
t2->player->kartstuff[k_eggmanblame] = t2->player-players;
@ -283,15 +272,19 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2)
if (t2->player)
{
if (t2->player->powers[pw_flashing])
if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0)
return true;
// Bomb punting
if ((t1->state >= &states[S_SSMINE1] && t1->state <= &states[S_SSMINE4])
|| (t1->state >= &states[S_SSMINE_DEPLOY8] && t1->state <= &states[S_SSMINE_DEPLOY13]))
{
P_KillMobj(t1, t2, t2, DMG_NORMAL);
}
else
{
K_PuntMine(t1, t2);
}
}
else if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD
|| t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD)
@ -300,11 +293,6 @@ boolean K_MineCollide(mobj_t *t1, mobj_t *t2)
P_KillMobj(t1, t2, t2, DMG_NORMAL);
// Other Item Damage
if (t2->eflags & MFE_VERTICALFLIP)
t2->z -= t2->height;
else
t2->z += t2->height;
S_StartSound(t2, t2->info->deathsound);
P_KillMobj(t2, t1, t1, DMG_NORMAL);
@ -326,10 +314,17 @@ boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2)
{
if (t2->player)
{
if (t2->player->powers[pw_flashing])
if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0)
return true;
P_DamageMobj(t2, t1, t1->target, 1, (t1->state == &states[S_MINEEXPLOSION1]) ? DMG_EXPLODE : DMG_NORMAL);
if (t1->state == &states[S_MINEEXPLOSION1])
{
P_DamageMobj(t2, t1, t1->target, 1, DMG_EXPLODE);
}
else
{
P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL);
}
}
else if (t2->flags & MF_SHOOTABLE)
{
@ -340,6 +335,73 @@ boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2)
return true;
}
boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2)
{
if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
return true;
if (t1->health <= 0 || t2->health <= 0)
return true;
if (t2->player)
{
if (t2->player->powers[pw_flashing])
return true;
// Banana snipe!
if (t1->health > 1)
S_StartSound(t2, sfx_bsnipe);
if (t2->player->kartstuff[k_flamedash] && t2->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)
{
// Melt item
S_StartSound(t2, sfx_s3k43);
}
else
{
// Player Damage
P_DamageMobj(t2, t1, t1->target, 1, DMG_TUMBLE);
}
P_KillMobj(t1, t2, t2, DMG_NORMAL);
}
else if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD
|| t2->type == MT_ORBINAUT || t2->type == MT_ORBINAUT_SHIELD
|| t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD || t2->type == MT_JAWZ_SHIELD
|| t2->type == MT_BALLHOG)
{
// Other Item Damage
if (t2->eflags & MFE_VERTICALFLIP)
t2->z -= t2->height;
else
t2->z += t2->height;
S_StartSound(t2, t2->info->deathsound);
P_KillMobj(t2, t1, t1, DMG_NORMAL);
P_SetObjectMomZ(t2, 8*FRACUNIT, false);
P_InstaThrust(t2, R_PointToAngle2(t1->x, t1->y, t2->x, t2->y)+ANGLE_90, 16*FRACUNIT);
P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH);
P_KillMobj(t1, t2, t2, DMG_NORMAL);
}
else if (t2->type == MT_SSMINE_SHIELD || t2->type == MT_SSMINE || t2->type == MT_LANDMINE)
{
P_KillMobj(t1, t2, t2, DMG_NORMAL);
// Bomb death
P_KillMobj(t2, t1, t1, DMG_NORMAL);
}
else if (t2->flags & MF_SHOOTABLE)
{
// Shootable damage
P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL);
P_KillMobj(t1, t2, t2, DMG_NORMAL);
}
return true;
}
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2)
{
if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
@ -347,14 +409,16 @@ boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2)
if (t2->player)
{
if (t2->player->powers[pw_flashing])
if (t2->player->powers[pw_flashing] > 0 && t2->hitlag == 0)
return true;
S_StartSound(NULL, sfx_bsnipe); // let all players hear it.
HU_SetCEchoFlags(0);
HU_SetCEchoDuration(5);
HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[t2->player-players]));
I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[t2->player-players]);
P_DamageMobj(t2, t1, t1->target, 1, DMG_INSTAKILL);
P_KillMobj(t1, t2, t2, DMG_NORMAL);
}
@ -393,10 +457,112 @@ boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2)
if (t1->health)
P_KillMobj(t1, t2, t2, DMG_NORMAL);
/*if (t2->player && (t2->player->kartstuff[k_invincibilitytimer] > 0
/*
if (t2->player && (t2->player->kartstuff[k_invincibilitytimer] > 0
|| t2->player->kartstuff[k_growshrinktimer] > 0))
return true;*/
return true;
*/
K_KartBouncing(t2, t1, false, true);
return false;
}
boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
{
boolean t1Condition = false;
boolean t2Condition = false;
boolean stung = false;
// Grow damage
t1Condition = (t1->scale > t2->scale + (mapobjectscale/8));
t2Condition = (t2->scale > t1->scale + (mapobjectscale/8));
if (t1Condition == true && t2Condition == false)
{
P_DamageMobj(t2, t1, t1, 1, DMG_TUMBLE);
return true;
}
else if (t1Condition == false && t2Condition == true)
{
P_DamageMobj(t1, t2, t2, 1, DMG_TUMBLE);
return true;
}
// Invincibility damage
t1Condition = (t1->player->kartstuff[k_invincibilitytimer] > 0);
t2Condition = (t2->player->kartstuff[k_invincibilitytimer] > 0);
if (t1Condition == true && t2Condition == false)
{
P_DamageMobj(t2, t1, t1, 1, DMG_TUMBLE);
return true;
}
else if (t1Condition == false && t2Condition == true)
{
P_DamageMobj(t1, t2, t2, 1, DMG_TUMBLE);
return true;
}
// Flame Shield dash damage
t1Condition = (t1->player->kartstuff[k_flamedash] > 0 && t1->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD);
t2Condition = (t2->player->kartstuff[k_flamedash] > 0 && t2->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD);
if (t1Condition == true && t2Condition == false)
{
P_DamageMobj(t2, t1, t1, 1, DMG_WIPEOUT);
return true;
}
else if (t1Condition == false && t2Condition == true)
{
P_DamageMobj(t1, t2, t2, 1, DMG_WIPEOUT);
return true;
}
// Battle Mode Sneaker damage
// (Pogo Spring damage is handled in head-stomping code)
if (gametyperules & GTR_BUMPERS)
{
t1Condition = (t1->player->kartstuff[k_sneakertimer] > 0 && t1->player->powers[pw_flashing] != 0);
t2Condition = (t2->player->kartstuff[k_sneakertimer] > 0 && t2->player->powers[pw_flashing] != 0);
if (t1Condition == true && t2Condition == false)
{
P_DamageMobj(t2, t1, t1, 1, DMG_WIPEOUT|DMG_STEAL);
return true;
}
else if (t1Condition == false && t2Condition == true)
{
P_DamageMobj(t1, t2, t2, 1, DMG_WIPEOUT|DMG_STEAL);
return true;
}
}
// Ring sting, this is a bit more unique
t1Condition = (K_GetShieldFromItem(t2->player->kartstuff[k_itemtype]) == KSHIELD_NONE);
t2Condition = (K_GetShieldFromItem(t1->player->kartstuff[k_itemtype]) == KSHIELD_NONE);
if (t1Condition == true)
{
if (t2->player->rings <= 0)
{
P_DamageMobj(t2, t1, t1, 1, DMG_STING);
stung = true;
}
P_PlayerRingBurst(t2->player, 1);
stung = true;
}
if (t2Condition == true)
{
if (t1->player->rings <= 0)
{
P_DamageMobj(t1, t2, t2, 1, DMG_STING);
stung = true;
}
P_PlayerRingBurst(t2->player, 1);
}
return stung;
}

View file

@ -9,8 +9,10 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2);
boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2);
boolean K_MineCollide(mobj_t *t1, mobj_t *t2);
boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2);
boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2);
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2);
boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2);
boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2);
boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2);
#endif

View file

@ -50,6 +50,7 @@ static patch_t *kp_bumperstickerwide;
static patch_t *kp_capsulesticker;
static patch_t *kp_capsulestickerwide;
static patch_t *kp_karmasticker;
static patch_t *kp_spheresticker;
static patch_t *kp_splitkarmabomb;
static patch_t *kp_timeoutsticker;
@ -87,6 +88,9 @@ static patch_t *kp_rankbumper;
static patch_t *kp_tinybumper[2];
static patch_t *kp_ranknobumpers;
static patch_t *kp_rankcapsule;
static patch_t *kp_rankemerald;
static patch_t *kp_rankemeraldflash;
static patch_t *kp_rankemeraldback;
static patch_t *kp_battlewin;
static patch_t *kp_battlecool;
@ -111,6 +115,7 @@ static patch_t *kp_eggman[2];
static patch_t *kp_orbinaut[5];
static patch_t *kp_jawz[2];
static patch_t *kp_mine[2];
static patch_t *kp_landmine[2];
static patch_t *kp_ballhog[2];
static patch_t *kp_selfpropelledbomb[2];
static patch_t *kp_grow[2];
@ -174,6 +179,7 @@ void K_LoadKartHUDGraphics(void)
kp_capsulesticker = W_CachePatchName("K_STCAPN", PU_HUDGFX);
kp_capsulestickerwide = W_CachePatchName("K_STCAPW", PU_HUDGFX);
kp_karmasticker = W_CachePatchName("K_STKARM", PU_HUDGFX);
kp_spheresticker = W_CachePatchName("K_STBSMT", PU_HUDGFX);
kp_splitkarmabomb = W_CachePatchName("K_SPTKRM", PU_HUDGFX);
kp_timeoutsticker = W_CachePatchName("K_STTOUT", PU_HUDGFX);
@ -348,6 +354,9 @@ void K_LoadKartHUDGraphics(void)
kp_tinybumper[1] = W_CachePatchName("K_BLNB", PU_HUDGFX);
kp_ranknobumpers = W_CachePatchName("K_NOBLNS", PU_HUDGFX);
kp_rankcapsule = W_CachePatchName("K_CAPICO", PU_HUDGFX);
kp_rankemerald = W_CachePatchName("K_EMERC", PU_HUDGFX);
kp_rankemeraldflash = W_CachePatchName("K_EMERW", PU_HUDGFX);
kp_rankemeraldback = W_CachePatchName("K_EMERBK", PU_HUDGFX);
// Battle graphics
kp_battlewin = W_CachePatchName("K_BWIN", PU_HUDGFX);
@ -386,6 +395,7 @@ void K_LoadKartHUDGraphics(void)
}
kp_jawz[0] = W_CachePatchName("K_ITJAWZ", PU_HUDGFX);
kp_mine[0] = W_CachePatchName("K_ITMINE", PU_HUDGFX);
kp_landmine[0] = W_CachePatchName("K_ITLNDM", PU_HUDGFX);
kp_ballhog[0] = W_CachePatchName("K_ITBHOG", PU_HUDGFX);
kp_selfpropelledbomb[0] = W_CachePatchName("K_ITSPB", PU_HUDGFX);
kp_grow[0] = W_CachePatchName("K_ITGROW", PU_HUDGFX);
@ -435,6 +445,7 @@ void K_LoadKartHUDGraphics(void)
kp_orbinaut[4] = W_CachePatchName("K_ISORBN", PU_HUDGFX);
kp_jawz[1] = W_CachePatchName("K_ISJAWZ", PU_HUDGFX);
kp_mine[1] = W_CachePatchName("K_ISMINE", PU_HUDGFX);
kp_landmine[1] = W_CachePatchName("K_ISLNDM", PU_HUDGFX);
kp_ballhog[1] = W_CachePatchName("K_ISBHOG", PU_HUDGFX);
kp_selfpropelledbomb[1] = W_CachePatchName("K_ISSPB", PU_HUDGFX);
kp_grow[1] = W_CachePatchName("K_ISGROW", PU_HUDGFX);
@ -611,6 +622,8 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny)
return (tiny ? "K_ISJAWZ" : "K_ITJAWZ");
case KITEM_MINE:
return (tiny ? "K_ISMINE" : "K_ITMINE");
case KITEM_LANDMINE:
return (tiny ? "K_ISLNDM" : "K_ITLNDM");
case KITEM_BALLHOG:
return (tiny ? "K_ISBHOG" : "K_ITBHOG");
case KITEM_SPB:
@ -729,11 +742,12 @@ void K_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du
if (options & V_SLIDEIN)
{
tic_t length = TICRATE/2;
const tic_t length = TICRATE/2;
const tic_t end = (lt_endtime + length);
if (leveltime < introtime + length)
if (lt_ticker < end)
{
INT32 offset = screenwidth - (((leveltime - introtime) * screenwidth) / length);
INT32 offset = screenwidth - ((lt_exitticker * screenwidth) / length);
boolean slidefromright = false;
if (r_splitscreen > 1)
@ -961,6 +975,10 @@ static void K_drawKartItem(void)
localpatch = kp_superring[offset];
//localcolor = SKINCOLOR_GOLD;
break;
case 15: // Land Mine
localpatch = kp_landmine[offset];
//localcolor = SKINCOLOR_JET;
break;
/*case 15: // Pogo Spring
localpatch = kp_pogospring[offset];
localcolor = SKINCOLOR_TANGERINE;
@ -1046,6 +1064,9 @@ static void K_drawKartItem(void)
case KITEM_MINE:
localpatch = kp_mine[offset];
break;
case KITEM_LANDMINE:
localpatch = kp_landmine[offset];
break;
case KITEM_BALLHOG:
localpatch = kp_ballhog[offset];
break;
@ -1513,7 +1534,7 @@ static boolean K_drawKartPositionFaces(void)
INT32 i, j, ranklines, strank = -1;
boolean completed[MAXPLAYERS];
INT32 rankplayer[MAXPLAYERS];
INT32 bumperx, numplayersingame = 0;
INT32 bumperx, emeraldx, numplayersingame = 0;
UINT8 *colormap;
ranklines = 0;
@ -1594,6 +1615,7 @@ static boolean K_drawKartPositionFaces(void)
if (!players[rankplayer[i]].mo) continue;
bumperx = FACE_X+19;
emeraldx = FACE_X+16;
if (players[rankplayer[i]].mo->color)
{
@ -1607,22 +1629,35 @@ static boolean K_drawKartPositionFaces(void)
if (LUA_HudEnabled(hud_battlebumpers))
{
if (gametype == GT_BATTLE && players[rankplayer[i]].kartstuff[k_bumper] > 0)
if ((gametyperules & GTR_BUMPERS) && players[rankplayer[i]].bumpers > 0)
{
V_DrawMappedPatch(bumperx-2, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_tinybumper[0], colormap);
for (j = 1; j < players[rankplayer[i]].kartstuff[k_bumper]; j++)
for (j = 1; j < players[rankplayer[i]].bumpers; j++)
{
bumperx += 5;
V_DrawMappedPatch(bumperx, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_tinybumper[1], colormap);
}
}
} // A new level of stupidity: checking if lua is enabled to close a bracket. :Fascinating:
}
}
for (j = 0; j < 7; j++)
{
UINT32 emeraldFlag = (1 << j);
UINT16 emeraldColor = SKINCOLOR_CHAOSEMERALD1 + j;
if (players[rankplayer[i]].powers[pw_emeralds] & emeraldFlag)
{
colormap = R_GetTranslationColormap(TC_DEFAULT, emeraldColor, GTC_CACHE);
V_DrawMappedPatch(emeraldx, Y+7, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_rankemerald, colormap);
emeraldx += 7;
}
}
if (i == strank)
V_DrawScaledPatch(FACE_X, Y, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_facehighlight[(leveltime / 4) % 8]);
if (gametype == GT_BATTLE && players[rankplayer[i]].kartstuff[k_bumper] <= 0)
if (gametype == GT_BATTLE && players[rankplayer[i]].bumpers <= 0)
V_DrawScaledPatch(FACE_X-4, Y-3, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_ranknobumpers);
else
{
@ -1639,6 +1674,59 @@ static boolean K_drawKartPositionFaces(void)
return false;
}
static void K_drawKartEmeralds(void)
{
static const INT32 emeraldOffsets[7][2] = {
{34, 0},
{25, 8},
{43, 8},
{16, 0},
{52, 0},
{7, 8},
{61, 8}
};
const INT32 startx = BASEVIDWIDTH - 77 - 8;
const INT32 starty = BASEVIDHEIGHT - 29 - 8;
INT32 i;
V_DrawScaledPatch(startx, starty, V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT, kp_rankemeraldback);
for (i = 0; i < 7; i++)
{
UINT32 emeraldFlag = (1 << i);
UINT16 emeraldColor = SKINCOLOR_CHAOSEMERALD1 + i;
if (stplyr->powers[pw_emeralds] & emeraldFlag)
{
boolean whiteFlash = (leveltime & 1);
UINT8 *colormap;
if (i & 1)
{
whiteFlash = !whiteFlash;
}
colormap = R_GetTranslationColormap(TC_DEFAULT, emeraldColor, GTC_CACHE);
V_DrawMappedPatch(
startx + emeraldOffsets[i][0], starty + emeraldOffsets[i][1],
V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT,
kp_rankemerald, colormap
);
if (whiteFlash == true)
{
V_DrawScaledPatch(
startx + emeraldOffsets[i][0], starty + emeraldOffsets[i][1],
V_HUDTRANSHALF|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT,
kp_rankemeraldflash
);
}
}
}
}
//
// HU_DrawTabRankings -- moved here to take advantage of kart stuff!
//
@ -1720,11 +1808,11 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN
colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE);
V_DrawMappedPatch(x, y-4, 0, faceprefix[players[tab[i].num].skin][FACE_RANK], colormap);
/*if (gametype == GT_BATTLE && players[tab[i].num].kartstuff[k_bumper] > 0) -- not enough space for this
/*if (gametype == GT_BATTLE && players[tab[i].num].bumpers > 0) -- not enough space for this
{
INT32 bumperx = x+19;
V_DrawMappedPatch(bumperx-2, y-4, 0, kp_tinybumper[0], colormap);
for (j = 1; j < players[tab[i].num].kartstuff[k_bumper]; j++)
for (j = 1; j < players[tab[i].num].bumpers; j++)
{
bumperx += 5;
V_DrawMappedPatch(bumperx, y-4, 0, kp_tinybumper[1], colormap);
@ -1735,7 +1823,7 @@ void K_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, IN
if (tab[i].num == whiteplayer)
V_DrawScaledPatch(x, y-4, 0, kp_facehighlight[(leveltime / 4) % 8]);
if (gametype == GT_BATTLE && players[tab[i].num].kartstuff[k_bumper] <= 0)
if (gametype == GT_BATTLE && players[tab[i].num].bumpers <= 0)
V_DrawScaledPatch(x-4, y-7, 0, kp_ranknobumpers);
else
{
@ -1903,11 +1991,7 @@ static void K_drawKartLapsAndRings(void)
{
// Laps
V_DrawScaledPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_lapsticker);
if (stplyr->exiting)
V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, "FIN");
else
V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", stplyr->laps, cv_numlaps.value));
V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", min(stplyr->laps, cv_numlaps.value), cv_numlaps.value));
// Rings
if (!uselives)
@ -1951,7 +2035,7 @@ static void K_drawKartSpeedometer(void)
UINT8 labeln = 0;
UINT8 numbers[3];
INT32 splitflags = V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN;
UINT8 battleoffset = 0;
INT32 battleoffset = 0;
if (!stplyr->exiting) // Keep the same speed value as when you crossed the finish line!
{
@ -1986,7 +2070,7 @@ static void K_drawKartSpeedometer(void)
numbers[2] = (convSpeed % 10);
if (gametype == GT_BATTLE)
battleoffset = 8;
battleoffset = -4;
V_DrawScaledPatch(LAPS_X, LAPS_Y-25 + battleoffset, V_HUDTRANS|V_SLIDEIN|splitflags, kp_speedometersticker);
V_DrawScaledPatch(LAPS_X+7, LAPS_Y-25 + battleoffset, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[numbers[0]]);
@ -1995,6 +2079,36 @@ static void K_drawKartSpeedometer(void)
V_DrawScaledPatch(LAPS_X+29, LAPS_Y-25 + battleoffset, V_HUDTRANS|V_SLIDEIN|splitflags, kp_speedometerlabel[labeln]);
}
static void K_drawBlueSphereMeter(void)
{
const UINT8 maxBars = 4;
const UINT8 segColors[] = {73, 64, 52, 54, 55, 35, 34, 33, 202, 180, 181, 182, 164, 165, 166, 153, 152};
const UINT8 sphere = max(min(stplyr->spheres, 40), 0);
UINT8 numBars = min((sphere / 10), maxBars);
UINT8 colorIndex = (sphere * sizeof(segColors)) / (40 + 1);
INT32 x = LAPS_X + 25;
UINT8 i;
V_DrawScaledPatch(LAPS_X, LAPS_Y - 22, V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN, kp_spheresticker);
for (i = 0; i <= numBars; i++)
{
UINT8 segLen = 10;
if (i == numBars)
{
segLen = (sphere % 10);
}
V_DrawFill(x, LAPS_Y - 16, segLen, 3, segColors[max(colorIndex-1, 0)] | V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN);
V_DrawFill(x, LAPS_Y - 15, segLen, 1, segColors[max(colorIndex-2, 0)] | V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN);
V_DrawFill(x, LAPS_Y - 13, segLen, 3, segColors[colorIndex] | V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN);
x += 15;
}
}
static void K_drawKartBumpersOrKarma(void)
{
UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, stplyr->skincolor, GTC_CACHE);
@ -2058,37 +2172,28 @@ static void K_drawKartBumpersOrKarma(void)
}
else
{
if (stplyr->kartstuff[k_bumper] <= 0)
INT32 maxbumper = K_StartingBumperCount();
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap);
if (stplyr->bumpers > 9 || maxbumper > 9)
{
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_splitkarmabomb, colormap);
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->kartstuff[k_comebackpoints]) % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[2]);
UINT8 ln[2];
ln[0] = (stplyr->bumpers / 10 % 10);
ln[1] = (stplyr->bumpers % 10);
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]);
V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]);
ln[0] = ((abs(maxbumper) / 10) % 10);
ln[1] = (abs(maxbumper) % 10);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]);
V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]);
}
else
{
INT32 maxbumper = K_StartingBumperCount();
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap);
if (stplyr->kartstuff[k_bumper] > 9 || maxbumper > 9)
{
UINT8 ln[2];
ln[0] = ((abs(stplyr->kartstuff[k_bumper]) / 10) % 10);
ln[1] = (abs(stplyr->kartstuff[k_bumper]) % 10);
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]);
V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]);
ln[0] = ((abs(maxbumper) / 10) % 10);
ln[1] = (abs(maxbumper) % 10);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]);
V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]);
}
else
{
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->kartstuff[k_bumper]) % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(maxbumper) % 10]);
}
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(stplyr->bumpers) % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(maxbumper) % 10]);
}
}
}
@ -2104,22 +2209,14 @@ static void K_drawKartBumpersOrKarma(void)
}
else
{
if (stplyr->kartstuff[k_bumper] <= 0)
{
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_karmasticker, colormap);
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/2", stplyr->kartstuff[k_comebackpoints]));
}
INT32 maxbumper = K_StartingBumperCount();
if (stplyr->bumpers > 9 && maxbumper > 9)
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumperstickerwide, colormap);
else
{
INT32 maxbumper = K_StartingBumperCount();
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumpersticker, colormap);
if (stplyr->kartstuff[k_bumper] > 9 && maxbumper > 9)
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumperstickerwide, colormap);
else
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumpersticker, colormap);
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", stplyr->kartstuff[k_bumper], maxbumper));
}
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", stplyr->bumpers, maxbumper));
}
}
}
@ -2130,6 +2227,9 @@ static void K_drawKartWanted(void)
UINT8 *colormap = NULL;
INT32 basex = 0, basey = 0;
if (!splitscreen)
return;
if (stplyr != &players[displayplayers[0]])
return;
@ -2542,6 +2642,18 @@ static void K_drawKartNameTags(void)
continue;
}
if (ntplayer->mo->drawflags & K_GetPlayerDontDrawFlag(stplyr))
{
// Invisible on this screen
continue;
}
if ((gametyperules & GTR_BUMPERS) && (ntplayer->bumpers <= 0))
{
// Dead in Battle
continue;
}
if (!P_CheckSight(stplyr->mo, ntplayer->mo))
{
// Can't see
@ -2864,7 +2976,7 @@ static void K_drawKartMinimap(void)
if (i != displayplayers[0] || r_splitscreen)
{
if (gametype == GT_BATTLE && players[i].kartstuff[k_bumper] <= 0)
if (gametype == GT_BATTLE && players[i].bumpers <= 0)
continue;
if (players[i].kartstuff[k_hyudorotimer] > 0)
@ -3300,9 +3412,9 @@ static void K_drawBattleFullscreen(void)
else
K_drawKartFinish();
}
else if (stplyr->kartstuff[k_bumper] <= 0 && stplyr->kartstuff[k_comebacktimer] && comeback && !stplyr->spectator && drawcomebacktimer)
else if (stplyr->bumpers <= 0 && stplyr->karmadelay && comeback && !stplyr->spectator && drawcomebacktimer)
{
UINT16 t = stplyr->kartstuff[k_comebacktimer]/(10*TICRATE);
UINT16 t = stplyr->karmadelay/(10*TICRATE);
INT32 txoff, adjust = (r_splitscreen > 1) ? 4 : 6; // normal string is 8, kart string is 12, half of that for ease
INT32 ty = (BASEVIDHEIGHT/2)+66;
@ -3332,11 +3444,11 @@ static void K_drawBattleFullscreen(void)
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, splitflags, kp_battlewait, NULL);
if (r_splitscreen > 1)
V_DrawString(x-txoff, ty, 0, va("%d", stplyr->kartstuff[k_comebacktimer]/TICRATE));
V_DrawString(x-txoff, ty, 0, va("%d", stplyr->karmadelay/TICRATE));
else
{
V_DrawFixedPatch(x<<FRACBITS, ty<<FRACBITS, scale, 0, kp_timeoutsticker, NULL);
V_DrawKartString(x-txoff, ty, 0, va("%d", stplyr->kartstuff[k_comebacktimer]/TICRATE));
V_DrawKartString(x-txoff, ty, 0, va("%d", stplyr->karmadelay/TICRATE));
}
}
@ -3523,7 +3635,7 @@ static void K_drawInput(void)
#define BUTTH 11
#define drawbutt(xoffs, butt, symb)\
if (stplyr->cmd.buttons & butt)\
if (!stplyr->exiting && (cmd->buttons & butt))\
{\
offs = 2;\
col = accent1;\
@ -3549,7 +3661,7 @@ static void K_drawInput(void)
y -= 1;
if (!cmd->turning) // no turn
if (stplyr->exiting || !cmd->turning) // no turn
target = 0;
else // turning of multiple strengths!
{
@ -3722,6 +3834,7 @@ static void K_drawDistributionDebugger(void)
kp_orbinaut[4],
kp_jawz[1],
kp_mine[1],
kp_landmine[1],
kp_ballhog[1],
kp_selfpropelledbomb[1],
kp_grow[1],
@ -3757,8 +3870,8 @@ static void K_drawDistributionDebugger(void)
if (!playeringame[i] || players[i].spectator)
continue;
pingame++;
if (players[i].kartstuff[k_bumper] > bestbumper)
bestbumper = players[i].kartstuff[k_bumper];
if (players[i].bumpers > bestbumper)
bestbumper = players[i].bumpers;
}
// lovely double loop......
@ -3879,11 +3992,12 @@ void K_drawKartHUD(void)
return;
}
battlefullscreen = ((gametype == GT_BATTLE)
battlefullscreen = ((gametyperules & (GTR_BUMPERS|GTR_KARMA)) == (GTR_BUMPERS|GTR_KARMA)
&& (stplyr->exiting
|| (stplyr->kartstuff[k_bumper] <= 0
&& stplyr->kartstuff[k_comebacktimer]
&& comeback
|| (stplyr->bumpers <= 0
&& stplyr->karmadelay > 0
&& stplyr->eliminated == false
&& comeback == true
&& stplyr->playerstate == PST_LIVE)));
if (!demo.title && (!battlefullscreen || r_splitscreen))
@ -3995,6 +4109,11 @@ void K_drawKartHUD(void)
if (LUA_HudEnabled(hud_gametypeinfo))
K_drawKartBumpersOrKarma();
}
if (gametyperules & GTR_SPHERES)
{
K_drawBlueSphereMeter();
}
}
// Draw the countdowns after everything else.
@ -4084,4 +4203,9 @@ void K_drawKartHUD(void)
}
K_DrawWaypointDebugger();
if (gametype == GT_BATTLE)
{
K_drawKartEmeralds();
}
}

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum
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);
boolean 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);
@ -39,14 +39,17 @@ void K_KartMoveAnimation(player_t *player);
void K_KartPlayerHUDUpdate(player_t *player);
void K_KartPlayerThink(player_t *player, ticcmd_t *cmd);
void K_KartPlayerAfterThink(player_t *player);
angle_t K_MomentumAngle(mobj_t *mo);
void K_SetHitLagForObjects(mobj_t *mo1, mobj_t *mo2, INT32 tics);
void K_DoInstashield(player_t *player);
void K_BattleHitPlayer(player_t *player, player_t *victim, UINT8 points, boolean reducewanted);
void K_RemoveBumper(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UINT8 bumpersRemoved);
void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type);
void K_SquishPlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_TumblePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_DebtStingPlayer(player_t *player, mobj_t *source);
void K_StealBumper(player_t *player, player_t *victim);
void K_HandleBumperChanges(player_t *player, UINT8 prevBumpers);
void K_DestroyBumpers(player_t *player, UINT8 amount);
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source);
void K_SpawnMineExplosion(mobj_t *source, UINT8 color);
UINT16 K_DriftSparkColor(player_t *player, INT32 charge);
@ -70,6 +73,7 @@ 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);
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount);
void K_DropItems(player_t *player);
void K_DropRocketSneaker(player_t *player);
void K_DropKitchenSink(player_t *player);
@ -77,7 +81,7 @@ 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);
INT16 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);

View file

@ -314,7 +314,7 @@ waypoint_t *K_GetBestWaypointForMobj(mobj_t *const mobj)
}
else if (checkdist < closestdist && bestfindist == INT32_MAX)
{
if (!P_CheckSight(mobj, checkwaypoint->mobj))
if (!P_TraceBlockingLines(mobj, checkwaypoint->mobj))
{
// Save sight checks for the end, so we only do it if we have to
continue;

View file

@ -387,7 +387,8 @@ static int lib_pAproxDistance(lua_State *L)
fixed_t dx = luaL_checkfixed(L, 1);
fixed_t dy = luaL_checkfixed(L, 2);
//HUDSAFE
lua_pushfixed(L, P_AproxDistance(dx, dy));
LUA_Deprecated(L, "P_AproxDistance", "FixedHypot");
lua_pushfixed(L, FixedHypot(dx, dy));
return 1;
}
@ -1409,6 +1410,18 @@ static int lib_pCheckSight(lua_State *L)
return 1;
}
static int lib_pTraceBlockingLines(lua_State *L)
{
mobj_t *t1 = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
mobj_t *t2 = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
//HUDSAFE?
INLEVEL
if (!t1 || !t2)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_TraceBlockingLines(t1, t2));
return 1;
}
static int lib_pCheckHoopPosition(lua_State *L)
{
mobj_t *hoopthing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -3400,7 +3413,7 @@ static int lib_kSpinPlayer(lua_State *L)
return 0;
}
static int lib_kSquishPlayer(lua_State *L)
static int lib_kTumblePlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
mobj_t *inflictor = NULL;
@ -3412,7 +3425,7 @@ static int lib_kSquishPlayer(lua_State *L)
inflictor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
source = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
K_SquishPlayer(player, inflictor, source);
K_TumblePlayer(player, inflictor, source);
return 0;
}
@ -3432,16 +3445,17 @@ static int lib_kExplodePlayer(lua_State *L)
return 0;
}
static int lib_kStealBumper(lua_State *L)
static int lib_kTakeBumpersFromPlayer(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
player_t *victim = *((player_t **)luaL_checkudata(L, 2, META_PLAYER));
UINT8 amount = (UINT8)luaL_optinteger(L, 3, 1);
NOHUD
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!victim)
return LUA_ErrInvalid(L, "player_t");
K_StealBumper(player, victim);
K_TakeBumpersFromPlayer(player, victim, amount);
return 0;
}
@ -3782,6 +3796,7 @@ static luaL_Reg lib[] = {
{"P_SlideMove",lib_pSlideMove},
{"P_BounceMove",lib_pBounceMove},
{"P_CheckSight", lib_pCheckSight},
{"P_TraceBlockingLines", lib_pTraceBlockingLines},
{"P_CheckHoopPosition",lib_pCheckHoopPosition},
{"P_RadiusAttack",lib_pRadiusAttack},
{"P_FloorzAtPos",lib_pFloorzAtPos},
@ -3916,9 +3931,9 @@ static luaL_Reg lib[] = {
{"K_DoInstashield",lib_kDoInstashield},
{"K_SpawnBattlePoints",lib_kSpawnBattlePoints},
{"K_SpinPlayer",lib_kSpinPlayer},
{"K_SquishPlayer",lib_kSquishPlayer},
{"K_TumblePlayer",lib_kTumblePlayer},
{"K_ExplodePlayer",lib_kExplodePlayer},
{"K_StealBumper",lib_kStealBumper},
{"K_TakeBumpersFromPlayer",lib_kTakeBumpersFromPlayer},
{"K_SpawnKartExplosion",lib_kSpawnKartExplosion},
{"K_SpawnMineExplosion",lib_kSpawnMineExplosion},
{"K_SpawnBoostTrail",lib_kSpawnBoostTrail},

View file

@ -536,7 +536,6 @@ static luaL_Reg lib[] = {
{"CV_StealthSet", lib_cvStealthSet},
{"CV_AddValue", lib_cvAddValue},
{"CONS_Printf", lib_consPrintf},
{"CV_FindVar", lib_cvFindVar},
{NULL, NULL}
};

View file

@ -109,10 +109,10 @@ void LUAh_PlayerQuit(player_t *plr, kickreason_t reason); // Hook for player qui
boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boolean *looping,
UINT32 *position, UINT32 *prefadems, UINT32 *fadeinms); // Hook for music changes
boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them.
boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Allows to write to player cmd before the game does anything with them.
void LUAh_IntermissionThinker(void); // Hook for Y_Ticker
void LUAh_VoteThinker(void); // Hook for Y_VoteTicker
void LUAh_VoteThinker(void); // Hook for Y_VoteTicker
#define LUAh_ShieldSpawn(player) LUAh_PlayerHook(player, hook_ShieldSpawn) // Hook for P_SpawnShieldOrb
#define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities
@ -128,4 +128,3 @@ boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend); // Hook for MT_
#define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink
boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname); // Hook for whether a jingle of the given music should continue playing
void LUAh_GameQuit(void); // Hook for game quitting
boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Hook for building player's ticcmd struct (Ported from SRB2Kart)

View file

@ -313,8 +313,6 @@ static int PopPivotSubTable(spriteframepivot_t *pivot, lua_State *L, int stk, in
pivot[idx].x = (INT32)value;
else if (ikey == 2 || (key && fastcmp(key, "y")))
pivot[idx].y = (INT32)value;
else if (ikey == 3 || (key && fastcmp(key, "rotaxis")))
pivot[idx].rotaxis = (UINT8)value;
else if (ikey == -1 && (key != NULL))
FIELDERROR("pivot key", va("invalid option %s", key));
okcool = 1;
@ -579,8 +577,6 @@ static int framepivot_get(lua_State *L)
lua_pushinteger(L, framepivot->x);
else if (fastcmp("y", field))
lua_pushinteger(L, framepivot->y);
else if (fastcmp("rotaxis", field))
lua_pushinteger(L, (UINT8)framepivot->rotaxis);
else
return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field));
@ -605,8 +601,6 @@ static int framepivot_set(lua_State *L)
framepivot->x = luaL_checkinteger(L, 3);
else if (fastcmp("y", field))
framepivot->y = luaL_checkinteger(L, 3);
else if (fastcmp("rotaxis", field))
framepivot->rotaxis = luaL_checkinteger(L, 3);
else
return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field));

View file

@ -14,7 +14,7 @@
//#include "fastcmp.h"
#include "tables.h"
#include "p_local.h"
#include "doomstat.h" // for ALL7EMERALDS
#include "doomstat.h" // for ALLCHAOSEMERALDS
#include "lua_script.h"
#include "lua_libs.h"
@ -162,7 +162,7 @@ static int lib_getsecspecial(lua_State *L)
static int lib_all7emeralds(lua_State *L)
{
lua_pushboolean(L, ALL7EMERALDS(luaL_checkinteger(L, 1)));
lua_pushboolean(L, ALLCHAOSEMERALDS(luaL_checkinteger(L, 1)));
return 1;
}

View file

@ -95,7 +95,8 @@ enum mobj_e {
mobj_whiteshadow,
mobj_sprxoff,
mobj_spryoff,
mobj_sprzoff
mobj_sprzoff,
mobj_hitlag
};
static const char *const mobj_opt[] = {
@ -170,6 +171,7 @@ static const char *const mobj_opt[] = {
"sprxoff",
"spryoff",
"sprzoff",
"hitlag",
NULL};
#define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field])
@ -430,6 +432,9 @@ static int mobj_get(lua_State *L)
case mobj_sprzoff:
lua_pushfixed(L, mo->sprzoff);
break;
case mobj_hitlag:
lua_pushinteger(L, mo->hitlag);
break;
default: // extra custom variables in Lua memory
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));
@ -787,6 +792,9 @@ static int mobj_set(lua_State *L)
case mobj_sprzoff:
mo->sprzoff = luaL_checkfixed(L, 3);
break;
case mobj_hitlag:
mo->hitlag = luaL_checkinteger(L, 3);
break;
default:
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));

View file

@ -26,25 +26,35 @@
static int lib_iteratePlayers(lua_State *L)
{
INT32 i = -1;
if (lua_gettop(L) < 2)
{
//return luaL_error(L, "Don't call players.iterate() directly, use it as 'for player in players.iterate do <block> end'.");
lua_pushcfunction(L, lib_iteratePlayers);
return 1;
}
lua_settop(L, 2);
lua_remove(L, 1); // state is unused.
if (!lua_isnil(L, 1))
i = (INT32)(*((player_t **)luaL_checkudata(L, 1, META_PLAYER)) - players);
for (i++; i < MAXPLAYERS; i++)
i++;
if (i == serverplayer)
{
return LUA_PushServerPlayer(L);
}
for (; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (!players[i].mo)
continue;
LUA_PushUserdata(L, &players[i], META_PLAYER);
return 1;
}
return 0;
}
@ -57,10 +67,10 @@ static int lib_getPlayer(lua_State *L)
lua_Integer i = luaL_checkinteger(L, 2);
if (i < 0 || i >= MAXPLAYERS)
return luaL_error(L, "players[] index %d out of range (0 - %d)", i, MAXPLAYERS-1);
if (i == serverplayer)
return LUA_PushServerPlayer(L);
if (!playeringame[i])
return 0;
if (!players[i].mo)
return 0;
LUA_PushUserdata(L, &players[i], META_PLAYER);
return 1;
}
@ -121,8 +131,6 @@ static int lib_iterateDisplayplayers(lua_State *L)
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)
continue;
LUA_PushUserdata(L, &players[displayplayers[i]], META_PLAYER);
lua_pushinteger(L, i); // push this to recall what number we were on for the next function call. I suppose this also means you can retrieve the splitscreen player number with 'for p, n in displayplayers.iterate'!
return 2;
@ -143,8 +151,6 @@ static int lib_getDisplayplayers(lua_State *L)
return 0;
if (!playeringame[displayplayers[i]])
return 0;
if (!players[displayplayers[i]].mo)
return 0;
LUA_PushUserdata(L, &players[displayplayers[i]], META_PLAYER);
return 1;
}
@ -182,17 +188,8 @@ static int player_get(lua_State *L)
lua_pushboolean(L, true);
else if (fastcmp(field,"name"))
lua_pushstring(L, player_names[plr-players]);
else if (fastcmp(field,"realmo"))
LUA_PushUserdata(L, plr->mo, META_MOBJ);
// Kept for backward-compatibility
// Should be fixed to work like "realmo" later
else if (fastcmp(field,"mo"))
{
if (plr->spectator)
lua_pushnil(L);
else
LUA_PushUserdata(L, plr->mo, META_MOBJ);
}
LUA_PushUserdata(L, plr->mo, META_MOBJ);
else if (fastcmp(field,"cmd"))
LUA_PushUserdata(L, &plr->cmd, META_TICCMD);
else if (fastcmp(field,"playerstate"))
@ -209,12 +206,30 @@ static int player_get(lua_State *L)
lua_pushangle(L, plr->drawangle);
else if (fastcmp(field,"rings"))
lua_pushinteger(L, plr->rings);
else if (fastcmp(field,"spheres"))
lua_pushinteger(L, plr->spheres);
else if (fastcmp(field,"powers"))
LUA_PushUserdata(L, plr->powers, META_POWERS);
else if (fastcmp(field,"kartstuff"))
LUA_PushUserdata(L, plr->kartstuff, META_KARTSTUFF);
else if (fastcmp(field,"airtime"))
lua_pushinteger(L, plr->airtime);
else if (fastcmp(field,"tumbleBounces"))
lua_pushinteger(L, plr->tumbleBounces);
else if (fastcmp(field,"tumbleHeight"))
lua_pushinteger(L, plr->tumbleHeight);
else if (fastcmp(field,"tumbleLastBounce"))
lua_pushboolean(L, plr->tumbleLastBounce);
else if (fastcmp(field,"trickpanel"))
lua_pushinteger(L, plr->trickpanel);
else if (fastcmp(field,"trickdelay"))
lua_pushinteger(L, plr->trickdelay);
else if (fastcmp(field,"trickmomx"))
lua_pushfixed(L, plr->trickmomx);
else if (fastcmp(field,"trickmomy"))
lua_pushfixed(L, plr->trickmomy);
else if (fastcmp(field,"trickmomz"))
lua_pushfixed(L, plr->trickmomz);
else if (fastcmp(field,"pflags"))
lua_pushinteger(L, plr->pflags);
else if (fastcmp(field,"panim"))
@ -447,7 +462,7 @@ static int player_set(lua_State *L)
if (hook_cmd_running)
return luaL_error(L, "Do not alter player_t in BuildCMD code!");
if (fastcmp(field,"mo") || fastcmp(field,"realmo")) {
if (fastcmp(field,"mo")) {
mobj_t *newmo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
plr->mo->player = NULL; // remove player pointer from old mobj
(newmo->player = plr)->mo = newmo; // set player pointer for new mobj, and set new mobj as the player's mobj
@ -478,6 +493,8 @@ static int player_set(lua_State *L)
plr->drawangle = luaL_checkangle(L, 3);
else if (fastcmp(field,"rings"))
plr->rings = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"spheres"))
plr->spheres = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"powers"))
return NOSET;
else if (fastcmp(field,"pflags"))
@ -502,6 +519,22 @@ static int player_set(lua_State *L)
return NOSET;
else if (fastcmp(field,"airtime"))
plr->airtime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"tumbleBounces"))
plr->tumbleBounces = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"tumbleHeight"))
plr->tumbleHeight = (UINT16)luaL_checkinteger(L, 3);
else if (fastcmp(field,"tumbleLastBounce"))
plr->tumbleLastBounce = luaL_checkboolean(L, 3);
else if (fastcmp(field,"trickpanel"))
plr->trickpanel = luaL_checkinteger(L, 3);
else if (fastcmp(field,"trickdelay"))
plr->trickdelay = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"trickmomx"))
plr->trickmomx = (fixed_t)luaL_checkfixed(L, 3);
else if (fastcmp(field,"trickmomy"))
plr->trickmomy = (fixed_t)luaL_checkfixed(L, 3);
else if (fastcmp(field,"trickmomz"))
plr->trickmomz = (fixed_t)luaL_checkfixed(L, 3);
else if (fastcmp(field,"kartspeed"))
plr->kartspeed = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"kartweight"))

View file

@ -731,6 +731,14 @@ void LUA_PushUserdata(lua_State *L, void *data, const char *meta)
lua_remove(L, -2); // remove LREG_VALID
}
int LUA_PushServerPlayer(lua_State *L)
{
if ((!multiplayer || !(netgame || demo.playback)) && !playeringame[serverplayer])
return 0;
LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
return 1;
}
// When userdata is freed, use this function to remove it from Lua.
void LUA_InvalidateUserdata(void *data)
{

View file

@ -49,6 +49,7 @@ void LUA_DumpFile(const char *filename);
fixed_t LUA_EvalMath(const char *word);
void LUA_PushLightUserdata(lua_State *L, void *data, const char *meta);
void LUA_PushUserdata(lua_State *L, void *data, const char *meta);
int LUA_PushServerPlayer(lua_State *L);
void LUA_InvalidateUserdata(void *data);
void LUA_InvalidateLevel(void);
void LUA_InvalidateMapthings(void);

View file

@ -771,12 +771,13 @@ void Command_Savecheckpoint_f(void)
}
// Like M_GetAllEmeralds() but for console devmode junkies.
/*void Command_Getallemeralds_f(void)
/*
void Command_Getallemeralds_f(void)
{
REQUIRE_SINGLEPLAYER;
REQUIRE_PANDORA;
emeralds = ((EMERALD7)*2)-1;
emeralds = EMERALD_ALL;
CONS_Printf(M_GetText("You now have all 7 emeralds.\n"));
}
@ -788,7 +789,8 @@ void Command_Resetemeralds_f(void)
emeralds = 0;
CONS_Printf(M_GetText("Emeralds reset to zero.\n"));
}*/
}
*/
void Command_Devmode_f(void)
{

View file

@ -341,6 +341,12 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
UINT8 M_AnySecretUnlocked(void)
{
INT32 i;
#ifdef DEVELOP
if (1)
return true;
#endif
for (i = 0; i < MAXUNLOCKABLES; ++i)
{
if (!unlockables[i].nocecho && unlockables[i].unlocked)
@ -376,6 +382,12 @@ UINT8 M_SecretUnlocked(INT32 type)
UINT8 M_MapLocked(INT32 mapnum)
{
#ifdef DEVELOP
if (1)
return false;
#endif
if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0)
return false;
if (!unlockables[mapheaderinfo[mapnum-1]->unlockrequired].unlocked)

View file

@ -18,8 +18,10 @@
#define HAVE_SQRTF
#endif
#endif
#include "doomdef.h"
#include "m_fixed.h"
#include "tables.h" // ANGLETOFINESHIFT
#ifdef __USE_C_FIXEDMUL__
@ -105,20 +107,34 @@ fixed_t FixedSqrt(fixed_t x)
fixed_t FixedHypot(fixed_t x, fixed_t y)
{
fixed_t ax, yx, yx2, yx1;
if (abs(y) > abs(x)) // |y|>|x|
// Moved the code from R_PointToDist2 to here,
// since R_PointToDist2 did the same thing,
// except less prone to overflowing.
angle_t angle;
fixed_t dist;
x = abs(x);
y = abs(y);
if (y > x)
{
ax = abs(y); // |y| => ax
yx = FixedDiv(x, y); // (x/y)
fixed_t temp;
temp = x;
x = y;
y = temp;
}
else // |x|>|y|
{
ax = abs(x); // |x| => ax
yx = FixedDiv(y, x); // (x/y)
}
yx2 = FixedMul(yx, yx); // (x/y)^2
yx1 = FixedSqrt(1 * FRACUNIT + yx2); // (1 + (x/y)^2)^1/2
return FixedMul(ax, yx1); // |x|*((1 + (x/y)^2)^1/2)
if (!y)
return x;
angle = (tantoangle[FixedDiv(y, x)>>DBITS] + ANGLE_90) >> ANGLETOFINESHIFT;
// use as cosine
dist = FixedDiv(x, FINESINE(angle));
return dist;
}
vector2_t *FV2_Load(vector2_t *vec, fixed_t x, fixed_t y)

View file

@ -6369,7 +6369,7 @@ static void M_GetAllEmeralds(INT32 choice)
{
(void)choice;
emeralds = ((EMERALD7)*2)-1;
emeralds = EMERALD_ALL;
M_StartMessage(M_GetText("You now have all 7 emeralds.\nUse them wisely.\nWith great power comes great ring drain.\n"),NULL,MM_NOTHING);
G_SetGameModified(multiplayer, true);
@ -8134,11 +8134,11 @@ static void M_ReplayTimeAttack(INT32 choice)
break;
case 3: // guest
// srb2/replay/main/map01-guest.lmp
G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)));
G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)));
return;
}
// srb2/replay/main/map01-sonic-time-best.lmp
G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which));
G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which));
}
/*else if (currentMenu == &SP_NightsReplayDef)
{
@ -8160,13 +8160,13 @@ static void M_ReplayTimeAttack(INT32 choice)
break;
}
// srb2/replay/main/map01-score-best.lmp
G_DoPlayDemo(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which));
G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), which));
}*/
}
static void M_EraseGuest(INT32 choice)
{
const char *rguest = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value));
const char *rguest = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value));
(void)choice;
if (FIL_FileExists(rguest))
remove(rguest);
@ -8181,10 +8181,10 @@ static void M_EraseGuest(INT32 choice)
static void M_OverwriteGuest(const char *which)
{
char *rguest = Z_StrDup(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)));
char *rguest = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)));
UINT8 *buf;
size_t len;
len = FIL_ReadFile(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which), &buf);
len = FIL_ReadFile(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, which), &buf);
if (!len) {
return;
}
@ -8253,7 +8253,7 @@ static void M_SetGuestReplay(INT32 choice)
M_StartMessage(M_GetText("Are you sure you want to\ndelete the guest replay data?\n\n(Press 'Y' to confirm)\n"),M_EraseGuest,MM_YESNO);
return;
}
if (FIL_FileExists(va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))))
if (FIL_FileExists(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value))))
M_StartMessage(M_GetText("Are you sure you want to\noverwrite the guest replay data?\n\n(Press 'Y' to confirm)\n"),which,MM_YESNO);
else
which(0);

View file

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2020 by Sonic Team Junior.
// Copyright (C) 1999-2018 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
@ -14,30 +14,34 @@
#ifndef __M_SWAP__
#define __M_SWAP__
// Endianess handling.
// WAD files are stored little endian.
#include "endian.h"
// Little to big endian
#define SWAP_SHORT(x) ((INT16)(\
(((UINT16)(x) & (UINT16)0x00ffU) << 8) \
| \
(((UINT16)(x) & (UINT16)0xff00U) >> 8))) \
#define SWAP_LONG(x) ((INT32)(\
(((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \
| \
(((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \
| \
(((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) \
| \
(((UINT32)(x) & (UINT32)0xff000000UL) >> 24)))
// Endianess handling.
// WAD files are stored little endian.
#ifdef SRB2_BIG_ENDIAN
#define SHORT(x) ((INT16)(\
(((UINT16)(x) & (UINT16)0x00ffU) << 8) \
| \
(((UINT16)(x) & (UINT16)0xff00U) >> 8))) \
#define LONG(x) ((INT32)(\
(((UINT32)(x) & (UINT32)0x000000ffUL) << 24) \
| \
(((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) \
| \
(((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) \
| \
(((UINT32)(x) & (UINT32)0xff000000UL) >> 24)))
#define SHORT SWAP_SHORT
#define LONG SWAP_LONG
#define MSBF_SHORT(x) ((INT16)(x))
#define MSBF_LONG(x) ((INT32)(x))
#else
#define SHORT(x) ((INT16)(x))
#define LONG(x) ((INT32)(x))
#define SHORT(x) ((INT16)(x))
#define LONG(x) ((INT32)(x))
#define MSBF_SHORT SWAP_SHORT
#define MSBF_LONG SWAP_LONG
#endif
// Big to little endian

View file

@ -68,6 +68,7 @@ static CV_PossibleValue_t masterserver_update_rate_cons_t[] = {
};
consvar_t cv_masterserver = CVAR_INIT ("masterserver", "https://ms.kartkrew.org/ms/api", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange);
consvar_t cv_rendezvousserver = CVAR_INIT ("rendezvousserver", "jart-dev.jameds.org", CV_SAVE, NULL, NULL);
consvar_t cv_servername = CVAR_INIT ("servername", "SRB2Kart server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters);
consvar_t cv_server_contact = CVAR_INIT ("server_contact", "", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters);
@ -99,6 +100,7 @@ void AddMServCommands(void)
CV_RegisterVar(&cv_masterserver_debug);
CV_RegisterVar(&cv_masterserver_token);
CV_RegisterVar(&cv_advertise);
CV_RegisterVar(&cv_rendezvousserver);
CV_RegisterVar(&cv_servername);
CV_RegisterVar(&cv_server_contact);
#ifdef MASTERSERVER

View file

@ -58,6 +58,7 @@ extern consvar_t cv_masterserver_update_rate;
extern consvar_t cv_masterserver_timeout;
extern consvar_t cv_masterserver_debug;
extern consvar_t cv_masterserver_token;
extern consvar_t cv_rendezvousserver;
extern consvar_t cv_advertise;

View file

@ -4428,7 +4428,7 @@ static inline boolean PIT_GrenadeRing(mobj_t *thing)
return true;
if (thing->player && (thing->player->kartstuff[k_hyudorotimer]
|| ((gametyperules & GTR_BUMPERS) && thing->player && thing->player->kartstuff[k_bumper] <= 0 && thing->player->kartstuff[k_comebacktimer])))
|| ((gametyperules & GTR_BUMPERS) && thing->player && thing->player->bumpers <= 0 && thing->player->karmadelay)))
return true;
// see if it went over / under
@ -4481,7 +4481,7 @@ static inline boolean PIT_MineExplode(mobj_t *thing)
if (!grenade || P_MobjWasRemoved(grenade))
return false; // There's the possibility these can chain react onto themselves after they've already died if there are enough all in one spot
if (grenade->flags2 & MF2_DEBRIS) // don't explode twice
if (grenade->flags2 & MF2_DEBRIS) // don't explode twice
return false;
if (thing == grenade || thing->type == MT_MINEEXPLOSIONSOUND) // Don't explode yourself! Endless loop!
@ -4493,7 +4493,7 @@ static inline boolean PIT_MineExplode(mobj_t *thing)
if (netgame && thing->player && thing->player->spectator)
return true;
if ((gametyperules & GTR_BUMPERS) && grenade->target && grenade->target->player && grenade->target->player->kartstuff[k_bumper] <= 0 && thing == grenade->target)
if ((gametyperules & GTR_BUMPERS) && grenade->target && grenade->target->player && grenade->target->player->bumpers <= 0 && thing == grenade->target)
return true;
// see if it went over / under
@ -8642,7 +8642,7 @@ void A_ItemPop(mobj_t *actor)
if (actor->info->deathsound)
S_StartSound(remains, actor->info->deathsound);
if (!((gametyperules & GTR_BUMPERS) && actor->target->player->kartstuff[k_bumper] <= 0))
if (!((gametyperules & GTR_BUMPERS) && actor->target->player->bumpers <= 0))
actor->target->player->kartstuff[k_itemroulette] = 1;
remains->flags2 &= ~MF2_AMBUSH;
@ -8676,7 +8676,7 @@ void A_JawzChase(mobj_t *actor)
angle_t angledelta = actor->angle - targetangle;
boolean turnclockwise = true;
if ((gametyperules & GTR_CIRCUIT))
if (gametyperules & GTR_CIRCUIT)
{
const fixed_t distbarrier = FixedMul(512*mapobjectscale, FRACUNIT + ((gamespeed-1) * (FRACUNIT/4)));
const fixed_t distaway = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y);
@ -8757,7 +8757,7 @@ void A_JawzChase(mobj_t *actor)
if (!actor->tracer)
{
actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy);
actor->angle = K_MomentumAngle(actor);
}
P_Thrust(actor, actor->angle, thrustamount);
@ -8887,7 +8887,7 @@ static void SpawnSPBAIZDust(mobj_t *mo, INT32 dir)
if (mo->eflags & MFE_VERTICALFLIP)
sz = mo->ceilingz;
travelangle = R_PointToAngle2(0, 0, mo->momx, mo->momy);
travelangle = K_MomentumAngle(mo);
if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*64)
{
newx = mo->x + P_ReturnThrustX(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale));
@ -8917,7 +8917,7 @@ static void SpawnSPBSpeedLines(mobj_t *actor)
MT_FASTLINE);
P_SetTarget(&fast->target, actor);
fast->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy);
fast->angle = K_MomentumAngle(actor);
fast->color = SKINCOLOR_RED;
fast->colorized = true;
K_MatchGenericExtraFlags(fast, actor);
@ -9003,7 +9003,7 @@ void A_SPBChase(mobj_t *actor)
actor->lastlook = actor->tracer->player-players; // Save the player num for death scumming...
actor->tracer->player->kartstuff[k_ringlock] = 1; // set ring lock
if (!P_IsObjectOnGround(actor->tracer) /*&& !actor->tracer->player->kartstuff[k_pogospring]*/)
if (!P_IsObjectOnGround(actor->tracer))
{
// In the air you have no control; basically don't hit unless you make a near complete stop
defspeed = (7 * actor->tracer->player->speed) / 8;
@ -9708,7 +9708,7 @@ void A_ReaperThinker(mobj_t *actor)
continue;
player = &players[i];
if (player && player->mo && player->kartstuff[k_bumper] && player->score >= maxscore)
if (player && player->mo && player->bumpers && player->score >= maxscore)
{
targetplayermo = player->mo;
maxscore = player->score;

View file

@ -2371,7 +2371,7 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
P_SetThingPosition(thing);
if (thing->flags & MF_SHOOTABLE)
P_DamageMobj(thing, puncher, puncher, 1, DMG_NORMAL);
else if (thing->type == MT_RING || thing->type == MT_COIN || thing->type == MT_RANDOMITEM)
else if (thing->type == MT_RING || thing->type == MT_RANDOMITEM)
{
thing->momz = FixedMul(3*FRACUNIT, thing->scale);
P_TouchSpecialThing(thing, puncher, false);

View file

@ -30,7 +30,7 @@
#include "f_finale.h"
// SRB2kart
#include "k_kart.h"
#include "k_kart.h"
#include "k_battle.h"
#include "k_pwrlv.h"
#include "k_grandprix.h"
@ -108,11 +108,13 @@ void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End)
//
boolean P_CanPickupItem(player_t *player, UINT8 weapon)
{
if (player->exiting || mapreset)
if (player->exiting || mapreset || player->eliminated)
return false;
/*if ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0) // No bumpers in Match
return false;*/
#ifndef OTHERKARMAMODES
if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0) // No bumpers in Match
return false;
#endif
if (weapon)
{
@ -182,15 +184,24 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (heightcheck)
{
fixed_t toucher_bottom = toucher->z;
fixed_t special_bottom = special->z;
if (toucher->flags & MF_PICKUPFROMBELOW)
toucher_bottom -= toucher->height;
if (special->flags & MF_PICKUPFROMBELOW)
special_bottom -= special->height;
if (toucher->momz < 0) {
if (toucher->z + toucher->momz > special->z + special->height)
if (toucher_bottom + toucher->momz > special->z + special->height)
return;
} else if (toucher->z > special->z + special->height)
} else if (toucher_bottom > special->z + special->height)
return;
if (toucher->momz > 0) {
if (toucher->z + toucher->height + toucher->momz < special->z)
if (toucher->z + toucher->height + toucher->momz < special_bottom)
return;
} else if (toucher->z + toucher->height < special->z)
} else if (toucher->z + toucher->height < special_bottom)
return;
}
@ -231,11 +242,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_SetObjectMomZ(player->mo, 12<<FRACBITS, false);
P_InstaThrust(player->mo, player->mo->angle, 20<<FRACBITS);
return;
case MT_FLOATINGITEM: // SRB2kart
case MT_FLOATINGITEM: // SRB2Kart
if (!P_CanPickupItem(player, 3) || (player->kartstuff[k_itemamount] && player->kartstuff[k_itemtype] != special->threshold))
return;
if ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0)
if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0)
return;
player->kartstuff[k_itemtype] = special->threshold;
@ -252,15 +263,19 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
special->flags &= ~MF_SPECIAL;
return;
case MT_RANDOMITEM: // SRB2kart
case MT_RANDOMITEM:
if (!P_CanPickupItem(player, 1))
return;
if ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0)
if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0)
{
if (player->kartstuff[k_comebackmode] || player->kartstuff[k_comebacktimer])
#ifdef OTHERKARMAMODES
if (player->kartstuff[k_comebackmode] || player->karmadelay)
return;
player->kartstuff[k_comebackmode] = 1;
#else
return;
#endif
}
special->momx = special->momy = special->momz = 0;
@ -272,7 +287,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return;
if (player == special->target->player)
return;
if (player->kartstuff[k_bumper] <= 0)
if (player->bumpers <= 0)
return;
if (special->target->player->exiting || player->exiting)
return;
@ -280,53 +295,38 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (P_PlayerInPain(special->target->player))
return;
if (special->target->player->karmadelay > 0)
return;
#ifdef OTHERKARMAMODES
if (!special->target->player->kartstuff[k_comebackmode])
{
if (player->kartstuff[k_growshrinktimer] || player->kartstuff[k_squishedtimer]
|| player->kartstuff[k_hyudorotimer] || P_PlayerInPain(player)
|| player->kartstuff[k_invincibilitytimer] || player->powers[pw_flashing])
return;
else
#endif
{
mobj_t *boom = P_SpawnMobj(special->target->x, special->target->y, special->target->z, MT_BOOMEXPLODE);
UINT8 ptadd = (K_IsPlayerWanted(player) ? 2 : 1);
mobj_t *boom;
if (P_DamageMobj(toucher, special, special->target, 1, DMG_KARMA) == false)
{
return;
}
boom = P_SpawnMobj(special->target->x, special->target->y, special->target->z, MT_BOOMEXPLODE);
boom->scale = special->target->scale;
boom->destscale = special->target->scale;
boom->momz = 5*FRACUNIT;
if (special->target->color)
boom->color = special->target->color;
else
boom->color = SKINCOLOR_KETCHUP;
S_StartSound(boom, special->info->attacksound);
if (player->kartstuff[k_bumper] == 1) // If you have only one bumper left, and see if it's a 1v1
{
INT32 numingame = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].kartstuff[k_bumper] <= 0)
continue;
numingame++;
}
if (numingame <= 2) // If so, then an extra karma point so they are 100% certain to switch places; it's annoying to end matches with a bomb kill
ptadd++;
}
special->target->player->kartstuff[k_comebackpoints] += ptadd;
if (ptadd > 1)
special->target->player->karthud[khud_yougotem] = 2*TICRATE;
if (special->target->player->kartstuff[k_comebackpoints] >= 2)
K_StealBumper(special->target->player, player);
special->target->player->kartstuff[k_comebacktimer] = comebacktime;
P_DamageMobj(toucher, special, special->target, 1, DMG_EXPLODE);
special->target->player->karthud[khud_yougotem] = 2*TICRATE;
special->target->player->karmadelay = comebacktime;
}
#ifdef OTHERKARMAMODES
}
else if (special->target->player->kartstuff[k_comebackmode] == 1 && P_CanPickupItem(player, 1))
{
@ -349,8 +349,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
special->target->player->kartstuff[k_comebackpoints]++;
if (special->target->player->kartstuff[k_comebackpoints] >= 2)
K_StealBumper(special->target->player, player);
special->target->player->kartstuff[k_comebacktimer] = comebacktime;
K_StealBumper(special->target->player, player, 1);
special->target->player->karmadelay = comebacktime;
player->kartstuff[k_itemroulette] = 1;
player->kartstuff[k_roulettetype] = 1;
@ -362,13 +362,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
S_StartSound(poof, special->info->seesound);
if (player->kartstuff[k_bumper] == 1) // If you have only one bumper left, and see if it's a 1v1
if (player->bumpers == 1) // If you have only one bumper left, and see if it's a 1v1
{
INT32 numingame = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].kartstuff[k_bumper] <= 0)
if (!playeringame[i] || players[i].spectator || players[i].bumpers <= 0)
continue;
numingame++;
}
@ -384,9 +384,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
special->target->player->karthud[khud_yougotem] = 2*TICRATE;
if (special->target->player->kartstuff[k_comebackpoints] >= 2)
K_StealBumper(special->target->player, player);
K_StealBumper(special->target->player, player, 1);
special->target->player->kartstuff[k_comebacktimer] = comebacktime;
special->target->player->karmadelay = comebacktime;
K_DropItems(player); //K_StripItems(player);
//K_StripOther(player);
@ -404,6 +404,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
special->target->player->kartstuff[k_eggmanblame] = -1;
}
#endif
return;
case MT_SPB:
if ((special->target == toucher || special->target == toucher->target) && (special->threshold > 0))
@ -441,10 +442,25 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_DamageMobj(player->mo, special, special->target, 1, DMG_NORMAL);
}
return;
/*case MT_EERIEFOG:
case MT_EMERALD:
if (!P_CanPickupItem(player, 0))
return;
if (special->threshold > 0)
return;
if (toucher->hitlag > 0)
return;
player->powers[pw_emeralds] |= special->extravalue1;
K_CheckEmeralds(player);
break;
/*
case MT_EERIEFOG:
special->frame &= ~FF_TRANS80;
special->frame |= FF_TRANS90;
return;*/
return;
*/
case MT_SMK_MOLE:
if (special->target && !P_MobjWasRemoved(special->target))
return;
@ -465,8 +481,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
// no interaction
if (player->powers[pw_flashing] > 0 || player->kartstuff[k_hyudorotimer] > 0
|| player->kartstuff[k_squishedtimer] > 0 || P_PlayerInPain(player))
if (player->powers[pw_flashing] > 0 || player->kartstuff[k_hyudorotimer] > 0 || P_PlayerInPain(player))
return;
// attach to player!
@ -474,7 +489,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
S_StartSound(special, sfx_s1a2);
return;
case MT_CDUFO: // SRB2kart
if (special->fuse || !P_CanPickupItem(player, 1) || ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0))
if (special->fuse || !P_CanPickupItem(player, 1) || ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0))
return;
player->kartstuff[k_itemroulette] = 1;
@ -553,6 +568,22 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return;
case MT_BLUESPHERE:
if (!(P_CanPickupItem(player, 0)))
return;
// Reached the cap, don't waste 'em!
if (player->spheres >= 40)
return;
// Not alive
if ((gametyperules & GTR_BUMPERS) && (player->bumpers <= 0))
return;
special->momx = special->momy = special->momz = 0;
player->spheres++;
break;
// Secret emblem thingy
case MT_EMBLEM:
{
@ -714,7 +745,7 @@ void P_TouchStarPost(mobj_t *post, player_t *player, boolean snaptopost)
}
// Easily make it so that overtime works offline
//#define TESTOVERTIMEINFREEPLAY
#define TESTOVERTIMEINFREEPLAY
/** Checks if the level timer is over the timelimit and the round should end,
* unless you are in overtime. In which case leveltime may stretch out beyond
@ -731,11 +762,10 @@ void P_CheckTimeLimit(void)
if (!cv_timelimit.value)
return;
if (!(multiplayer || netgame))
return;
#ifndef TESTOVERTIMEINFREEPLAY
if (battlecapsules) // capsules override any time limit settings
return;
#endif
if (!(gametyperules & GTR_TIMELIMIT))
return;
@ -754,58 +784,53 @@ void P_CheckTimeLimit(void)
{
if (!playeringame[i] || players[i].spectator)
continue;
if (foundone)
{
#endif
// Initiate the kill zone
if (!battleovertime.enabled)
{
INT32 b = 0;
thinker_t *th;
mobj_t *item = NULL;
mobj_t *center = NULL;
P_RespawnBattleBoxes(); // FORCE THESE TO BE RESPAWNED FOR THIS!!!!!!!
// Find us an item box to center on.
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
mobj_t *thismo;
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
thismo = (mobj_t *)th;
if (thismo->type != MT_RANDOMITEM)
continue;
if (thismo->threshold == 69) // Disappears
continue;
b++;
// Only select items that are on the ground, ignore ones in the air. Ambush flag inverts this rule.
if ((!P_IsObjectOnGround(thismo)) != (thismo->flags2 & MF2_AMBUSH))
continue;
if (item == NULL || (b < nummapboxes && P_RandomChance(((nummapboxes-b)*FRACUNIT)/nummapboxes))) // This is to throw off the RNG some
item = thismo;
if (b >= nummapboxes) // end early if we've found them all already
if (thismo->type == MT_OVERTIME_CENTER)
{
center = thismo;
break;
}
}
if (item == NULL) // no item found, could happen if every item is in the air or has ambush flag, or the map has none
if (center == NULL || P_MobjWasRemoved(center))
{
CONS_Alert(CONS_WARNING, "No usuable items for Battle overtime!\n");
return;
CONS_Alert(CONS_WARNING, "No center point for overtime!\n");
battleovertime.x = 0;
battleovertime.y = 0;
battleovertime.z = 0;
}
else
{
battleovertime.x = center->x;
battleovertime.y = center->y;
battleovertime.z = center->z;
}
item->threshold = 70; // Set constant respawn
battleovertime.x = item->x;
battleovertime.y = item->y;
battleovertime.z = item->z;
battleovertime.radius = 4096*mapobjectscale;
battleovertime.minradius = (cv_overtime.value == 2 ? 40 : 512) * mapobjectscale;
battleovertime.radius = 4096 * mapobjectscale;
battleovertime.enabled = 1;
S_StartSound(NULL, sfx_kc47);
}
return;
#ifndef TESTOVERTIMEINFREEPLAY
}
@ -1039,12 +1064,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
{
mobj_t *mo;
//if (inflictor && (inflictor->type == MT_SHELL || inflictor->type == MT_FIREBALL))
// P_SetTarget(&target->tracer, inflictor);
if (G_IsSpecialStage(gamemap) && target->player && target->player->nightstime > 6)
target->player->nightstime = 6; // Just let P_Ticker take care of the rest.
if (target->flags & (MF_ENEMY|MF_BOSS))
target->momx = target->momy = target->momz = 0;
@ -1070,11 +1089,17 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SPECIAL);
target->flags2 &= ~(MF2_SKULLFLY|MF2_NIGHTSPULL);
target->health = 0; // This makes it easy to check if something's dead elsewhere.
target->shadowscale = 0;
if (target->type != MT_BATTLEBUMPER)
{
target->shadowscale = 0;
}
if (LUAh_MobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target))
return;
//K_SetHitLagForObjects(target, inflictor, 15);
// SRB2kart
// I wish I knew a better way to do this
if (target->target && target->target->player && target->target->player->mo)
@ -1191,10 +1216,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
}
}
if ((gametyperules & GTR_BUMPERS))
if (gametyperules & GTR_BUMPERS)
K_CheckBumpers();
target->player->kartstuff[k_pogospring] = 0;
target->player->trickpanel = 0;
}
if (source && target && target->player && source->player)
@ -1421,6 +1446,35 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
}
break;
case MT_BATTLEBUMPER:
{
mobj_t *owner = target->target;
mobj_t *overlay;
S_StartSound(target, sfx_kc52);
target->flags &= ~MF_NOGRAVITY;
target->destscale = (3 * target->destscale) / 2;
target->scalespeed = FRACUNIT/100;
if (owner && !P_MobjWasRemoved(owner))
{
P_Thrust(target, R_PointToAngle2(owner->x, owner->y, target->x, target->y), 4 * target->scale);
}
target->momz += (24 * target->scale) * P_MobjFlip(target);
target->fuse = 8;
overlay = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_OVERLAY);
P_SetTarget(&target->tracer, overlay);
P_SetTarget(&overlay->target, target);
overlay->color = target->color;
P_SetMobjState(overlay, S_INVISIBLE);
}
break;
default:
break;
}
@ -1646,8 +1700,10 @@ static boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj_t *sou
return true;
}
static boolean P_KillPlayer(player_t *player, UINT8 type)
static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 type)
{
(void)source;
if (player->exiting)
{
player->mo->destscale = 1;
@ -1655,7 +1711,7 @@ static boolean P_KillPlayer(player_t *player, UINT8 type)
return false;
}
K_RemoveBumper(player, NULL, NULL);
K_DestroyBumpers(player, 1);
switch (type)
{
@ -1668,12 +1724,12 @@ static boolean P_KillPlayer(player_t *player, UINT8 type)
break;
}
K_DropEmeraldsFromPlayer(player, player->powers[pw_emeralds]);
K_SetHitLagForObjects(player->mo, inflictor, 15);
player->pflags &= ~PF_SLIDING;
player->powers[pw_carry] = CR_NONE;
// Get rid of shield
player->powers[pw_shield] = SH_NONE;
player->mo->color = player->skincolor;
player->mo->colorized = false;
@ -1688,15 +1744,21 @@ static boolean P_KillPlayer(player_t *player, UINT8 type)
if (type == DMG_TIMEOVER)
{
mobj_t *boom;
if (gametyperules & GTR_CIRCUIT)
{
mobj_t *boom;
player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP);
player->mo->drawflags |= MFD_DONTDRAW;
player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP);
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;
P_SetTarget(&boom->target, player->mo);
boom = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_FZEROBOOM);
boom->scale = player->mo->scale;
boom->angle = player->mo->angle;
P_SetTarget(&boom->target, player->mo);
}
K_DestroyBumpers(player, player->bumpers);
player->eliminated = true;
}
return true;
@ -1753,6 +1815,8 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
player_t *player;
boolean force = false;
INT32 laglength = 10;
if (objectplacing)
return false;
@ -1760,13 +1824,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
return false;
// Spectator handling
if (multiplayer)
{
if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator)
return false;
if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator)
return false;
if (source && source->player && source->player->spectator)
return false;
if (source && source->player && source->player->spectator)
return false;
if (((damagetype & DMG_TYPEMASK) == DMG_STING)
|| ((inflictor && !P_MobjWasRemoved(inflictor)) && inflictor->type == MT_BANANA && inflictor->health <= 1))
{
laglength = 5;
}
// Everything above here can't be forced.
@ -1786,8 +1853,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (!(target->flags & MF_SHOOTABLE))
return false; // shouldn't happen...
// Make sure that boxes cannot be popped by enemies, red rings, etc.
if (target->flags & MF_MONITOR && ((!source || !source->player) || (inflictor && !inflictor->player)))
if (target->hitlag > 0)
return false;
}
@ -1811,7 +1877,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (player) // Player is the target
{
const UINT8 type = (damagetype & DMG_TYPEMASK);
const boolean combo = (type == DMG_EXPLODE); // This damage type can be comboed from other damage
const boolean combo = (type == DMG_EXPLODE || type == DMG_KARMA || type == DMG_TUMBLE); // This damage type can be comboed from other damage
INT16 ringburst = 5;
if (player->pflags & PF_GODMODE)
@ -1830,7 +1896,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
// Instant-Death
if ((damagetype & DMG_DEATHMASK))
{
if (!P_KillPlayer(player, damagetype))
if (!P_KillPlayer(player, inflictor, source, damagetype))
return false;
}
else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype))
@ -1845,9 +1911,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
{
if (gametyperules & GTR_BUMPERS)
{
if ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1)
if ((player->bumpers <= 0 && player->karmadelay) || (player->kartstuff[k_comebackmode] == 1))
{
// No bumpers, can't be hurt
// No bumpers & in WAIT, can't be hurt
K_DoInstashield(player);
return false;
}
@ -1880,20 +1946,60 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
}
}
// We successfully hit 'em!
// We successfully damaged them! Give 'em some bumpers!
if (type != DMG_STING)
{
UINT8 takeBumpers = 1;
if (damagetype & DMG_STEAL)
{
takeBumpers = 2;
if (type == DMG_KARMA)
{
takeBumpers = player->bumpers;
}
}
else
{
if (type == DMG_KARMA)
{
// Take half of their bumpers for karma comeback damage
takeBumpers = max(1, player->bumpers / 2);
}
}
if (source && source != player->mo && source->player)
{
K_PlayHitEmSound(source);
K_BattleAwardHit(source->player, player, inflictor, takeBumpers);
K_TakeBumpersFromPlayer(source->player, player, takeBumpers);
if (type == DMG_KARMA)
{
// Destroy any remainder bumpers from the player for karma comeback damage
K_DestroyBumpers(player, player->bumpers);
}
if (damagetype & DMG_STEAL)
{
K_StealBumper(source->player, player);
// Give them ALL of your emeralds instantly :)
source->player->powers[pw_emeralds] |= player->powers[pw_emeralds];
player->powers[pw_emeralds] = 0;
K_CheckEmeralds(source->player);
}
}
else
{
K_DestroyBumpers(player, takeBumpers);
}
K_RemoveBumper(player, inflictor, source);
if (!(damagetype & DMG_STEAL))
{
// Drop all of your emeralds
K_DropEmeraldsFromPlayer(player, player->powers[pw_emeralds]);
}
}
player->kartstuff[k_sneakertimer] = player->kartstuff[k_numsneakers] = 0;
@ -1907,13 +2013,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
K_KartPainEnergyFling(player);
ringburst = 0;
break;
case DMG_TUMBLE:
K_TumblePlayer(player, inflictor, source);
break;
case DMG_EXPLODE:
case DMG_KARMA:
K_ExplodePlayer(player, inflictor, source);
break;
case DMG_WIPEOUT:
if (P_IsDisplayPlayer(player))
P_StartQuake(32<<FRACBITS, 5);
K_SpinPlayer(player, inflictor, source, KSPIN_WIPEOUT);
K_KartPainEnergyFling(player);
break;
@ -1924,14 +2033,20 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
}
if (type != DMG_STING)
{
player->powers[pw_flashing] = K_GetKartFlashing(player);
}
P_PlayRinglossSound(player->mo);
if (ringburst > 0)
{
P_PlayerRingBurst(player, ringburst);
}
K_PlayPainSound(player->mo);
if ((type == DMG_EXPLODE) || (cv_kartdebughuddrop.value && !modeattacking))
if ((combo == true) || (cv_kartdebughuddrop.value && !modeattacking))
{
K_DropItems(player);
}
@ -1941,6 +2056,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
}
player->kartstuff[k_instashield] = 15;
K_SetHitLagForObjects(target, inflictor, laglength);
return true;
}
}
@ -1962,12 +2078,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
if (source && source->player && target)
G_GhostAddHit((INT32) (source->player - players), target);
K_SetHitLagForObjects(target, inflictor, laglength);
if (target->health <= 0)
{
P_KillMobj(target, inflictor, source, damagetype);
return true;
}
//K_SetHitLagForObjects(target, inflictor, laglength);
if (player)
P_ResetPlayer(target->player);
else
@ -2000,7 +2120,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
fixed_t momxy = 5<<FRACBITS, momz = 12<<FRACBITS; // base horizonal/vertical thrusts
// Rings shouldn't be in Battle!
if (!(gametyperules & GTR_RINGS))
if (gametyperules & GTR_SPHERES)
return;
// Better safe than sorry.

View file

@ -400,6 +400,7 @@ void P_UnsetThingPosition(mobj_t *thing);
void P_SetThingPosition(mobj_t *thing);
void P_SetUnderlayPosition(mobj_t *thing);
boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing);
boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y);
boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam);
boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
@ -409,6 +410,7 @@ void P_SlideMove(mobj_t *mo);
void P_BouncePlayerMove(mobj_t *mo);
void P_BounceMove(mobj_t *mo);
boolean P_CheckSight(mobj_t *t1, mobj_t *t2);
boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2);
void P_CheckHoopPosition(mobj_t *hoopthing, fixed_t x, fixed_t y, fixed_t z, fixed_t radius);
boolean P_CheckSector(sector_t *sector, boolean crunch);
@ -465,8 +467,9 @@ typedef struct BasicFF_s
#define DMG_NORMAL 0x00
#define DMG_WIPEOUT 0x01 // Normal, but with extra flashy effects
#define DMG_EXPLODE 0x02
#define DMG_SQUISH 0x03
#define DMG_TUMBLE 0x03
#define DMG_STING 0x04
#define DMG_KARMA 0x05 // Karma Bomb explosion -- works like DMG_EXPLODE, but steals half of their bumpers & deletes the rest
//// Death types - cannot be combined with damage types
#define DMG_INSTAKILL 0x80
#define DMG_DEATHPIT 0x81
@ -517,5 +520,6 @@ boolean P_CheckMissileSpawn(mobj_t *th);
void P_Thrust(mobj_t *mo, angle_t angle, fixed_t move);
void P_ExplodeMissile(mobj_t *mo);
void P_CheckGravity(mobj_t *mo, boolean affect);
void P_SetPitchRollFromSlope(mobj_t *mo, pslope_t *slope);
#endif // __P_LOCAL__

View file

@ -357,7 +357,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
mobj_t *grease;
grease = P_SpawnMobj(object->x, object->y, object->z, MT_TIREGREASE);
P_SetTarget(&grease->target, object);
grease->angle = R_PointToAngle2(0, 0, object->momx, object->momy);
grease->angle = K_MomentumAngle(object);
grease->extravalue1 = i;
}
}
@ -445,9 +445,14 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
{
if (object->eflags & MFE_SPRUNG)
break;
if (object->player)
object->player->kartstuff[k_pogospring] = 1;
K_DoPogoSpring(object, 0, 0);
{
object->player->trickpanel = 1;
object->player->trickdelay = 1;
}
K_DoPogoSpring(object, 32<<FRACBITS, 0);
return;
}
else
@ -725,7 +730,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|| (thing->player && thing->player->kartstuff[k_bubbleblowup]))
&& (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD
|| tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG
|| tmthing->type == MT_SSMINE || tmthing->type == MT_SINK
|| tmthing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || tmthing->type == MT_SINK
|| (tmthing->type == MT_PLAYER && thing->target != tmthing)))
{
// see if it went over / under
@ -783,7 +788,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|| (tmthing->player && tmthing->player->kartstuff[k_bubbleblowup]))
&& (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD
|| thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG
|| thing->type == MT_SSMINE || thing->type == MT_SINK
|| thing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || thing->type == MT_SINK
|| (thing->type == MT_PLAYER && tmthing->target != thing)))
{
// see if it went over / under
@ -928,6 +933,27 @@ static boolean PIT_CheckThing(mobj_t *thing)
return K_MineExplosionCollide(thing, tmthing);
}
if (tmthing->type == MT_LANDMINE)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
return K_LandMineCollide(tmthing, thing);
}
else if (thing->type == MT_LANDMINE)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
return K_LandMineCollide(thing, tmthing);
}
if (tmthing->type == MT_SINK)
{
// see if it went over / under
@ -1209,57 +1235,8 @@ static boolean PIT_CheckThing(mobj_t *thing)
return false;
}
// Damage other players when invincible
if (tmthing->player && thing->player
// Make sure they aren't able to damage you ANYWHERE along the Z axis, you have to be TOUCHING the person.
&& !(thing->z + thing->height < tmthing->z || thing->z > tmthing->z + tmthing->height))
{
if (!G_GametypeHasTeams() || tmthing->player->ctfteam != thing->player->ctfteam)
{
if (tmthing->scale > thing->scale + (mapobjectscale/8)) // SRB2kart - Handle squishes first!
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SQUISH);
else if (thing->scale > tmthing->scale + (mapobjectscale/8))
P_DamageMobj(tmthing, thing, thing, 1, DMG_SQUISH);
else if (tmthing->player->kartstuff[k_invincibilitytimer] && !thing->player->kartstuff[k_invincibilitytimer]) // SRB2kart - Then invincibility!
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT);
else if (thing->player->kartstuff[k_invincibilitytimer] && !tmthing->player->kartstuff[k_invincibilitytimer])
P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT);
else if ((tmthing->player->kartstuff[k_flamedash] && tmthing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)
&& !(thing->player->kartstuff[k_flamedash] && thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)) // SRB2kart - Then flame shield!
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT);
else if ((thing->player->kartstuff[k_flamedash] && thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD)
&& !(tmthing->player->kartstuff[k_flamedash] && tmthing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD))
P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT);
}
}
if (thing->player)
{
// Doesn't matter what gravity player's following! Just do your stuff in YOUR direction only
if (tmthing->eflags & MFE_VERTICALFLIP
&& (tmthing->z + tmthing->height + tmthing->momz < thing->z
|| tmthing->z + tmthing->height + tmthing->momz >= thing->z + thing->height))
;
else if (!(tmthing->eflags & MFE_VERTICALFLIP)
&& (tmthing->z + tmthing->momz > thing->z + thing->height
|| tmthing->z + tmthing->momz <= thing->z))
;
else if (P_IsObjectOnGround(thing)
&& !P_IsObjectOnGround(tmthing) // Don't crush if the monitor is on the ground...
&& (tmthing->flags & MF_SOLID))
{
if (tmthing->flags & (MF_MONITOR|MF_PUSHABLE))
{
// Objects kill you if it falls from above.
if (thing != tmthing->target)
P_DamageMobj(thing, tmthing, tmthing->target, 1, DMG_CRUSHED);
tmthing->momz = -tmthing->momz/2; // Bounce, just for fun!
// The tmthing->target allows the pusher of the object
// to get the point if he topples it on an opponent.
}
}
if (tmthing->type == MT_FAN || tmthing->type == MT_STEAM)
P_DoFanAndGasJet(tmthing, thing);
}
@ -1287,17 +1264,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (thing->player->kartstuff[k_squishedtimer] || thing->player->kartstuff[k_hyudorotimer]
|| thing->player->kartstuff[k_justbumped] || thing->scale > tmthing->scale + (mapobjectscale/8)
|| tmthing->player->kartstuff[k_squishedtimer] || tmthing->player->kartstuff[k_hyudorotimer]
|| tmthing->player->kartstuff[k_justbumped] || tmthing->scale > thing->scale + (mapobjectscale/8))
if (thing->player->kartstuff[k_hyudorotimer] || tmthing->player->kartstuff[k_hyudorotimer])
{
return true;
}
if ((gametyperules & GTR_BUMPERS)
&& ((thing->player->kartstuff[k_bumper] && !tmthing->player->kartstuff[k_bumper])
|| (tmthing->player->kartstuff[k_bumper] && !thing->player->kartstuff[k_bumper])))
&& ((thing->player->bumpers && !tmthing->player->bumpers)
|| (tmthing->player->bumpers && !thing->player->bumpers)))
{
return true;
}
@ -1314,30 +1288,21 @@ static boolean PIT_CheckThing(mobj_t *thing)
mo1 = thing;
mo2 = tmthing;
if (tmthing->player->kartstuff[k_pogospring])
if (tmthing->player->trickpanel)
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT|DMG_STEAL);
}
else if (P_IsObjectOnGround(tmthing) && thing->momz < 0)
{
zbounce = true;
if (thing->player->kartstuff[k_pogospring])
if (thing->player->trickpanel)
P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL);
}
if ((gametyperules & GTR_BUMPERS))
if (K_KartBouncing(mo1, mo2, zbounce, false))
{
if (thing->player->kartstuff[k_sneakertimer] && !(tmthing->player->kartstuff[k_sneakertimer]) && !(thing->player->powers[pw_flashing])) // Don't steal bumpers while intangible
{
P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL);
}
else if (tmthing->player->kartstuff[k_sneakertimer] && !(thing->player->kartstuff[k_sneakertimer]) && !(tmthing->player->powers[pw_flashing]))
{
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_WIPEOUT|DMG_STEAL);
}
K_PvPTouchDamage(mo1, mo2);
}
K_KartBouncing(mo1, mo2, zbounce, false);
}
return true;
@ -1417,22 +1382,13 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true;
}
// continue to squish
if (tmthing->player->kartstuff[k_squishedtimer])
{
tmthing->player->kartstuff[k_squishedtimer] = 2*TICRATE;
tmthing->player->powers[pw_flashing] = K_GetKartFlashing(tmthing->player);
return true;
}
// no interaction
if (tmthing->player->powers[pw_flashing] > 0 || tmthing->player->kartstuff[k_hyudorotimer] > 0
|| tmthing->player->kartstuff[k_spinouttimer] > 0) //|| tmthing->player->kartstuff[k_squishedtimer] > 0
if (tmthing->player->powers[pw_flashing] > 0 || tmthing->player->kartstuff[k_hyudorotimer] > 0 || tmthing->player->kartstuff[k_spinouttimer] > 0)
return true;
// collide
if (tmthing->z < thing->z && thing->momz < 0)
K_SquishPlayer(tmthing->player, thing, thing);
P_DamageMobj(tmthing, thing, thing, 1, DMG_TUMBLE);
else
{
if (thing->flags2 & MF2_AMBUSH)
@ -1616,6 +1572,23 @@ static boolean PIT_CheckCameraLine(line_t *ld)
return true;
}
boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing)
{
// missiles can cross uncrossable lines
if ((thing->flags & MF_MISSILE))
return false;
else
{
return
(
(ld->flags & ML_IMPASSABLE) || // block objects from moving through this linedef.
(thing->player && !thing->player->spectator &&
ld->flags & ML_BLOCKPLAYERS) || // SRB2Kart: Only block players, not items
((thing->flags & (MF_ENEMY|MF_BOSS)) && ld->special == 81) // case 81: block monsters only
);
}
}
//
// PIT_CheckLine
// Adjusts tmfloorz and tmceilingz as lines are contacted
@ -1691,14 +1664,8 @@ static boolean PIT_CheckLine(line_t *ld)
return false;
}
// missiles can cross uncrossable lines
if (!(tmthing->flags & MF_MISSILE))
{
if (ld->flags & ML_IMPASSABLE) // block objects from moving through this linedef.
return false;
if (tmthing->player && !tmthing->player->spectator && ld->flags & ML_BLOCKPLAYERS)
return false; // SRB2Kart: Only block players, not items
}
if (P_IsLineBlocking(ld, tmthing))
return false;
// set openrange, opentop, openbottom
P_LineOpening(ld, tmthing);
@ -2267,7 +2234,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam)
{
subsector_t *s = R_PointInSubsector(x, y);
boolean retval = true;
UINT8 i;
floatok = false;
@ -2472,6 +2439,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
if (radius < mapobjectscale)
radius = mapobjectscale;
if (thing->hitlag > 0)
{
// Do not move during hitlag
return false;
}
do {
if (thing->flags & MF_NOCLIP) {
tryx = x;
@ -2633,9 +2606,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
if (thing->momz <= 0)
{
thing->standingslope = tmfloorslope;
#ifdef HWRENDER
thing->modeltilt = thing->standingslope;
#endif
P_SetPitchRollFromSlope(thing, thing->standingslope);
if (thing->momz == 0 && thing->player && !startingonground)
P_PlayerHitFloor(thing->player, true);
@ -2648,9 +2619,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
if (thing->momz >= 0)
{
thing->standingslope = tmceilingslope;
#ifdef HWRENDER
thing->modeltilt = thing->standingslope;
#endif
P_SetPitchRollFromSlope(thing, thing->standingslope);
if (thing->momz == 0 && thing->player && !startingonground)
P_PlayerHitFloor(thing->player, true);
@ -3162,14 +3131,8 @@ static boolean PTR_LineIsBlocking(line_t *li)
if (!li->backsector)
return !P_PointOnLineSide(slidemo->x, slidemo->y, li);
if (!(slidemo->flags & MF_MISSILE))
{
if (li->flags & ML_IMPASSABLE)
return true;
if (slidemo->player && !slidemo->player->spectator && li->flags & ML_BLOCKPLAYERS)
return true;
}
if (P_IsLineBlocking(li, slidemo))
return true;
// set openrange, opentop, openbottom
P_LineOpening(li, slidemo);
@ -3656,7 +3619,7 @@ void P_BouncePlayerMove(mobj_t *mo)
mmomx = mo->player->rmomx;
mmomy = mo->player->rmomy;
mo->player->kartstuff[k_pogospring] = 0;
mo->player->trickpanel = 0;
// trace along the three leading corners
if (mo->momx > 0)

View file

@ -24,19 +24,6 @@
#include "p_slopes.h"
#include "z_zone.h"
//
// P_AproxDistance
// Gives an estimation of distance (not exact)
//
fixed_t P_AproxDistance(fixed_t dx, fixed_t dy)
{
dx = abs(dx);
dy = abs(dy);
if (dx < dy)
return dx + dy - (dx>>1);
return dx + dy - (dy>>1);
}
//
// P_ClosestPointOnLine
// Finds the closest point on a given line to the supplied point

View file

@ -41,7 +41,7 @@ typedef boolean (*traverser_t)(intercept_t *in);
boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2,
INT32 pflags, traverser_t ptrav);
FUNCMATH fixed_t P_AproxDistance(fixed_t dx, fixed_t dy);
#define P_AproxDistance(dx, dy) FixedHypot(dx, dy)
void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result);
void P_ClosestPointOnLine3D(const vector3_t *p, const vector3_t *line, vector3_t *result);
INT32 P_PointOnLineSide(fixed_t x, fixed_t y, line_t *line);

View file

@ -1096,14 +1096,19 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
P_PlayerFlip(mo);
}
if (mo->player->kartstuff[k_pogospring])
if (mo->player->kartstuff[k_waterskip])
{
gravityadd = (4*gravityadd)/3;
}
if (mo->player->trickpanel == 2 || mo->player->trickpanel == 3)
{
gravityadd = (5*gravityadd)/2;
}
if (mo->player->kartstuff[k_waterskip])
if (mo->player->tumbleBounces > 0)
{
gravityadd = (4*gravityadd)/3;
gravityadd = (5*gravityadd)/2;
}
}
else
@ -1130,7 +1135,6 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
case MT_FLINGCOIN:
case MT_FLINGBLUESPHERE:
case MT_FLINGNIGHTSCHIP:
case MT_FLINGEMERALD:
case MT_BOUNCERING:
case MT_RAILRING:
case MT_INFINITYRING:
@ -1158,18 +1162,20 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
break;
case MT_WATERDROP:
case MT_CYBRAKDEMON:
case MT_BATTLEBUMPER:
gravityadd /= 2;
break;
case MT_BANANA:
case MT_EGGMANITEM:
case MT_SSMINE:
case MT_LANDMINE:
case MT_SINK:
case MT_EMERALD:
if (mo->extravalue2 > 0)
{
gravityadd *= mo->extravalue2;
/* FALLTHRU */
case MT_ORBINAUT:
case MT_JAWZ:
case MT_JAWZ_DUD:
}
gravityadd = (5*gravityadd)/2;
break;
case MT_KARMAFIREWORK:
@ -1216,6 +1222,26 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
}
}
//
// P_SetPitchRollFromSlope
//
void P_SetPitchRollFromSlope(mobj_t *mo, pslope_t *slope)
{
if (slope)
{
fixed_t tempz = slope->normal.z;
fixed_t tempy = slope->normal.y;
fixed_t tempx = slope->normal.x;
mo->pitch = R_PointToAngle2(0, 0, FixedSqrt(FixedMul(tempy, tempy) + FixedMul(tempz, tempz)), tempx);
mo->roll = R_PointToAngle2(0, 0, tempz, tempy);
}
else
{
mo->pitch = mo->roll = 0;
}
}
#define STOPSPEED (FRACUNIT)
//
@ -1620,8 +1646,10 @@ void P_XYMovement(mobj_t *mo)
relation = transferslope->xydirection - R_PointToAngle2(0, 0, mo->momx, mo->momy);
else // Give it for free, I guess.
relation = ANGLE_90;
transfermomz = FixedMul(transfermomz,
abs(FINESINE((relation >> ANGLETOFINESHIFT) & FINEMASK)));
if (P_MobjFlip(mo)*(transfermomz - mo->momz) > 2*FRACUNIT) // Do the actual launch!
{
mo->momz = transfermomz;
@ -1696,7 +1724,7 @@ void P_XYMovement(mobj_t *mo)
if (oldslope != mo->standingslope) { // First, compare different slopes
angle_t oldangle, newangle;
angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy);
angle_t moveangle = K_MomentumAngle(mo);
oldangle = FixedMul((signed)oldslope->zangle, FINECOSINE((moveangle - oldslope->xydirection) >> ANGLETOFINESHIFT));
@ -1708,9 +1736,7 @@ void P_XYMovement(mobj_t *mo)
// Now compare the Zs of the different quantizations
if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) { // Allow for a bit of sticking - this value can be adjusted later
mo->standingslope = oldslope;
#ifdef HWRENDER
mo->modeltilt = mo->standingslope;
#endif
P_SetPitchRollFromSlope(mo, mo->standingslope);
P_SlopeLaunch(mo);
//CONS_Printf("launched off of slope - ");
@ -1728,7 +1754,7 @@ void P_XYMovement(mobj_t *mo)
P_SlopeLaunch(mo);
}
} else if (moved && mo->standingslope && predictedz) {
angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy);
angle_t moveangle = K_MomentumAngle(mo);
angle_t newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT));
/*CONS_Printf("flat to angle %f - predicted z of %f\n",
@ -2085,6 +2111,7 @@ boolean P_ZMovement(mobj_t *mo)
case MT_JAWZ_DUD:
case MT_BALLHOG:
case MT_SSMINE:
case MT_LANDMINE:
case MT_BUBBLESHIELDTRAP:
// Remove stuff from death pits.
if (P_CheckDeathPitCollide(mo))
@ -2093,6 +2120,7 @@ boolean P_ZMovement(mobj_t *mo)
return false;
}
break;
case MT_REDFLAG:
case MT_BLUEFLAG:
// Remove from death pits. DON'T FUCKING DESPAWN IT DAMMIT
@ -2103,19 +2131,23 @@ boolean P_ZMovement(mobj_t *mo)
}
break;
case MT_EMERALD:
if (P_CheckDeathPitCollide(mo))
{
P_RemoveMobj(mo);
return false;
}
if (mo->z <= mo->floorz || mo->z + mo->height >= mo->ceilingz)
{
// Stop when hitting the floor
mo->momx = mo->momy = 0;
}
break;
case MT_RING: // Ignore still rings
case MT_COIN:
case MT_BLUESPHERE:
case MT_BOMBSPHERE:
case MT_NIGHTSCHIP:
case MT_NIGHTSSTAR:
case MT_REDTEAMRING:
case MT_BLUETEAMRING:
case MT_FLINGRING:
case MT_FLINGCOIN:
case MT_FLINGBLUESPHERE:
case MT_FLINGNIGHTSCHIP:
case MT_FLINGEMERALD:
// Remove flinged stuff from death pits.
if (P_CheckDeathPitCollide(mo))
{
@ -2228,9 +2260,7 @@ boolean P_ZMovement(mobj_t *mo)
if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM))
{
mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope;
#ifdef HWRENDER
mo->modeltilt = mo->standingslope;
#endif
P_SetPitchRollFromSlope(mo, mo->standingslope);
P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope);
}
@ -2603,7 +2633,7 @@ void P_PlayerZMovement(mobj_t *mo)
mo->z = mo->floorz;
// Get up if you fell.
if (mo->player->panim == PA_PAIN && mo->player->kartstuff[k_spinouttimer] == 0 && mo->player->kartstuff[k_squishedtimer] == 0)
if (mo->player->panim == PA_PAIN && mo->player->kartstuff[k_spinouttimer] == 0 && mo->player->tumbleBounces == 0)
P_SetPlayerMobjState(mo, S_KART_STILL);
if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)) {
@ -4471,7 +4501,8 @@ boolean P_IsKartItem(INT32 type)
type == MT_JAWZ || type == MT_JAWZ_DUD || type == MT_JAWZ_SHIELD ||
type == MT_SSMINE || type == MT_SSMINE_SHIELD ||
type == MT_SINK || type == MT_SINK_SHIELD ||
type == MT_SPB || type == MT_BALLHOG || type == MT_BUBBLESHIELDTRAP)
type == MT_SPB || type == MT_BALLHOG || type == MT_BUBBLESHIELDTRAP ||
type == MT_LANDMINE)
return true;
else
return false;
@ -4881,8 +4912,6 @@ static boolean P_ParticleGenSceneryThink(mobj_t *mobj)
mobj->angle += mobj->movedir;
}
mobj->angle += (angle_t)mobj->movecount;
}
return true;
@ -5277,7 +5306,117 @@ static void P_MobjSceneryThink(mobj_t *mobj)
}
break;
case MT_BATTLEBUMPER:
if (mobj->health > 0 && mobj->target && mobj->target->player
if (mobj->health <= 0)
{
mobj->fuse--;
if (!S_SoundPlaying(mobj, sfx_cdfm71))
{
S_StartSound(mobj, sfx_cdfm71);
}
if (mobj->fuse <= 0)
{
statenum_t curState = (mobj->state - states);
if (curState == S_BATTLEBUMPER1)
{
P_SetMobjState(mobj, S_BATTLEBUMPER_EXCRYSTALA1);
if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer))
{
P_SetMobjState(mobj->tracer, S_BATTLEBUMPER_EXSHELLA1);
}
mobj->shadowscale *= 2;
mobj->fuse = 12;
}
else if (curState >= S_BATTLEBUMPER_EXCRYSTALA1 && curState <= S_BATTLEBUMPER_EXCRYSTALA4)
{
P_SetMobjState(mobj, S_BATTLEBUMPER_EXCRYSTALB1);
if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer))
{
P_SetMobjState(mobj->tracer, S_BATTLEBUMPER_EXSHELLB1);
}
mobj->shadowscale *= 2;
mobj->fuse = 24;
break;
}
else if (curState >= S_BATTLEBUMPER_EXCRYSTALB1 && curState <= S_BATTLEBUMPER_EXCRYSTALB4)
{
P_SetMobjState(mobj, S_BATTLEBUMPER_EXCRYSTALC1);
if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer))
{
P_SetMobjState(mobj->tracer, S_BATTLEBUMPER_EXSHELLC1);
}
mobj->shadowscale *= 2;
mobj->fuse = 32;
break;
}
else
{
const INT16 spacing = 64;
UINT8 i;
for (i = 0; i < 10; i++)
{
mobj_t *debris = P_SpawnMobjFromMobj(
mobj,
P_RandomRange(-spacing, spacing) * FRACUNIT,
P_RandomRange(-spacing, spacing) * FRACUNIT,
P_RandomRange(-spacing, spacing) * FRACUNIT,
MT_BATTLEBUMPER_DEBRIS
);
P_SetScale(debris, (debris->destscale *= 2));
debris->color = mobj->color;
debris->momz = -debris->scale * P_MobjFlip(debris);
}
for (i = 0; i < 2; i++)
{
mobj_t *blast = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_BATTLEBUMPER_BLAST);
blast->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy) + ANGLE_45;
blast->destscale *= 4;
if (i & 1)
{
blast->angle += ANGLE_90;
S_StartSound(blast, sfx_cdfm64);
}
}
for (i = 0; i < 10; i++)
{
mobj_t *puff = P_SpawnMobjFromMobj(
mobj,
P_RandomRange(-spacing, spacing) * FRACUNIT,
P_RandomRange(-spacing, spacing) * FRACUNIT,
P_RandomRange(-spacing, spacing) * FRACUNIT,
MT_SPINDASHDUST
);
P_SetScale(puff, (puff->destscale *= 5));
puff->momz = puff->scale * P_MobjFlip(puff);
P_Thrust(puff, R_PointToAngle2(mobj->x, mobj->y, puff->x, puff->y), puff->scale);
}
P_RemoveMobj(mobj);
return;
}
}
break;
}
if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player
&& mobj->target->health > 0 && !mobj->target->player->spectator)
{
fixed_t rad = 32*mobj->target->scale;
@ -5285,14 +5424,14 @@ static void P_MobjSceneryThink(mobj_t *mobj)
angle_t ang, diff;
if (!((mobj->target->player-players) & 1))
ang = (FixedAngle(mobj->info->speed) * -1);
ang = -FixedAngle(mobj->info->speed);
else
ang = FixedAngle(mobj->info->speed);
if (mobj->target->player->kartstuff[k_bumper] <= 1)
if (mobj->target->player->bumpers <= 1)
diff = 0;
else
diff = FixedAngle(360*FRACUNIT/mobj->target->player->kartstuff[k_bumper]);
diff = FixedAngle(360*FRACUNIT/mobj->target->player->bumpers);
ang = (ang*leveltime) + (diff * (mobj->threshold-1));
@ -5311,51 +5450,66 @@ static void P_MobjSceneryThink(mobj_t *mobj)
mobj->drawflags = (mobj->target->drawflags & MFD_DONTDRAW);
if (mobj->target->eflags & MFE_VERTICALFLIP)
{
offz += 4*FRACUNIT;
}
else
{
offz -= 4*FRACUNIT;
}
if (mobj->tracer && mobj->tracer->player && mobj->tracer->player->mo
if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer) && mobj->tracer->player
&& mobj->tracer->health > 0 && !mobj->tracer->player->spectator) // STOLEN
mobj->color = mobj->tracer->player->skincolor; // don't do star flashing for stolen bumpers
{
mobj->color = mobj->tracer->color;
}
else
mobj->color = mobj->target->color; // but do so if it belongs to you :B
{
mobj->color = mobj->target->color;
}
if (mobj->target->player->kartstuff[k_bumper] < 2)
if (mobj->target->player->bumpers < 2)
P_SetMobjState(mobj, S_BATTLEBUMPER3);
else if (mobj->target->player->kartstuff[k_bumper] < 3)
else if (mobj->target->player->bumpers < 3)
P_SetMobjState(mobj, S_BATTLEBUMPER2);
else
P_SetMobjState(mobj, S_BATTLEBUMPER1);
// Shrink your items if the player shrunk too.
mobj->scale = mobj->target->scale;
P_SetScale(mobj, mobj->target->scale);
P_UnsetThingPosition(mobj);
{
const angle_t fa = ang>>ANGLETOFINESHIFT;
const angle_t fa = ang >> ANGLETOFINESHIFT;
mobj->x = mobj->target->x + FixedMul(FINECOSINE(fa), rad);
mobj->y = mobj->target->y + FixedMul(FINESINE(fa), rad);
mobj->z = mobj->target->z + offz;
P_SetThingPosition(mobj);
}
// Was this so hard?
if (mobj->target->player->kartstuff[k_bumper] <= mobj->threshold)
if (mobj->target->player->bumpers <= mobj->threshold)
{
P_RemoveMobj(mobj);
return;
// Do bumper destruction
P_KillMobj(mobj, NULL, NULL, DMG_NORMAL);
break;
}
}
else if ((mobj->health > 0
&& (!mobj->target || !mobj->target->player || !mobj->target->player->mo || mobj->target->health <= 0 || mobj->target->player->spectator))
|| (mobj->health <= 0 && P_IsObjectOnGround(mobj))
|| P_CheckDeathPitCollide(mobj)) // When in death state
else
{
// Sliently remove
P_RemoveMobj(mobj);
return;
}
break;
case MT_BATTLEBUMPER_DEBRIS:
if (mobj->state == states + S_BATTLEBUMPER_EXDEBRIS2)
{
mobj->drawflags ^= MFD_DONTDRAW;
}
break;
case MT_PLAYERARROW:
if (mobj->target && mobj->target->health
&& mobj->target->player && !mobj->target->player->spectator
@ -5366,7 +5520,7 @@ static void P_MobjSceneryThink(mobj_t *mobj)
mobj->color = mobj->target->color;
K_MatchGenericExtraFlags(mobj, mobj->target);
if ((gametype == GT_RACE || mobj->target->player->kartstuff[k_bumper] <= 0)
if ((gametype == GT_RACE || mobj->target->player->bumpers <= 0)
#if 1 // Set to 0 to test without needing to host
|| (P_IsDisplayPlayer(mobj->target->player))
#endif
@ -5623,6 +5777,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
if (mobj->tics > 0)
mobj->drawflags ^= MFD_DONTDRAW;
break;
case MT_SPINDASHWIND:
mobj->drawflags ^= MFD_DONTDRAW;
break;
case MT_VWREF:
case MT_VWREB:
{
@ -5751,6 +5908,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
case MT_ORBINAUT:
case MT_BANANA:
case MT_EGGMANITEM:
case MT_LANDMINE:
case MT_SPB:
if (P_IsObjectOnGround(mobj))
{
@ -6139,7 +6297,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
frictionsafety = FRACUNIT;
}
mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy);
mobj->angle = K_MomentumAngle(mobj);
if (mobj->health <= 5)
{
INT32 i;
@ -6194,6 +6352,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if (P_MobjTouchingSectorSpecial(mobj, 3, 1, true))
K_DoPogoSpring(mobj, 0, 1);
if (!(gametyperules & GTR_CIRCUIT))
mobj->friction = max(0, 3 * mobj->friction / 4);
break;
}
case MT_JAWZ_DUD:
@ -6241,7 +6402,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
thrustamount = beatfriction + FixedDiv(mobj->movefactor - currentspeed, frictionsafety);
}
mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy);
mobj->angle = K_MomentumAngle(mobj);
P_Thrust(mobj, mobj->angle, thrustamount);
if (P_MobjTouchingSectorSpecial(mobj, 3, 1, true))
@ -6345,7 +6506,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
ghost->colorized = true; // already has color!
}
if (P_IsObjectOnGround(mobj) && (mobj->state == &states[S_SSMINE_AIR1] || mobj->state == &states[S_SSMINE_AIR2]))
if (P_IsObjectOnGround(mobj) && (mobj->momz * P_MobjFlip(mobj)) <= 0
&& (mobj->state == &states[S_SSMINE_AIR1] || mobj->state == &states[S_SSMINE_AIR2]))
{
if (mobj->extravalue1 > 0)
mobj->extravalue1--;
@ -6361,6 +6523,25 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|| (mobj->state >= &states[S_SSMINE_DEPLOY8] && mobj->state <= &states[S_SSMINE_DEPLOY13]))
A_GrenadeRing(mobj);
if (mobj->threshold > 0)
mobj->threshold--;
break;
case MT_LANDMINE:
mobj->friction = ORIG_FRICTION/4;
if (mobj->momx || mobj->momy || mobj->momz)
{
mobj_t *ghost = P_SpawnGhostMobj(mobj);
ghost->colorized = true; // already has color!
}
if (P_IsObjectOnGround(mobj) && mobj->health > 1)
{
S_StartSound(mobj, mobj->info->activesound);
mobj->momx = mobj->momy = 0;
mobj->health = 1;
}
if (mobj->threshold > 0)
mobj->threshold--;
break;
@ -6395,6 +6576,37 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
S_StartSound(mobj, sfx_s3k4e);
mobj->health--;
break;
case MT_EMERALD:
{
if (battleovertime.enabled >= 10*TICRATE)
{
fixed_t distance = R_PointToDist2(mobj->x, mobj->y, battleovertime.x, battleovertime.y);
if (distance > battleovertime.radius)
{
// Delete emeralds to let them reappear
P_KillMobj(mobj, NULL, NULL, DMG_NORMAL);
}
}
if (leveltime % 3 == 0)
{
mobj_t *sparkle = P_SpawnMobjFromMobj(
mobj,
P_RandomRange(-48, 48) * FRACUNIT,
P_RandomRange(-48, 48) * FRACUNIT,
P_RandomRange(0, 64) * FRACUNIT,
MT_EMERALDSPARK
);
sparkle->color = mobj->color;
sparkle->momz += 8 * mobj->scale * P_MobjFlip(mobj);
}
if (mobj->threshold > 0)
mobj->threshold--;
}
break;
case MT_DRIFTEXPLODE:
if (!mobj->target || !mobj->target->health)
{
@ -6404,7 +6616,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
//mobj->angle = mobj->target->angle;
{
angle_t angle = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy);
angle_t angle = K_MomentumAngle(mobj->target);
fixed_t nudge;
mobj->angle = angle;
@ -6426,9 +6638,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->target->z);
}
P_SetScale(mobj, mobj->target->scale);
#ifdef HWRENDER
mobj->modeltilt = mobj->target->modeltilt;
#endif
mobj->roll = mobj->target->roll;
mobj->pitch = mobj->target->pitch;
if (mobj->fuse <= 16)
{
@ -6442,7 +6654,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->color = K_RainbowColor(
(SKINCOLOR_PURPLE - SKINCOLOR_PINK) // Smoothly transition into the other state
+ ((mobj->fuse - 32) * 2) // Make the color flashing slow down while it runs out
);
);
switch (mobj->extravalue1)
{
@ -6490,9 +6702,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
P_TeleportMove(mobj, mobj->target->x + P_ReturnThrustX(mobj, mobj->angle+ANGLE_180, mobj->target->radius),
mobj->target->y + P_ReturnThrustY(mobj, mobj->angle+ANGLE_180, mobj->target->radius), mobj->target->z);
P_SetScale(mobj, mobj->target->scale);
#ifdef HWRENDER
mobj->modeltilt = mobj->target->modeltilt;
#endif
mobj->roll = mobj->target->roll;
mobj->pitch = mobj->target->pitch;
{
player_t *p = NULL;
@ -6672,7 +6884,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
{
const angle_t off = FixedAngle(40*FRACUNIT);
angle_t ang = mobj->target->angle;
angle_t ang = K_MomentumAngle(mobj->target);
fixed_t z;
UINT8 trans = (mobj->target->player->kartstuff[k_tiregrease] * (NUMTRANSMAPS+1)) / greasetics;
@ -6685,9 +6897,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if (mobj->eflags & MFE_VERTICALFLIP)
z += mobj->target->height;
if (mobj->target->momx || mobj->target->momy)
ang = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy);
if (mobj->extravalue1)
ang = (signed)(ang - off);
else
@ -6982,10 +7191,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
P_TeleportMove(mobj, destx, desty, mobj->target->z);
if (mobj->target->momx || mobj->target->momy)
mobj->angle = R_PointToAngle2(0, 0, mobj->target->momx, mobj->target->momy);
else
mobj->angle = mobj->target->angle;
mobj->angle = K_MomentumAngle(mobj->target);
if (underlayst != S_NULL)
{
@ -7022,7 +7228,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
statenum_t state = (mobj->state-states);
if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->spectator
|| (gametype == GT_RACE || mobj->target->player->kartstuff[k_bumper]))
|| (gametype == GT_RACE || mobj->target->player->bumpers))
{
P_RemoveMobj(mobj);
return false;
@ -7043,11 +7249,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->radius = 24*mobj->target->scale;
mobj->height = 2*mobj->radius;
if (mobj->target->player->kartstuff[k_comebacktimer] > 0)
if (mobj->target->player->karmadelay > 0)
{
if (state < S_PLAYERBOMB1 || state > S_PLAYERBOMB20)
P_SetMobjState(mobj, S_PLAYERBOMB1);
if (mobj->target->player->kartstuff[k_comebacktimer] < TICRATE && (leveltime & 1))
if (mobj->target->player->karmadelay < TICRATE && (leveltime & 1))
mobj->drawflags &= ~MFD_DONTDRAW;
else
mobj->drawflags |= MFD_DONTDRAW;
@ -7862,7 +8068,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->momx = (23*mobj->momx)/24;
mobj->momy = (23*mobj->momy)/24;
mobj->angle = R_PointToAngle2(0,0,mobj->momx,mobj->momy);
mobj->angle = K_MomentumAngle(mobj);
if ((mobj->z - mobj->floorz) < (24*mobj->scale) && (leveltime % 3 != 0))
{
@ -8354,6 +8560,7 @@ static boolean P_FuseThink(mobj_t *mobj)
if (mobj->threshold == 70)
newmobj->threshold = 70;
}
P_RemoveMobj(mobj); // make sure they disappear
return false;
case MT_SMK_ICEBLOCK:
@ -8400,12 +8607,6 @@ void P_MobjThinker(mobj_t *mobj)
I_Assert(mobj != NULL);
I_Assert(!P_MobjWasRemoved(mobj));
if (mobj->flags & MF_NOTHINK)
return;
if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<<mobj->spawnpoint->extrainfo)))
return;
// Remove dead target/tracer.
if (mobj->target && P_MobjWasRemoved(mobj->target))
P_SetTarget(&mobj->target, NULL);
@ -8416,6 +8617,19 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->hprev && P_MobjWasRemoved(mobj->hprev))
P_SetTarget(&mobj->hprev, NULL);
if (mobj->flags & MF_NOTHINK)
return;
if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<<mobj->spawnpoint->extrainfo)))
return;
// Don't run any thinker code while in hitlag
if (mobj->hitlag > 0)
{
mobj->hitlag--;
return;
}
mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL);
tmfloorthing = tmhitthing = NULL;
@ -8433,7 +8647,7 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->scale != mobj->destscale)
P_MobjScaleThink(mobj); // Slowly scale up/down to reach your destscale.
if ((mobj->type == MT_GHOST || mobj->type == MT_THOK) && mobj->fuse > 0) // Not guaranteed to be MF_SCENERY or not MF_SCENERY!
if (mobj->type == MT_GHOST && mobj->fuse > 0) // Not guaranteed to be MF_SCENERY or not MF_SCENERY!
{
if (mobj->flags2 & MF2_BOSSNOTRAP) // "fast" flag
{
@ -8499,7 +8713,8 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->type == MT_BANANA || mobj->type == MT_EGGMANITEM
|| mobj->type == MT_ORBINAUT || mobj->type == MT_BALLHOG
|| mobj->type == MT_JAWZ || mobj->type == MT_JAWZ_DUD
|| mobj->type == MT_SSMINE || mobj->type == MT_BUBBLESHIELDTRAP)
|| mobj->type == MT_SSMINE || mobj->type == MT_BUBBLESHIELDTRAP
|| mobj->type == MT_LANDMINE)
{
if (mobj->health > 0 && P_MobjTouchingSectorSpecial(mobj, 4, 7, true))
{
@ -8577,7 +8792,7 @@ void P_MobjThinker(mobj_t *mobj)
|| mobj->type == MT_FLINGCOIN
|| mobj->type == MT_FLINGBLUESPHERE
|| mobj->type == MT_FLINGNIGHTSCHIP
|| mobj->type == MT_FLINGEMERALD
|| mobj->type == MT_EMERALD
|| mobj->type == MT_BIGTUMBLEWEED
|| mobj->type == MT_LITTLETUMBLEWEED
|| mobj->type == MT_CANNONBALLDECOR
@ -8880,6 +9095,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
case MT_JAWZ_SHIELD:
case MT_SSMINE:
case MT_SSMINE_SHIELD:
case MT_LANDMINE:
case MT_BALLHOG:
case MT_SINK:
case MT_ROCKETSNEAKER:
@ -8909,6 +9125,8 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
break;
case MT_RING:
case MT_FLOATINGITEM:
case MT_BLUESPHERE:
case MT_EMERALD:
thing->shadowscale = FRACUNIT/2;
break;
case MT_DRIFTCLIP:
@ -9017,6 +9235,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
mobj->colorized = false;
mobj->hitlag = 0;
// Set shadowscale here, before spawn hook so that Lua can change it
P_DefaultMobjShadowScale(mobj);
@ -9198,8 +9418,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
mobj->color = skincolor_blueteam;
break;
case MT_RING:
case MT_COIN:
case MT_NIGHTSSTAR:
if (nummaprings >= 0)
nummaprings++;
break;
@ -9557,10 +9775,7 @@ void P_RemoveMobj(mobj_t *mobj)
// Rings only, please!
if (mobj->spawnpoint &&
(mobj->type == MT_RING
|| mobj->type == MT_COIN
|| mobj->type == MT_NIGHTSSTAR
|| mobj->type == MT_REDTEAMRING
|| mobj->type == MT_BLUETEAMRING)
|| mobj->type == MT_BLUESPHERE)
&& !(mobj->flags2 & MF2_DONTRESPAWN))
{
itemrespawnque[iquehead] = mobj->spawnpoint;
@ -9959,11 +10174,11 @@ mobjtype_t P_GetMobjtype(UINT16 mthingtype)
void P_RespawnSpecials(void)
{
UINT8 p, pcount = 0;
tic_t time = 30*TICRATE; // Respawn things in empty dedicated servers
INT32 time = 30*TICRATE; // Respawn things in empty dedicated servers
mapthing_t *mthing = NULL;
if (!(gametyperules & GTR_CIRCUIT) && numgotboxes >= (4*nummapboxes/5)) // Battle Mode respawns all boxes in a different way
P_RespawnBattleBoxes();
//if (!(gametyperules & GTR_CIRCUIT) && numgotboxes >= (4*nummapboxes/5)) // Battle Mode respawns all boxes in a different way
//P_RespawnBattleBoxes();
// wait time depends on player count
for (p = 0; p < MAXPLAYERS; p++)
@ -9972,22 +10187,33 @@ void P_RespawnSpecials(void)
pcount++;
}
if (pcount == 1) // No respawn when alone
return;
else if (pcount > 1)
if (gametyperules & GTR_SPHERES)
{
time = (120 - ((pcount-2) * 10))*TICRATE;
if (pcount > 2)
time -= (5*TICRATE) * (pcount-2);
// 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);
if (time < 10*TICRATE)
if (time < 5*TICRATE)
time = 5*TICRATE;
}
else
{
if (pcount == 1) // No respawn when alone
return;
else if (pcount > 1)
{
// Ensure it doesn't go into absurdly low values
time = 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);
if (time < 10*TICRATE)
{
// Ensure it doesn't go into absurdly low values
time = 10*TICRATE;
}
}
}
@ -9996,7 +10222,7 @@ void P_RespawnSpecials(void)
return;
// the first item in the queue is the first to respawn
if (leveltime - itemrespawntime[iquetail] < time)
if (leveltime - itemrespawntime[iquetail] < (tic_t)time)
return;
mthing = itemrespawnque[iquetail];
@ -10048,7 +10274,7 @@ void P_SpawnPlayer(INT32 playernum)
/*
if (bonusgame || specialstage)
{
// Bots should avoid
// Bots should avoid
p->spectator = true;
}
*/
@ -10145,30 +10371,35 @@ void P_SpawnPlayer(INT32 playernum)
P_SetScale(mobj, mobj->destscale);
P_FlashPal(p, 0, 0); // Resets
if ((gametyperules & GTR_BUMPERS)) // SRB2kart
if (gametyperules & GTR_BUMPERS)
{
mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height + 16*FRACUNIT, MT_PLAYERARROW);
P_SetTarget(&overheadarrow->target, mobj);
overheadarrow->drawflags |= MFD_DONTDRAW;
P_SetScale(overheadarrow, mobj->destscale);
if (p->spectator && pcount > 1) // HEY! No being cheap...
p->kartstuff[k_bumper] = 0;
else if (p->kartstuff[k_bumper] > 0 || leveltime < 1
|| (p->jointime <= 1 && pcount <= 1))
if (p->spectator)
{
if (leveltime < 1 || (p->jointime <= 1 && pcount <= 1)) // Start of the map?
p->kartstuff[k_bumper] = K_StartingBumperCount(); // Reset those bumpers!
if (p->kartstuff[k_bumper])
// HEY! No being cheap...
p->bumpers = 0;
}
else if ((p->bumpers > 0) || (leveltime < starttime) || (pcount <= 1))
{
if ((leveltime < starttime) || (pcount <= 1)) // Start of the map?
{
angle_t diff = FixedAngle(360*FRACUNIT/p->kartstuff[k_bumper]);
// Reset those bumpers!
p->bumpers = K_StartingBumperCount();
}
if (p->bumpers)
{
angle_t diff = FixedAngle(360*FRACUNIT/p->bumpers);
angle_t newangle = mobj->angle;
fixed_t newx = mobj->x + P_ReturnThrustX(mobj, newangle + ANGLE_180, 64*FRACUNIT);
fixed_t newy = mobj->y + P_ReturnThrustY(mobj, newangle + ANGLE_180, 64*FRACUNIT);
mobj_t *mo;
for (i = 0; i < p->kartstuff[k_bumper]; i++)
for (i = 0; i < p->bumpers; i++)
{
mo = P_SpawnMobj(newx, newy, mobj->z, MT_BATTLEBUMPER);
mo->threshold = i;
@ -10182,7 +10413,7 @@ void P_SpawnPlayer(INT32 playernum)
}
}
}
else if (p->kartstuff[k_bumper] <= 0)
else if (p->bumpers <= 0)
{
mobj_t *karmahitbox = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_KARMAHITBOX); // Player hitbox is too small!!
P_SetTarget(&karmahitbox->target, mobj);
@ -10403,6 +10634,7 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt
case MT_SPIKEBALL:
case MT_EMBLEM:
case MT_RING:
case MT_BLUESPHERE:
offset += mthing->options & MTF_AMBUSH ? 24*mapobjectscale : 0;
break;
@ -10509,8 +10741,14 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i)
{
// Don't need this for Kart YET!
(void)mthing;
if ((gametyperules & GTR_SPHERES) && (i == MT_RING))
return MT_BLUESPHERE;
if ((gametyperules & GTR_PAPERITEMS) && (i == MT_RANDOMITEM))
return MT_PAPERITEMSPOT;
return i;
}
@ -11594,8 +11832,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
static void P_SetAmbush(mobj_t *mobj)
{
if (mobj->type == MT_YELLOWDIAG || mobj->type == MT_REDDIAG || mobj->type == MT_BLUEDIAG)
mobj->angle += ANGLE_22h;
if (mobj->flags & MF_SPRING)
{
// gravity toggle
mobj->flags ^= MF_NOGRAVITY;
}
if (mobj->flags & MF_NIGHTSITEM)
{
@ -11624,9 +11865,6 @@ static void P_SetAmbush(mobj_t *mobj)
static void P_SetObjectSpecial(mobj_t *mobj)
{
if (mobj->type == MT_YELLOWDIAG || mobj->type == MT_REDDIAG || mobj->type == MT_BLUEDIAG)
mobj->flags |= MF_NOGRAVITY;
if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
{
// flag for strong/weak random boxes

View file

@ -157,6 +157,8 @@ typedef enum
MF_RUNSPAWNFUNC = 1<<27,
// Don't remap in Encore mode. (Not a drawflag so that it's settable by mobjinfo.)
MF_DONTENCOREMAP = 1<<28,
// Hitbox extends just as far below as above.
MF_PICKUPFROMBELOW = 1<<29,
// free: to and including 1<<31
} mobjflag_t;
@ -408,9 +410,6 @@ typedef struct mobj_s
INT32 cvmem;
struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?)
#ifdef HWRENDER
struct pslope_s *modeltilt; // Slope used for model tilting. Also is not synched, this is totally visual.
#endif
boolean colorized; // Whether the mobj uses the rainbow colormap
boolean mirrored; // The object's rotations will be mirrored left to right, e.g., see frame AL from the right and AR from the left
@ -420,6 +419,8 @@ typedef struct mobj_s
fixed_t sprxoff, spryoff, sprzoff; // Sprite offsets in real space, does NOT affect position or collision
INT32 hitlag; // Sal-style hit lag, straight from Captain Fetch's jowls
// WARNING: New fields must be added separately to savegame and Lua.
} mobj_t;
@ -530,7 +531,6 @@ boolean P_ZMovement(mobj_t *mo);
void P_RingZMovement(mobj_t *mo);
boolean P_SceneryZMovement(mobj_t *mo);
void P_PlayerZMovement(mobj_t *mo);
void P_EmeraldManager(void);
extern INT32 modulothing;

View file

@ -876,6 +876,10 @@ static void Polyobj_carryThings(polyobj_t *po, fixed_t dx, fixed_t dy)
for (; mo; mo = mo->bnext)
{
// lastlook is used by the SPB to determine targets, do not let it affect it
if (mo->type == MT_SPB)
continue;
if (mo->lastlook == pomovecount)
continue;
@ -1106,6 +1110,10 @@ static void Polyobj_rotateThings(polyobj_t *po, vector2_t origin, angle_t delta,
for (; mo; mo = mo->bnext)
{
// lastlook is used by the SPB to determine targets, do not let it affect it
if (mo->type == MT_SPB)
continue;
if (mo->lastlook == pomovecount)
continue;

View file

@ -111,6 +111,7 @@ static void P_NetArchivePlayers(void)
WRITEANGLE(save_p, players[i].awayviewaiming);
WRITEINT32(save_p, players[i].awayviewtics);
WRITEINT16(save_p, players[i].rings);
WRITEINT16(save_p, players[i].spheres);
for (j = 0; j < NUMPOWERS; j++)
WRITEUINT16(save_p, players[i].powers[j]);
@ -234,7 +235,7 @@ static void P_NetArchivePlayers(void)
if (flags & FOLLOWITEM)
WRITEUINT32(save_p, players[i].followmobj->mobjnum);
WRITEUINT32(save_p, (UINT32)players[i].followitem);
WRITEUINT32(save_p, players[i].charflags);
@ -255,6 +256,19 @@ static void P_NetArchivePlayers(void)
WRITEUINT32(save_p, players[i].distancetofinish);
WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].nextwaypoint));
WRITEUINT32(save_p, players[i].airtime);
WRITEUINT8(save_p, players[i].trickpanel);
WRITEUINT8(save_p, players[i].trickdelay);
WRITEUINT32(save_p, players[i].trickmomx);
WRITEUINT32(save_p, players[i].trickmomy);
WRITEUINT32(save_p, players[i].trickmomz);
WRITEUINT8(save_p, players[i].bumpers);
WRITEINT16(save_p, players[i].karmadelay);
WRITEUINT8(save_p, players[i].eliminated);
WRITEUINT8(save_p, players[i].tumbleBounces);
WRITEUINT16(save_p, players[i].tumbleHeight);
WRITEUINT8(save_p, players[i].tumbleLastBounce);
// respawnvars_t
WRITEUINT8(save_p, players[i].respawn.state);
@ -304,6 +318,7 @@ static void P_NetUnArchivePlayers(void)
players[i].awayviewaiming = READANGLE(save_p);
players[i].awayviewtics = READINT32(save_p);
players[i].rings = READINT16(save_p);
players[i].spheres = READINT16(save_p);
for (j = 0; j < NUMPOWERS; j++)
players[i].powers[j] = READUINT16(save_p);
@ -418,7 +433,7 @@ static void P_NetUnArchivePlayers(void)
if (flags & FOLLOWITEM)
players[i].followmobj = (mobj_t *)(size_t)READUINT32(save_p);
players[i].followitem = (mobjtype_t)READUINT32(save_p);
//SetPlayerSkinByNum(i, players[i].skin);
@ -440,6 +455,19 @@ static void P_NetUnArchivePlayers(void)
players[i].distancetofinish = READUINT32(save_p);
players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save_p);
players[i].airtime = READUINT32(save_p);
players[i].trickpanel = READUINT8(save_p);
players[i].trickdelay = READUINT8(save_p);
players[i].trickmomx = READUINT32(save_p);
players[i].trickmomy = READUINT32(save_p);
players[i].trickmomz = READUINT32(save_p);
players[i].bumpers = READUINT8(save_p);
players[i].karmadelay = READINT16(save_p);
players[i].eliminated = (boolean)READUINT8(save_p);
players[i].tumbleBounces = READUINT8(save_p);
players[i].tumbleHeight = READUINT16(save_p);
players[i].tumbleLastBounce = (boolean)READUINT8(save_p);
// respawnvars_t
players[i].respawn.state = READUINT8(save_p);
@ -1369,9 +1397,10 @@ typedef enum
MD2_ROLLANGLE = 1<<14,
MD2_SHADOWSCALE = 1<<15,
MD2_DRAWFLAGS = 1<<16,
MD2_WAYPOINTCAP = 1<<17,
MD2_KITEMCAP = 1<<18,
MD2_ITNEXT = 1<<19,
MD2_HITLAG = 1<<17,
MD2_WAYPOINTCAP = 1<<18,
MD2_KITEMCAP = 1<<19,
MD2_ITNEXT = 1<<20,
} mobj_diff2_t;
typedef enum
@ -1586,6 +1615,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
diff2 |= MD2_SHADOWSCALE;
if (mobj->drawflags)
diff2 |= MD2_DRAWFLAGS;
if (mobj->hitlag)
diff2 |= MD2_HITLAG;
if (mobj == waypointcap)
diff2 |= MD2_WAYPOINTCAP;
if (mobj == kitemcap)
@ -1750,6 +1781,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
WRITEUINT16(save_p, df);
}
if (diff2 & MD2_HITLAG)
WRITEINT32(save_p, mobj->hitlag);
WRITEUINT32(save_p, mobj->mobjnum);
}
@ -2795,12 +2828,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
if (diff2 & MD2_ITNEXT)
mobj->itnext = (mobj_t *)(size_t)READUINT32(save_p);
if (diff2 & MD2_SLOPE)
{
mobj->standingslope = P_SlopeById(READUINT16(save_p));
#ifdef HWRENDER
mobj->modeltilt = mobj->standingslope;
#endif
}
if (diff2 & MD2_COLORIZED)
mobj->colorized = READUINT8(save_p);
if (diff2 & MD2_MIRRORED)
@ -2814,6 +2842,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
}
if (diff2 & MD2_DRAWFLAGS)
mobj->drawflags = READUINT16(save_p);
if (diff2 & MD2_HITLAG)
mobj->hitlag = READINT32(save_p);
if (diff & MD_REDFLAG)
{
@ -4117,7 +4147,6 @@ static void P_NetArchiveMisc(void)
// battleovertime_t
WRITEUINT16(save_p, battleovertime.enabled);
WRITEFIXED(save_p, battleovertime.radius);
WRITEFIXED(save_p, battleovertime.minradius);
WRITEFIXED(save_p, battleovertime.x);
WRITEFIXED(save_p, battleovertime.y);
WRITEFIXED(save_p, battleovertime.z);
@ -4251,7 +4280,6 @@ static inline boolean P_NetUnArchiveMisc(void)
// battleovertime_t
battleovertime.enabled = READUINT16(save_p);
battleovertime.radius = READFIXED(save_p);
battleovertime.minradius = READFIXED(save_p);
battleovertime.x = READFIXED(save_p);
battleovertime.y = READFIXED(save_p);
battleovertime.z = READFIXED(save_p);

View file

@ -3919,40 +3919,40 @@ boolean P_LoadLevel(boolean fromnetsave)
}
*/
// Make sure all sounds are stopped before Z_FreeTags.
S_StopSounds();
S_ClearSfx();
// Fade out music here. Deduct 2 tics so the fade volume actually reaches 0.
// But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug.
if (!titlemapinaction)
S_FadeMusic(0, FixedMul(
FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE));
// Reset the palette now all fades have been done
if (rendermode != render_none)
V_SetPaletteLump(GetPalette()); // Set the level palette
if (!titlemapinaction)
{
if (ranspecialwipe == 2)
{
pausedelay = -3; // preticker plus one
S_StartSound(NULL, sfx_s3k73);
}
// As oddly named as this is, this handles music only.
// We should be fine starting it here.
// Don't do this during titlemap, because the menu code handles music by itself.
S_Start();
}
levelfadecol = (encoremode ? 0 : 31);
// Let's fade to white here
// But only if we didn't do the encore startup wipe
if (!demo.rewinding)
{
// Make sure all sounds are stopped before Z_FreeTags.
S_StopSounds();
S_ClearSfx();
// Fade out music here. Deduct 2 tics so the fade volume actually reaches 0.
// But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug.
if (!titlemapinaction)
S_FadeMusic(0, FixedMul(
FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE));
// Reset the palette now all fades have been done
if (rendermode != render_none)
V_SetPaletteLump(GetPalette()); // Set the level palette
if (!titlemapinaction)
{
if (ranspecialwipe == 2)
{
pausedelay = -3; // preticker plus one
S_StartSound(NULL, sfx_s3k73);
}
// As oddly named as this is, this handles music only.
// We should be fine starting it here.
// Don't do this during titlemap, because the menu code handles music by itself.
S_Start();
}
levelfadecol = (encoremode ? 0 : 31);
if (rendermode != render_none)
{
F_WipeStartScreen();

View file

@ -498,3 +498,161 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
// the head node is the last node output
return P_CrossBSPNode((INT32)numnodes - 1, &los);
}
//
// P_TraceBlockingLines
//
// Returns true if a straight line between t1 and t2 is unobstructed.
// Unlike P_CheckSight, simplifed down to only check for explicit blocking lines on the 2D plane.
// Intended for Kart waypoints.
// Might be better in it's own file?
//
typedef struct {
fixed_t t2x, t2y;
divline_t strace; // from t1 to t2
fixed_t bbox[4];
mobj_t *compareThing;
} traceblocking_t;
static boolean P_CrossBlockingSubsector(size_t num, register traceblocking_t *tb)
{
seg_t *seg;
INT32 count;
#ifdef RANGECHECK
if (num >= numsubsectors)
I_Error("P_CrossBlockingSubsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors));
#endif
// haleyjd 02/23/06: this assignment should be after the above check
seg = segs + subsectors[num].firstline;
for (count = subsectors[num].numlines; --count >= 0; seg++) // check lines
{
line_t *line = seg->linedef;
divline_t divl;
const vertex_t *v1,*v2;
if (seg->glseg)
continue;
// already checked other side?
if (line->validcount == validcount)
continue;
line->validcount = validcount;
// OPTIMIZE: killough 4/20/98: Added quick bounding-box rejection test
if (line->bbox[BOXLEFT ] > tb->bbox[BOXRIGHT ] ||
line->bbox[BOXRIGHT ] < tb->bbox[BOXLEFT ] ||
line->bbox[BOXBOTTOM] > tb->bbox[BOXTOP ] ||
line->bbox[BOXTOP] < tb->bbox[BOXBOTTOM])
continue;
v1 = line->v1;
v2 = line->v2;
// line isn't crossed?
if (P_DivlineSide(v1->x, v1->y, &tb->strace) ==
P_DivlineSide(v2->x, v2->y, &tb->strace))
continue;
// stop because it is not two sided anyway
if (!(line->flags & ML_TWOSIDED))
return false;
divl.dx = v2->x - (divl.x = v1->x);
divl.dy = v2->y - (divl.y = v1->y);
// line isn't crossed?
if (P_DivlineSide(tb->strace.x, tb->strace.y, &divl) ==
P_DivlineSide(tb->t2x, tb->t2y, &divl))
continue;
if (P_IsLineBlocking(line, tb->compareThing) == true)
{
// This line will block us
return false;
}
}
// passed the subsector ok
return true;
}
static boolean P_CrossBSPNodeBlocking(INT32 bspnum, register traceblocking_t *tb)
{
while (!(bspnum & NF_SUBSECTOR))
{
register node_t *bsp = nodes + bspnum;
INT32 side = P_DivlineSide(tb->strace.x,tb->strace.y,(divline_t *)bsp)&1;
if (side == P_DivlineSide(tb->t2x, tb->t2y, (divline_t *) bsp))
bspnum = bsp->children[side]; // doesn't touch the other side
else // the partition plane is crossed here
{
if (!P_CrossBSPNodeBlocking(bsp->children[side], tb))
return false; // cross the starting side
else
bspnum = bsp->children[side^1]; // cross the ending side
}
}
return P_CrossBlockingSubsector((bspnum == -1 ? 0 : bspnum & ~NF_SUBSECTOR), tb);
}
boolean P_TraceBlockingLines(mobj_t *t1, mobj_t *t2)
{
const sector_t *s1, *s2;
size_t pnum;
traceblocking_t tb;
// First check for trivial rejection.
if (!t1 || !t2)
return false;
I_Assert(!P_MobjWasRemoved(t1));
I_Assert(!P_MobjWasRemoved(t2));
if (!t1->subsector || !t2->subsector
|| !t1->subsector->sector || !t2->subsector->sector)
return false;
s1 = t1->subsector->sector;
s2 = t2->subsector->sector;
pnum = (s1-sectors)*numsectors + (s2-sectors);
if (rejectmatrix != NULL)
{
// Check in REJECT table.
if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
return false;
}
// killough 11/98: shortcut for melee situations
// same subsector? obviously visible
// haleyjd 02/23/06: can't do this if there are polyobjects in the subsec
if (!t1->subsector->polyList &&
t1->subsector == t2->subsector)
return true;
validcount++;
tb.strace.dx = (tb.t2x = t2->x) - (tb.strace.x = t1->x);
tb.strace.dy = (tb.t2y = t2->y) - (tb.strace.y = t1->y);
if (t1->x > t2->x)
tb.bbox[BOXRIGHT] = t1->x, tb.bbox[BOXLEFT] = t2->x;
else
tb.bbox[BOXRIGHT] = t2->x, tb.bbox[BOXLEFT] = t1->x;
if (t1->y > t2->y)
tb.bbox[BOXTOP] = t1->y, tb.bbox[BOXBOTTOM] = t2->y;
else
tb.bbox[BOXTOP] = t2->y, tb.bbox[BOXBOTTOM] = t1->y;
tb.compareThing = t1;
// the head node is the last node output
return P_CrossBSPNodeBlocking((INT32)numnodes - 1, &tb);
}

View file

@ -897,9 +897,8 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
if (P_MobjFlip(thing)*(thing->momz) < 0) // falling, land on slope
{
thing->standingslope = slope;
#ifdef HWRENDER
thing->modeltilt = thing->standingslope;
#endif
P_SetPitchRollFromSlope(thing, slope);
if (!thing->player || !(thing->player->pflags & PF_BOUNCING))
thing->momz = -P_MobjFlip(thing);
}
@ -916,9 +915,7 @@ void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
thing->momx = mom.x;
thing->momy = mom.y;
thing->standingslope = slope;
#ifdef HWRENDER
thing->modeltilt = thing->standingslope;
#endif
P_SetPitchRollFromSlope(thing, slope);
if (!thing->player || !(thing->player->pflags & PF_BOUNCING))
thing->momz = -P_MobjFlip(thing);
}

View file

@ -1612,7 +1612,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
{
if (GETSECSPECIAL(caller->special, 2) == 6)
{
if (!(ALL7EMERALDS(emeralds)))
if (!(ALLCHAOSEMERALDS(emeralds)))
return false;
}
@ -2028,6 +2028,14 @@ static void K_HandleLapIncrement(player_t *player)
player->karthud[khud_laphand] = 0; // No hands in FREE PLAY
player->karthud[khud_lapanimation] = 80;
// save best lap for record attack
if (player == &players[consoleplayer])
{
if (curlap < bestlap || bestlap == 0)
bestlap = curlap;
curlap = 0;
}
}
if (rainbowstartavailable == true)
@ -2041,14 +2049,6 @@ static void K_HandleLapIncrement(player_t *player)
if (netgame && player->laps >= (UINT8)cv_numlaps.value)
CON_LogMessage(va(M_GetText("%s has finished the race.\n"), player_names[player-players]));
// SRB2Kart: save best lap for record attack
if (player == &players[consoleplayer])
{
if (curlap < bestlap || bestlap == 0)
bestlap = curlap;
curlap = 0;
}
player->starpostnum = 0;
if (P_IsDisplayPlayer(player))
@ -2133,6 +2133,7 @@ static void K_HandleLapDecrement(player_t *player)
{
player->starpostnum = numstarposts;
player->laps--;
curlap = UINT32_MAX;
}
}
}
@ -4602,49 +4603,43 @@ DoneSection2:
switch (special)
{
case 1: // SRB2kart: Spring Panel
case 3:
if (roversector || P_MobjReadyToTrigger(player->mo, sector))
{
const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale);
const fixed_t minspeed = 24*hscale;
angle_t pushangle = FixedHypot(player->mo->momx, player->mo->momy) ? R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy) : player->mo->angle;
// if we have no speed for SOME REASON, use the player's angle, otherwise we'd be forcefully thrusted to what I can only assume is angle 0
fixed_t speed = FixedHypot(player->mo->momx, player->mo->momy);
fixed_t upwards = 32*FRACUNIT;
if (player->mo->eflags & MFE_SPRUNG)
{
break;
}
if (player->speed < minspeed) // Push forward to prevent getting stuck
P_InstaThrust(player->mo, pushangle, minspeed);
if (special == 3)
{
upwards /= 2;
}
player->kartstuff[k_pogospring] = 1;
K_DoPogoSpring(player->mo, 0, 1);
player->trickpanel = 1;
player->trickdelay = 1;
K_DoPogoSpring(player->mo, upwards, 1);
// Reduce speed
speed /= 2;
if (speed < minspeed)
{
speed = minspeed;
}
P_InstaThrust(player->mo, player->mo->angle, speed);
}
break;
case 2: // Wind/Current
break;
case 3: // SRB2kart: Spring Panel (capped speed)
if (roversector || P_MobjReadyToTrigger(player->mo, sector))
{
const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale);
const fixed_t minspeed = 24*hscale;
const fixed_t maxspeed = 28*hscale;
angle_t pushangle = FixedHypot(player->mo->momx, player->mo->momy) ? R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy) : player->mo->angle;
// if we have no speed for SOME REASON, use the player's angle, otherwise we'd be forcefully thrusted to what I can only assume is angle 0
if (player->mo->eflags & MFE_SPRUNG)
break;
if (player->speed > maxspeed) // Prevent overshooting jumps
P_InstaThrust(player->mo, pushangle, maxspeed);
else if (player->speed < minspeed) // Push forward to prevent getting stuck
P_InstaThrust(player->mo, pushangle, minspeed);
player->kartstuff[k_pogospring] = 2;
K_DoPogoSpring(player->mo, 0, 1);
}
break;
case 4: // Conveyor Belt
break;
@ -4677,14 +4672,14 @@ DoneSection2:
}
lineangle = K_ReflectAngle(
R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy), lineangle,
K_MomentumAngle(player->mo), lineangle,
playerspeed, linespeed
);
P_InstaThrust(player->mo, lineangle, max(linespeed, 2*playerspeed));
player->kartstuff[k_dashpadcooldown] = TICRATE/3;
player->kartstuff[k_pogospring] = 0;
player->trickpanel = 0;
player->kartstuff[k_floorboost] = 2;
S_StartSound(player->mo, sfx_cdfm62);
}
@ -4838,9 +4833,6 @@ DoneSection2:
if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ZOOMTUBE)
break;
if (player->powers[pw_ignorelatch] & (1<<15))
break;
// Find line #3 tagged to this sector
lineindex = P_FindSpecialLineFromTag(3, sector->tag, -1);

View file

@ -332,6 +332,11 @@ static inline void P_RunThinkers(void)
ps_thlist_times[i] = I_GetTimeMicros() - ps_thlist_times[i];
}
if (gametyperules & GTR_PAPERITEMS)
K_RunPaperItemSpawners();
if ((gametyperules & GTR_BUMPERS) && battleovertime.enabled)
K_RunBattleOvertime();
}
//
@ -516,6 +521,8 @@ void P_Ticker(boolean run)
if (demo.rewinding && leveltime > 0)
{
leveltime = (leveltime-1) & ~3;
if (timeinmap > 0)
timeinmap = (timeinmap-1) & ~3;
G_PreviewRewind(leveltime);
}
else if (demo.freecam && democam.cam) // special case: allow freecam to MOVE during pause!
@ -592,9 +599,6 @@ void P_Ticker(boolean run)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerAfterThink(&players[i]);
if ((gametyperules & GTR_BUMPERS) && battleovertime.enabled)
K_RunBattleOvertime();
ps_lua_thinkframe_time = I_GetTimeMicros();
LUAh_ThinkFrame();
ps_lua_thinkframe_time = I_GetTimeMicros() - ps_lua_thinkframe_time;
@ -613,9 +617,7 @@ void P_Ticker(boolean run)
if (run)
leveltime++;
// as this is mostly used for HUD stuff, add the record attack specific hack to it as well!
if (!(modeattacking && !demo.playback) || leveltime >= starttime - TICRATE*4)
timeinmap++;
timeinmap++;
if (G_GametypeHasTeams())
P_DoTeamStuff();
@ -752,9 +754,6 @@ void P_PreTicker(INT32 frames)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerAfterThink(&players[i]);
if ((gametyperules & GTR_BUMPERS) && battleovertime.enabled)
K_RunBattleOvertime();
LUAh_ThinkFrame();
// Run shield positioning

View file

@ -461,15 +461,9 @@ UINT8 P_FindHighestLap(void)
//
boolean P_PlayerInPain(player_t *player)
{
if (player->kartstuff[k_spinouttimer] || player->kartstuff[k_squishedtimer] || player->respawn.state != RESPAWNST_NONE)
if (player->kartstuff[k_spinouttimer] || player->tumbleBounces > 0)
return true;
if (gametyperules & GTR_KARMA)
{
if (player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer])
return true;
}
return false;
}
@ -485,7 +479,7 @@ void P_ResetPlayer(player_t *player)
player->onconveyor = 0;
//player->kartstuff[k_drift] = player->kartstuff[k_driftcharge] = 0;
player->kartstuff[k_pogospring] = 0;
player->trickpanel = 0;
}
//
@ -1290,6 +1284,8 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
ghost->colorized = mobj->colorized; // Kart: they should also be colorized if their origin is
ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle);
ghost->roll = mobj->roll;
ghost->pitch = mobj->pitch;
ghost->sprite = mobj->sprite;
ghost->sprite2 = mobj->sprite2;
ghost->frame = mobj->frame;
@ -1298,13 +1294,11 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
ghost->fuse = ghost->info->damage;
ghost->skin = mobj->skin;
ghost->standingslope = mobj->standingslope;
#ifdef HWRENDER
ghost->modeltilt = mobj->modeltilt;
#endif
ghost->sprxoff = mobj->sprxoff;
ghost->spryoff = mobj->spryoff;
ghost->sprzoff = mobj->sprzoff;
ghost->rollangle = mobj->rollangle;
if (mobj->flags2 & MF2_OBJECTFLIP)
ghost->flags |= MF2_OBJECTFLIP;
@ -1924,8 +1918,7 @@ static void P_3dMovement(player_t *player)
//}
// Do not let the player control movement if not onground.
// SRB2Kart: pogo spring and speed bumps are supposed to control like you're on the ground
onground = (P_IsObjectOnGround(player->mo) || (player->kartstuff[k_pogospring]));
onground = P_IsObjectOnGround(player->mo);
K_AdjustPlayerFriction(player);
@ -1941,11 +1934,6 @@ static void P_3dMovement(player_t *player)
totalthrust.x += P_ReturnThrustX(player->mo, movepushangle, movepushforward);
totalthrust.y += P_ReturnThrustY(player->mo, movepushangle, movepushforward);
if (K_PlayerUsesBotMovement(player) == true)
{
K_MomentumToFacing(player);
}
}
if ((totalthrust.x || totalthrust.y)
@ -2157,18 +2145,41 @@ void P_MovePlayer(player_t *player)
P_3dMovement(player);
// Kart frames
if (player->kartstuff[k_squishedtimer] > 0)
if (player->tumbleBounces > 0)
{
P_SetPlayerMobjState(player->mo, S_KART_SQUISH);
fixed_t playerSpeed = P_AproxDistance(player->mo->momx, player->mo->momy); // maybe momz too?
const UINT8 minSpinSpeed = 4;
UINT8 spinSpeed = max(minSpinSpeed, min(8 + minSpinSpeed, (playerSpeed / player->mo->scale) * 2));
UINT8 rollSpeed = max(1, min(8, player->tumbleHeight / 10));
if (player->tumbleLastBounce == true)
spinSpeed = 2;
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
player->drawangle -= (ANGLE_11hh * spinSpeed);
player->mo->rollangle -= (ANGLE_11hh * rollSpeed);
if (player->tumbleLastBounce == true)
{
if (abs((signed)(player->mo->angle - player->drawangle)) < ANGLE_22h)
player->drawangle = player->mo->angle;
if (abs((signed)player->mo->rollangle) < ANGLE_22h)
player->mo->rollangle = 0;
}
}
else if (player->pflags & PF_SLIDING)
{
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
player->drawangle -= ANGLE_22h;
player->mo->rollangle = 0;
}
else if (player->kartstuff[k_spinouttimer] > 0)
{
INT32 speed = max(1, min(8, player->kartstuff[k_spinouttimer]/8));
UINT8 speed = max(1, min(8, player->kartstuff[k_spinouttimer]/8));
P_SetPlayerMobjState(player->mo, S_KART_SPINOUT);
@ -2176,6 +2187,8 @@ void P_MovePlayer(player_t *player)
player->drawangle = player->mo->angle; // Face forward at the end of the animation
else
player->drawangle -= (ANGLE_11hh * speed);
player->mo->rollangle = 0;
}
else if (player->pflags & PF_FAULT)
{
@ -2185,15 +2198,21 @@ void P_MovePlayer(player_t *player)
player->drawangle += ANGLE_11hh;
else
player->drawangle -= ANGLE_11hh;
player->mo->rollangle = 0;
}
else
{
K_KartMoveAnimation(player);
if (player->kartstuff[k_pogospring])
if (player->trickpanel == 2)
{
player->drawangle += ANGLE_22h;
}
else if (player->trickpanel == 3)
{
player->drawangle -= ANGLE_22h;
}
else
{
player->drawangle = player->mo->angle;
@ -2204,6 +2223,8 @@ void P_MovePlayer(player_t *player)
player->drawangle += a;
}
}
player->mo->rollangle = 0;
}
player->mo->movefactor = FRACUNIT; // We're not going to do any more with this, so let's change it back for the next frame.
@ -2271,7 +2292,7 @@ void P_MovePlayer(player_t *player)
if (trailScale > 0)
{
const angle_t forwardangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
const angle_t forwardangle = K_MomentumAngle(player->mo);
const fixed_t playerVisualRadius = player->mo->radius + 8*FRACUNIT;
const size_t numFrames = S_WATERTRAIL8 - S_WATERTRAIL1;
const statenum_t curOverlayFrame = S_WATERTRAIL1 + (leveltime % numFrames);
@ -2358,7 +2379,7 @@ void P_MovePlayer(player_t *player)
// Crush test...
if ((player->mo->ceilingz - player->mo->floorz < player->mo->height) && !(player->mo->flags & MF_NOCLIP))
{
if ((netgame || multiplayer) && player->spectator)
if (player->spectator)
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_SPECTATOR); // Respawn crushed spectators
else
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_CRUSHED);
@ -2644,7 +2665,7 @@ static void P_DeathThink(player_t *player)
{
if (player->spectator || !circuitmap)
curlap = 0;
else
else if (curlap != UINT32_MAX)
curlap++; // This is too complicated to sync to realtime, just sorta hope for the best :V
}
}
@ -3189,17 +3210,40 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
}
// sets ideal cam pos
dist = camdist;
{
const fixed_t speedthreshold = 48*mapobjectscale;
const fixed_t olddist = P_AproxDistance(mo->x - thiscam->x, mo->y - thiscam->y);
/* player->speed subtracts conveyors, janks up the camera */
speed = R_PointToDist2(0, 0, player->mo->momx, player->mo->momy);
fixed_t lag, distoffset;
if (speed > K_GetKartSpeed(player, false))
dist += 4*(speed - K_GetKartSpeed(player, false));
dist += abs(thiscam->momz)/4;
dist = camdist;
if (player->karthud[khud_boostcam])
dist -= FixedMul(11*dist/16, player->karthud[khud_boostcam]);
if (player->karthud[khud_boostcam])
{
dist -= FixedMul(11*dist/16, player->karthud[khud_boostcam]);
}
speed = P_AproxDistance(P_AproxDistance(mo->momx, mo->momy), mo->momz / 16);
lag = FRACUNIT - ((FixedDiv(speed, speedthreshold) - FRACUNIT) * 2);
if (lag > FRACUNIT)
{
lag = FRACUNIT;
}
if (lag < camspeed)
{
lag = camspeed;
}
distoffset = dist - olddist;
dist = olddist + FixedMul(distoffset, lag);
if (dist < 0)
{
dist = 0;
}
}
if (mo->standingslope)
{
@ -3488,7 +3532,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
thiscam->momz = 0;
}
else if (player->exiting || timeover == 2)
{
thiscam->momx = thiscam->momy = thiscam->momz = 0;
}
else if (leveltime < introtime)
{
thiscam->momx = FixedMul(x - thiscam->x, camspeed);
@ -4071,7 +4117,7 @@ static void P_HandleFollower(player_t *player)
player->follower->drawflags |= MFD_DONTDRAW;
if (player->speed && (player->follower->momx || player->follower->momy))
player->follower->angle = R_PointToAngle2(0, 0, player->follower->momx, player->follower->momy);
player->follower->angle = K_MomentumAngle(player->follower);
// if we're moving let's make the angle the direction we're moving towards. This is to avoid drifting / reverse looking awkward.
// Make sure the follower itself is also moving however, otherwise we'll be facing angle 0
@ -4217,6 +4263,11 @@ void P_PlayerThink(player_t *player)
}
#endif
if (player->mo->hitlag > 0)
{
return;
}
if (player->awayviewmobj && P_MobjWasRemoved(player->awayviewmobj))
{
P_SetTarget(&player->awayviewmobj, NULL); // remove awayviewmobj asap if invalid
@ -4235,7 +4286,8 @@ void P_PlayerThink(player_t *player)
// Track airtime
if (P_IsObjectOnGround(player->mo))
{
player->airtime = 0;
if (!P_PlayerInPain(player))
player->airtime = 0;
}
else
{
@ -4303,6 +4355,7 @@ void P_PlayerThink(player_t *player)
if (player->playerstate == PST_DEAD)
{
LUAh_PlayerThink(player);
return;
}
}
@ -4379,7 +4432,7 @@ void P_PlayerThink(player_t *player)
{
if (player->spectator || !circuitmap)
curlap = 0;
else
else if (curlap != UINT32_MAX)
curlap++; // This is too complicated to sync to realtime, just sorta hope for the best :V
}
}
@ -4496,10 +4549,6 @@ void P_PlayerThink(player_t *player)
else
player->pflags &= ~PF_SPINDOWN;
// IF PLAYER NOT HERE THEN FLASH END IF
if (player->quittime && player->powers[pw_flashing] < K_GetKartFlashing(player) && !player->gotflag)
player->powers[pw_flashing] = K_GetKartFlashing(player);
// Counters, time dependent power ups.
// Time Bonus & Ring Bonus count settings
@ -4518,11 +4567,6 @@ void P_PlayerThink(player_t *player)
else
player->powers[pw_nocontrol] = 0;
if (player->powers[pw_ignorelatch] & ((1<<15)-1) && player->powers[pw_ignorelatch] < UINT16_MAX)
player->powers[pw_ignorelatch]--;
else
player->powers[pw_ignorelatch] = 0;
//pw_super acts as a timer now
if (player->powers[pw_super])
player->powers[pw_super]++;
@ -4532,7 +4576,7 @@ void P_PlayerThink(player_t *player)
|| player->kartstuff[k_growshrinktimer] > 0 // Grow doesn't flash either.
|| (player->respawn.state != RESPAWNST_NONE) // Respawn timer (for drop dash effect)
|| (player->pflags & PF_GAMETYPEOVER) // NO CONTEST explosion
|| ((gametyperules & GTR_BUMPERS) && player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer])
|| ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0 && player->karmadelay)
|| leveltime < starttime)) // Level intro
{
if (player->powers[pw_flashing] > 0 && player->powers[pw_flashing] < K_GetKartFlashing(player)

View file

@ -368,29 +368,7 @@ angle_t R_PointToAngle2(fixed_t pviewx, fixed_t pviewy, fixed_t x, fixed_t y)
fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1)
{
angle_t angle;
fixed_t dx, dy, dist;
dx = abs(px1 - px2);
dy = abs(py1 - py2);
if (dy > dx)
{
fixed_t temp;
temp = dx;
dx = dy;
dy = temp;
}
if (!dy)
return dx;
angle = (tantoangle[FixedDiv(dy, dx)>>DBITS] + ANGLE_90) >> ANGLETOFINESHIFT;
// use as cosine
dist = FixedDiv(dx, FINESINE(angle));
return dist;
return FixedHypot(px1 - px2, py1 - py2);
}
// Little extra utility. Works in the same way as R_PointToAngle2

View file

@ -23,6 +23,7 @@
#include "v_video.h"
#include "z_zone.h"
#include "w_wad.h"
#include "r_main.h" // R_PointToAngle
#ifdef HWRENDER
#include "hardware/hw_glob.h"
@ -1605,6 +1606,27 @@ void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps)
}
#ifdef ROTSPRITE
//
// R_SpriteRotationAngle
//
// Gets the rollangle for the input object.
//
angle_t R_SpriteRotationAngle(mobj_t *mobj)
{
#if 0
angle_t viewingAngle = R_PointToAngle(mobj->x, mobj->y);
fixed_t pitchMul = -FINESINE(viewingAngle >> ANGLETOFINESHIFT);
fixed_t rollMul = FINECOSINE(viewingAngle >> ANGLETOFINESHIFT);
angle_t rollOrPitch = FixedMul(mobj->pitch, pitchMul) + FixedMul(mobj->roll, rollMul);
return (rollOrPitch + mobj->rollangle);
#else
return mobj->rollangle;
#endif
}
//
// R_GetRollAngle
//

View file

@ -122,6 +122,7 @@ void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum);
// Sprite rotation
#ifdef ROTSPRITE
angle_t R_SpriteRotationAngle(mobj_t *mobj);
INT32 R_GetRollAngle(angle_t rollangle);
void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, spriteframe_t *sprframe, INT32 rot, UINT8 flip);
void R_FreeSingleRotSprite(spritedef_t *spritedef);

View file

@ -876,6 +876,11 @@ boolean SetPlayerFollower(INT32 playernum, const char *skinname)
INT32 i;
player_t *player = &players[playernum];
if (stricmp("None", skinname) == 0)
{
SetFollower(playernum, -1); // reminder that -1 is nothing
return true;
}
for (i = 0; i < numfollowers; i++)
{
// search in the skin list

View file

@ -1074,14 +1074,6 @@ static void R_SplitSprite(vissprite_t *sprite)
sprite->sz = cutfrac;
newsprite->szt = (INT16)(sprite->sz - 1);
if (testheight < sprite->pzt && testheight > sprite->pz)
sprite->pz = newsprite->pzt = testheight;
else
{
newsprite->pz = newsprite->gz;
newsprite->pzt = newsprite->gzt;
}
newsprite->szt -= 8;
newsprite->cut |= SC_TOP;
@ -1305,16 +1297,12 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
shadow->patch = patch;
shadow->heightsec = vis->heightsec;
shadow->thingheight = FRACUNIT;
shadow->pz = groundz + (isflipped ? -shadow->thingheight : 0);
shadow->pzt = shadow->pz + shadow->thingheight;
shadow->mobjflags = 0;
shadow->sortscale = vis->sortscale;
shadow->dispoffset = vis->dispoffset - 5;
shadow->gx = thing->x;
shadow->gy = thing->y;
shadow->gzt = (isflipped ? shadow->pzt : shadow->pz) + SHORT(patch->height) * shadowyscale / 2;
shadow->gzt = groundz + SHORT(patch->height) * shadowyscale / 2;
shadow->gz = shadow->gzt - SHORT(patch->height) * shadowyscale;
shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale));
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
@ -1387,9 +1375,9 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
//
static void R_ProjectSprite(mobj_t *thing)
{
const fixed_t thingxpos = thing->x + thing->sprxoff;
const fixed_t thingypos = thing->y + thing->spryoff;
const fixed_t thingzpos = thing->z + thing->sprzoff;
fixed_t thingxpos = thing->x + thing->sprxoff;
fixed_t thingypos = thing->y + thing->spryoff;
fixed_t thingzpos = thing->z + thing->sprzoff;
mobj_t *oldthing = thing;
@ -1446,8 +1434,24 @@ static void R_ProjectSprite(mobj_t *thing)
#ifdef ROTSPRITE
patch_t *rotsprite = NULL;
INT32 rollangle = 0;
angle_t spriterotangle = 0;
#endif
// hitlag vibrating
if (thing->hitlag > 0)
{
fixed_t mul = thing->hitlag * (FRACUNIT / 10);
if (leveltime & 1)
{
mul = -mul;
}
thingxpos += FixedMul(thing->momx, mul);
thingypos += FixedMul(thing->momy, mul);
thingzpos += FixedMul(thing->momz, mul);
}
// transform the origin point
tr_x = thingxpos - viewx;
tr_y = thingypos - viewy;
@ -1571,9 +1575,11 @@ static void R_ProjectSprite(mobj_t *thing)
spr_topoffset = spritecachedinfo[lump].topoffset;
#ifdef ROTSPRITE
if (thing->rollangle)
spriterotangle = R_SpriteRotationAngle(thing);
if (spriterotangle != 0)
{
rollangle = R_GetRollAngle(thing->rollangle);
rollangle = R_GetRollAngle(spriterotangle);
if (!(sprframe->rotsprite.cached & (1<<rot)))
R_CacheRotSprite(thing->sprite, frame, sprinfo, sprframe, rot, flip);
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
@ -1812,9 +1818,6 @@ static void R_ProjectSprite(mobj_t *thing)
vis->gy = thingypos;
vis->gz = gz;
vis->gzt = gzt;
vis->thingheight = thing->height;
vis->pz = thingzpos;
vis->pzt = vis->pz + vis->thingheight;
vis->texturemid = vis->gzt - viewz;
vis->scalestep = scalestep;
vis->paperoffset = paperoffset;
@ -2032,9 +2035,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
vis->gy = thing->y;
vis->gz = gz;
vis->gzt = gzt;
vis->thingheight = 4*FRACUNIT;
vis->pz = thing->z;
vis->pzt = vis->pz + vis->thingheight;
vis->texturemid = vis->gzt - viewz;
vis->scalestep = 0;
vis->paperdistance = 0;
@ -2425,19 +2425,15 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy, r2->plane->height);
planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy, r2->plane->height);
if (rover->mobjflags & MF_NOCLIPHEIGHT)
// bird: if any part of the sprite peeks in front the plane
if (planecameraz < viewz)
{
//Objects with NOCLIPHEIGHT can appear halfway in.
if (planecameraz < viewz && rover->pz+(rover->thingheight/2) >= planeobjectz)
continue;
if (planecameraz > viewz && rover->pzt-(rover->thingheight/2) <= planeobjectz)
if (rover->gzt >= planeobjectz)
continue;
}
else
else if (planecameraz > viewz)
{
if (planecameraz < viewz && rover->pz >= planeobjectz)
continue;
if (planecameraz > viewz && rover->pzt <= planeobjectz)
if (rover->gz <= planeobjectz)
continue;
}
@ -2470,7 +2466,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
}
else if (r2->thickseg)
{
fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz;
//fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz;
if (rover->x1 > r2->thickseg->x2 || rover->x2 < r2->thickseg->x1)
continue;
@ -2481,6 +2477,11 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
if (scale <= rover->sortscale)
continue;
// bird: Always sort sprites behind segs. This helps the plane
// sorting above too. Basically if the sprite gets sorted behind
// the seg here, it will be behind the plane too, since planes
// are added after segs in the list.
#if 0
topplaneobjectz = P_GetFFloorTopZAt (r2->ffloor, rover->gx, rover->gy);
topplanecameraz = P_GetFFloorTopZAt (r2->ffloor, viewx, viewy);
botplaneobjectz = P_GetFFloorBottomZAt(r2->ffloor, rover->gx, rover->gy);
@ -2489,6 +2490,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
if ((topplanecameraz > viewz && botplanecameraz < viewz) ||
(topplanecameraz < viewz && rover->gzt < topplaneobjectz) ||
(botplanecameraz > viewz && rover->gz > botplaneobjectz))
#endif
{
entry = R_CreateDrawNode(NULL);
(entry->prev = r2->prev)->next = entry;

View file

@ -138,8 +138,7 @@ typedef struct vissprite_s
INT32 x1, x2;
fixed_t gx, gy; // for line side calculation
fixed_t gz, gzt; // global bottom/top for silhouette clipping
fixed_t pz, pzt; // physical bottom/top for sorting with 3D floors
fixed_t gz, gzt; // global bottom/top for silhouette clipping and sorting with 3D floors
fixed_t startfrac; // horizontal position of x1
fixed_t scale, sortscale; // sortscale only differs from scale for paper sprites and MF2_LINKDRAW
@ -171,7 +170,6 @@ typedef struct vissprite_s
fixed_t xscale;
// Precalculated top and bottom screen coords for the sprite.
fixed_t thingheight; // The actual height of the thing (for 3D floors)
sector_t *sector; // The sector containing the thing.
INT16 sz, szt;

View file

@ -2336,7 +2336,7 @@ static boolean S_PlayMusic(boolean looping, UINT32 fadeinms)
S_InitMusicVolume(); // switch between digi and sequence volume
if (S_MusicNotInFocus())
S_PauseAudio();
I_SetMusicVolume(0);
return true;
}
@ -2781,9 +2781,9 @@ static void PlayMusicIfUnfocused_OnChange(void)
if (window_notinfocus)
{
if (cv_playmusicifunfocused.value)
I_PauseSong();
I_SetMusicVolume(0);
else
I_ResumeSong();
S_InitMusicVolume();
}
}

View file

@ -651,7 +651,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
window_notinfocus = false;
if (!paused)
S_ResumeAudio(); //resume it
S_InitMusicVolume();
if (cv_gamesounds.value)
S_EnableSound();
@ -670,7 +670,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
// Tell game we lost focus, pause music
window_notinfocus = true;
if (!cv_playmusicifunfocused.value)
I_PauseSong();
I_SetMusicVolume(0);
if (!cv_playsoundifunfocused.value)
S_DisableSound();

View file

@ -740,14 +740,14 @@ sfxinfo_t S_sfx[NUMSFX] =
{"cdfm61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Speed boost"},
{"cdfm63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm64", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm64", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm65", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm66", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm67", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm68", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm69", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm70", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm71", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm71", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm72", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm73", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"cdfm74", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
@ -808,7 +808,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"kc4f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc50", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc51", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc52", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc52", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc53", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc54", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
{"kc55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},

View file

@ -673,10 +673,8 @@ void ST_preDrawTitleCard(void)
if (lt_ticker >= (lt_endtime + TICRATE))
return;
if (!lt_exitticker)
st_translucency = 0;
else
st_translucency = max(0, min((INT32)lt_exitticker-4, cv_translucenthud.value));
// Kart: nothing
st_translucency = cv_translucenthud.value;
}
//

235
src/stun.c Normal file
View file

@ -0,0 +1,235 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2020 by James R.
//
// 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 stun.c
/// \brief RFC 5389 client implementation to fetch external IP address.
/* https://tools.ietf.org/html/rfc5389 */
#if defined (__linux__)
#include <sys/random.h>
#elif defined (_WIN32)
#define _CRT_RAND_S
#elif defined (__APPLE__)
#include <CommonCrypto/CommonRandom.h>
#else
#error "Need CSPRNG."
#endif
#include "doomdef.h"
#include "d_clisrv.h"
#include "command.h"
#include "i_net.h"
#include "stun.h"
/* https://gist.github.com/zziuni/3741933 */
/* I can only trust google to keep their shit up :y */
consvar_t cv_stunserver = CVAR_INIT (
"stunserver", "stun.l.google.com:19302", CV_SAVE, NULL, NULL
);
static stun_callback_t stun_callback;
/* 18.4 STUN UDP and TCP Port Numbers */
#define STUN_PORT "3478"
/* 6. STUN Message Structure */
#define BIND_REQUEST 0x0001
#define BIND_RESPONSE 0x0101
static const UINT32 MAGIC_COOKIE = MSBF_LONG (0x2112A442);
static char transaction_id[12];
/* 18.2 STUN Attribute Registry */
#define XOR_MAPPED_ADDRESS 0x0020
/* 15.1 MAPPED-ADDRESS */
#define STUN_IPV4 0x01
static SINT8
STUN_node (void)
{
SINT8 node;
char * const colon = strchr(cv_stunserver.zstring, ':');
const char * const host = cv_stunserver.zstring;
const char * const port = &colon[1];
I_Assert(I_NetMakeNodewPort != NULL);
if (colon != NULL)
{
*colon = '\0';
node = I_NetMakeNodewPort(host, port);
*colon = ':';
}
else
{
node = I_NetMakeNodewPort(host, STUN_PORT);
}
return node;
}
static void
csprng
(
void * const buffer,
const size_t size
){
#if defined (_WIN32)
size_t o;
for (o = 0; o < size; o += sizeof (unsigned int))
{
rand_s((unsigned int *)&((char *)buffer)[o]);
}
#elif defined (__linux__)
getrandom(buffer, size, 0U);
#elif defined (__APPLE__)
CCRandomGenerateBytes(buffer, size);
#elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__)
arc4random_buf(buffer, size);
#endif
}
void
STUN_bind (stun_callback_t callback)
{
/* 6. STUN Message Structure */
const UINT16 type = MSBF_SHORT (BIND_REQUEST);
const SINT8 node = STUN_node();
doomcom->remotenode = node;
doomcom->datalength = 20;
csprng(transaction_id, 12U);
memcpy(&doomcom->data[0], &type, 2U);
memset(&doomcom->data[2], 0, 2U);
memcpy(&doomcom->data[4], &MAGIC_COOKIE, 4U);
memcpy(&doomcom->data[8], transaction_id, 12U);
stun_callback = callback;
I_NetSend();
Net_CloseConnection(node);/* will handle response at I_NetGet */
}
static size_t
STUN_xor_mapped_address (const char * const value)
{
const UINT32 xaddr = *(const UINT32 *)&value[4];
const UINT32 addr = xaddr ^ MAGIC_COOKIE;
(*stun_callback)(addr);
return 0U;
}
static size_t
align4 (size_t n)
{
return n + n % 4U;
}
static size_t
STUN_parse_attribute (const char * const attribute)
{
/* 15. STUN Attributes */
const UINT16 type = MSBF_SHORT (*(const UINT16 *)&attribute[0]);
const UINT16 length = MSBF_SHORT (*(const UINT16 *)&attribute[2]);
/* 15.2 XOR-MAPPED-ADDRESS */
if (
type == XOR_MAPPED_ADDRESS &&
length == 8U &&
(unsigned char)attribute[5] == STUN_IPV4
){
return STUN_xor_mapped_address(&attribute[4]);
}
return align4(4U + length);
}
boolean
STUN_got_response
(
const char * const buffer,
const size_t size
){
const char * const end = &buffer[size];
const char * p = &buffer[20];
UINT16 type;
UINT16 length;
/*
Check for STUN response.
Header is 20 bytes.
XOR-MAPPED-ADDRESS attribute is required.
Each attribute has a 2 byte header.
The XOR-MAPPED-ADDRESS attribute also has a 8 byte value.
This totals 10 bytes for the attribute.
*/
if (size < 30U || stun_callback == NULL)
{
return false;
}
/* 6. STUN Message Structure */
if (
*(const UINT32 *)&buffer[4] == MAGIC_COOKIE &&
memcmp(&buffer[8], transaction_id, 12U) == 0
){
type = MSBF_SHORT (*(const UINT16 *)&buffer[0]);
length = MSBF_SHORT (*(const UINT16 *)&buffer[2]);
if (
(type >> 14) == 0U &&
(length & 0x02) == 0U &&
(20U + length) <= size
){
if (type == BIND_RESPONSE)
{
do
{
length = STUN_parse_attribute(p);
if (length == 0U)
{
break;
}
p += length;
}
while (p < end) ;
}
stun_callback = NULL;
return true;
}
}
return false;
}

20
src/stun.h Normal file
View file

@ -0,0 +1,20 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2020 by James R.
//
// 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 stun.h
/// \brief RFC 5389 client implementation to fetch external IP address.
#ifndef KART_STUN_H
#define KART_STUN_H
typedef void (*stun_callback_t)(UINT32 address);
void STUN_bind (stun_callback_t);
boolean STUN_got_response (const char * const buffer, const size_t size);
#endif/*KART_STUN_H*/