Merge branch 'trick-panels-changes' into 'trick-panels'

Trick panels changes

See merge request KartKrew/Kart!343
This commit is contained in:
Sal 2021-01-06 17:17:10 -05:00
commit e2552d59d4
77 changed files with 3819 additions and 1908 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;
@ -616,7 +617,14 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->airtime = (tic_t)LONG(players[i].airtime);
rsp->trickpanel = (UINT8)players[i].trickpanel;
rsp->trickdelay = (tic_t)LONG(players[i].trickdelay);
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;
// respawnvars_t
rsp->respawn_state = players[i].respawn.state;
@ -692,6 +700,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;
@ -761,7 +770,14 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].airtime = (tic_t)LONG(rsp->airtime);
players[i].trickpanel = (UINT8)rsp->trickpanel;
players[i].trickdelay = (tic_t)LONG(rsp->trickdelay);
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;
// respawnvars_t
players[i].respawn.state = rsp->respawn_state;
@ -1250,7 +1266,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:
@ -1994,6 +2010,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];
@ -2116,7 +2135,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])
@ -2139,7 +2158,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])
@ -2350,7 +2369,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;
}
@ -2384,7 +2406,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
{
boolean waitmore;
INT32 i;
#ifdef NONET
(void)tmpsave;
#endif
@ -2421,7 +2443,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
{
curl_transfers++;
}
cl_mode = CL_DOWNLOADHTTPFILES;
}
break;
@ -2986,9 +3008,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
@ -3579,6 +3599,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);
@ -3654,6 +3744,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);
@ -5491,7 +5585,10 @@ static void CL_SendClientCmd(void)
boolean mis = false;
if (lowest_lag && ( gametic % lowest_lag ))
{
cl_packetmissed = true;
return;
}
netbuffer->packettype = PT_CLIENTCMD;
@ -6016,6 +6113,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)
{
@ -6054,6 +6164,11 @@ void NetKeepAlive(void)
MasterClient_Ticker();
#endif
if (netgame && serverrunning)
{
RenewHolePunch();
}
if (client)
{
// send keep alive
@ -6113,6 +6228,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;
@ -281,7 +282,14 @@ typedef struct
INT32 kartstuff[NUMKARTSTUFF];
tic_t airtime;
UINT8 trickpanel;
tic_t trickdelay;
boolean trickdelay;
fixed_t trickmomx;
fixed_t trickmomy;
fixed_t trickmomz;
UINT8 bumpers;
INT16 karmadelay;
boolean eliminated;
// respawnvars_t
UINT8 respawn_state;
@ -569,6 +577,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

@ -1494,6 +1494,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...
@ -453,8 +453,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 +461,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 +748,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);
}
@ -2854,13 +2857,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);
}
mapnumber = M_MapNumber(mapname[3], mapname[4]);
LUAh_MapChange(mapnumber);
@ -3470,8 +3466,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);
@ -4330,15 +4325,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

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

@ -449,6 +449,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 +516,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,9 +527,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
UINT8 trickpanel; // Trick panel state
tic_t trickdelay;
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.

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;
@ -6174,10 +6172,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",
@ -6236,13 +6267,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",
@ -8687,6 +8722,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",
@ -9287,9 +9360,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",
@ -9317,6 +9391,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
@ -9465,16 +9542,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",
@ -10169,6 +10240,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",
@ -10383,9 +10456,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",
@ -10397,6 +10469,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
@ -10717,67 +10794,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[] = {
@ -11169,13 +11246,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},
@ -11269,6 +11356,7 @@ struct {
{"DMG_EXPLODE",DMG_EXPLODE},
{"DMG_SQUISH",DMG_SQUISH},
{"DMG_STING",DMG_STING},
{"DMG_KARMA",DMG_KARMA},
//// Death types
{"DMG_INSTAKILL",DMG_INSTAKILL},
{"DMG_DEATHPIT",DMG_DEATHPIT},
@ -11480,11 +11568,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

@ -456,30 +456,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
};
@ -521,15 +522,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
@ -419,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;
@ -619,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)
@ -722,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)
@ -836,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)
@ -1067,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)
@ -1086,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);
@ -1096,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)
@ -1109,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)
@ -1205,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...
@ -1294,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)
{
@ -1314,6 +1316,7 @@ skippedghosttic:
Z_Free(g);
continue;
}
p = g;
#undef follow
}
@ -1436,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];
@ -1462,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
@ -1899,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;
@ -2033,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));
@ -2712,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.
@ -3101,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.
@ -3145,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.
@ -3211,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

@ -1252,7 +1252,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;
@ -1575,7 +1575,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;
}
@ -2056,6 +2056,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
UINT8 botdifficulty;
INT16 rings;
INT16 spheres;
angle_t playerangleturn;
UINT8 botdiffincrease;
@ -2071,9 +2072,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;
@ -2139,8 +2140,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
@ -2165,9 +2167,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];
}
@ -2215,6 +2218,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;
@ -2225,9 +2229,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;
@ -2787,9 +2791,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
@ -557,6 +558,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 +718,9 @@ char sprnames[NUMSPRITES + 1][5] =
"DRAF",
"GRES",
"OTFG",
"OTBU",
"OTLS",
"OTCP",
"DBOS", // Drift boost flame
@ -730,6 +737,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 +1809,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 +1904,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 +3758,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
@ -4362,9 +4405,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 +5076,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 +5108,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 +8008,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 +8047,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 +8058,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 +8250,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 +8263,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 +8290,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 +8358,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 +8489,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 +8516,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 +8543,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 +8570,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 +8597,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 +8624,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 +8651,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 +8678,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
},
@ -19073,7 +19002,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 +22837,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
},
@ -24200,7 +24129,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 +24143,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 +28385,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 +28403,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 +28412,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 +28429,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 +28631,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 +28901,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
@ -828,6 +829,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 +989,9 @@ typedef enum sprite
SPR_DRAF,
SPR_GRES,
SPR_OTFG,
SPR_OTBU,
SPR_OTLS,
SPR_OTCP,
SPR_DBOS, // Drift boost flame
@ -1002,6 +1009,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 +2026,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 +2119,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,
@ -4527,6 +4574,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 +5232,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 +5263,9 @@ typedef enum state
S_WATERTRAILUNDERLAY7,
S_WATERTRAILUNDERLAY8,
S_SPINDASHDUST,
S_SPINDASHWIND,
#ifdef SEENAMES
S_NAMECHECK,
#endif
@ -5345,16 +5434,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,
@ -6049,6 +6132,8 @@ typedef enum mobj_type
MT_SINKTRAIL,
MT_BATTLEBUMPER, // Battle Mode bumpers
MT_BATTLEBUMPER_DEBRIS,
MT_BATTLEBUMPER_BLAST,
MT_DEZLASER,
@ -6263,9 +6348,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 +6361,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

@ -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);
@ -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);
@ -184,11 +168,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 +198,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 +236,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 +266,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 +287,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 +308,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)
{
@ -347,14 +336,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);
}

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;
@ -174,6 +178,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 +353,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);
@ -729,11 +737,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)
@ -1513,7 +1522,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 +1603,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 +1617,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 +1662,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 +1796,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 +1811,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 +1979,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 +2023,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 +2058,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 +2067,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 +2160,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 +2197,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 +2215,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 +2630,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 +2964,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 +3400,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 +3432,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 +3623,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 +3649,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!
{
@ -3757,8 +3857,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 +3979,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 +4096,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 +4190,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_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

@ -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;
}
@ -3431,16 +3432,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;
}
@ -3917,7 +3919,7 @@ static luaL_Reg lib[] = {
{"K_SpinPlayer",lib_kSpinPlayer},
{"K_SquishPlayer",lib_kSquishPlayer},
{"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,6 +206,8 @@ 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"))
@ -219,6 +218,12 @@ static int player_get(lua_State *L)
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"))
@ -451,7 +456,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
@ -482,6 +487,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"))
@ -510,6 +517,12 @@ static int player_set(lua_State *L)
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

@ -6374,7 +6374,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);
@ -8139,11 +8139,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)
{
@ -8165,13 +8165,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);
@ -8186,10 +8186,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;
}
@ -8258,7 +8258,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
@ -4457,6 +4457,9 @@ void A_GrenadeRing(mobj_t *actor)
if (actor->flags2 & MF2_DEBRIS)
return;
if (actor->hitlag > 0)
return;
if (actor->state == &states[S_SSMINE_DEPLOY8])
explodedist = (3*explodedist)/2;
@ -4493,7 +4496,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
@ -4524,6 +4527,9 @@ void A_SSMineExplode(mobj_t *actor)
if (actor->flags2 & MF2_DEBRIS)
return;
if (actor->hitlag > 0)
return;
type = (mobjtype_t)locvar1;
// Use blockmap to check for nearby shootables
@ -8642,7 +8648,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 +8682,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 +8763,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 +8893,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 +8923,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);
@ -9708,7 +9714,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;
@ -474,7 +490,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 +569,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 +746,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 +763,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 +785,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 +1065,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 +1090,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,7 +1217,7 @@ 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->trickpanel = 0;
@ -1421,6 +1447,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 +1701,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 +1712,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 +1725,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 +1745,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 +1816,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 +1825,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.
@ -1830,7 +1898,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 +1913,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 +1948,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;
@ -1908,6 +2016,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
ringburst = 0;
break;
case DMG_EXPLODE:
case DMG_KARMA:
K_ExplodePlayer(player, inflictor, source);
break;
case DMG_WIPEOUT:
@ -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 ((type == DMG_EXPLODE || type == DMG_KARMA) || (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

@ -467,6 +467,7 @@ typedef struct BasicFF_s
#define DMG_EXPLODE 0x02
#define DMG_SQUISH 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 +518,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;
}
}
@ -449,7 +449,7 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
if (object->player)
{
object->player->trickpanel = 1;
object->player->trickdelay = TICRATE/2;
object->player->trickdelay = 1;
}
K_DoPogoSpring(object, 32<<FRACBITS, 0);
@ -1222,19 +1222,31 @@ static boolean PIT_CheckThing(mobj_t *thing)
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);
}
}
}
@ -1301,8 +1313,8 @@ static boolean PIT_CheckThing(mobj_t *thing)
}
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;
}
@ -1329,17 +1341,13 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (thing->player->trickpanel)
P_DamageMobj(tmthing, thing, thing, 1, DMG_WIPEOUT|DMG_STEAL);
}
if ((gametyperules & GTR_BUMPERS))
else if (thing->player->kartstuff[k_sneakertimer] && !(tmthing->player->kartstuff[k_sneakertimer]) && !(thing->player->powers[pw_flashing])) // Don't steal bumpers while intangible
{
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);
}
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_KartBouncing(mo1, mo2, zbounce, false);
@ -1621,6 +1629,23 @@ static boolean PIT_CheckCameraLine(line_t *ld)
return true;
}
static 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
@ -1696,14 +1721,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);
@ -2272,7 +2291,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;
@ -2477,6 +2496,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;
@ -2638,9 +2663,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);
@ -2653,9 +2676,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);
@ -3167,14 +3188,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);

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

@ -1130,7 +1130,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 +1157,19 @@ 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_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 +1216,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 +1640,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 +1718,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 +1730,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 +1748,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",
@ -2093,6 +2113,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 +2124,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 +2253,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);
}
@ -4881,8 +4904,6 @@ static boolean P_ParticleGenSceneryThink(mobj_t *mobj)
mobj->angle += mobj->movedir;
}
mobj->angle += (angle_t)mobj->movecount;
}
return true;
@ -5277,7 +5298,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 +5416,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 +5442,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 +5512,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 +5769,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:
{
@ -6139,7 +6288,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 +6343,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 +6393,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))
@ -6395,6 +6547,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 +6587,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 +6609,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 +6625,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 +6673,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 +6855,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 +6868,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 +7162,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 +7199,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 +7220,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 +8039,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 +8531,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:
@ -8416,6 +8594,13 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->hprev && P_MobjWasRemoved(mobj->hprev))
P_SetTarget(&mobj->hprev, NULL);
// 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 +8618,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
{
@ -8577,7 +8762,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
@ -8909,6 +9094,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 +9204,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 +9387,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 +9744,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 +10143,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 +10156,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 +10191,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 +10243,7 @@ void P_SpawnPlayer(INT32 playernum)
/*
if (bonusgame || specialstage)
{
// Bots should avoid
// Bots should avoid
p->spectator = true;
}
*/
@ -10145,30 +10340,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 +10382,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 +10603,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 +10710,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 +11801,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 +11834,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);
@ -256,7 +257,14 @@ static void P_NetArchivePlayers(void)
WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].nextwaypoint));
WRITEUINT32(save_p, players[i].airtime);
WRITEUINT8(save_p, players[i].trickpanel);
WRITEUINT32(save_p, players[i].trickdelay);
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);
// respawnvars_t
WRITEUINT8(save_p, players[i].respawn.state);
@ -306,6 +314,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);
@ -420,7 +429,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);
@ -443,7 +452,14 @@ static void P_NetUnArchivePlayers(void)
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 = READUINT32(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);
// respawnvars_t
players[i].respawn.state = READUINT8(save_p);
@ -1373,9 +1389,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
@ -1590,6 +1607,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)
@ -1754,6 +1773,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);
}
@ -2799,12 +2820,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)
@ -2818,6 +2834,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)
{
@ -4121,7 +4139,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);
@ -4255,7 +4272,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

@ -3924,40 +3924,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

@ -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;
}
}
}
@ -4617,7 +4618,7 @@ DoneSection2:
}
player->trickpanel = 1;
player->trickdelay = TICRATE/2;
player->trickdelay = 1;
K_DoPogoSpring(player->mo, upwards, 1);
// Reduce speed
@ -4667,7 +4668,7 @@ DoneSection2:
}
lineangle = K_ReflectAngle(
R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy), lineangle,
K_MomentumAngle(player->mo), lineangle,
playerspeed, linespeed
);

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->kartstuff[k_squishedtimer])
return true;
if (gametyperules & GTR_KARMA)
{
if (player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer])
return true;
}
return false;
}
@ -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;
@ -1940,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)
@ -2274,7 +2263,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);
@ -2647,7 +2636,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
}
}
@ -4074,7 +4063,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
@ -4220,6 +4209,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
@ -4306,6 +4300,7 @@ void P_PlayerThink(player_t *player)
if (player->playerstate == PST_DEAD)
{
LUAh_PlayerThink(player);
return;
}
}
@ -4382,7 +4377,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
}
}
@ -4535,7 +4530,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

@ -1230,32 +1230,6 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope)
return groundz;
}
static void R_SetSpritePlaneHeights(vissprite_t *vis)
{
ffloor_t *rover;
fixed_t top;
fixed_t bot;
vis->pt = vis->sector->floorheight;
vis->pb = vis->sector->ceilingheight;
for (rover = vis->sector->ffloors; rover; rover = rover->next)
{
if (rover->flags & FF_EXISTS)
{
top = P_GetFFloorTopZAt (rover, vis->gx, vis->gy);
bot = P_GetFFloorBottomZAt (rover, vis->gx, vis->gy);
if (top <= vis->gzt && top > vis->pt)
vis->pt = top;
if (bot >= vis->gz && bot < vis->pb)
vis->pb = bot;
}
}
}
static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, fixed_t tx, fixed_t tz)
{
vissprite_t *shadow;
@ -1344,8 +1318,6 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
shadow->xscale = FixedMul(xscale, shadowxscale); //SoM: 4/17/2000
shadow->scale = FixedMul(yscale, shadowyscale);
shadow->sector = vis->sector;
shadow->pt = vis->pt;
shadow->pb = vis->pb;
shadow->szt = (INT16)((centeryfrac - FixedMul(shadow->gzt - viewz, yscale))>>FRACBITS);
shadow->sz = (INT16)((centeryfrac - FixedMul(shadow->gz - viewz, yscale))>>FRACBITS);
shadow->cut = SC_ISSCALED|SC_SHADOW; //check this
@ -1403,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;
@ -1462,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;
@ -1587,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];
@ -1845,9 +1835,6 @@ static void R_ProjectSprite(mobj_t *thing)
vis->sector = thing->subsector->sector;
vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS);
vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS);
R_SetSpritePlaneHeights(vis);
vis->cut = cut;
if (thing->subsector->sector->numlights)
vis->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap;
@ -2062,8 +2049,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, yscale))>>FRACBITS);
vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, yscale))>>FRACBITS);
R_SetSpritePlaneHeights(vis);
iscale = FixedDiv(FRACUNIT, xscale);
vis->startfrac = 0;
@ -2443,12 +2428,12 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps
// bird: if any part of the sprite peeks in front the plane
if (planecameraz < viewz)
{
if (rover->pt >= planeobjectz && rover->gzt >= planeobjectz)
if (rover->gzt >= planeobjectz)
continue;
}
else if (planecameraz > viewz)
{
if (rover->pb <= planeobjectz && rover->gz <= planeobjectz)
if (rover->gz <= planeobjectz)
continue;
}
@ -2481,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;
@ -2492,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);
@ -2500,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

@ -171,7 +171,6 @@ typedef struct vissprite_s
// Precalculated top and bottom screen coords for the sprite.
sector_t *sector; // The sector containing the thing.
fixed_t pt, pb; // plane heights, also for sorting against 3D floors
INT16 sz, szt;
spritecut_e cut;

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;
}
@ -2780,9 +2780,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*/