diff --git a/src/Makefile b/src/Makefile index 5b47b4871..a6f18a72a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -487,6 +487,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/f_wipe.o \ $(OBJDIR)/g_game.o \ $(OBJDIR)/g_input.o \ + $(OBJDIR)/g_splitscreen.o\ $(OBJDIR)/am_map.o \ $(OBJDIR)/command.o \ $(OBJDIR)/console.o \ diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 087fa663d..084a6fd81 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -85,6 +85,8 @@ static boolean serverrunning = false; INT32 serverplayer = 0; char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support) +UINT8 playerconsole[MAXPLAYERS]; + // Server specific vars UINT8 playernode[MAXPLAYERS]; @@ -1508,6 +1510,8 @@ static boolean SV_SendServerConfig(INT32 node) UINT8 *p, *op; boolean waspacketsent; + memset(&netbuffer->u.servercfg, 0, sizeof netbuffer->u.servercfg); + netbuffer->packettype = PT_SERVERCFG; netbuffer->u.servercfg.version = VERSION; @@ -1527,7 +1531,6 @@ static boolean SV_SendServerConfig(INT32 node) memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor)); memset(netbuffer->u.servercfg.adminplayers, -1, sizeof(netbuffer->u.servercfg.adminplayers)); - memset(netbuffer->u.servercfg.powerlevels, 0, sizeof(netbuffer->u.servercfg.powerlevels)); for (i = 0; i < MAXPLAYERS; i++) { @@ -1538,6 +1541,19 @@ static boolean SV_SendServerConfig(INT32 node) if (!playeringame[i]) continue; + netbuffer->u.servercfg.consoleplayers[i] = playerconsole[i]; + netbuffer->u.servercfg.invitations[i] = splitscreen_invitations[i]; + netbuffer->u.servercfg.party_size[i] = splitscreen_party_size[i]; + netbuffer->u.servercfg.original_party_size[i] = + splitscreen_original_party_size[i]; + + for (j = 0; j < MAXSPLITSCREENPLAYERS; ++j) + { + netbuffer->u.servercfg.party[i][j] = splitscreen_party[i][j]; + netbuffer->u.servercfg.original_party[i][j] = + splitscreen_original_party[i][j]; + } + netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin; netbuffer->u.servercfg.playercolor[i] = (UINT8)players[i].skincolor; } @@ -2622,6 +2638,8 @@ static void ResetNode(INT32 node); // void CL_ClearPlayer(INT32 playernum) { + int i; + if (players[playernum].mo) { // Don't leave a NiGHTS ghost! @@ -2629,6 +2647,17 @@ void CL_ClearPlayer(INT32 playernum) P_RemoveMobj(players[playernum].mo->tracer); P_RemoveMobj(players[playernum].mo); } + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (splitscreen_invitations[i] == playernum) + splitscreen_invitations[i] = -1; + } + + splitscreen_invitations[playernum] = -1; + splitscreen_party_size[playernum] = 0; + splitscreen_original_party_size[playernum] = 0; + memset(&players[playernum], 0, sizeof (player_t)); } @@ -2704,6 +2733,8 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) (void)reason; #endif + G_RemovePartyMember(playernum); + // Reset player data CL_ClearPlayer(playernum); @@ -2721,8 +2752,8 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) RemoveAdminPlayer(playernum); // don't stay admin after you're gone } - if (playernum == displayplayers[0] && !demo.playback) - displayplayers[0] = consoleplayer; // don't look through someone's view who isn't there + if (playernum == g_localplayers[0] && !demo.playback) + g_localplayers[0] = consoleplayer; // don't look through someone's view who isn't there #ifdef HAVE_BLUA LUA_InvalidatePlayer(&players[playernum]); @@ -3354,8 +3385,11 @@ void SV_ResetServer(void) sprintf(player_names[i], "Player %d", i + 1); adminplayers[i] = -1; // Populate the entire adminplayers array with -1. K_ClearClientPowerLevels(); + splitscreen_invitations[i] = -1; } + memset(splitscreen_partied, 0, sizeof splitscreen_partied); + mynode = 0; cl_packetmissed = false; @@ -3458,6 +3492,7 @@ static inline void SV_AddNode(INT32 node) static void Got_AddPlayer(UINT8 **p, INT32 playernum) { INT16 node, newplayernum; + UINT8 console; UINT8 splitscreenplayer = 0; UINT8 i; @@ -3478,6 +3513,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) node = (UINT8)READUINT8(*p); newplayernum = (UINT8)READUINT8(*p); + console = (UINT8)READUINT8(*p); splitscreenplayer = (UINT8)READUINT8(*p); CONS_Debug(DBG_NETPLAY, "addplayer: %d %d %d\n", node, newplayernum, splitscreenplayer); @@ -3498,6 +3534,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) if (splitscreenplayer) { displayplayers[splitscreenplayer] = newplayernum; + g_localplayers[splitscreenplayer] = newplayernum; DEBFILE(va("spawning sister # %d\n", splitscreenplayer)); if (splitscreenplayer == 1 && botingame) players[newplayernum].bot = 1; @@ -3506,7 +3543,11 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) { consoleplayer = newplayernum; for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) + { displayplayers[i] = newplayernum; + g_localplayers[i] = newplayernum; + } + splitscreen_partied[newplayernum] = true; DEBFILE("spawning me\n"); } @@ -3516,6 +3557,12 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) players[newplayernum].splitscreenindex = splitscreenplayer; + playerconsole[newplayernum] = console; + splitscreen_original_party_size[console] = + ++splitscreen_party_size[console]; + splitscreen_original_party[console][splitscreenplayer] = + splitscreen_party[console][splitscreenplayer] = newplayernum; + if (netgame) { if (server && cv_showjoinaddress.value) @@ -3577,7 +3624,7 @@ static boolean SV_AddWaitingPlayers(void) // splitscreen can allow 2+ players in one node for (; nodewaiting[node] > 0; nodewaiting[node]--) { - UINT8 buf[3]; + UINT8 buf[4]; UINT8 *buf_p = buf; newplayer = true; @@ -3614,6 +3661,7 @@ static boolean SV_AddWaitingPlayers(void) else if (playerpernode[node] < 4) nodetoplayer4[node] = newplayernum; + WRITEUINT8(buf_p, nodetoplayer[node]); // consoleplayer WRITEUINT8(buf_p, playerpernode[node]); // splitscreen num playerpernode[node]++; @@ -4144,6 +4192,21 @@ static void HandlePacketFromAwayNode(SINT8 node) adminplayers[j] = netbuffer->u.servercfg.adminplayers[j]; for (k = 0; k < PWRLV_NUMTYPES; k++) clientpowerlevels[j][k] = netbuffer->u.servercfg.powerlevels[j][k]; + + /* all spitscreen related */ + playerconsole[j] = netbuffer->u.servercfg.consoleplayers[j]; + splitscreen_invitations[j] = netbuffer->u.servercfg.invitations[j]; + splitscreen_original_party_size[j] = + netbuffer->u.servercfg.original_party_size[j]; + splitscreen_party_size[j] = + netbuffer->u.servercfg.party_size[j]; + for (k = 0; k < MAXSPLITSCREENPLAYERS; ++k) + { + splitscreen_original_party[j][k] = + netbuffer->u.servercfg.original_party[j][k]; + splitscreen_party[j][k] = + netbuffer->u.servercfg.party[j][k]; + } } memcpy(server_context, netbuffer->u.servercfg.server_context, 8); } @@ -5455,7 +5518,7 @@ static void UpdatePingTable(void) { if (playeringame[i] && playernode[i] > 0) { - if (! server_lagless && playernode[i] > 0) + if (! server_lagless && playernode[i] > 0 && !players[i].spectator) { lag = GetLag(playernode[i]); realpingtable[i] += G_TicsToMilliseconds(lag); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index a33d06a2c..49945de7c 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -328,6 +328,14 @@ typedef struct SINT8 adminplayers[MAXPLAYERS]; // Needs to be signed UINT16 powerlevels[MAXPLAYERS][PWRLV_NUMTYPES]; // SRB2kart: player power levels + UINT8 consoleplayers[MAXPLAYERS]; + /* splitscreen */ + SINT8 invitations[MAXPLAYERS]; + UINT8 party_size[MAXPLAYERS]; + UINT8 party[MAXPLAYERS][MAXSPLITSCREENPLAYERS]; + UINT8 original_party_size[MAXPLAYERS]; + UINT8 original_party[MAXPLAYERS][MAXSPLITSCREENPLAYERS]; + char server_context[8]; // Unique context id, generated at server startup. UINT8 varlengthinputs[0]; // Playernames and netvars @@ -601,6 +609,8 @@ SINT8 nametonum(const char *name); extern char motd[254], server_context[8]; extern UINT8 playernode[MAXPLAYERS]; +/* consoleplayer of this player (splitscreen) */ +extern UINT8 playerconsole[MAXPLAYERS]; INT32 D_NumPlayers(void); void D_ResetTiccmds(void); diff --git a/src/d_main.c b/src/d_main.c index 88c501345..aed861e7d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -152,6 +152,7 @@ char srb2path[256] = "."; #endif boolean usehome = true; const char *pandf = "%s" PATHSEP "%s"; +static char addonsdir[MAX_WADPATH]; // // EVENT HANDLING @@ -416,7 +417,7 @@ static void D_Display(void) // draw the view directly if (cv_renderview.value && !automapactive) { - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (players[displayplayers[i]].mo || players[displayplayers[i]].playerstate == PST_DEAD) { @@ -443,7 +444,7 @@ static void D_Display(void) switch (i) { case 1: - if (splitscreen > 1) + if (r_splitscreen > 1) { viewwindowx = viewwidth; viewwindowy = 0; @@ -482,7 +483,7 @@ static void D_Display(void) if (rendermode == render_soft) { - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (postimgtype[i]) V_DoPostProcessor(i, postimgtype[i], postimgparam[i]); @@ -780,6 +781,7 @@ void D_StartTitle(void) gameaction = ga_nothing; memset(displayplayers, 0, sizeof(displayplayers)); + memset(g_localplayers, 0, sizeof g_localplayers); consoleplayer = 0; //demosequence = -1; gametype = GT_RACE; // SRB2kart @@ -1090,7 +1092,6 @@ void D_SRB2Main(void) // can't use sprintf since there is %u in savegamename strcatbf(savegamename, srb2home, PATHSEP); - I_mkdir(srb2home, 0700); #else snprintf(srb2home, sizeof srb2home, "%s", userhome); snprintf(downloaddir, sizeof downloaddir, "%s", userhome); @@ -1111,6 +1112,10 @@ void D_SRB2Main(void) #endif } + // Create addons dir + snprintf(addonsdir, sizeof addonsdir, "%s%s%s", srb2home, PATHSEP, "addons"); + I_mkdir(addonsdir, 0755); + // rand() needs seeded regardless of password srand((unsigned int)time(NULL)); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 21bdd033e..bd7f16228 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -64,6 +64,10 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum); static void Got_WeaponPref(UINT8 **cp, INT32 playernum); static void Got_PowerLevel(UINT8 **cp, INT32 playernum); +static void Got_PartyInvite(UINT8 **cp, INT32 playernum); +static void Got_AcceptPartyInvite(UINT8 **cp, INT32 playernum); +static void Got_CancelPartyInvite(UINT8 **cp, INT32 playernum); +static void Got_LeaveParty(UINT8 **cp, INT32 playernum); static void Got_Mapcmd(UINT8 **cp, INT32 playernum); static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum); static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum); @@ -137,6 +141,12 @@ static void Command_ResetCamera_f(void); static void Command_View_f (void); static void Command_SetViews_f(void); +static void Command_Invite_f(void); +static void Command_CancelInvite_f(void); +static void Command_AcceptInvite_f(void); +static void Command_RejectInvite_f(void); +static void Command_LeaveParty_f(void); + static void Command_Addfile(void); static void Command_ListWADS_f(void); #ifdef DELFILE @@ -347,6 +357,8 @@ consvar_t cv_selfpropelledbomb = {"selfpropelledbomb", "On", CV_NETVAR|CV_CHEAT consvar_t cv_grow = {"grow", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_shrink = {"shrink", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_thundershield = {"thundershield", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_bubbleshield = {"bubbleshield", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_flameshield = {"flameshield", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_hyudoro = {"hyudoro", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_pogospring = {"pogospring", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_kitchensink = {"kitchensink", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -553,6 +565,10 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_NAMEANDCOLOR, Got_NameAndColor); RegisterNetXCmd(XD_WEAPONPREF, Got_WeaponPref); RegisterNetXCmd(XD_POWERLEVEL, Got_PowerLevel); + RegisterNetXCmd(XD_PARTYINVITE, Got_PartyInvite); + RegisterNetXCmd(XD_ACCEPTPARTYINVITE, Got_AcceptPartyInvite); + RegisterNetXCmd(XD_CANCELPARTYINVITE, Got_CancelPartyInvite); + RegisterNetXCmd(XD_LEAVEPARTY, Got_LeaveParty); RegisterNetXCmd(XD_MAP, Got_Mapcmd); RegisterNetXCmd(XD_EXITLEVEL, Got_ExitLevelcmd); RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd); @@ -764,6 +780,12 @@ void D_RegisterClientCommands(void) COM_AddCommand("changeteam3", Command_Teamchange3_f); COM_AddCommand("changeteam4", Command_Teamchange4_f); + COM_AddCommand("invite", Command_Invite_f); + COM_AddCommand("cancelinvite", Command_CancelInvite_f); + COM_AddCommand("acceptinvite", Command_AcceptInvite_f); + COM_AddCommand("rejectinvite", Command_RejectInvite_f); + COM_AddCommand("leaveparty", Command_LeaveParty_f); + COM_AddCommand("playdemo", Command_Playdemo_f); COM_AddCommand("timedemo", Command_Timedemo_f); COM_AddCommand("stopdemo", Command_Stopdemo_f); @@ -791,6 +813,8 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_screenshot_folder); CV_RegisterVar(&cv_screenshot_colorprofile); CV_RegisterVar(&cv_moviemode); + CV_RegisterVar(&cv_movie_option); + CV_RegisterVar(&cv_movie_folder); // PNG variables CV_RegisterVar(&cv_zlib_level); CV_RegisterVar(&cv_zlib_memory); @@ -1215,11 +1239,11 @@ static void CleanupPlayerName(INT32 playernum, const char *newname) // spaces may have been removed if (playernum == consoleplayer) CV_StealthSet(&cv_playername, tmpname); - else if (playernum == displayplayers[1] || (!netgame && playernum == 1)) + else if (playernum == g_localplayers[1] || (!netgame && playernum == 1)) CV_StealthSet(&cv_playername2, tmpname); - else if (playernum == displayplayers[2] || (!netgame && playernum == 2)) + else if (playernum == g_localplayers[2] || (!netgame && playernum == 2)) CV_StealthSet(&cv_playername3, tmpname); - else if (playernum == displayplayers[3] || (!netgame && playernum == 3)) + else if (playernum == g_localplayers[3] || (!netgame && playernum == 3)) CV_StealthSet(&cv_playername4, tmpname); else I_Assert(((void)"CleanupPlayerName used on non-local player", 0)); @@ -1327,16 +1351,50 @@ static void ForceAllSkins(INT32 forcedskin) { if (i == consoleplayer) CV_StealthSet(&cv_skin, skins[forcedskin].name); - else if (i == displayplayers[1]) + else if (i == g_localplayers[1]) CV_StealthSet(&cv_skin2, skins[forcedskin].name); - else if (i == displayplayers[2]) + else if (i == g_localplayers[2]) CV_StealthSet(&cv_skin3, skins[forcedskin].name); - else if (i == displayplayers[3]) + else if (i == g_localplayers[3]) CV_StealthSet(&cv_skin4, skins[forcedskin].name); } } } +static const char * +VaguePartyDescription (int playernum, int *party_sizes, int default_color) +{ + static char party_description + [1 + MAXPLAYERNAME + 1 + sizeof " and x others"]; + const char *name; + int size; + name = player_names[playernum]; + size = party_sizes[playernum]; + /* + less than check for the dumb compiler because I KNOW it'll + complain about "writing x bytes into an area of y bytes"!!! + */ + if (size > 1 && size <= MAXSPLITSCREENPLAYERS) + { + sprintf(party_description, + "\x83%s%c and %d other%s", + name, + default_color, + ( size - 1 ), + ( (size > 2) ? "s" : "" ) + ); + } + else + { + sprintf(party_description, + "\x83%s%c", + name, + default_color + ); + } + return party_description; +} + static INT32 snacpending = 0, snac2pending = 0, snac3pending = 0, snac4pending = 0, chmappending = 0; // name, color, or skin has changed @@ -1466,8 +1524,8 @@ static void SendNameAndColor2(void) if (splitscreen < 1 && !botingame) return; // can happen if skin2/color2/name2 changed - if (displayplayers[1] != consoleplayer) - secondplaya = displayplayers[1]; + if (g_localplayers[1] != consoleplayer) + secondplaya = g_localplayers[1]; else if (!netgame) // HACK secondplaya = 1; @@ -1555,14 +1613,14 @@ static void SendNameAndColor2(void) snac2pending++; // Don't change name if muted - if (cv_mute.value && !(server || IsPlayerAdmin(displayplayers[1]))) - CV_StealthSet(&cv_playername2, player_names[displayplayers[1]]); + if (cv_mute.value && !(server || IsPlayerAdmin(g_localplayers[1]))) + CV_StealthSet(&cv_playername2, player_names[g_localplayers[1]]); else // Cleanup name if changing it - CleanupPlayerName(displayplayers[1], cv_playername2.zstring); + CleanupPlayerName(g_localplayers[1], cv_playername2.zstring); // Don't change skin if the server doesn't want you to. - if (!CanChangeSkin(displayplayers[1])) - CV_StealthSet(&cv_skin2, skins[players[displayplayers[1]].skin].name); + if (!CanChangeSkin(g_localplayers[1])) + CV_StealthSet(&cv_skin2, skins[players[g_localplayers[1]].skin].name); // check if player has the skin loaded (cv_skin2 may have // the name of a skin that was available in the previous game) @@ -1589,8 +1647,8 @@ static void SendNameAndColor3(void) if (splitscreen < 2) return; // can happen if skin3/color3/name3 changed - if (displayplayers[2] != consoleplayer) - thirdplaya = displayplayers[2]; + if (g_localplayers[2] != consoleplayer) + thirdplaya = g_localplayers[2]; else if (!netgame) // HACK thirdplaya = 2; @@ -1670,14 +1728,14 @@ static void SendNameAndColor3(void) snac3pending++; // Don't change name if muted - if (cv_mute.value && !(server || IsPlayerAdmin(displayplayers[2]))) - CV_StealthSet(&cv_playername3, player_names[displayplayers[2]]); + if (cv_mute.value && !(server || IsPlayerAdmin(g_localplayers[2]))) + CV_StealthSet(&cv_playername3, player_names[g_localplayers[2]]); else // Cleanup name if changing it - CleanupPlayerName(displayplayers[2], cv_playername3.zstring); + CleanupPlayerName(g_localplayers[2], cv_playername3.zstring); // Don't change skin if the server doesn't want you to. - if (!CanChangeSkin(displayplayers[2])) - CV_StealthSet(&cv_skin3, skins[players[displayplayers[2]].skin].name); + if (!CanChangeSkin(g_localplayers[2])) + CV_StealthSet(&cv_skin3, skins[players[g_localplayers[2]].skin].name); // check if player has the skin loaded (cv_skin3 may have // the name of a skin that was available in the previous game) @@ -1704,8 +1762,8 @@ static void SendNameAndColor4(void) if (splitscreen < 3) return; // can happen if skin4/color4/name4 changed - if (displayplayers[3] != consoleplayer) - fourthplaya = displayplayers[3]; + if (g_localplayers[3] != consoleplayer) + fourthplaya = g_localplayers[3]; else if (!netgame) // HACK fourthplaya = 3; @@ -1793,14 +1851,14 @@ static void SendNameAndColor4(void) snac4pending++; // Don't change name if muted - if (cv_mute.value && !(server || IsPlayerAdmin(displayplayers[3]))) - CV_StealthSet(&cv_playername4, player_names[displayplayers[3]]); + if (cv_mute.value && !(server || IsPlayerAdmin(g_localplayers[3]))) + CV_StealthSet(&cv_playername4, player_names[g_localplayers[3]]); else // Cleanup name if changing it - CleanupPlayerName(displayplayers[3], cv_playername4.zstring); + CleanupPlayerName(g_localplayers[3], cv_playername4.zstring); // Don't change skin if the server doesn't want you to. - if (!CanChangeSkin(displayplayers[3])) - CV_StealthSet(&cv_skin4, skins[players[displayplayers[3]].skin].name); + if (!CanChangeSkin(g_localplayers[3])) + CV_StealthSet(&cv_skin4, skins[players[g_localplayers[3]].skin].name); // check if player has the skin loaded (cv_skin4 may have // the name of a skin that was available in the previous game) @@ -1831,11 +1889,11 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) if (playernum == consoleplayer) snacpending--; // TODO: make snacpending an array instead of 4 separate vars? - else if (playernum == displayplayers[1]) + else if (playernum == g_localplayers[1]) snac2pending--; - else if (playernum == displayplayers[2]) + else if (playernum == g_localplayers[2]) snac3pending--; - else if (playernum == displayplayers[3]) + else if (playernum == g_localplayers[3]) snac4pending--; #ifdef PARANOIA @@ -1858,8 +1916,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) demo_extradata[playernum] |= DXD_COLOR; // normal player colors - if (server && (p != &players[consoleplayer] && p != &players[displayplayers[1]] - && p != &players[displayplayers[2]] && p != &players[displayplayers[3]])) + if (server && (p != &players[consoleplayer] && p != &players[g_localplayers[1]] + && p != &players[g_localplayers[2]] && p != &players[g_localplayers[3]])) { boolean kick = false; @@ -1896,11 +1954,11 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) if (playernum == consoleplayer) CV_StealthSet(&cv_skin, skins[forcedskin].name); - else if (playernum == displayplayers[1]) + else if (playernum == g_localplayers[1]) CV_StealthSet(&cv_skin2, skins[forcedskin].name); - else if (playernum == displayplayers[2]) + else if (playernum == g_localplayers[2]) CV_StealthSet(&cv_skin3, skins[forcedskin].name); - else if (playernum == displayplayers[3]) + else if (playernum == g_localplayers[3]) CV_StealthSet(&cv_skin4, skins[forcedskin].name); } else @@ -1967,6 +2025,193 @@ static void Got_PowerLevel(UINT8 **cp,INT32 playernum) CONS_Debug(DBG_GAMELOGIC, "set player %d to power %d\n", playernum, race); } +static void Got_PartyInvite(UINT8 **cp,INT32 playernum) +{ + UINT8 invitee; + + boolean kick = false; + + invitee = READUINT8 (*cp); + + if ( + invitee < MAXPLAYERS && + playeringame[invitee] && + playerconsole[playernum] == playernum/* only consoleplayer may! */ + ){ + invitee = playerconsole[invitee]; + /* you cannot invite yourself or your computer */ + if (invitee == playernum) + kick = true; + } + else + kick = true; + + if (kick) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal splitscreen invitation received from %s\n"), player_names[playernum]); + if (server) + { + XBOXSTATIC UINT8 buf[2]; + + buf[0] = (UINT8)playernum; + buf[1] = KICK_MSG_CON_FAIL; + SendNetXCmd(XD_KICK, &buf, 2); + } + return; + } + + if (splitscreen_invitations[invitee] < 0) + { + splitscreen_invitations[invitee] = playernum; + + if (invitee == consoleplayer)/* hey that's me! */ + { + HU_AddChatText(va( + "\x82*You have been invited to join %s.", + VaguePartyDescription( + playernum, splitscreen_party_size, '\x82') + ), true); + } + } +} + +static void Got_AcceptPartyInvite(UINT8 **cp,INT32 playernum) +{ + int invitation; + int old_party_size; + int views; + + (void)cp; + + if (playerconsole[playernum] != playernum) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal accept splitscreen invite received from %s\n"), player_names[playernum]); + if (server) + { + XBOXSTATIC UINT8 buf[2]; + + buf[0] = (UINT8)playernum; + buf[1] = KICK_MSG_CON_FAIL; + SendNetXCmd(XD_KICK, &buf, 2); + } + return; + } + + invitation = splitscreen_invitations[playernum]; + + if (invitation >= 0) + { + if (splitscreen_partied[invitation]) + { + HU_AddChatText(va( + "\x82*%s joined your party!", + VaguePartyDescription( + playernum, splitscreen_original_party_size, '\x82') + ), true); + } + else if (playernum == consoleplayer) + { + HU_AddChatText(va( + "\x82*You joined %s's party!", + VaguePartyDescription( + invitation, splitscreen_party_size, '\x82') + ), true); + } + + old_party_size = splitscreen_party_size[invitation]; + views = splitscreen_original_party_size[playernum]; + + if (( old_party_size + views ) <= MAXSPLITSCREENPLAYERS) + { + G_RemovePartyMember(playernum); + G_AddPartyMember(invitation, playernum); + } + + splitscreen_invitations[playernum] = -1; + } +} + +static void Got_CancelPartyInvite(UINT8 **cp,INT32 playernum) +{ + UINT8 invitee; + + invitee = READUINT8 (*cp); + + if ( + invitee < MAXPLAYERS && + playeringame[invitee] + ){ + invitee = playerconsole[invitee]; + + if (splitscreen_invitations[invitee] == playerconsole[playernum]) + { + splitscreen_invitations[invitee] = -1; + + if (consoleplayer == invitee) + { + HU_AddChatText("\x85*Your invitation has been rescinded.", true); + } + } + } + else + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal cancel splitscreen invite received from %s\n"), player_names[playernum]); + if (server) + { + XBOXSTATIC UINT8 buf[2]; + + buf[0] = (UINT8)playernum; + buf[1] = KICK_MSG_CON_FAIL; + SendNetXCmd(XD_KICK, &buf, 2); + } + } +} + +static void Got_LeaveParty(UINT8 **cp,INT32 playernum) +{ + (void)cp; + + if (playerconsole[playernum] != playernum) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal accept splitscreen invite received from %s\n"), player_names[playernum]); + if (server) + { + XBOXSTATIC UINT8 buf[2]; + + buf[0] = (UINT8)playernum; + buf[1] = KICK_MSG_CON_FAIL; + SendNetXCmd(XD_KICK, &buf, 2); + } + return; + } + + if (consoleplayer == splitscreen_invitations[playernum]) + { + HU_AddChatText(va( + "\x85*\x83%s\x85 rejected your invitation.", + player_names[playernum] + ), true); + } + + splitscreen_invitations[playernum] = -1; + + if (splitscreen_party_size[playernum] > + splitscreen_original_party_size[playernum]) + { + if (splitscreen_partied[playernum] && playernum != consoleplayer) + { + HU_AddChatText(va( + "\x85*%s left your party.", + VaguePartyDescription( + playernum, splitscreen_original_party_size, '\x85') + ), true); + } + + G_RemovePartyMember(playernum); + G_ResetSplitscreen(playernum); + } +} + void D_SendPlayerConfig(void) { SendNameAndColor(); @@ -2013,7 +2258,7 @@ void D_SendPlayerConfig(void) // Only works for displayplayer, sorry! static void Command_ResetCamera_f(void) { - P_ResetCamera(&players[displayplayers[0]], &camera[0]); + P_ResetCamera(&players[g_localplayers[0]], &camera[0]); } /* Consider replacing nametonum with this */ @@ -2169,7 +2414,7 @@ static void Command_View_f(void) } else/* print current view */ { - if (splitscreen < viewnum-1)/* We can't see those guys! */ + if (r_splitscreen < viewnum-1)/* We can't see those guys! */ return; PRINTVIEWPOINT ("Currently ",) } @@ -2194,7 +2439,7 @@ static void Command_SetViews_f(void) return; } - splits = splitscreen+1; + splits = r_splitscreen+1; newsplits = atoi(COM_Argv(1)); newsplits = min(max(newsplits, 1), 4); @@ -2202,11 +2447,157 @@ static void Command_SetViews_f(void) G_AdjustView(newsplits, 0, true); else { - splitscreen = newsplits-1; + r_splitscreen = newsplits-1; R_ExecuteSetViewSize(); } } +static void +Command_Invite_f (void) +{ + UINT8 buffer[1]; + + int invitee; + + if (COM_Argc() != 2) + { + CONS_Printf("invite : Invite a player to your party.\n"); + return; + } + + if (r_splitscreen >= MAXSPLITSCREENPLAYERS) + { + CONS_Alert(CONS_WARNING, "Your party is full!\n"); + return; + } + + invitee = LookupPlayer(COM_Argv(1)); + + if (invitee == -1) + { + CONS_Alert(CONS_WARNING, "There is no player by that name!\n"); + return; + } + if (!playeringame[invitee]) + { + CONS_Alert(CONS_WARNING, "There is no player using that slot!\n"); + return; + } + + if (invitee == consoleplayer) + { + CONS_Alert(CONS_WARNING, "You cannot invite yourself! Bruh!\n"); + return; + } + + if (splitscreen_invitations[invitee] >= 0) + { + CONS_Alert(CONS_WARNING, + "That player has already been invited to join another party.\n"); + } + + if (( splitscreen_party_size[consoleplayer] + + splitscreen_original_party_size[invitee] ) > MAXSPLITSCREENPLAYERS) + { + CONS_Alert(CONS_WARNING, + "That player joined with too many " + "splitscreen players for your party.\n"); + } + + CONS_Printf( + "Inviting %s...\n", + VaguePartyDescription( + invitee, splitscreen_original_party_size, '\x80') + ); + + buffer[0] = invitee; + + SendNetXCmd(XD_PARTYINVITE, buffer, sizeof buffer); +} + +static void +Command_CancelInvite_f (void) +{ + UINT8 buffer[1]; + + int invitee; + + if (COM_Argc() != 2) + { + CONS_Printf("cancelinvite : Rescind a party invitation.\n"); + return; + } + + invitee = LookupPlayer(COM_Argv(1)); + + if (invitee == -1) + { + CONS_Alert(CONS_WARNING, "There is no player by that name!\n"); + return; + } + if (!playeringame[invitee]) + { + CONS_Alert(CONS_WARNING, "There is no player using that slot!\n"); + return; + } + + if (splitscreen_invitations[invitee] != consoleplayer) + { + CONS_Alert(CONS_WARNING, + "You have not invited this player!\n"); + } + + CONS_Printf( + "Rescinding invite to %s...\n", + VaguePartyDescription( + invitee, splitscreen_original_party_size, '\x80') + ); + + buffer[0] = invitee; + + SendNetXCmd(XD_CANCELPARTYINVITE, buffer, sizeof buffer); +} + +static boolean +CheckPartyInvite (void) +{ + if (splitscreen_invitations[consoleplayer] < 0) + { + CONS_Alert(CONS_WARNING, "There is no open party invitation.\n"); + return false; + } + return true; +} + +static void +Command_AcceptInvite_f (void) +{ + if (CheckPartyInvite()) + SendNetXCmd(XD_ACCEPTPARTYINVITE, NULL, 0); +} + +static void +Command_RejectInvite_f (void) +{ + if (CheckPartyInvite()) + { + CONS_Printf("\x85Rejecting invite...\n"); + + SendNetXCmd(XD_LEAVEPARTY, NULL, 0); + } +} + +static void +Command_LeaveParty_f (void) +{ + if (r_splitscreen > splitscreen) + { + CONS_Printf("\x85Leaving party...\n"); + + SendNetXCmd(XD_LEAVEPARTY, NULL, 0); + } +} + // ======================================================================== // play a demo, add .lmp for external demos @@ -2451,7 +2842,7 @@ void D_ModifyClientVote(SINT8 voted, UINT8 splitplayer) UINT8 player = consoleplayer; if (splitplayer > 0) - player = displayplayers[splitplayer]; + player = g_localplayers[splitplayer]; WRITESINT8(p, voted); WRITEUINT8(p, player); @@ -3105,11 +3496,11 @@ static void Command_Teamchange2_f(void) return; } - if (players[displayplayers[1]].spectator) - error = !(NetPacket.packet.newteam || (players[displayplayers[1]].pflags & PF_WANTSTOJOIN)); + if (players[g_localplayers[1]].spectator) + error = !(NetPacket.packet.newteam || (players[g_localplayers[1]].pflags & PF_WANTSTOJOIN)); else if (G_GametypeHasTeams()) - error = (NetPacket.packet.newteam == (unsigned)players[displayplayers[1]].ctfteam); - else if (G_GametypeHasSpectators() && !players[displayplayers[1]].spectator) + error = (NetPacket.packet.newteam == (unsigned)players[g_localplayers[1]].ctfteam); + else if (G_GametypeHasSpectators() && !players[g_localplayers[1]].spectator) error = (NetPacket.packet.newteam == 3); #ifdef PARANOIA else @@ -3196,11 +3587,11 @@ static void Command_Teamchange3_f(void) return; } - if (players[displayplayers[2]].spectator) - error = !(NetPacket.packet.newteam || (players[displayplayers[2]].pflags & PF_WANTSTOJOIN)); + if (players[g_localplayers[2]].spectator) + error = !(NetPacket.packet.newteam || (players[g_localplayers[2]].pflags & PF_WANTSTOJOIN)); else if (G_GametypeHasTeams()) - error = (NetPacket.packet.newteam == (unsigned)players[displayplayers[2]].ctfteam); - else if (G_GametypeHasSpectators() && !players[displayplayers[2]].spectator) + error = (NetPacket.packet.newteam == (unsigned)players[g_localplayers[2]].ctfteam); + else if (G_GametypeHasSpectators() && !players[g_localplayers[2]].spectator) error = (NetPacket.packet.newteam == 3); #ifdef PARANOIA else @@ -3287,11 +3678,11 @@ static void Command_Teamchange4_f(void) return; } - if (players[displayplayers[3]].spectator) - error = !(NetPacket.packet.newteam || (players[displayplayers[3]].pflags & PF_WANTSTOJOIN)); + if (players[g_localplayers[3]].spectator) + error = !(NetPacket.packet.newteam || (players[g_localplayers[3]].pflags & PF_WANTSTOJOIN)); else if (G_GametypeHasTeams()) - error = (NetPacket.packet.newteam == (unsigned)players[displayplayers[3]].ctfteam); - else if (G_GametypeHasSpectators() && !players[displayplayers[3]].spectator) + error = (NetPacket.packet.newteam == (unsigned)players[g_localplayers[3]].ctfteam); + else if (G_GametypeHasSpectators() && !players[g_localplayers[3]].spectator) error = (NetPacket.packet.newteam == 3); #ifdef PARANOIA else @@ -3688,8 +4079,8 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) HU_AddChatText(va("\x82*%s became a spectator.", player_names[playernum]), false); // "entered the game" text was moved to P_SpectatorJoinGame //reset view if you are changed, or viewing someone who was changed. - if (playernum == consoleplayer || displayplayers[0] == playernum) - displayplayers[0] = consoleplayer; + if (playernum == consoleplayer || g_localplayers[0] == playernum) + g_localplayers[0] = consoleplayer; if (G_GametypeHasTeams()) { @@ -5334,7 +5725,29 @@ static void Got_PickVotecmd(UINT8 **cp, INT32 playernum) */ static void Command_Displayplayer_f(void) { - CONS_Printf(M_GetText("Displayplayer is %d\n"), displayplayers[0]); + int playernum; + int i; + for (i = 0; i <= splitscreen; ++i) + { + playernum = g_localplayers[i]; + CONS_Printf( + "local player %d: \x84(%d) \x83%s\x80\n", + i, + playernum, + player_names[playernum] + ); + } + CONS_Printf("\x83----------------------------------------\x80\n"); + for (i = 0; i <= r_splitscreen; ++i) + { + playernum = displayplayers[i]; + CONS_Printf( + "display player %d: \x84(%d) \x83%s\x80\n", + i, + playernum, + player_names[playernum] + ); + } } /** Quits a game and returns to the title screen. @@ -5529,7 +5942,7 @@ static void Name2_OnChange(void) if (cv_mute.value) //Secondary player can't be admin. { CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); - CV_StealthSet(&cv_playername2, player_names[displayplayers[1]]); + CV_StealthSet(&cv_playername2, player_names[g_localplayers[1]]); } else SendNameAndColor2(); @@ -5540,7 +5953,7 @@ static void Name3_OnChange(void) if (cv_mute.value) //Third player can't be admin. { CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); - CV_StealthSet(&cv_playername3, player_names[displayplayers[2]]); + CV_StealthSet(&cv_playername3, player_names[g_localplayers[2]]); } else SendNameAndColor3(); @@ -5551,7 +5964,7 @@ static void Name4_OnChange(void) if (cv_mute.value) //Secondary player can't be admin. { CONS_Alert(CONS_NOTICE, M_GetText("You may not change your name when chat is muted.\n")); - CV_StealthSet(&cv_playername4, player_names[displayplayers[3]]); + CV_StealthSet(&cv_playername4, player_names[g_localplayers[3]]); } else SendNameAndColor4(); @@ -5592,12 +6005,12 @@ static void Skin2_OnChange(void) if (!Playing() || !splitscreen) return; // do whatever you want - if (CanChangeSkin(displayplayers[1]) && !P_PlayerMoving(displayplayers[1])) + if (CanChangeSkin(g_localplayers[1]) && !P_PlayerMoving(g_localplayers[1])) SendNameAndColor2(); else { CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); - CV_StealthSet(&cv_skin2, skins[players[displayplayers[1]].skin].name); + CV_StealthSet(&cv_skin2, skins[players[g_localplayers[1]].skin].name); } } @@ -5606,12 +6019,12 @@ static void Skin3_OnChange(void) if (!Playing() || splitscreen < 2) return; // do whatever you want - if (CanChangeSkin(displayplayers[2]) && !P_PlayerMoving(displayplayers[2])) + if (CanChangeSkin(g_localplayers[2]) && !P_PlayerMoving(g_localplayers[2])) SendNameAndColor3(); else { CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); - CV_StealthSet(&cv_skin3, skins[players[displayplayers[2]].skin].name); + CV_StealthSet(&cv_skin3, skins[players[g_localplayers[2]].skin].name); } } @@ -5620,12 +6033,12 @@ static void Skin4_OnChange(void) if (!Playing() || splitscreen < 3) return; // do whatever you want - if (CanChangeSkin(displayplayers[3]) && !P_PlayerMoving(displayplayers[3])) + if (CanChangeSkin(g_localplayers[3]) && !P_PlayerMoving(g_localplayers[3])) SendNameAndColor4(); else { CONS_Alert(CONS_NOTICE, M_GetText("You can't change your skin at the moment.\n")); - CV_StealthSet(&cv_skin4, skins[players[displayplayers[3]].skin].name); + CV_StealthSet(&cv_skin4, skins[players[g_localplayers[3]].skin].name); } } @@ -5666,7 +6079,7 @@ static void Color2_OnChange(void) if (!Playing() || !splitscreen) return; // do whatever you want - if (!P_PlayerMoving(displayplayers[1])) + if (!P_PlayerMoving(g_localplayers[1])) { // Color change menu scrolling fix is no longer necessary SendNameAndColor2(); @@ -5674,7 +6087,7 @@ static void Color2_OnChange(void) else { CV_StealthSetValue(&cv_playercolor2, - players[displayplayers[1]].skincolor); + players[g_localplayers[1]].skincolor); } } @@ -5683,7 +6096,7 @@ static void Color3_OnChange(void) if (!Playing() || splitscreen < 2) return; // do whatever you want - if (!P_PlayerMoving(displayplayers[2])) + if (!P_PlayerMoving(g_localplayers[2])) { // Color change menu scrolling fix is no longer necessary SendNameAndColor3(); @@ -5691,7 +6104,7 @@ static void Color3_OnChange(void) else { CV_StealthSetValue(&cv_playercolor3, - players[displayplayers[2]].skincolor); + players[g_localplayers[2]].skincolor); } } @@ -5700,7 +6113,7 @@ static void Color4_OnChange(void) if (!Playing() || splitscreen < 3) return; // do whatever you want - if (!P_PlayerMoving(displayplayers[3])) + if (!P_PlayerMoving(g_localplayers[3])) { // Color change menu scrolling fix is no longer necessary SendNameAndColor4(); @@ -5708,7 +6121,7 @@ static void Color4_OnChange(void) else { CV_StealthSetValue(&cv_playercolor4, - players[displayplayers[3]].skincolor); + players[g_localplayers[3]].skincolor); } } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index c20ebb69e..81854bc71 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -104,7 +104,8 @@ extern consvar_t cv_recycler;*/ extern consvar_t cv_superring, cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana; extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine; extern consvar_t cv_ballhog, cv_selfpropelledbomb, cv_grow, cv_shrink; -extern consvar_t cv_thundershield, cv_hyudoro, cv_pogospring, cv_kitchensink; +extern consvar_t cv_thundershield, cv_bubbleshield, cv_flameshield; +extern consvar_t cv_hyudoro, cv_pogospring, cv_kitchensink; extern consvar_t cv_triplesneaker, cv_triplebanana, cv_decabanana; extern consvar_t cv_tripleorbinaut, cv_quadorbinaut, cv_dualjawz; @@ -182,9 +183,13 @@ typedef enum XD_PICKVOTE, // 24 XD_REMOVEPLAYER,// 25 XD_POWERLEVEL, // 26 + XD_PARTYINVITE, // 27 + XD_ACCEPTPARTYINVITE, // 28 + XD_LEAVEPARTY, // 29 + XD_CANCELPARTYINVITE, // 30 #ifdef HAVE_BLUA - XD_LUACMD, // 27 - XD_LUAVAR, // 28 + XD_LUACMD, // 31 + XD_LUAVAR, // 32 #endif MAXNETXCMD } netxcmd_t; diff --git a/src/d_netfil.c b/src/d_netfil.c index 155700807..cac5a2d80 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -742,7 +742,7 @@ void SV_FileSendTicker(void) if (ram) M_Memcpy(p->data, &f->id.ram[transfer[i].position], size); else if (fread(p->data, 1, size, transfer[i].currentfile) != size) - I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile))); + I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile)); p->position = LONG(transfer[i].position); // Put flag so receiver knows the total size if (transfer[i].position + size == f->size) @@ -818,7 +818,7 @@ void Got_Filetxpak(void) // We can receive packet in the wrong order, anyway all os support gaped file fseek(file->file, pos, SEEK_SET); if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1) - I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file))); + I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file)); file->currentsize += size; // Finished? diff --git a/src/d_player.h b/src/d_player.h index 07e0f7a97..2465b90ef 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -217,6 +217,8 @@ typedef enum KITEM_GROW, KITEM_SHRINK, KITEM_THUNDERSHIELD, + KITEM_BUBBLESHIELD, + KITEM_FLAMESHIELD, KITEM_HYUDORO, KITEM_POGOSPRING, KITEM_SUPERRING, @@ -235,6 +237,15 @@ typedef enum NUMKARTRESULTS } kartitems_t; +typedef enum +{ + KSHIELD_NONE = 0, + KSHIELD_THUNDER = 1, + KSHIELD_BUBBLE = 2, + KSHIELD_FLAME = 3, + NUMKARTSHIELDS +} kartshields_t; + //{ SRB2kart - kartstuff typedef enum { @@ -290,20 +301,25 @@ typedef enum k_itemtype, // KITEM_ constant for item number k_itemamount, // Amount of said item k_itemheld, // Are you holding an item? + k_holdready, // Hold button-style item is ready to activate // Some items use timers for their duration or effects - //k_thunderanim, // Duration of Thunder Shield's use animation k_curshield, // 0 = no shield, 1 = thunder shield k_hyudorotimer, // Duration of the Hyudoro offroad effect itself k_stealingtimer, // You are stealing an item, this is your timer k_stolentimer, // You are being stolen from, this is your timer k_superring, // Spawn rings on top of you every tic! k_sneakertimer, // Duration of the Sneaker Boost itself - k_levelbooster, // Duration of a level booster's boost (same as sneaker, but separated for ) + k_levelbooster, // Duration of a level booster's boost (same as sneaker, but separated for boost stacking) k_growshrinktimer, // > 0 = Big, < 0 = small k_squishedtimer, // Squished frame timer k_rocketsneakertimer, // Rocket Sneaker duration timer k_invincibilitytimer, // Invincibility timer + k_bubblecool, // Bubble Shield use cooldown + k_bubbleblowup, // Bubble Shield usage blowup + k_flamedash, // Flame Shield dash power + k_flamemeter, // Flame Shield dash meter left + k_flamelength, // Flame Shield dash meter, number of segments k_eggmanheld, // Eggman monitor held, separate from k_itemheld so it doesn't stop you from getting items k_eggmanexplode, // Fake item recieved, explode in a few seconds k_eggmanblame, // Fake item recieved, who set this fake @@ -325,7 +341,6 @@ typedef enum k_getsparks, // Disable drift sparks at low speed, JUST enough to give acceleration the actual headstart above speed k_jawztargetdelay, // Delay for Jawz target switching, to make it less twitchy k_spectatewait, // How long have you been waiting as a spectator - k_growcancel, // Hold the item button down to cancel Grow k_tiregrease, // Reduced friction timer after hitting a horizontal spring k_springstars, // Spawn stars around a player when they hit a spring k_springcolor, // Color of spring stars @@ -372,6 +387,9 @@ typedef enum // QUICKLY GET EITHER SNEAKER OR LEVEL BOOSTER SINCE THEY ARE FUNCTIONALLY IDENTICAL #define EITHERSNEAKER(p) (p->kartstuff[k_sneakertimer] || p->kartstuff[k_levelbooster]) +// QUICKLY GET RING TOTAL, INCLUDING RINGS CURRENTLY IN THE PICKUP ANIMATION +#define RINGTOTAL(p) (p->kartstuff[k_rings] + p->kartstuff[k_pickuprings]) + //} #define WEP_AUTO 1 diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h index dab758f8d..c73c161b5 100644 --- a/src/d_ticcmd.h +++ b/src/d_ticcmd.h @@ -32,8 +32,9 @@ typedef enum BT_ATTACK = 1<<4, // Use Item BT_FORWARD = 1<<5, // Aim Item Forward BT_BACKWARD = 1<<6, // Aim Item Backward + BT_LOOKBACK = 1<<7, // Look Backward - // free: 1<<7 to 1<<12 + // free: 1<<8 to 1<<12 // Lua garbage BT_CUSTOM1 = 1<<13, diff --git a/src/dehacked.c b/src/dehacked.c index f053a080c..e2a95eb83 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1887,6 +1887,7 @@ static actionpointer_t actionpointers[] = {{A_ReaperThinker}, "A_REAPERTHINKER"}, //SRB2kart {{A_MementosTPParticles}, "A_MEMENTOSTPPARTICLES"}, //SRB2kart {{A_FlameParticle}, "A_FLAMEPARTICLE"}, // SRB2kart + {{A_FlameShieldPaper}, "A_FLAMESHIELDPAPER"}, // SRB2kart {{A_OrbitNights}, "A_ORBITNIGHTS"}, {{A_GhostMe}, "A_GHOSTME"}, {{A_SetObjectState}, "A_SETOBJECTSTATE"}, @@ -6646,6 +6647,85 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_THUNDERSHIELD23", "S_THUNDERSHIELD24", + // Bubble Shield + "S_BUBBLESHIELD1", + "S_BUBBLESHIELD2", + "S_BUBBLESHIELD3", + "S_BUBBLESHIELD4", + "S_BUBBLESHIELD5", + "S_BUBBLESHIELD6", + "S_BUBBLESHIELD7", + "S_BUBBLESHIELD8", + "S_BUBBLESHIELD9", + "S_BUBBLESHIELD10", + "S_BUBBLESHIELD11", + "S_BUBBLESHIELD12", + "S_BUBBLESHIELD13", + "S_BUBBLESHIELD14", + "S_BUBBLESHIELD15", + "S_BUBBLESHIELD16", + "S_BUBBLESHIELD17", + "S_BUBBLESHIELD18", + "S_BUBBLESHIELDBLOWUP", + "S_BUBBLESHIELDTRAP1", + "S_BUBBLESHIELDTRAP2", + "S_BUBBLESHIELDTRAP3", + "S_BUBBLESHIELDTRAP4", + "S_BUBBLESHIELDTRAP5", + "S_BUBBLESHIELDTRAP6", + "S_BUBBLESHIELDTRAP7", + "S_BUBBLESHIELDTRAP8", + "S_BUBBLESHIELDWAVE1", + "S_BUBBLESHIELDWAVE2", + "S_BUBBLESHIELDWAVE3", + "S_BUBBLESHIELDWAVE4", + "S_BUBBLESHIELDWAVE5", + "S_BUBBLESHIELDWAVE6", + + // Flame Shield + "S_FLAMESHIELD1", + "S_FLAMESHIELD2", + "S_FLAMESHIELD3", + "S_FLAMESHIELD4", + "S_FLAMESHIELD5", + "S_FLAMESHIELD6", + "S_FLAMESHIELD7", + "S_FLAMESHIELD8", + "S_FLAMESHIELD9", + "S_FLAMESHIELD10", + "S_FLAMESHIELD11", + "S_FLAMESHIELD12", + "S_FLAMESHIELD13", + "S_FLAMESHIELD14", + "S_FLAMESHIELD15", + "S_FLAMESHIELD16", + "S_FLAMESHIELD17", + "S_FLAMESHIELD18", + + "S_FLAMESHIELDDASH1", + "S_FLAMESHIELDDASH2", + "S_FLAMESHIELDDASH3", + "S_FLAMESHIELDDASH4", + "S_FLAMESHIELDDASH5", + "S_FLAMESHIELDDASH6", + "S_FLAMESHIELDDASH7", + "S_FLAMESHIELDDASH8", + "S_FLAMESHIELDDASH9", + "S_FLAMESHIELDDASH10", + "S_FLAMESHIELDDASH11", + "S_FLAMESHIELDDASH12", + + "S_FLAMESHIELDDASH2_UNDERLAY", + "S_FLAMESHIELDDASH5_UNDERLAY", + "S_FLAMESHIELDDASH8_UNDERLAY", + "S_FLAMESHIELDDASH11_UNDERLAY", + + "S_FLAMESHIELDPAPER", + "S_FLAMESHIELDLINE1", + "S_FLAMESHIELDLINE2", + "S_FLAMESHIELDLINE3", + "S_FLAMESHIELDFLASH", + // The legend "S_SINK", "S_SINK_SHIELD", @@ -7802,7 +7882,12 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_SPB", // Self-Propelled Bomb "MT_SPBEXPLOSION", - "MT_THUNDERSHIELD", // Thunder Shield stuff + "MT_THUNDERSHIELD", // Shields + "MT_BUBBLESHIELD", + "MT_FLAMESHIELD", + "MT_FLAMESHIELDUNDERLAY", + "MT_FLAMESHIELDPAPER", + "MT_BUBBLESHIELDTRAP", "MT_SINK", // Kitchen Sink Stuff "MT_SINK_SHIELD", @@ -8203,8 +8288,8 @@ static const char *const PLAYERFLAG_LIST[] = { #ifdef HAVE_BLUA // Linedef flags static const char *const ML_LIST[16] = { - "IMPASSIBLE", - "BLOCKMONSTERS", + "IMPASSABLE", + "BLOCKPLAYERS", "TWOSIDED", "DONTPEGTOP", "DONTPEGBOTTOM", @@ -8478,6 +8563,7 @@ static const char *const KARTSTUFF_LIST[] = { "ITEMTYPE", "ITEMAMOUNT", "ITEMHELD", + "HOLDREADY", "CURSHIELD", "HYUDOROTIMER", @@ -8490,6 +8576,11 @@ static const char *const KARTSTUFF_LIST[] = { "SQUISHEDTIMER", "ROCKETSNEAKERTIMER", "INVINCIBILITYTIMER", + "BUBBLECOOL", + "BUBBLEBLOWUP", + "FLAMEDASH", + "FLAMEMETER", + "FLAMELENGTH", "EGGMANHELD", "EGGMANEXPLODE", "EGGMANBLAME", @@ -8509,7 +8600,6 @@ static const char *const KARTSTUFF_LIST[] = { "GETSPARKS", "JAWZTARGETDELAY", "SPECTATEWAIT", - "GROWCANCEL", "TIREGREASE", "SPRINGSTARS", "SPRINGCOLOR", @@ -9037,6 +9127,8 @@ struct { {"KITEM_GROW",KITEM_GROW}, {"KITEM_SHRINK",KITEM_SHRINK}, {"KITEM_THUNDERSHIELD",KITEM_THUNDERSHIELD}, + {"KITEM_BUBBLESHIELD",KITEM_BUBBLESHIELD}, + {"KITEM_FLAMESHIELD",KITEM_FLAMESHIELD}, {"KITEM_HYUDORO",KITEM_HYUDORO}, {"KITEM_POGOSPRING",KITEM_POGOSPRING}, {"KITEM_SUPERRING",KITEM_SUPERRING}, @@ -9050,6 +9142,13 @@ struct { {"KRITEM_DUALJAWZ",KRITEM_DUALJAWZ}, {"NUMKARTRESULTS",NUMKARTRESULTS}, + // kartshields_t + {"KSHIELD_NONE",KSHIELD_NONE}, + {"KSHIELD_THUNDER",KSHIELD_THUNDER}, + {"KSHIELD_BUBBLE",KSHIELD_BUBBLE}, + {"KSHIELD_FLAME",KSHIELD_FLAME}, + {"NUMKARTSHIELDS",NUMKARTSHIELDS}, + // translation colormaps {"TC_DEFAULT",TC_DEFAULT}, {"TC_BOSS",TC_BOSS}, diff --git a/src/doomdata.h b/src/doomdata.h index aa4ea1a54..767e47383 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -97,10 +97,10 @@ typedef struct // // Solid, is an obstacle. -#define ML_IMPASSIBLE 1 +#define ML_IMPASSABLE 1 -// Blocks monsters only. -#define ML_BLOCKMONSTERS 2 +// SRB2Kart: Blocks players only; items can be thrown through these. +#define ML_BLOCKPLAYERS 2 // Backside will not be present at all if not two sided. #define ML_TWOSIDED 4 diff --git a/src/doomdef.h b/src/doomdef.h index bb21e3d0f..ef7a2f8cb 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -138,6 +138,7 @@ #ifdef LOGMESSAGES extern FILE *logstream; +extern char logfilename[1024]; #endif //#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3 @@ -242,6 +243,7 @@ extern FILE *logstream; // NOTE: it needs more than this to increase the number of players... #define MAXPLAYERS 16 +#define MAXSPLITSCREENPLAYERS 4 // Max number of players on a single computer #define MAXSKINS 128 #define PLAYERSMASK (MAXPLAYERS-1) #define MAXPLAYERNAME 21 diff --git a/src/doomstat.h b/src/doomstat.h index 855866483..952586231 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -98,8 +98,8 @@ extern boolean multiplayer; extern INT16 gametype; -#define MAXSPLITSCREENPLAYERS 4 // Max number of players on a single computer extern UINT8 splitscreen; +extern int r_splitscreen; extern boolean circuitmap; // Does this level have 'circuit mode'? extern boolean fromlevelselect; @@ -140,6 +140,20 @@ extern boolean gamedataloaded; // Player taking events, and displaying. extern INT32 consoleplayer; extern INT32 displayplayers[MAXSPLITSCREENPLAYERS]; +/* g_localplayers[0] = consoleplayer */ +extern INT32 g_localplayers[MAXSPLITSCREENPLAYERS]; + +/* spitscreen players sync */ +extern int splitscreen_original_party_size[MAXPLAYERS]; +extern int splitscreen_original_party[MAXPLAYERS][MAXSPLITSCREENPLAYERS]; + +/* parties */ +extern int splitscreen_invitations[MAXPLAYERS]; +extern int splitscreen_party_size[MAXPLAYERS]; +extern int splitscreen_party[MAXPLAYERS][MAXSPLITSCREENPLAYERS]; + +/* the only local one */ +extern boolean splitscreen_partied[MAXPLAYERS]; // Maps of special importance extern INT16 spstage_start; @@ -451,12 +465,14 @@ extern INT32 hyudorotime; extern INT32 stealtime; extern INT32 sneakertime; extern INT32 itemtime; +extern INT32 bubbletime; extern INT32 comebacktime; extern INT32 bumptime; extern INT32 greasetics; extern INT32 wipeoutslowtime; extern INT32 wantedreduce; extern INT32 wantedfrequency; +extern INT32 flameseg; extern UINT8 introtoplay; extern UINT8 creditscutscene; diff --git a/src/filesrch.c b/src/filesrch.c index d132e9fb4..1be74f9b9 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -868,7 +868,7 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut) } else if (ext == EXT_TXT) { - if (!strcmp(dent->d_name, "log.txt") || !strcmp(dent->d_name, "errorlog.txt")) + if (!strncmp(dent->d_name, "log-", 4) || !strcmp(dent->d_name, "errorlog.txt")) ext |= EXT_LOADED; } diff --git a/src/g_game.c b/src/g_game.c index 3018c33e8..684e73492 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -129,6 +129,7 @@ player_t players[MAXPLAYERS]; INT32 consoleplayer; // player taking events and displaying INT32 displayplayers[MAXSPLITSCREENPLAYERS]; // view being displayed +INT32 g_localplayers[MAXSPLITSCREENPLAYERS]; tic_t gametic; tic_t levelstarttic; // gametic at level start @@ -225,12 +226,14 @@ INT32 hyudorotime = 7*TICRATE; INT32 stealtime = TICRATE/2; INT32 sneakertime = TICRATE + (TICRATE/3); INT32 itemtime = 8*TICRATE; +INT32 bubbletime = TICRATE/2; INT32 comebacktime = 10*TICRATE; INT32 bumptime = 6; INT32 greasetics = 3*TICRATE; INT32 wipeoutslowtime = 20; INT32 wantedreduce = 5*TICRATE; INT32 wantedfrequency = 10*TICRATE; +INT32 flameseg = TICRATE/4; INT32 gameovertics = 15*TICRATE; @@ -1237,7 +1240,6 @@ INT32 JoyAxis(axis_input_e axissel, UINT8 p) // INT32 localaiming[MAXSPLITSCREENPLAYERS]; angle_t localangle[MAXSPLITSCREENPLAYERS]; -boolean camspin[MAXSPLITSCREENPLAYERS]; static fixed_t forwardmove[2] = {25<>16, 50<>16}; static fixed_t sidemove[2] = {2<>16, 4<>16}; @@ -1263,7 +1265,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) if (ssplayer == 1) player = &players[consoleplayer]; else - player = &players[displayplayers[ssplayer-1]]; + player = &players[g_localplayers[ssplayer-1]]; if (ssplayer == 2) thiscam = (player->bot == 2 ? &camera[0] : &camera[ssplayer-1]); @@ -1462,6 +1464,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) if (InputDown(gc_drift, ssplayer) || (usejoystick && axis > 0)) cmd->buttons |= BT_DRIFT; + // rear view with any button/key + axis = JoyAxis(AXISLOOKBACK, ssplayer); + if (InputDown(gc_lookback, ssplayer) || (usejoystick && axis > 0)) + cmd->buttons |= BT_LOOKBACK; + // Lua scriptable buttons if (InputDown(gc_custom1, ssplayer)) cmd->buttons |= BT_CUSTOM1; @@ -1582,7 +1589,6 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) keyboard_look[ssplayer-1] = kbl; turnheld[ssplayer-1] = th; resetdown[ssplayer-1] = rd; - camspin[ssplayer-1] = InputDown(gc_lookback, ssplayer); } /* Lua: Allow this hook to overwrite ticcmd. @@ -1602,7 +1608,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) //Reset away view if a command is given. if ((cmd->forwardmove || cmd->sidemove || cmd->buttons) - && displayplayers[0] != consoleplayer && ssplayer == 1) + && ! r_splitscreen && displayplayers[0] != consoleplayer && ssplayer == 1) displayplayers[0] = consoleplayer; } @@ -1755,12 +1761,12 @@ void G_DoLoadLevel(boolean resetplayer) if (!resetplayer) P_FindEmerald(); - displayplayers[0] = consoleplayer; // view the guy you are playing + g_localplayers[0] = consoleplayer; // view the guy you are playing for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) { - if (i > 0 && !(i == 1 && botingame) && splitscreen < i) - displayplayers[i] = consoleplayer; + if (i > 0 && !(i == 1 && botingame) && r_splitscreen < i) + g_localplayers[i] = consoleplayer; } gameaction = ga_nothing; @@ -1768,10 +1774,10 @@ void G_DoLoadLevel(boolean resetplayer) Z_CheckHeap(-2); #endif - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (camera[i].chase) - P_ResetCamera(&players[displayplayers[i]], &camera[i]); + P_ResetCamera(&players[g_localplayers[i]], &camera[i]); } // clear cmd building stuff @@ -1883,8 +1889,8 @@ boolean G_Responder(event_t *ev) if (gamestate == GS_LEVEL && ev->type == ev_keydown && (ev->data1 == KEY_F12 || ev->data1 == gamecontrol[gc_viewpoint][0] || ev->data1 == gamecontrol[gc_viewpoint][1])) { - if (!demo.playback && (splitscreen || !netgame)) - displayplayers[0] = consoleplayer; + if (!demo.playback && (r_splitscreen || !netgame)) + g_localplayers[0] = consoleplayer; else { G_AdjustView(1, 1, true); @@ -2148,7 +2154,7 @@ boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive) if (!(onlyactive ? G_CouldView(playernum) : (playeringame[playernum] && !players[playernum].spectator))) return false; - splits = splitscreen+1; + splits = r_splitscreen+1; if (viewnum > splits) viewnum = splits; @@ -2219,7 +2225,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) INT32 olddisplayplayer; INT32 playersviewable; - splits = splitscreen+1; + splits = r_splitscreen+1; /* Promote splits */ if (viewnum > splits) @@ -2230,7 +2236,7 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive) if (viewnum > playersviewable) viewnum = playersviewable; - splitscreen = viewnum-1; + r_splitscreen = viewnum-1; /* Prepare extra views for G_FindView to pass. */ for (viewd = splits+1; viewd < viewnum; ++viewd) @@ -2303,14 +2309,14 @@ void G_ResetViews(void) INT32 playersviewable; - splits = splitscreen+1; + splits = r_splitscreen+1; playersviewable = G_CountPlayersPotentiallyViewable(false); /* Demote splits */ if (playersviewable < splits) { splits = playersviewable; - splitscreen = max(splits-1, 0); + r_splitscreen = max(splits-1, 0); R_ExecuteSetViewSize(); } @@ -2892,18 +2898,18 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) if (nummapthings) { if (playernum == consoleplayer - || (splitscreen && playernum == displayplayers[1]) - || (splitscreen > 1 && playernum == displayplayers[2]) - || (splitscreen > 2 && playernum == displayplayers[3])) + || (splitscreen && playernum == g_localplayers[1]) + || (splitscreen > 1 && playernum == g_localplayers[2]) + || (splitscreen > 2 && playernum == g_localplayers[3])) CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the first mapthing!\n")); spawnpoint = &mapthings[0]; } else { if (playernum == consoleplayer - || (splitscreen && playernum == displayplayers[1]) - || (splitscreen > 1 && playernum == displayplayers[2]) - || (splitscreen > 2 && playernum == displayplayers[3])) + || (splitscreen && playernum == g_localplayers[1]) + || (splitscreen > 1 && playernum == g_localplayers[2]) + || (splitscreen > 2 && playernum == g_localplayers[3])) CONS_Alert(CONS_ERROR, M_GetText("No player spawns found, spawning at the origin!\n")); //P_MovePlayerToSpawn handles this fine if the spawnpoint is NULL. } @@ -2998,17 +3004,17 @@ mapthing_t *G_FindMatchStart(INT32 playernum) return deathmatchstarts[i]; } if (playernum == consoleplayer - || (splitscreen && playernum == displayplayers[1]) - || (splitscreen > 1 && playernum == displayplayers[2]) - || (splitscreen > 2 && playernum == displayplayers[3])) + || (splitscreen && playernum == g_localplayers[1]) + || (splitscreen > 1 && playernum == g_localplayers[2]) + || (splitscreen > 2 && playernum == g_localplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Deathmatch starts!\n")); return NULL; } if (playernum == consoleplayer - || (splitscreen && playernum == displayplayers[1]) - || (splitscreen > 1 && playernum == displayplayers[2]) - || (splitscreen > 2 && playernum == displayplayers[3])) + || (splitscreen && playernum == g_localplayers[1]) + || (splitscreen > 1 && playernum == g_localplayers[2]) + || (splitscreen > 2 && playernum == g_localplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("No Deathmatch starts in this map!\n")); return NULL; } @@ -3096,17 +3102,17 @@ mapthing_t *G_FindRaceStart(INT32 playernum) //return playerstarts[0]; if (playernum == consoleplayer - || (splitscreen && playernum == displayplayers[1]) - || (splitscreen > 1 && playernum == displayplayers[2]) - || (splitscreen > 2 && playernum == displayplayers[3])) + || (splitscreen && playernum == g_localplayers[1]) + || (splitscreen > 1 && playernum == g_localplayers[2]) + || (splitscreen > 2 && playernum == g_localplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("Could not spawn at any Race starts!\n")); return NULL; } if (playernum == consoleplayer - || (splitscreen && playernum == displayplayers[1]) - || (splitscreen > 1 && playernum == displayplayers[2]) - || (splitscreen > 2 && playernum == displayplayers[3])) + || (splitscreen && playernum == g_localplayers[1]) + || (splitscreen > 1 && playernum == g_localplayers[2]) + || (splitscreen > 2 && playernum == g_localplayers[3])) CONS_Alert(CONS_WARNING, M_GetText("No Race starts in this map!\n")); return NULL; } @@ -3721,7 +3727,7 @@ static void G_DoCompleted(void) } // play some generic music if there's no win/cool/lose music going on (for exitlevel commands) - if (G_RaceGametype() && ((multiplayer && demo.playback) || j == splitscreen+1) && (cv_inttime.value > 0)) + if (G_RaceGametype() && ((multiplayer && demo.playback) || j == r_splitscreen+1) && (cv_inttime.value > 0)) S_ChangeMusicInternal("racent", true); if (automapactive) diff --git a/src/g_game.h b/src/g_game.h index de482fe7f..08af3a2b5 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -129,6 +129,7 @@ typedef enum AXISDEAD, //Axises that don't want deadzones AXISFIRE, AXISDRIFT, + AXISLOOKBACK, } axis_input_e; // mouseaiming (looking up/down with the mouse or keyboard) @@ -154,7 +155,6 @@ INT32 JoyAxis(axis_input_e axissel, UINT8 p); extern angle_t localangle[MAXSPLITSCREENPLAYERS]; extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but signed -extern boolean camspin[MAXSPLITSCREENPLAYERS]; // SRB2Kart // // GAME @@ -308,6 +308,10 @@ void G_ResetViews(void); void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive); void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive); +void G_AddPartyMember (INT32 party_member, INT32 new_party_member); +void G_RemovePartyMember (INT32 party_member); +void G_ResetSplitscreen (INT32 playernum); + void G_AddPlayer(INT32 playernum); void G_SetExitGameFlag(void); diff --git a/src/g_splitscreen.c b/src/g_splitscreen.c new file mode 100644 index 000000000..ffc548147 --- /dev/null +++ b/src/g_splitscreen.c @@ -0,0 +1,209 @@ +// 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 g_splitscreen.c +/// \brief some splitscreen stuff + +#include "doomdef.h" +#include "g_game.h" +#include "p_local.h" +#include "r_local.h" + +INT32 splitscreen_original_party_size[MAXPLAYERS]; +INT32 splitscreen_original_party[MAXPLAYERS][MAXSPLITSCREENPLAYERS]; + +INT32 splitscreen_invitations[MAXPLAYERS]; +INT32 splitscreen_party_size[MAXPLAYERS]; +INT32 splitscreen_party[MAXPLAYERS][MAXSPLITSCREENPLAYERS]; + +boolean splitscreen_partied[MAXPLAYERS]; + +void +G_ResetSplitscreen (INT32 playernum) +{ + INT32 old_displayplayers[MAXSPLITSCREENPLAYERS]; + + INT32 i; + + splitscreen_party_size[playernum] = + splitscreen_original_party_size[playernum]; + + memcpy(splitscreen_party[playernum], splitscreen_original_party[playernum], + sizeof splitscreen_party[playernum]); + + if (playernum == consoleplayer) + { + memset(splitscreen_partied, 0, sizeof splitscreen_partied); + splitscreen_partied[consoleplayer] = true; + + memcpy(old_displayplayers, displayplayers, sizeof old_displayplayers); + + /* easier to just rebuild displayplayers with local players */ + for (i = 0; i <= splitscreen; ++i) + { + displayplayers[i] = g_localplayers[i]; + P_ResetCamera(&players[displayplayers[i]], &camera[i]); + } + while (i < MAXSPLITSCREENPLAYERS) + { + displayplayers[i] = consoleplayer; + + i++; + } + + r_splitscreen = splitscreen; + + R_ExecuteSetViewSize(); + } +} + +void +G_RemovePartyMember (INT32 playernum) +{ + INT32 old_party[MAXSPLITSCREENPLAYERS]; + INT32 new_party[MAXSPLITSCREENPLAYERS]; + + INT32 old_party_size; + INT32 before; + INT32 after; + INT32 views; + + INT32 i; + INT32 n; + + old_party_size = splitscreen_party_size[playernum]; + + for (i = 0; i < old_party_size; ++i) + { + /* exploit that splitscreen players keep order */ + if (splitscreen_party[playernum][i] == playernum) + { + before = i; + + views = splitscreen_original_party_size[playernum]; + after = ( before + views ); + + memcpy(old_party, splitscreen_party[playernum], sizeof old_party); + memcpy(new_party, old_party, before * sizeof *old_party); + + memcpy(&new_party[before], &old_party[after], + ( old_party_size - after ) * sizeof *new_party); + + views = ( old_party_size - views ); + + for (i = 0; i < old_party_size; ++i) + { + n = old_party[i]; + if (n != playernum && playerconsole[n] == n) + { + splitscreen_party_size[n] = views; + memcpy(splitscreen_party[n], new_party, + sizeof splitscreen_party[n]); + } + } + + /* don't want to remove yourself from your own screen! */ + if (playernum != consoleplayer && splitscreen_partied[playernum]) + { + splitscreen_partied[playernum] = false; + + for (i = 0; i < views; ++i) + { + displayplayers[i] = new_party[i]; + P_ResetCamera(&players[displayplayers[i]], &camera[i]); + } + while (i < MAXSPLITSCREENPLAYERS) + { + displayplayers[i] = displayplayers[0]; + + i++; + } + + r_splitscreen = ( views - 1 ); + + R_ExecuteSetViewSize(); + } + + break; + } + } +} + +void +G_AddPartyMember (INT32 invitation, INT32 playernum) +{ + INT32 * party; + INT32 *add_party; + + INT32 old_party_size; + INT32 new_party_size; + + INT32 views; + + INT32 i; + INT32 n; + + views = splitscreen_original_party_size[playernum]; + + old_party_size = splitscreen_party_size[invitation]; + new_party_size = ( old_party_size + views ); + + party = splitscreen_party[invitation]; + add_party = splitscreen_original_party[playernum]; + + for (i = 0; i < old_party_size; ++i) + { + n = party[i]; + if (playerconsole[n] == n) + { + splitscreen_party_size[n] = new_party_size; + memcpy(&splitscreen_party[n][old_party_size], add_party, + views * sizeof *splitscreen_party[n]); + } + } + + splitscreen_party_size[playernum] = new_party_size; + memcpy(splitscreen_party[playernum], party, + sizeof splitscreen_party[playernum]); + + /* in my party or adding me? */ + if (splitscreen_partied[invitation]) + { + splitscreen_partied[playernum] = true; + + for (i = old_party_size; i < new_party_size; ++i) + { + displayplayers[i] = party[i]; + P_ResetCamera(&players[displayplayers[i]], &camera[i]); + } + + r_splitscreen += views; + + R_ExecuteSetViewSize(); + } + else if (playernum == consoleplayer) + { + for (i = 0; i < new_party_size; ++i) + { + splitscreen_partied[playerconsole[party[i]]] = true; + + displayplayers[i] = party[i]; + P_ResetCamera(&players[displayplayers[i]], &camera[i]); + } + while (i < MAXSPLITSCREENPLAYERS) + { + displayplayers[i] = displayplayers[0]; + + i++; + } + + r_splitscreen = ( new_party_size - 1 ); + + R_ExecuteSetViewSize(); + } +} diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index a22e5b586..6298bff7a 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -2023,7 +2023,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac) // Single sided line... Deal only with the middletexture (if one exists) gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture); if (gr_midtexture - && gr_linedef->special != 41) // Ignore horizon line for OGL + && gr_linedef->special != HORIZONSPECIAL) // Ignore horizon line for OGL { { fixed_t texturevpeg; @@ -5364,7 +5364,7 @@ static void HWR_AddSprites(sector_t *sec) if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) continue; - if (splitscreen) + if (r_splitscreen) { if (thing->eflags & MFE_DRAWONLYFORP1) if (viewssnum != 0) @@ -5374,11 +5374,11 @@ static void HWR_AddSprites(sector_t *sec) if (viewssnum != 1) continue; - if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) + if (thing->eflags & MFE_DRAWONLYFORP3 && r_splitscreen > 1) if (viewssnum != 2) continue; - if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) + if (thing->eflags & MFE_DRAWONLYFORP4 && r_splitscreen > 2) if (viewssnum != 3) continue; } @@ -5399,7 +5399,7 @@ static void HWR_AddSprites(sector_t *sec) if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) continue; - if (splitscreen) + if (r_splitscreen) { if (thing->eflags & MFE_DRAWONLYFORP1) if (viewssnum != 0) @@ -5409,11 +5409,11 @@ static void HWR_AddSprites(sector_t *sec) if (viewssnum != 1) continue; - if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) + if (thing->eflags & MFE_DRAWONLYFORP3 && r_splitscreen > 1) if (viewssnum != 2) continue; - if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) + if (thing->eflags & MFE_DRAWONLYFORP4 && r_splitscreen > 2) if (viewssnum != 3) continue; } @@ -5847,7 +5847,7 @@ static void HWR_DrawSkyBackground(void) dimensionmultiply = ((float)tex->height/(128.0f*aspectratio)); - if (splitscreen == 1) + if (r_splitscreen == 1) { dimensionmultiply *= 2; angle *= 2; @@ -5919,10 +5919,10 @@ void HWR_SetViewSize(void) gr_viewwidth = (float)vid.width; gr_viewheight = (float)vid.height; - if (splitscreen) + if (r_splitscreen) gr_viewheight /= 2; - if (splitscreen > 1) + if (r_splitscreen > 1) gr_viewwidth /= 2; gr_basecenterx = gr_viewwidth / 2; @@ -5978,13 +5978,13 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) gr_viewwindowy = gr_baseviewwindowy; gr_windowcentery = gr_basewindowcentery; - if ((splitscreen == 1 && viewnumber == 1) || (splitscreen > 1 && viewnumber > 1)) + if ((r_splitscreen == 1 && viewnumber == 1) || (r_splitscreen > 1 && viewnumber > 1)) { gr_viewwindowy += gr_viewheight; gr_windowcentery += gr_viewheight; } - if (splitscreen > 1 && viewnumber & 1) + if (r_splitscreen > 1 && viewnumber & 1) { gr_viewwindowx += gr_viewwidth; gr_windowcenterx += gr_viewwidth; @@ -6026,7 +6026,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) atransform.scalez = 1; atransform.fovxangle = fpov; // Tails atransform.fovyangle = fpov; // Tails - atransform.splitscreen = splitscreen; + atransform.splitscreen = r_splitscreen; gr_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l))); @@ -6045,7 +6045,7 @@ if (0) HWR_DrawSkyBackground(); //Hurdler: it doesn't work in splitscreen mode - drawsky = splitscreen; + drawsky = r_splitscreen; HWR_ClearSprites(); @@ -6078,11 +6078,11 @@ if (0) // Make a viewangle int so we can render things based on mouselook if (player == &players[consoleplayer]) viewangle = localaiming[0]; - else if (splitscreen && player == &players[displayplayers[1]]) + else if (r_splitscreen && player == &players[displayplayers[1]]) viewangle = localaiming[1]; - else if (splitscreen > 1 && player == &players[displayplayers[2]]) + else if (r_splitscreen > 1 && player == &players[displayplayers[2]]) viewangle = localaiming[2]; - else if (splitscreen > 2 && player == &players[displayplayers[3]]) + else if (r_splitscreen > 2 && player == &players[displayplayers[3]]) viewangle = localaiming[3]; // Handle stuff when you are looking farther up or down. @@ -6212,13 +6212,13 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) gr_viewwindowy = gr_baseviewwindowy; gr_windowcentery = gr_basewindowcentery; - if ((splitscreen == 1 && viewnumber == 1) || (splitscreen > 1 && viewnumber > 1)) + if ((r_splitscreen == 1 && viewnumber == 1) || (r_splitscreen > 1 && viewnumber > 1)) { gr_viewwindowy += gr_viewheight; gr_windowcentery += gr_viewheight; } - if (splitscreen > 1 && viewnumber & 1) + if (r_splitscreen > 1 && viewnumber & 1) { gr_viewwindowx += gr_viewwidth; gr_windowcenterx += gr_viewwidth; @@ -6260,7 +6260,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) atransform.scalez = 1; atransform.fovxangle = fpov; // Tails atransform.fovyangle = fpov; // Tails - atransform.splitscreen = splitscreen; + atransform.splitscreen = r_splitscreen; gr_fovlud = (float)(1.0l/tan((double)(fpov*M_PIl/360l))); @@ -6279,7 +6279,7 @@ if (0) HWR_DrawSkyBackground(); //Hurdler: it doesn't work in splitscreen mode - drawsky = splitscreen; + drawsky = r_splitscreen; HWR_ClearSprites(); @@ -6312,11 +6312,11 @@ if (0) // Make a viewangle int so we can render things based on mouselook if (player == &players[consoleplayer]) viewangle = localaiming[0]; - else if (splitscreen && player == &players[displayplayers[1]]) + else if (r_splitscreen && player == &players[displayplayers[1]]) viewangle = localaiming[1]; - else if (splitscreen > 1 && player == &players[displayplayers[2]]) + else if (r_splitscreen > 1 && player == &players[displayplayers[2]]) viewangle = localaiming[2]; - else if (splitscreen > 2 && player == &players[displayplayers[3]]) + else if (r_splitscreen > 2 && player == &players[displayplayers[3]]) viewangle = localaiming[3]; // Handle stuff when you are looking farther up or down. @@ -6796,7 +6796,7 @@ void HWR_DoPostProcessor(player_t *player) postimg_t *type = &postimgtype[0]; UINT8 i; - for (i = splitscreen; i > 0; i--) + for (i = r_splitscreen; i > 0; i--) { if (player == &players[displayplayers[i]]) { @@ -6834,7 +6834,7 @@ void HWR_DoPostProcessor(player_t *player) if(gamestate != GS_INTERMISSION) HWD.pfnMakeScreenTexture(); - if (splitscreen) // Not supported in splitscreen - someone want to add support? + if (r_splitscreen) // Not supported in splitscreen - someone want to add support? return; // Drunken vision! WooOOooo~ diff --git a/src/hu_stuff.c b/src/hu_stuff.c index a454aaecc..faa92c95e 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -78,6 +78,7 @@ patch_t *cred_font[CRED_FONTSIZE]; // Note: I'd like to adress that at this point we might *REALLY* want to work towards a common drawString function that can take any font we want because this is really turning into a MESS. :V -Lat' patch_t *pingnum[10]; patch_t *pinggfx[5]; // small ping graphic +patch_t *mping[5]; // smaller ping graphic patch_t *framecounter; patch_t *frameslash; // framerate stuff. Used in screen.c @@ -311,6 +312,8 @@ void HU_LoadGraphics(void) { sprintf(buffer, "PINGGFX%d", i+1); pinggfx[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); + sprintf(buffer, "MPING%d", i+1); + mping[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); } // fps stuff @@ -1477,7 +1480,7 @@ static void HU_drawMiniChat(void) if (!chat_nummsg_min) return; // needless to say it's useless to do anything if we don't have anything to draw. - if (splitscreen > 1) + if (r_splitscreen > 1) boxw = max(64, boxw/2); for (; i>0; i--) @@ -1529,10 +1532,10 @@ static void HU_drawMiniChat(void) y = chaty - charheight*(msglines+1); #ifdef NETSPLITSCREEN - if (splitscreen) + if (r_splitscreen) { y -= BASEVIDHEIGHT/2; - if (splitscreen > 1) + if (r_splitscreen > 1) y += 16; } else @@ -1620,10 +1623,10 @@ static void HU_drawChatLog(INT32 offset) chat_scroll = chat_maxscroll; #ifdef NETSPLITSCREEN - if (splitscreen) + if (r_splitscreen) { boxh = max(6, boxh/2); - if (splitscreen > 1) + if (r_splitscreen > 1) boxw = max(64, boxw/2); } #endif @@ -1631,10 +1634,10 @@ static void HU_drawChatLog(INT32 offset) y = chaty - offset*charheight - (chat_scroll*charheight) - boxh*charheight - 12; #ifdef NETSPLITSCREEN - if (splitscreen) + if (r_splitscreen) { y -= BASEVIDHEIGHT/2; - if (splitscreen > 1) + if (r_splitscreen > 1) y += 16; } else @@ -1739,10 +1742,10 @@ static void HU_DrawChat(void) const char *mute = "Chat has been muted."; #ifdef NETSPLITSCREEN - if (splitscreen) + if (r_splitscreen) { y -= BASEVIDHEIGHT/2; - if (splitscreen > 1) + if (r_splitscreen > 1) { y += 16; boxw = max(64, boxw/2); @@ -1836,10 +1839,10 @@ static void HU_DrawChat(void) INT32 count = 0; INT32 p_dispy = chaty - charheight -1; #ifdef NETSPLITSCREEN - if (splitscreen) + if (r_splitscreen) { p_dispy -= BASEVIDHEIGHT/2; - if (splitscreen > 1) + if (r_splitscreen > 1) p_dispy += 16; } else @@ -2250,7 +2253,7 @@ void HU_DrawSongCredits(void) { char *str; INT32 len, destx; - INT32 y = (splitscreen ? (BASEVIDHEIGHT/2)-4 : 32); + INT32 y = (r_splitscreen ? (BASEVIDHEIGHT/2)-4 : 32); INT32 bgt; if (!cursongcredit.def) // No def @@ -2480,22 +2483,30 @@ void HU_Erase(void) // IN-LEVEL MULTIPLAYER RANKINGS //====================================================================== +static int +Ping_gfx_num (int ping) +{ + if (ping < 76) + return 0; + else if (ping < 137) + return 1; + else if (ping < 256) + return 2; + else if (ping < 500) + return 3; + else + return 4; +} + // // HU_drawPing // void HU_drawPing(INT32 x, INT32 y, UINT32 ping, INT32 flags) { - INT32 gfxnum = 4; // gfx to draw + INT32 gfxnum; // gfx to draw UINT8 const *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_SALMON, GTC_CACHE); - if (ping < 76) - gfxnum = 0; - else if (ping < 137) - gfxnum = 1; - else if (ping < 256) - gfxnum = 2; - else if (ping < 500) - gfxnum = 3; + gfxnum = Ping_gfx_num(ping); V_DrawScaledPatch(x, y, flags, pinggfx[gfxnum]); if (servermaxping && ping > servermaxping && hu_tick < 4) // flash ping red if too high @@ -2504,6 +2515,19 @@ void HU_drawPing(INT32 x, INT32 y, UINT32 ping, INT32 flags) V_DrawPingNum(x, y+9, flags, ping, NULL); } +void +HU_drawMiniPing (INT32 x, INT32 y, UINT32 ping, INT32 flags) +{ + patch_t *patch; + + patch = mping[Ping_gfx_num(ping)]; + + if (( flags & V_SNAPTORIGHT )) + x += ( BASEVIDWIDTH - SHORT (patch->width) ); + + V_DrawScaledPatch(x, y, flags, patch); +} + // // HU_DrawTabRankings -- moved to k_kart.c // @@ -3022,7 +3046,7 @@ static void HU_DrawRankings(void) // When you play, you quickly see your score because your name is displayed in white. // When playing back a demo, you quickly see who's the view. - if (!splitscreen) + if (!r_splitscreen) whiteplayer = demo.playback ? displayplayers[0] : consoleplayer; scorelines = 0; diff --git a/src/hu_stuff.h b/src/hu_stuff.h index be6798a82..c3da1d2a2 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -115,6 +115,7 @@ char HU_dequeueChatChar(void); void HU_Erase(void); void HU_clearChatChars(void); void HU_drawPing(INT32 x, INT32 y, UINT32 ping, INT32 flags); // Lat': Ping drawer for scoreboard. +void HU_drawMiniPing(INT32 x, INT32 y, UINT32 ping, INT32 flags); //void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer); //void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer); void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol); diff --git a/src/info.c b/src/info.c index ab9dd44eb..981773387 100644 --- a/src/info.c +++ b/src/info.c @@ -57,20 +57,22 @@ char sprnames[NUMSPRITES + 1][5] = "SRBL","SRBM","SRBN","SRBO", //SRB2kart Sprites "RNDM","RPOP","SGNS","FAST","DSHR","BOST","BOSM","KFRE","KINV","KINF", - "WIPD","DRIF","BDRF","DUST","DRWS","RSHE","FITM","BANA","ORBN","JAWZ", - "SSMN","KRBM","BHOG","BHBM","SPBM","THNS","SINK","SITR","KBLN","DEZL", - "POKE","AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB","CHOM","SACO", - "CRAB","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA","ISTB","ARRO","ITEM", - "ITMO","ITMI","ITMN","WANT","PBOM","HIT1","HIT2","HIT3","RETI","AIDU", - "KSPK","LZI1","LZI2","KLIT","FZSM","FZBM","FPRT","SBUS","MARB","FUFO", - "RUST","BLON","VAPE","HTZA","HTZB","SGVA","SGVB","SGVC","PGTR","PGF1", - "PGF2","PGF3","PGBH","DPLR","SPTL","ENM1","GARU","MARR","REAP","JITB", - "CDMO","CDBU","PINE","PPLR","DPPT","AATR","COCO","BDST","FROG","CBRA", - "HOLE","BBRA","EGFG","SMKP","MTYM","THWP","SNOB","ICEB","CNDL","DOCH", - "DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS","ZTCH","MKMA","MKMP", - "RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH","BFRT","OFRT","RFRT", - "PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN","FWRK","MXCL","RGSP", - "DRAF","GRES","OTFG","DBOS","XMS4","XMS5","VIEW" + "WIPD","DRIF","BDRF","DUST","DRWS","RSHE","FITM","BANA","ORBN","JAWZ","SSMN", + "KRBM","BHOG","BHBM","SPBM","THNS","BUBS","BWVE", + "FLMS","FLMD","FLMP","FLML","FLMF", + "SINK","SITR", + "KBLN","DEZL","POKE","AUDI","DECO","DOOD","SNES","GBAS","SPRS","BUZB", + "CHOM","SACO","CRAB","BRNG","BUMP","FLEN","CLAS","PSHW","ISTA", + "ISTB","ARRO","ITEM","ITMO","ITMI","ITMN","WANT","PBOM","HIT1","HIT2", + "HIT3","RETI","AIDU","KSPK","LZI1","LZI2","KLIT","FZSM","FZBM","FPRT", + "SBUS","MARB","FUFO","RUST","BLON","VAPE","HTZA","HTZB","SGVA","SGVB", + "SGVC","PGTR","PGF1","PGF2","PGF3","PGBH","DPLR","SPTL","ENM1","GARU", + "MARR","REAP","JITB","CDMO","CDBU","PINE","PPLR","DPPT","AATR","COCO", + "BDST","FROG","CBRA","HOLE","BBRA","EGFG","SMKP","MTYM","THWP","SNOB", + "ICEB","CNDL","DOCH","DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS", + "ZTCH","MKMA","MKMP","RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH", + "BFRT","OFRT","RFRT","PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN", + "FWRK","MXCL","RGSP","DRAF","GRES","OTFG","DBOS","XMS4","XMS5","VIEW" }; // Doesn't work with g++, needs actionf_p1 (don't modify this comment) @@ -2866,6 +2868,83 @@ state_t states[NUMSTATES] = {SPR_THNS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_THUNDERSHIELD24}, // S_THUNDERSHIELD23 {SPR_THNS, FF_FULLBRIGHT|0, 2, {NULL}, 0, 0, S_THUNDERSHIELD1}, // S_THUNDERSHIELD24 + {SPR_BUBS, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BUBBLESHIELD2}, // S_BUBBLESHIELD1 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD3}, // S_BUBBLESHIELD2 + {SPR_BUBS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_BUBBLESHIELD4}, // S_BUBBLESHIELD3 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD5}, // S_BUBBLESHIELD4 + {SPR_BUBS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_BUBBLESHIELD6}, // S_BUBBLESHIELD5 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD7}, // S_BUBBLESHIELD6 + {SPR_BUBS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_BUBBLESHIELD8}, // S_BUBBLESHIELD7 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD9}, // S_BUBBLESHIELD8 + {SPR_BUBS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_BUBBLESHIELD10}, // S_BUBBLESHIELD9 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD11}, // S_BUBBLESHIELD10 + {SPR_BUBS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_BUBBLESHIELD12}, // S_BUBBLESHIELD11 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD13}, // S_BUBBLESHIELD12 + {SPR_BUBS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_BUBBLESHIELD14}, // S_BUBBLESHIELD13 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD15}, // S_BUBBLESHIELD14 + {SPR_BUBS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_BUBBLESHIELD16}, // S_BUBBLESHIELD15 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD17}, // S_BUBBLESHIELD16 + {SPR_BUBS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_BUBBLESHIELD18}, // S_BUBBLESHIELD17 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELD1}, // S_BUBBLESHIELD18 + {SPR_BUBS, FF_FULLBRIGHT|13, -1, {NULL}, 0, 0, S_BUBBLESHIELDBLOWUP}, // S_BUBBLESHIELDBLOWUP + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP2}, // S_BUBBLESHIELDTRAP1 + {SPR_BUBS, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP3}, // S_BUBBLESHIELDTRAP2 + {SPR_BUBS, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP4}, // S_BUBBLESHIELDTRAP3 + {SPR_BUBS, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP5}, // S_BUBBLESHIELDTRAP4 + {SPR_BUBS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP6}, // S_BUBBLESHIELDTRAP5 + {SPR_BUBS, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP7}, // S_BUBBLESHIELDTRAP6 + {SPR_BUBS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP8}, // S_BUBBLESHIELDTRAP7 + {SPR_BUBS, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_BUBBLESHIELDTRAP1}, // S_BUBBLESHIELDTRAP8 + {SPR_BWVE, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BUBBLESHIELDWAVE2}, // S_BUBBLESHIELDWAVE1 + {SPR_BWVE, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BUBBLESHIELDWAVE3}, // S_BUBBLESHIELDWAVE2 + {SPR_BWVE, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_BUBBLESHIELDWAVE4}, // S_BUBBLESHIELDWAVE3 + {SPR_BWVE, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_BUBBLESHIELDWAVE5}, // S_BUBBLESHIELDWAVE4 + {SPR_BWVE, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_BUBBLESHIELDWAVE6}, // S_BUBBLESHIELDWAVE5 + {SPR_BWVE, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_NULL}, // S_BUBBLESHIELDWAVE6 + + {SPR_FLMS, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_FLAMESHIELD2}, // S_FLAMESHIELD1 + {SPR_FLMS, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_FLAMESHIELD3}, // S_FLAMESHIELD2 + {SPR_FLMS, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_FLAMESHIELD4}, // S_FLAMESHIELD3 + {SPR_FLMS, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_FLAMESHIELD5}, // S_FLAMESHIELD4 + {SPR_FLMS, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_FLAMESHIELD6}, // S_FLAMESHIELD5 + {SPR_FLMS, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_FLAMESHIELD7}, // S_FLAMESHIELD6 + {SPR_FLMS, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_FLAMESHIELD8}, // S_FLAMESHIELD7 + {SPR_FLMS, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_FLAMESHIELD9}, // S_FLAMESHIELD8 + {SPR_FLMS, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_FLAMESHIELD10}, // S_FLAMESHIELD9 + {SPR_FLMS, FF_FULLBRIGHT|13, 2, {NULL}, 0, 0, S_FLAMESHIELD11}, // S_FLAMESHIELD10 + {SPR_FLMS, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_FLAMESHIELD12}, // S_FLAMESHIELD11 + {SPR_FLMS, FF_FULLBRIGHT|14, 2, {NULL}, 0, 0, S_FLAMESHIELD13}, // S_FLAMESHIELD12 + {SPR_FLMS, FF_FULLBRIGHT|6, 2, {NULL}, 0, 0, S_FLAMESHIELD14}, // S_FLAMESHIELD13 + {SPR_FLMS, FF_FULLBRIGHT|15, 2, {NULL}, 0, 0, S_FLAMESHIELD15}, // S_FLAMESHIELD14 + {SPR_FLMS, FF_FULLBRIGHT|7, 2, {NULL}, 0, 0, S_FLAMESHIELD16}, // S_FLAMESHIELD15 + {SPR_FLMS, FF_FULLBRIGHT|16, 2, {NULL}, 0, 0, S_FLAMESHIELD17}, // S_FLAMESHIELD16 + {SPR_FLMS, FF_FULLBRIGHT|8, 2, {NULL}, 0, 0, S_FLAMESHIELD18}, // S_FLAMESHIELD17 + {SPR_FLMS, FF_FULLBRIGHT|17, 2, {NULL}, 0, 0, S_FLAMESHIELD1}, // S_FLAMESHIELD18 + + {SPR_FLMD, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH2}, // S_FLAMESHIELDDASH1 + {SPR_FLMD, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH3}, // S_FLAMESHIELDDASH2 + {SPR_FLMD, FF_FULLBRIGHT, 1, {A_FlameShieldPaper}, 0, 2, S_FLAMESHIELDDASH4}, // S_FLAMESHIELDDASH3 + {SPR_FLMD, FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH5}, // S_FLAMESHIELDDASH4 + {SPR_FLMD, FF_FULLBRIGHT|6, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH6}, // S_FLAMESHIELDDASH5 + {SPR_FLMD, FF_FULLBRIGHT, 1, {A_FlameShieldPaper}, 1, 3, S_FLAMESHIELDDASH7}, // S_FLAMESHIELDDASH6 + {SPR_FLMD, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH8}, // S_FLAMESHIELDDASH7 + {SPR_FLMD, FF_FULLBRIGHT|7, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH9}, // S_FLAMESHIELDDASH8 + {SPR_FLMD, FF_FULLBRIGHT, 1, {A_FlameShieldPaper}, 2, 0, S_FLAMESHIELDDASH10}, // S_FLAMESHIELDDASH9 + {SPR_FLMD, FF_FULLBRIGHT|4, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH11}, // S_FLAMESHIELDDASH10 + {SPR_FLMD, FF_FULLBRIGHT|8, 1, {NULL}, 0, 0, S_FLAMESHIELDDASH12}, // S_FLAMESHIELDDASH11 + {SPR_FLMD, FF_FULLBRIGHT, 1, {A_FlameShieldPaper}, 3, 1, S_FLAMESHIELDDASH1}, // S_FLAMESHIELDDASH12 + + {SPR_FLMD, FF_FULLBRIGHT|9, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDDASH2_UNDERLAY + {SPR_FLMD, FF_FULLBRIGHT|10, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDDASH5_UNDERLAY + {SPR_FLMD, FF_FULLBRIGHT|11, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDDASH8_UNDERLAY + {SPR_FLMD, FF_FULLBRIGHT|12, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDDASH11_UNDERLAY + + {SPR_FLMP, FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDPAPER + {SPR_FLML, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE, 7, {NULL}, 6, 1, S_NULL}, // S_FLAMESHIELDLINE1 + {SPR_FLML, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|7, 7, {NULL}, 6, 1, S_NULL}, // S_FLAMESHIELDLINE2 + {SPR_FLML, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|14, 7, {NULL}, 6, 1, S_NULL}, // S_FLAMESHIELDLINE3 + {SPR_FLMF, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDFLASH + {SPR_SINK, 0, 1, {A_SmokeTrailer}, MT_SINKTRAIL, 0, S_SINK}, // S_SINK {SPR_SINK, 0|FF_TRANS80|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_SINK_SHIELD}, // S_SINK_SHIELD {SPR_SITR, 0, 1, {NULL}, 0, 0, S_SINKTRAIL2}, // S_SINKTRAIL1 @@ -15582,7 +15661,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_cdfm28, // activesound - MF_SPECIAL|MF_BOUNCE|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_BOUNCE|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -15609,7 +15688,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -16143,7 +16222,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 8, // speed - 20*FRACUNIT, // radius + 28*FRACUNIT, // radius 56*FRACUNIT, // height 1, // display offset 16, // mass @@ -16153,6 +16232,141 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BUBBLESHIELD + -1, // doomednum + S_BUBBLESHIELD1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 28*FRACUNIT, // radius + 56*FRACUNIT, // height + 1, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_FLAMESHIELD + -1, // doomednum + S_FLAMESHIELD1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 28*FRACUNIT, // radius + 56*FRACUNIT, // height + 1, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_FLAMESHIELDUNDERLAY + -1, // doomednum + S_FLAMESHIELDDASH2_UNDERLAY, // 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<player->kartstuff[k_hyudorotimer]) return true; // no interaction - // Player Damage - P_DamageMobj(t2, t1, t1->target, 1); - K_KartBouncing(t2, t1, false, false); - S_StartSound(t2, sfx_s3k7b); + if (t2->player->kartstuff[k_flamedash] && t2->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + { + // Melt item + S_StartSound(t2, sfx_s3k43); + } + else + { + // Player Damage + P_DamageMobj(t2, t1, t1->target, 1); + K_KartBouncing(t2, t1, false, false); + S_StartSound(t2, sfx_s3k7b); + } damageitem = true; } @@ -126,8 +134,16 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) if (t1->type == MT_BANANA && t1->health > 1) S_StartSound(t2, sfx_bsnipe); - // Player Damage - K_SpinPlayer(t2->player, t1->target, 0, t1, (t1->type == MT_BANANA || t1->type == MT_BANANA_SHIELD)); + if (t2->player->kartstuff[k_flamedash] && t2->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + { + // Melt item + S_StartSound(t2, sfx_s3k43); + } + else + { + // Player Damage + K_SpinPlayer(t2->player, t1->target, 0, t1, (t1->type == MT_BANANA || t1->type == MT_BANANA_SHIELD)); + } damageitem = true; } @@ -181,9 +197,73 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2) { // Push fakes out of other item boxes if (t2->type == MT_RANDOMITEM || t2->type == MT_EGGMANITEM) + { P_InstaThrust(t1, R_PointToAngle2(t2->x, t2->y, t1->x, t1->y), t2->radius/4); + return true; + } + + if (t2->player) + { + if ((t1->target == t2 || t1->target == t2->target) && (t1->threshold > 0)) + return true; + + if (t1->health <= 0 || t2->health <= 0) + return true; + + if (!P_CanPickupItem(t2->player, 2)) + return true; + + if (G_BattleGametype() && t2->player->kartstuff[k_bumper] <= 0) + { + if (t2->player->kartstuff[k_comebackmode] || t2->player->kartstuff[k_comebacktimer]) + return true; + t2->player->kartstuff[k_comebackmode] = 2; + } + else + { + K_DropItems(t2->player); //K_StripItems(t2->player); + //K_StripOther(t2->player); + t2->player->kartstuff[k_itemroulette] = 1; + t2->player->kartstuff[k_roulettetype] = 2; + } + + if (t2->player->kartstuff[k_flamedash] && t2->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + { + // Melt item + S_StartSound(t2, sfx_s3k43); + P_KillMobj(t1, t2, t2); + return true; + } + else + { + mobj_t *poof = P_SpawnMobj(t1->x, t1->y, t1->z, MT_EXPLODE); + S_StartSound(poof, t1->info->deathsound); + +#if 0 + // Eggbox snipe! + if (t1->type == MT_EGGMANITEM && t1->health > 1) + S_StartSound(t2, sfx_bsnipe); +#endif + + if (t1->target && t1->target->player) + { + if (G_RaceGametype() || t1->target->player->kartstuff[k_bumper] > 0) + t2->player->kartstuff[k_eggmanblame] = t1->target->player-players; + else + t2->player->kartstuff[k_eggmanblame] = t2->player-players; + + if (t1->target->hnext == t1) + { + P_SetTarget(&t1->target->hnext, NULL); + t1->target->player->kartstuff[k_eggmanheld] = 0; + } + } + + P_RemoveMobj(t1); + return true; + } + } - // Player collision is handled by TouchSpecial return true; } diff --git a/src/k_kart.c b/src/k_kart.c index 878120164..1cf0eb365 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -559,6 +559,8 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_grow); CV_RegisterVar(&cv_shrink); CV_RegisterVar(&cv_thundershield); + CV_RegisterVar(&cv_bubbleshield); + CV_RegisterVar(&cv_flameshield); CV_RegisterVar(&cv_hyudoro); CV_RegisterVar(&cv_pogospring); CV_RegisterVar(&cv_superring); @@ -640,30 +642,61 @@ fixed_t K_GetKartGameSpeedScalar(SINT8 value) //{ SRB2kart Roulette Code - Position Based +consvar_t *KartItemCVars[NUMKARTRESULTS-1] = +{ + &cv_sneaker, + &cv_rocketsneaker, + &cv_invincibility, + &cv_banana, + &cv_eggmanmonitor, + &cv_orbinaut, + &cv_jawz, + &cv_mine, + &cv_ballhog, + &cv_selfpropelledbomb, + &cv_grow, + &cv_shrink, + &cv_thundershield, + &cv_bubbleshield, + &cv_flameshield, + &cv_hyudoro, + &cv_pogospring, + &cv_superring, + &cv_kitchensink, + &cv_triplesneaker, + &cv_triplebanana, + &cv_decabanana, + &cv_tripleorbinaut, + &cv_quadorbinaut, + &cv_dualjawz +}; + #define NUMKARTODDS 80 // Less ugly 2D arrays -static INT32 K_KartItemOddsRace[NUMKARTRESULTS][8] = +static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = { //P-Odds 0 1 2 3 4 5 6 7 - /*Sneaker*/ { 0, 0, 4, 6, 7, 0, 0, 0 }, // Sneaker - /*Rocket Sneaker*/ { 0, 0, 0, 0, 1, 4, 5, 3 }, // Rocket Sneaker - /*Invincibility*/ { 0, 0, 0, 0, 1, 4, 6,10 }, // Invincibility - /*Banana*/ { 9, 4, 2, 1, 0, 0, 0, 0 }, // Banana - /*Eggman Monitor*/ { 3, 2, 1, 0, 0, 0, 0, 0 }, // Eggman Monitor - /*Orbinaut*/ { 7, 6, 4, 2, 0, 0, 0, 0 }, // Orbinaut + /*Sneaker*/ { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker + /*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 2, 4, 6 }, // Rocket Sneaker + /*Invincibility*/ { 0, 0, 0, 0, 1, 4, 7, 9 }, // Invincibility + /*Banana*/ { 7, 3, 2, 0, 0, 0, 0, 0 }, // Banana + /*Eggman Monitor*/ { 3, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor + /*Orbinaut*/ { 7, 4, 3, 2, 0, 0, 0, 0 }, // Orbinaut /*Jawz*/ { 0, 3, 2, 1, 1, 0, 0, 0 }, // Jawz /*Mine*/ { 0, 2, 2, 1, 0, 0, 0, 0 }, // Mine /*Ballhog*/ { 0, 0, 2, 1, 0, 0, 0, 0 }, // Ballhog /*Self-Propelled Bomb*/ { 0, 1, 2, 3, 4, 2, 2, 0 }, // Self-Propelled Bomb - /*Grow*/ { 0, 0, 0, 0, 0, 2, 5, 7 }, // Grow + /*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow /*Shrink*/ { 0, 0, 0, 0, 0, 0, 2, 0 }, // Shrink /*Thunder Shield*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Thunder Shield - /*Hyudoro*/ { 0, 0, 0, 1, 2, 1, 0, 0 }, // Hyudoro + /*Bubble Shield*/ { 0, 2, 3, 3, 1, 0, 0, 0 }, // Bubble Shield + /*Flame Shield*/ { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield + /*Hyudoro*/ { 0, 0, 0, 1, 2, 0, 0, 0 }, // Hyudoro /*Pogo Spring*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring /*Super Ring*/ { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring /*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink - /*Sneaker x3*/ { 0, 0, 0, 3, 7, 9, 2, 0 }, // Sneaker x3 + /*Sneaker x3*/ { 0, 0, 0, 2, 6,10, 5, 0 }, // Sneaker x3 /*Banana x3*/ { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 /*Banana x10*/ { 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10 /*Orbinaut x3*/ { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3 @@ -671,7 +704,7 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS][8] = /*Jawz x2*/ { 0, 0, 1, 2, 0, 0, 0, 0 } // Jawz x2 }; -static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][6] = +static INT32 K_KartItemOddsBattle[NUMKARTRESULTS-1][6] = { //P-Odds 0 1 2 3 4 5 /*Sneaker*/ { 3, 2, 2, 2, 0, 2 }, // Sneaker @@ -687,6 +720,8 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][6] = /*Grow*/ { 0, 0, 1, 2, 4, 2 }, // Grow /*Shrink*/ { 0, 0, 0, 0, 0, 0 }, // Shrink /*Thunder Shield*/ { 0, 0, 0, 0, 0, 0 }, // Thunder Shield + /*Bubble Shield*/ { 0, 0, 0, 0, 0, 0 }, // Bubble Shield + /*Flame Shield*/ { 0, 0, 0, 0, 0, 0 }, // Flame Shield /*Hyudoro*/ { 1, 1, 0, 0, 0, 0 }, // Hyudoro /*Pogo Spring*/ { 1, 1, 0, 0, 0, 0 }, // Pogo Spring /*Super Ring*/ { 0, 0, 0, 0, 0, 0 }, // Super Ring @@ -701,6 +736,17 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][6] = #define DISTVAR (2048) // Magic number distance for use with item roulette tiers +INT32 K_GetShieldFromItem(INT32 item) +{ + switch (item) + { + case KITEM_THUNDERSHIELD: return KSHIELD_THUNDER; + case KITEM_BUBBLESHIELD: return KSHIELD_BUBBLE; + case KITEM_FLAMESHIELD: return KSHIELD_FLAME; + default: return KSHIELD_NONE; + } +} + /** \brief Item Roulette for Kart \param player player @@ -768,48 +814,32 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean sp INT32 newodds; INT32 i; UINT8 pingame = 0, pexiting = 0; - boolean thunderisout = false; SINT8 first = -1, second = -1; INT32 secondist = 0; - boolean itemenabled[NUMKARTRESULTS-1] = { - cv_sneaker.value, - cv_rocketsneaker.value, - cv_invincibility.value, - cv_banana.value, - cv_eggmanmonitor.value, - cv_orbinaut.value, - cv_jawz.value, - cv_mine.value, - cv_ballhog.value, - cv_selfpropelledbomb.value, - cv_grow.value, - cv_shrink.value, - cv_thundershield.value, - cv_hyudoro.value, - cv_pogospring.value, - cv_superring.value, - cv_kitchensink.value, - cv_triplesneaker.value, - cv_triplebanana.value, - cv_decabanana.value, - cv_tripleorbinaut.value, - cv_quadorbinaut.value, - cv_dualjawz.value - }; + INT32 shieldtype = KSHIELD_NONE; I_Assert(item > KITEM_NONE); // too many off by one scenarioes. + I_Assert(KartItemCVars[NUMKARTRESULTS-2] != NULL); // Make sure this exists - if (!itemenabled[item-1] && !modeattacking) + if (!KartItemCVars[item-1]->value && !modeattacking) return 0; if (G_BattleGametype()) + { + I_Assert(pos < 6); // DO NOT allow positions past the bounds of the table newodds = K_KartItemOddsBattle[item-1][pos]; + } else + { + I_Assert(pos < 8); // Ditto newodds = K_KartItemOddsRace[item-1][pos]; + } // Base multiplication to ALL item odds to simulate fractional precision newodds *= 4; + shieldtype = K_GetShieldFromItem(item); + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator) @@ -821,18 +851,18 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean sp if (players[i].exiting) pexiting++; - if (players[i].mo) + if (shieldtype != KSHIELD_NONE && shieldtype == K_GetShieldFromItem(players[i].kartstuff[k_itemtype])) { - if (players[i].kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) - thunderisout = true; + // Don't allow more than one of each shield type at a time + return 0; + } - if (!G_BattleGametype()) - { - if (players[i].kartstuff[k_position] == 1 && first == -1) - first = i; - if (players[i].kartstuff[k_position] == 2 && second == -1) - second = i; - } + if (players[i].mo && G_RaceGametype()) + { + if (players[i].kartstuff[k_position] == 1 && first == -1) + first = i; + if (players[i].kartstuff[k_position] == 2 && second == -1) + second = i; } } @@ -881,29 +911,43 @@ static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean sp case KITEM_INVINCIBILITY: case KITEM_MINE: case KITEM_GROW: + case KITEM_BUBBLESHIELD: + case KITEM_FLAMESHIELD: if (COOLDOWNONSTART) newodds = 0; else POWERITEMODDS(newodds); break; case KITEM_SPB: - if ((indirectitemcooldown > 0) || (secondist/DISTVAR < 3) - || (first != -1 && players[first].distancetofinish > 8*DISTVAR)) // No SPB near the end of the race + if ((indirectitemcooldown > 0) || COOLDOWNONSTART + || (first != -1 && players[first].distancetofinish < 8*DISTVAR)) // No SPB near the end of the race + { newodds = 0; + } else - newodds *= min((secondist/DISTVAR)-4, 3); // POWERITEMODDS(newodds); + { + INT32 multiplier = (secondist - (5*DISTVAR)) / DISTVAR; + + if (multiplier < 0) + multiplier = 0; + if (multiplier > 3) + multiplier = 3; + + newodds *= multiplier; + } break; case KITEM_SHRINK: - if ((indirectitemcooldown > 0) || (pingame-1 <= pexiting) || COOLDOWNONSTART) + if ((indirectitemcooldown > 0) || COOLDOWNONSTART || (pingame-1 <= pexiting)) newodds = 0; else POWERITEMODDS(newodds); break; case KITEM_THUNDERSHIELD: - if (thunderisout || spbplace != -1) + if (spbplace != -1 || COOLDOWNONSTART) newodds = 0; else POWERITEMODDS(newodds); + break; case KITEM_HYUDORO: if ((hyubgone > 0) || COOLDOWNONSTART) newodds = 0; @@ -1054,7 +1098,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) if ((player->kartstuff[k_itemroulette] % 3) == 1 && P_IsDisplayPlayer(player)) { #define PLAYROULETTESND S_StartSound(NULL, sfx_itrol1 + ((player->kartstuff[k_itemroulette] / 3) % 8)) - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (player == &players[displayplayers[i]] && players[displayplayers[i]].kartstuff[k_itemroulette]) PLAYROULETTESND; @@ -1091,7 +1135,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } if (mapobjectscale != FRACUNIT) - pdis = FixedDiv(pdis, mapobjectscale); + pdis = FixedDiv(pdis * FRACUNIT, mapobjectscale) / FRACUNIT; if (franticitems) // Frantic items make the distances between everyone artifically higher, for crazier items pdis = (15 * pdis) / 14; @@ -1184,16 +1228,35 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) return; } - // SPECIAL CASE No. 4: - // Being in ring debt occasionally forces Super Ring on you if you mashed - if (mashed && player->kartstuff[k_rings] < 0 && cv_superring.value) + if (G_RaceGametype()) { - INT32 debtamount = min(20, abs(player->kartstuff[k_rings])); - if (P_RandomChance((debtamount*FRACUNIT)/20)) + // SPECIAL CASE No. 4: + // Being in ring debt occasionally forces Super Ring on you if you mashed + if (mashed && player->kartstuff[k_rings] < 0 && cv_superring.value) { - K_KartGetItemResult(player, KITEM_SUPERRING); + INT32 debtamount = min(20, abs(player->kartstuff[k_rings])); + if (P_RandomChance((debtamount*FRACUNIT)/20)) + { + K_KartGetItemResult(player, KITEM_SUPERRING); + player->karthud[khud_itemblink] = TICRATE; + player->karthud[khud_itemblinkmode] = 1; + player->kartstuff[k_itemroulette] = 0; + player->kartstuff[k_roulettetype] = 0; + if (P_IsDisplayPlayer(player)) + S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf)); + return; + } + } + + // SPECIAL CASE No. 5: + // Force SPB onto 2nd if they get too far behind + if (player->kartstuff[k_position] == 2 && pdis > (DISTVAR*8) + && spbplace == -1 && !indirectitemcooldown && !dontforcespb + && cv_selfpropelledbomb.value) + { + K_KartGetItemResult(player, KITEM_SPB); player->karthud[khud_itemblink] = TICRATE; - player->karthud[khud_itemblinkmode] = 1; + player->karthud[khud_itemblinkmode] = (mashed ? 1 : 0); player->kartstuff[k_itemroulette] = 0; player->kartstuff[k_roulettetype] = 0; if (P_IsDisplayPlayer(player)) @@ -1202,22 +1265,6 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } } - // SPECIAL CASE No. 5: - // Force SPB onto 2nd if they get too far behind - if (player->kartstuff[k_position] == 2 && pdis > (DISTVAR*6) - && spbplace == -1 && !indirectitemcooldown && !dontforcespb - && cv_selfpropelledbomb.value) - { - K_KartGetItemResult(player, KITEM_SPB); - player->karthud[khud_itemblink] = TICRATE; - player->karthud[khud_itemblinkmode] = (mashed ? 1 : 0); - player->kartstuff[k_itemroulette] = 0; - player->kartstuff[k_roulettetype] = 0; - if (P_IsDisplayPlayer(player)) - S_StartSound(NULL, (mashed ? sfx_itrolm : sfx_itrolf)); - return; - } - // NOW that we're done with all of those specialized cases, we can move onto the REAL item roulette tables. // Initializes existing spawnchance values for (i = 0; i < NUMKARTRESULTS; i++) @@ -1257,52 +1304,72 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) //{ SRB2kart p_user.c Stuff +static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against) +{ + fixed_t weight = 5*FRACUNIT; + + if (!mobj->player) + return weight; + + if (against && !P_MobjWasRemoved(against) && against->player + && ((!against->player->kartstuff[k_spinouttimer] && mobj->player->kartstuff[k_spinouttimer]) // You're in spinout + || (against->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD && mobj->player->kartstuff[k_itemtype] != KITEM_BUBBLESHIELD))) // They have a Bubble Shield + { + weight = 0; // This player does not cause any bump action + } + else + { + weight = (mobj->player->kartweight) * FRACUNIT; + if (mobj->player->speed > K_GetKartSpeed(mobj->player, false)) + weight += (mobj->player->speed - K_GetKartSpeed(mobj->player, false))/8; + if (mobj->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD) + weight += 9*FRACUNIT; + } + + return weight; +} + static fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) { - fixed_t weight = 5<type) { case MT_PLAYER: if (!mobj->player) break; - if (against->player && !against->player->kartstuff[k_spinouttimer] && mobj->player->kartstuff[k_spinouttimer]) - weight = 0; // Do not bump - else - { - weight = (mobj->player->kartweight)<player->speed > K_GetKartSpeed(mobj->player, false)) - weight += (mobj->player->speed - K_GetKartSpeed(mobj->player, false))/8; - } + weight = K_PlayerWeight(mobj, against); + break; + case MT_BUBBLESHIELD: + weight = K_PlayerWeight(mobj->target, against); break; case MT_FALLINGROCK: if (against->player) { - if (against->player->kartstuff[k_invincibilitytimer] - || against->player->kartstuff[k_growshrinktimer] > 0) + if (against->player->kartstuff[k_invincibilitytimer] || against->player->kartstuff[k_growshrinktimer] > 0) weight = 0; else - weight = (against->player->kartweight)<player) - weight = (against->player->kartweight)<player) - weight = (against->player->kartweight+3)<scale); } // This kind of wipeout happens with no rings -- doesn't remove a bumper, has no invulnerability, and is much shorter. @@ -1465,7 +1532,10 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) } // Do the bump fx when we've CONFIRMED we can bump. - S_StartSound(mobj1, sfx_s3k49); + if ((mobj1->player && mobj1->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD) || (mobj2->player && mobj2->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD)) + S_StartSound(mobj1, sfx_s3k44); + else + S_StartSound(mobj1, sfx_s3k49); fx = P_SpawnMobj(mobj1->x/2 + mobj2->x/2, mobj1->y/2 + mobj2->y/2, mobj1->z/2 + mobj2->z/2, MT_BUMP); if (mobj1->eflags & MFE_VERTICALFLIP) @@ -1489,7 +1559,8 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj1->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj1->player->kartstuff[k_spinouttimer]); //mobj1->player->kartstuff[k_spinouttype] = 1; // Enforce type } - else if (mobj2->player) // Player VS player bumping only + else if (mobj2->player // Player VS player bumping only + && (K_GetShieldFromItem(mobj1->player->kartstuff[k_itemtype]) == KSHIELD_NONE)) // Ignore for shields { if (mobj1->player->kartstuff[k_rings] <= 0) { @@ -1513,7 +1584,8 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid) mobj2->player->kartstuff[k_spinouttimer] = max(wipeoutslowtime+1, mobj2->player->kartstuff[k_spinouttimer]); //mobj2->player->kartstuff[k_spinouttype] = 1; // Enforce type } - else if (mobj1->player) // Player VS player bumping only + else if (mobj1->player // Player VS player bumping only + && (K_GetShieldFromItem(mobj2->player->kartstuff[k_itemtype]) == KSHIELD_NONE)) // Ignore for shields { if (mobj2->player->kartstuff[k_rings] <= 0) { @@ -1587,11 +1659,16 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur SKINCOLOR_TAFFY }; fixed_t minimumdist = FixedMul(RING_DIST>>1, player->mo->scale); - UINT8 c = FixedMul(CHAOTIXBANDCOLORS<> FRACBITS; UINT8 n = CHAOTIXBANDLEN; UINT8 offset = ((leveltime / 3) % 3); fixed_t stepx, stepy, stepz; fixed_t curx, cury, curz; + UINT8 c; + + if (maxdist == 0) + c = 0; + else + c = FixedMul(CHAOTIXBANDCOLORS<> FRACBITS; stepx = (victim->mo->x - player->mo->x) / CHAOTIXBANDLEN; stepy = (victim->mo->y - player->mo->y) / CHAOTIXBANDLEN; @@ -1643,13 +1720,21 @@ static void K_UpdateDraft(player_t *player) UINT8 leniency; UINT8 i; - // Distance you have to be to draft. If you're still accelerating, then this distance is lessened. - // This distance biases toward low weight! (min weight gets 4096 units, max weight gets 3072 units) - // This distance is also scaled based on game speed. - draftdistance = (3072 + (128 * (9 - player->kartweight))) * player->mo->scale; - if (player->speed < topspd) - draftdistance = FixedMul(draftdistance, FixedDiv(player->speed, topspd)); - draftdistance = FixedMul(draftdistance, K_GetKartGameSpeedScalar(gamespeed)); + if (player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + { + // Flame Shield gets infinite draft distance as its passive effect. + draftdistance = 0; + } + else + { + // Distance you have to be to draft. If you're still accelerating, then this distance is lessened. + // This distance biases toward low weight! (min weight gets 4096 units, max weight gets 3072 units) + // This distance is also scaled based on game speed. + draftdistance = (3072 + (128 * (9 - player->kartweight))) * player->mo->scale; + if (player->speed < topspd) + draftdistance = FixedMul(draftdistance, FixedDiv(player->speed, topspd)); + draftdistance = FixedMul(draftdistance, K_GetKartGameSpeedScalar(gamespeed)); + } // On the contrary, the leniency period biases toward high weight. // (See also: the leniency variable in K_SpawnDraftDust) @@ -1709,7 +1794,7 @@ static void K_UpdateDraft(player_t *player) continue; // Not close enough to draft. - if (dist > draftdistance) + if (dist > draftdistance && draftdistance > 0) continue; #endif @@ -2463,6 +2548,12 @@ static void K_GetKartBoostPower(player_t *player) if (player->kartstuff[k_invincibilitytimer]) // Invincibility ADDBOOST((3*FRACUNIT)/8, 3*FRACUNIT); // + 37.5% top speed, + 300% acceleration + if (player->kartstuff[k_flamedash]) // Flame Shield dash + { + fixed_t dashval = ((player->kartstuff[k_flamedash]<kartstuff[k_startboost]) // Startup Boost ADDBOOST(FRACUNIT/4, 6*FRACUNIT); // + 25% top speed, + 600% acceleration @@ -2472,13 +2563,8 @@ static void K_GetKartBoostPower(player_t *player) if (player->kartstuff[k_ringboost]) // Ring Boost ADDBOOST(FRACUNIT/5, 4*FRACUNIT); // + 20% top speed, + 400% acceleration - if (player->kartstuff[k_growshrinktimer] > 0) // Grow - { - // Grow's design is weird with booster stacking. - // We'll see how to replace its design BEFORE v2 gets released. - speedboost += (FRACUNIT/5); // + 20% - //numboosts++; // Don't add any boost afterimages to Grow - } + if (player->kartstuff[k_eggmanexplode]) // Ready-to-explode + ADDBOOST(FRACUNIT/5, FRACUNIT); // + 20% top speed, + 100% acceleration if (player->kartstuff[k_draftpower] > 0) // Drafting { @@ -2765,7 +2851,6 @@ static void K_RemoveGrowShrink(player_t *player) } player->kartstuff[k_growshrinktimer] = 0; - player->kartstuff[k_growcancel] = -1; P_RestoreMusic(player); } @@ -3290,7 +3375,6 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I th = P_SpawnMobj(x, y, z, type); th->flags2 |= flags2; - th->threshold = 10; if (th->info->seesound) @@ -3298,6 +3382,9 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I P_SetTarget(&th->target, source); + P_SetScale(th, source->scale); + th->destscale = source->destscale; + if (P_IsObjectOnGround(source)) { // floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn @@ -3348,16 +3435,25 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I case MT_SPB: th->movefactor = finalspeed; break; + case MT_BUBBLESHIELDTRAP: + P_SetScale(th, ((5*th->destscale)>>2)*4); + th->destscale = (5*th->destscale)>>2; + S_StartSound(th, sfx_s3kbfl); + S_StartSound(th, sfx_cdfm35); + break; default: break; } - x = x + P_ReturnThrustX(source, an, source->radius + th->radius); - y = y + P_ReturnThrustY(source, an, source->radius + th->radius); - throwmo = P_SpawnMobj(x, y, z, MT_FIREDITEM); - throwmo->movecount = 1; - throwmo->movedir = source->angle - an; - P_SetTarget(&throwmo->target, source); + if (type != MT_BUBBLESHIELDTRAP) + { + x = x + P_ReturnThrustX(source, an, source->radius + th->radius); + y = y + P_ReturnThrustY(source, an, source->radius + th->radius); + throwmo = P_SpawnMobj(x, y, z, MT_FIREDITEM); + throwmo->movecount = 1; + throwmo->movedir = source->angle - an; + P_SetTarget(&throwmo->target, source); + } return NULL; } @@ -4057,8 +4153,16 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map { mobj_t *lasttrail = K_FindLastTrailMobj(player); - if (lasttrail) + if (mapthing == MT_BUBBLESHIELDTRAP) // Drop directly on top of you. { + newangle = player->mo->angle; + newx = player->mo->x + player->mo->momx; + newy = player->mo->y + player->mo->momy; + newz = player->mo->z; + } + else if (lasttrail) + { + newangle = lasttrail->angle; newx = lasttrail->x; newy = lasttrail->y; newz = lasttrail->z; @@ -4081,6 +4185,9 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map mo->threshold = 10; P_SetTarget(&mo->target, player->mo); + P_SetScale(mo, player->mo->scale); + mo->destscale = player->mo->destscale; + if (P_IsObjectOnGround(player->mo)) { // floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn @@ -4110,6 +4217,12 @@ static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t map if (mapthing == MT_SSMINE) mo->extravalue1 = 49; // Pads the start-up length from 21 frames to a full 2 seconds + else if (mapthing == MT_BUBBLESHIELDTRAP) + { + P_SetScale(mo, ((5*mo->destscale)>>2)*4); + mo->destscale = (5*mo->destscale)>>2; + S_StartSound(mo, sfx_s3kbfl); + } } } @@ -4169,7 +4282,6 @@ static void K_DoThunderShield(player_t *player) angle_t an; S_StartSound(player->mo, sfx_zio3); - //player->kartstuff[k_thunderanim] = 35; P_NukeEnemies(player->mo, player->mo, RING_DIST/4); // spawn vertical bolt @@ -4212,6 +4324,27 @@ static void K_DoThunderShield(player_t *player) #undef THUNDERRADIUS +static void K_FlameDashLeftoverSmoke(mobj_t *src) +{ + UINT8 i; + + for (i = 0; i < 2; i++) + { + mobj_t *smoke = P_SpawnMobj(src->x, src->y, src->z+(8<scale); + smoke->destscale = 3*src->scale/2; + smoke->scalespeed = src->scale/12; + + smoke->momx = 3*src->momx/4; + smoke->momy = 3*src->momy/4; + smoke->momz = 3*src->momz/4; + + P_Thrust(smoke, src->angle + FixedAngle(P_RandomRange(135, 225)<scale); + smoke->momz += P_RandomRange(0, 4) * src->scale; + } +} + static void K_DoHyudoroSteal(player_t *player) { INT32 i, numplayers = 0; @@ -4219,6 +4352,10 @@ static void K_DoHyudoroSteal(player_t *player) INT32 stealplayer = -1; // The player that's getting stolen from INT32 prandom = 0; boolean sink = P_RandomChance(FRACUNIT/64); + INT32 hyu = hyudorotime; + + if (G_RaceGametype()) + hyu *= 2; // double in race for (i = 0; i < MAXPLAYERS; i++) { @@ -4245,7 +4382,7 @@ static void K_DoHyudoroSteal(player_t *player) if (sink && numplayers > 0 && cv_kitchensink.value) // BEHOLD THE KITCHEN SINK { - player->kartstuff[k_hyudorotimer] = hyudorotime; + player->kartstuff[k_hyudorotimer] = hyu; player->kartstuff[k_stealingtimer] = stealtime; player->kartstuff[k_itemtype] = KITEM_KITCHENSINK; @@ -4255,7 +4392,7 @@ static void K_DoHyudoroSteal(player_t *player) } else if ((G_RaceGametype() && player->kartstuff[k_position] == 1) || numplayers == 0) // No-one can be stolen from? Oh well... { - player->kartstuff[k_hyudorotimer] = hyudorotime; + player->kartstuff[k_hyudorotimer] = hyu; player->kartstuff[k_stealingtimer] = stealtime; return; } @@ -4270,7 +4407,7 @@ static void K_DoHyudoroSteal(player_t *player) if (stealplayer > -1) // Now here's where we do the stealing, has to be done here because we still know the player we're stealing from { - player->kartstuff[k_hyudorotimer] = hyudorotime; + player->kartstuff[k_hyudorotimer] = hyu; player->kartstuff[k_stealingtimer] = stealtime; players[stealplayer].kartstuff[k_stolentimer] = stealtime; @@ -4282,7 +4419,7 @@ static void K_DoHyudoroSteal(player_t *player) players[stealplayer].kartstuff[k_itemamount] = 0; players[stealplayer].kartstuff[k_itemheld] = 0; - if (P_IsDisplayPlayer(&players[stealplayer]) && !splitscreen) + if (P_IsDisplayPlayer(&players[stealplayer]) && !r_splitscreen) S_StartSound(NULL, sfx_s3k92); } } @@ -4530,12 +4667,24 @@ void K_DropHnextList(player_t *player) flip = P_MobjFlip(player->mo); ponground = P_IsObjectOnGround(player->mo); - if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD && player->kartstuff[k_itemamount]) + if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) { K_DoThunderShield(player); - player->kartstuff[k_itemamount] = 0; player->kartstuff[k_itemtype] = KITEM_NONE; - player->kartstuff[k_curshield] = 0; + player->kartstuff[k_itemamount] = 0; + player->kartstuff[k_curshield] = KSHIELD_NONE; + } + else if (player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD) + { + player->kartstuff[k_itemtype] = KITEM_NONE; + player->kartstuff[k_itemamount] = 0; + player->kartstuff[k_curshield] = KSHIELD_NONE; + } + else if (player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD) + { + player->kartstuff[k_itemtype] = KITEM_NONE; + player->kartstuff[k_itemamount] = 0; + player->kartstuff[k_curshield] = KSHIELD_NONE; } nextwork = work->hnext; @@ -4657,9 +4806,12 @@ void K_DropHnextList(player_t *player) // For getting EXTRA hit! void K_DropItems(player_t *player) { - boolean thunderhack = (player->kartstuff[k_curshield] && player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD); + INT32 shieldhack = 0; - if (thunderhack) + if (player->kartstuff[k_curshield]) + shieldhack = K_GetShieldFromItem(player->kartstuff[k_itemtype]); + + if (shieldhack) player->kartstuff[k_itemtype] = KITEM_NONE; K_DropHnextList(player); @@ -4678,7 +4830,13 @@ void K_DropItems(player_t *player) if (drop->eflags & MFE_UNDERWATER) drop->momz = (117 * drop->momz) / 200; - drop->threshold = (thunderhack ? KITEM_THUNDERSHIELD : player->kartstuff[k_itemtype]); + switch (shieldhack) + { + case KSHIELD_THUNDER: drop->threshold = KITEM_THUNDERSHIELD; break; + case KSHIELD_BUBBLE: drop->threshold = KITEM_BUBBLESHIELD; break; + case KSHIELD_FLAME: drop->threshold = KITEM_FLAMESHIELD; break; + default: drop->threshold = player->kartstuff[k_itemtype]; break; + } drop->movecount = player->kartstuff[k_itemamount]; drop->flags |= MF_NOCLIPTHING; @@ -5382,17 +5540,17 @@ static void K_UpdateInvincibilitySounds(player_t *player) { if (cv_kartinvinsfx.value) { - if (player->kartstuff[k_growshrinktimer] > 0) // Prioritize Grow - sfxnum = sfx_alarmg; - else if (player->kartstuff[k_invincibilitytimer] > 0) + if (player->kartstuff[k_invincibilitytimer] > 0) // Prioritize invincibility sfxnum = sfx_alarmi; + else if (player->kartstuff[k_growshrinktimer] > 0) + sfxnum = sfx_alarmg; } else { - if (player->kartstuff[k_growshrinktimer] > 0) - sfxnum = sfx_kgrow; - else if (player->kartstuff[k_invincibilitytimer] > 0) + if (player->kartstuff[k_invincibilitytimer] > 0) sfxnum = sfx_kinvnc; + else if (player->kartstuff[k_growshrinktimer] > 0) + sfxnum = sfx_kgrow; } } @@ -5514,6 +5672,68 @@ void K_KartPlayerHUDUpdate(player_t *player) #undef RINGANIM_DELAYMAX +// SRB2Kart: blockmap iterate for attraction shield users +static mobj_t *attractmo; +static fixed_t attractdist; +static inline boolean PIT_AttractingRings(mobj_t *thing) +{ + if (!attractmo || P_MobjWasRemoved(attractmo)) + return false; + + if (!attractmo->player) + return false; // not a player + + if (thing->health <= 0 || !thing) + return true; // dead + + if (thing->type != MT_RING && thing->type != MT_FLINGRING) + return true; // not a ring + + if (thing->extravalue1) + return true; // in special ring animation + + if (thing->cusval) + return true; // already attracted + + // see if it went over / under + if (attractmo->z - (attractdist>>2) > thing->z + thing->height) + return true; // overhead + if (attractmo->z + attractmo->height + (attractdist>>2) < thing->z) + return true; // underneath + + if (P_AproxDistance(attractmo->x - thing->x, attractmo->y - thing->y) < attractdist) + return true; // Too far away + + // set target + P_SetTarget(&thing->tracer, attractmo); + // flag to show it's been attracted once before + thing->cusval = 1; + return true; // find other rings +} + +/** Looks for rings near a player in the blockmap. + * + * \param pmo Player object looking for rings to attract + * \sa A_AttractChase + */ +static void K_LookForRings(mobj_t *pmo) +{ + INT32 bx, by, xl, xh, yl, yh; + attractdist = FixedMul(RING_DIST, pmo->scale)>>2; + + // Use blockmap to check for nearby rings + yh = (unsigned)(pmo->y + attractdist - bmaporgy)>>MAPBLOCKSHIFT; + yl = (unsigned)(pmo->y - attractdist - bmaporgy)>>MAPBLOCKSHIFT; + xh = (unsigned)(pmo->x + attractdist - bmaporgx)>>MAPBLOCKSHIFT; + xl = (unsigned)(pmo->x - attractdist - bmaporgx)>>MAPBLOCKSHIFT; + + attractmo = pmo; + + for (by = yl; by <= yh; by++) + for (bx = xl; bx <= xh; bx++) + P_BlockThingsIterator(bx, by, PIT_AttractingRings); +} + /** \brief Decreases various kart timers and powers per frame. Called in P_PlayerThink in p_user.c \param player player object passed from P_PlayerThink @@ -5551,17 +5771,27 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { // Speed lines if (EITHERSNEAKER(player) || player->kartstuff[k_ringboost] - || player->kartstuff[k_driftboost] || player->kartstuff[k_startboost]) + || player->kartstuff[k_driftboost] || player->kartstuff[k_startboost] + || player->kartstuff[k_eggmanexplode]) { mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(-36,36) * player->mo->scale), player->mo->y + (P_RandomRange(-36,36) * player->mo->scale), player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale), MT_FASTLINE); + fast->angle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); fast->momx = 3*player->mo->momx/4; fast->momy = 3*player->mo->momy/4; fast->momz = 3*player->mo->momz/4; + K_MatchGenericExtraFlags(fast, player->mo); + + // Make it red when you have the eggman speed boost + if (player->kartstuff[k_eggmanexplode]) + { + fast->color = SKINCOLOR_RED; + fast->colorized = true; + } } if (player->kartstuff[k_numboosts] > 0) // Boosting after images @@ -5710,6 +5940,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->mo->colorized = false; } + if (player->kartstuff[k_itemtype] == KITEM_NONE) + player->kartstuff[k_holdready] = 0; + // DKR style camera for boosting if (player->karthud[khud_boostcam] != 0 || player->karthud[khud_destboostcam] != 0) { @@ -5796,6 +6029,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->kartstuff[k_levelbooster]) player->kartstuff[k_levelbooster]--; + if (player->kartstuff[k_flamedash]) + player->kartstuff[k_flamedash]--; + if (EITHERSNEAKER(player) && player->kartstuff[k_wipeoutslow] > 0 && player->kartstuff[k_wipeoutslow] < wipeoutslowtime+1) player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1; @@ -5930,6 +6166,29 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) } } + if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + { + if (RINGTOTAL(player) < 20 && !player->kartstuff[k_ringlock]) + K_LookForRings(player->mo); + } + + if (player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD) + { + if (player->kartstuff[k_bubblecool]) + player->kartstuff[k_bubblecool]--; + } + else + { + player->kartstuff[k_bubbleblowup] = 0; + player->kartstuff[k_bubblecool] = 0; + } + + if (player->kartstuff[k_itemtype] != KITEM_FLAMESHIELD || player->exiting) + { + if (player->kartstuff[k_flamedash]) + K_FlameDashLeftoverSmoke(player->mo); + } + if (player->kartstuff[k_comebacktimer]) player->kartstuff[k_comebackmode] = 0; @@ -6443,7 +6702,7 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) turnvalue = FixedMul(turnvalue, adjustangle); // Weight has a small effect on turning if (EITHERSNEAKER(player) || player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_growshrinktimer] > 0) - turnvalue = FixedMul(turnvalue, FixedDiv(5*FRACUNIT, 4*FRACUNIT)); + turnvalue = FixedMul(turnvalue, (5*FRACUNIT)/4); return turnvalue; } @@ -6783,8 +7042,7 @@ void K_StripItems(player_t *player) player->kartstuff[k_stealingtimer] = 0; player->kartstuff[k_stolentimer] = 0; - player->kartstuff[k_curshield] = 0; - //player->kartstuff[k_thunderanim] = 0; + player->kartstuff[k_curshield] = KSHIELD_NONE; player->kartstuff[k_bananadrag] = 0; player->kartstuff[k_sadtimer] = 0; @@ -6807,66 +7065,32 @@ void K_StripOther(player_t *player) } } -// SRB2Kart: blockmap iterate for attraction shield users -static mobj_t *attractmo; -static fixed_t attractdist; -static inline boolean PIT_AttractingRings(mobj_t *thing) +static INT32 K_FlameShieldMax(player_t *player) { - if (!attractmo || P_MobjWasRemoved(attractmo)) - return false; + UINT32 disttofinish = 0; + UINT8 numplayers = 0; + UINT8 i; - if (!attractmo->player) - return false; // not a player + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator) + numplayers++; + if (players[i].kartstuff[k_position] == 1) + disttofinish = players[i].distancetofinish; + } - if (thing->health <= 0 || !thing) - return true; // dead + if (numplayers <= 1) + { + return 16; // max when alone, for testing + } + else if (player->kartstuff[k_position] == 1) + { + return 0; // minimum for first + } - if (thing->type != MT_RING && thing->type != MT_FLINGRING) - return true; // not a ring + disttofinish = player->distancetofinish - disttofinish; - if (thing->extravalue1) - return true; // in special ring animation - - if (thing->cusval) - return true; // already attracted - - // see if it went over / under - if (attractmo->z - (attractdist>>2) > thing->z + thing->height) - return true; // overhead - if (attractmo->z + attractmo->height + (attractdist>>2) < thing->z) - return true; // underneath - - if (P_AproxDistance(attractmo->x - thing->x, attractmo->y - thing->y) < attractdist) - return true; // Too far away - - // set target - P_SetTarget(&thing->tracer, attractmo); - // flag to show it's been attracted once before - thing->cusval = 1; - return true; // find other rings -} - -/** Looks for rings near a player in the blockmap. - * - * \param pmo Player object looking for rings to attract - * \sa A_AttractChase - */ -static void K_LookForRings(mobj_t *pmo) -{ - INT32 bx, by, xl, xh, yl, yh; - attractdist = FixedMul(RING_DIST, pmo->scale)>>2; - - // Use blockmap to check for nearby rings - yh = (unsigned)(pmo->y + attractdist - bmaporgy)>>MAPBLOCKSHIFT; - yl = (unsigned)(pmo->y - attractdist - bmaporgy)>>MAPBLOCKSHIFT; - xh = (unsigned)(pmo->x + attractdist - bmaporgx)>>MAPBLOCKSHIFT; - xl = (unsigned)(pmo->x - attractdist - bmaporgx)>>MAPBLOCKSHIFT; - - attractmo = pmo; - - for (by = yl; by <= yh; by++) - for (bx = xl; bx <= xh; bx++) - P_BlockThingsIterator(bx, by, PIT_AttractingRings); + return min(16, 1 + (disttofinish / DISTVAR)); } // @@ -6906,7 +7130,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground) && NO_HYUDORO && !(HOLDING_ITEM || player->kartstuff[k_itemamount] || player->kartstuff[k_itemroulette] - || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_rocketsneakertimer] || player->kartstuff[k_eggmanexplode])) player->kartstuff[k_userings] = 1; @@ -7004,28 +7227,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->kartstuff[k_rocketsneakertimer] = 1; } } - // Grow Canceling - else if (player->kartstuff[k_growshrinktimer] > 0) - { - if (player->kartstuff[k_growcancel] >= 0) - { - if (cmd->buttons & BT_ATTACK) - { - player->kartstuff[k_growcancel]++; - if (player->kartstuff[k_growcancel] > 26) - K_RemoveGrowShrink(player); - } - else - player->kartstuff[k_growcancel] = 0; - } - else - { - if ((cmd->buttons & BT_ATTACK) || (player->pflags & PF_ATTACKDOWN)) - player->kartstuff[k_growcancel] = -1; - else - player->kartstuff[k_growcancel] = 0; - } - } else if (player->kartstuff[k_itemamount] <= 0) { player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0; @@ -7277,8 +7478,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } break; case KITEM_GROW: - if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO - && player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { if (player->kartstuff[k_growshrinktimer] < 0) // If you're shrunk, then "grow" will just make you normal again. K_RemoveGrowShrink(player); @@ -7307,14 +7507,15 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } break; case KITEM_THUNDERSHIELD: - if (player->kartstuff[k_curshield] != 1) + if (player->kartstuff[k_curshield] != KSHIELD_THUNDER) { mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD); P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); P_SetTarget(&shield->target, player->mo); - S_StartSound(shield, sfx_s3k41); - player->kartstuff[k_curshield] = 1; + S_StartSound(player->mo, sfx_s3k41); + player->kartstuff[k_curshield] = KSHIELD_THUNDER; } + if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { K_DoThunderShield(player); @@ -7322,6 +7523,126 @@ void K_MoveKartPlayer(player_t *player, boolean onground) K_PlayAttackTaunt(player->mo); } break; + case KITEM_BUBBLESHIELD: + if (player->kartstuff[k_curshield] != KSHIELD_BUBBLE) + { + mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BUBBLESHIELD); + P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); + P_SetTarget(&shield->target, player->mo); + S_StartSound(player->mo, sfx_s3k3f); + player->kartstuff[k_curshield] = KSHIELD_BUBBLE; + } + + if (!HOLDING_ITEM && NO_HYUDORO) + { + if ((cmd->buttons & BT_ATTACK) && player->kartstuff[k_holdready]) + { + if (player->kartstuff[k_bubbleblowup] == 0) + S_StartSound(player->mo, sfx_s3k75); + + player->kartstuff[k_bubbleblowup]++; + player->kartstuff[k_bubblecool] = player->kartstuff[k_bubbleblowup]*4; + + if (player->kartstuff[k_bubbleblowup] > bubbletime*2) + { + K_ThrowKartItem(player, (player->kartstuff[k_throwdir] > 0), MT_BUBBLESHIELDTRAP, -1, 0); + K_PlayAttackTaunt(player->mo); + player->kartstuff[k_bubbleblowup] = 0; + player->kartstuff[k_bubblecool] = 0; + player->kartstuff[k_holdready] = 0; + player->kartstuff[k_itemamount]--; + } + } + else + { + if (player->kartstuff[k_bubbleblowup] > bubbletime) + player->kartstuff[k_bubbleblowup] = bubbletime; + + if (player->kartstuff[k_bubbleblowup]) + player->kartstuff[k_bubbleblowup]--; + + player->kartstuff[k_holdready] = (player->kartstuff[k_bubblecool] ? 0 : 1); + } + } + break; + case KITEM_FLAMESHIELD: + if (player->kartstuff[k_curshield] != KSHIELD_FLAME) + { + mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_FLAMESHIELD); + P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2)); + P_SetTarget(&shield->target, player->mo); + S_StartSound(player->mo, sfx_s3k3e); + player->kartstuff[k_curshield] = KSHIELD_FLAME; + } + + if (!HOLDING_ITEM && NO_HYUDORO) + { + INT32 destlen = K_FlameShieldMax(player); + INT32 flamemax = 0; + + if (player->kartstuff[k_flamelength] < destlen) + player->kartstuff[k_flamelength]++; // Can always go up! + + flamemax = player->kartstuff[k_flamelength] * flameseg; + if (flamemax > 0) + flamemax += TICRATE; // leniency period + + if ((cmd->buttons & BT_ATTACK) && player->kartstuff[k_holdready]) + { + if (player->kartstuff[k_flamemeter] < 0) + player->kartstuff[k_flamemeter] = 0; + + if (player->kartstuff[k_flamedash] == 0) + { + S_StartSound(player->mo, sfx_s3k43); + K_PlayBoostTaunt(player->mo); + } + + player->kartstuff[k_flamedash] += 2; + player->kartstuff[k_flamemeter] += 2; + + if (!onground) + { + P_Thrust( + player->mo, R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy), + FixedMul(player->mo->scale, K_GetKartGameSpeedScalar(gamespeed)) + ); + } + + if (player->kartstuff[k_flamemeter] > flamemax) + { + P_Thrust( + player->mo, player->mo->angle, + FixedMul((50*player->mo->scale), K_GetKartGameSpeedScalar(gamespeed)) + ); + + player->kartstuff[k_flamemeter] = 0; + player->kartstuff[k_flamelength] = 0; + player->kartstuff[k_holdready] = 0; + player->kartstuff[k_itemamount]--; + } + } + else + { + player->kartstuff[k_holdready] = 1; + + if (player->kartstuff[k_flamemeter] > 0) + player->kartstuff[k_flamemeter]--; + + if (player->kartstuff[k_flamelength] > destlen) + { + player->kartstuff[k_flamelength]--; // Can ONLY go down if you're not using it + + flamemax = player->kartstuff[k_flamelength] * flameseg; + if (flamemax > 0) + flamemax += TICRATE; // leniency period + } + + if (player->kartstuff[k_flamemeter] > flamemax) + player->kartstuff[k_flamemeter] = flamemax; + } + } + break; case KITEM_HYUDORO: if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { @@ -7394,20 +7715,18 @@ void K_MoveKartPlayer(player_t *player, boolean onground) player->kartstuff[k_itemtype] = KITEM_NONE; } + if (K_GetShieldFromItem(player->kartstuff[k_itemtype]) == KSHIELD_NONE) + { + player->kartstuff[k_curshield] = KSHIELD_NONE; // RESET shield type + player->kartstuff[k_bubbleblowup] = 0; + player->kartstuff[k_bubblecool] = 0; + player->kartstuff[k_flamelength] = 0; + player->kartstuff[k_flamemeter] = 0; + } + if (spbplace == -1 || player->kartstuff[k_position] != spbplace) player->kartstuff[k_ringlock] = 0; // reset ring lock - if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) - { - if ((player->kartstuff[k_rings]+player->kartstuff[k_pickuprings]) < 20 && !player->kartstuff[k_ringlock]) - K_LookForRings(player->mo); - } - else - player->kartstuff[k_curshield] = 0; - - if (player->kartstuff[k_growshrinktimer] <= 0) - player->kartstuff[k_growcancel] = -1; - if (player->kartstuff[k_itemtype] == KITEM_SPB || player->kartstuff[k_itemtype] == KITEM_SHRINK || player->kartstuff[k_growshrinktimer] < 0) @@ -7415,20 +7734,25 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_hyudorotimer] > 0) { - if (splitscreen) + INT32 hyu = hyudorotime; + + if (G_RaceGametype()) + hyu *= 2; // double in race + + if (r_splitscreen) { if (leveltime & 1) player->mo->flags2 |= MF2_DONTDRAW; else player->mo->flags2 &= ~MF2_DONTDRAW; - if (player->kartstuff[k_hyudorotimer] >= (1*TICRATE/2) && player->kartstuff[k_hyudorotimer] <= hyudorotime-(1*TICRATE/2)) + if (player->kartstuff[k_hyudorotimer] >= (TICRATE/2) && player->kartstuff[k_hyudorotimer] <= hyu-(TICRATE/2)) { if (player == &players[displayplayers[1]]) player->mo->eflags |= MFE_DRAWONLYFORP2; - else if (player == &players[displayplayers[2]] && splitscreen > 1) + else if (player == &players[displayplayers[2]] && r_splitscreen > 1) player->mo->eflags |= MFE_DRAWONLYFORP3; - else if (player == &players[displayplayers[3]] && splitscreen > 2) + else if (player == &players[displayplayers[3]] && r_splitscreen > 2) player->mo->eflags |= MFE_DRAWONLYFORP4; else if (player == &players[displayplayers[0]]) player->mo->eflags |= MFE_DRAWONLYFORP1; @@ -7441,7 +7765,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else { if (P_IsDisplayPlayer(player) - || (!P_IsDisplayPlayer(player) && (player->kartstuff[k_hyudorotimer] < (1*TICRATE/2) || player->kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2)))) + || (!P_IsDisplayPlayer(player) && (player->kartstuff[k_hyudorotimer] < (TICRATE/2) || player->kartstuff[k_hyudorotimer] > hyu-(TICRATE/2)))) { if (leveltime & 1) player->mo->flags2 |= MF2_DONTDRAW; @@ -7546,7 +7870,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } // Play the starting countdown sounds - if (player == &players[displayplayers[0]]) // Don't play louder in splitscreen + if (player == &players[g_localplayers[0]]) // Don't play louder in splitscreen { if ((leveltime == starttime-(3*TICRATE)) || (leveltime == starttime-(2*TICRATE)) || (leveltime == starttime-TICRATE)) S_StartSound(NULL, sfx_s3ka7); @@ -7803,6 +8127,8 @@ static patch_t *kp_selfpropelledbomb[2]; static patch_t *kp_grow[2]; static patch_t *kp_shrink[2]; static patch_t *kp_thundershield[2]; +static patch_t *kp_bubbleshield[2]; +static patch_t *kp_flameshield[2]; static patch_t *kp_hyudoro[2]; static patch_t *kp_pogospring[2]; static patch_t *kp_kitchensink[2]; @@ -7812,6 +8138,9 @@ static patch_t *kp_check[6]; static patch_t *kp_eggnum[4]; +static patch_t *kp_flameshieldmeter[104][2]; +static patch_t *kp_flameshieldmeter_bg[16][2]; + static patch_t *kp_fpview[3]; static patch_t *kp_inputwheel[5]; @@ -8018,11 +8347,30 @@ void K_LoadKartHUDGraphics(void) kp_grow[0] = W_CachePatchName("K_ITGROW", PU_HUDGFX); kp_shrink[0] = W_CachePatchName("K_ITSHRK", PU_HUDGFX); kp_thundershield[0] = W_CachePatchName("K_ITTHNS", PU_HUDGFX); + kp_bubbleshield[0] = W_CachePatchName("K_ITBUBS", PU_HUDGFX); + kp_flameshield[0] = W_CachePatchName("K_ITFLMS", PU_HUDGFX); kp_hyudoro[0] = W_CachePatchName("K_ITHYUD", PU_HUDGFX); kp_pogospring[0] = W_CachePatchName("K_ITPOGO", PU_HUDGFX); kp_kitchensink[0] = W_CachePatchName("K_ITSINK", PU_HUDGFX); kp_sadface[0] = W_CachePatchName("K_ITSAD", PU_HUDGFX); + sprintf(buffer, "FSMFGxxx"); + for (i = 0; i < 104; i++) + { + buffer[5] = '0'+((i+1)/100); + buffer[6] = '0'+(((i+1)/10)%10); + buffer[7] = '0'+((i+1)%10); + kp_flameshieldmeter[i][0] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + + sprintf(buffer, "FSMBG0xx"); + for (i = 0; i < 16; i++) + { + buffer[6] = '0'+((i+1)/10); + buffer[7] = '0'+((i+1)%10); + kp_flameshieldmeter_bg[i][0] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + // Splitscreen kp_itembg[2] = W_CachePatchName("K_ISBG", PU_HUDGFX); kp_itembg[3] = W_CachePatchName("K_ISBGD", PU_HUDGFX); @@ -8048,11 +8396,30 @@ void K_LoadKartHUDGraphics(void) kp_grow[1] = W_CachePatchName("K_ISGROW", PU_HUDGFX); kp_shrink[1] = W_CachePatchName("K_ISSHRK", PU_HUDGFX); kp_thundershield[1] = W_CachePatchName("K_ISTHNS", PU_HUDGFX); + kp_bubbleshield[1] = W_CachePatchName("K_ISBUBS", PU_HUDGFX); + kp_flameshield[1] = W_CachePatchName("K_ISFLMS", PU_HUDGFX); kp_hyudoro[1] = W_CachePatchName("K_ISHYUD", PU_HUDGFX); kp_pogospring[1] = W_CachePatchName("K_ISPOGO", PU_HUDGFX); kp_kitchensink[1] = W_CachePatchName("K_ISSINK", PU_HUDGFX); kp_sadface[1] = W_CachePatchName("K_ISSAD", PU_HUDGFX); + sprintf(buffer, "FSMFSxxx"); + for (i = 0; i < 104; i++) + { + buffer[5] = '0'+((i+1)/100); + buffer[6] = '0'+(((i+1)/10)%10); + buffer[7] = '0'+((i+1)%10); + kp_flameshieldmeter[i][1] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + + sprintf(buffer, "FSMBS0xx"); + for (i = 0; i < 16; i++) + { + buffer[6] = '0'+((i+1)/10); + buffer[7] = '0'+((i+1)%10); + kp_flameshieldmeter_bg[i][1] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX); + } + // CHECK indicators sprintf(buffer, "K_CHECKx"); for (i = 0; i < 6; i++) @@ -8185,6 +8552,10 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny) return (tiny ? "K_ISSHRK" : "K_ITSHRK"); case KITEM_THUNDERSHIELD: return (tiny ? "K_ISTHNS" : "K_ITTHNS"); + case KITEM_BUBBLESHIELD: + return (tiny ? "K_ISBUBS" : "K_ITBUBS"); + case KITEM_FLAMESHIELD: + return (tiny ? "K_ISFLMS" : "K_ITFLMS"); case KITEM_HYUDORO: return (tiny ? "K_ISHYUD" : "K_ITHYUD"); case KITEM_POGOSPRING: @@ -8284,7 +8655,7 @@ static void K_initKartHUD(void) WANT_X = BASEVIDWIDTH - 55; // 270 WANT_Y = BASEVIDHEIGHT- 71; // 176 - if (splitscreen) // Splitscreen + if (r_splitscreen) // Splitscreen { ITEM_X = 5; ITEM_Y = 3; @@ -8297,7 +8668,7 @@ static void K_initKartHUD(void) MINI_Y = (BASEVIDHEIGHT/2); - if (splitscreen > 1) // 3P/4P Small Splitscreen + if (r_splitscreen > 1) // 3P/4P Small Splitscreen { // 1P (top left) ITEM_X = -9; @@ -8326,7 +8697,7 @@ static void K_initKartHUD(void) MINI_X = (3*BASEVIDWIDTH/4); MINI_Y = (3*BASEVIDHEIGHT/4); - if (splitscreen > 2) // 4P-only + if (r_splitscreen > 2) // 4P-only { MINI_X = (BASEVIDWIDTH/2); MINI_Y = (BASEVIDHEIGHT/2); @@ -8346,20 +8717,20 @@ INT32 K_calcSplitFlags(INT32 snapflags) { INT32 splitflags = 0; - if (splitscreen == 0) + if (r_splitscreen == 0) return snapflags; if (stplyr != &players[displayplayers[0]]) { - if (splitscreen == 1 && stplyr == &players[displayplayers[1]]) + if (r_splitscreen == 1 && stplyr == &players[displayplayers[1]]) { splitflags |= V_SPLITSCREEN; } - else if (splitscreen > 1) + else if (r_splitscreen > 1) { - if (stplyr == &players[displayplayers[2]] || (splitscreen == 3 && stplyr == &players[displayplayers[3]])) + if (stplyr == &players[displayplayers[2]] || (r_splitscreen == 3 && stplyr == &players[displayplayers[3]])) splitflags |= V_SPLITSCREEN; - if (stplyr == &players[displayplayers[1]] || (splitscreen == 3 && stplyr == &players[displayplayers[3]])) + if (stplyr == &players[displayplayers[1]] || (r_splitscreen == 3 && stplyr == &players[displayplayers[3]])) splitflags |= V_HORZSCREEN; } } @@ -8369,7 +8740,7 @@ INT32 K_calcSplitFlags(INT32 snapflags) else snapflags &= ~V_SNAPTOBOTTOM; - if (splitscreen > 1) + if (r_splitscreen > 1) { if (splitflags & V_HORZSCREEN) snapflags &= ~V_SNAPTOLEFT; @@ -8387,7 +8758,7 @@ static void K_drawKartItem(void) // Why write V_DrawScaledPatch calls over and over when they're all the same? // Set to 'no item' just in case. - const UINT8 offset = ((splitscreen > 1) ? 1 : 0); + const UINT8 offset = ((r_splitscreen > 1) ? 1 : 0); patch_t *localpatch = kp_nodraw; patch_t *localbg = ((offset) ? kp_itembg[2] : kp_itembg[0]); patch_t *localinv = ((offset) ? kp_invincibility[((leveltime % (6*3)) / 3) + 7] : kp_invincibility[(leveltime % (7*3)) / 3]); @@ -8396,7 +8767,7 @@ static void K_drawKartItem(void) const INT32 numberdisplaymin = ((!offset && stplyr->kartstuff[k_itemtype] == KITEM_ORBINAUT) ? 5 : 2); INT32 itembar = 0; INT32 maxl = 0; // itembar's normal highest value - const INT32 barlength = (splitscreen > 1 ? 12 : 26); + const INT32 barlength = (r_splitscreen > 1 ? 12 : 26); UINT8 localcolor = SKINCOLOR_NONE; SINT8 colormode = TC_RAINBOW; UINT8 *colmap = NULL; @@ -8516,19 +8887,6 @@ static void K_drawKartItem(void) else localpatch = kp_nodraw; } - else if (stplyr->kartstuff[k_growshrinktimer] > 0) - { - if (stplyr->kartstuff[k_growcancel] > 0) - { - itembar = stplyr->kartstuff[k_growcancel]; - maxl = 26; - } - - if (leveltime & 1) - localpatch = kp_grow[offset]; - else - localpatch = kp_nodraw; - } else if (stplyr->kartstuff[k_sadtimer] > 0) { if (leveltime & 2) @@ -8585,6 +8943,14 @@ static void K_drawKartItem(void) localpatch = kp_thundershield[offset]; localbg = kp_itembg[offset+1]; break; + case KITEM_BUBBLESHIELD: + localpatch = kp_bubbleshield[offset]; + localbg = kp_itembg[offset+1]; + break; + case KITEM_FLAMESHIELD: + localpatch = kp_flameshield[offset]; + localbg = kp_itembg[offset+1]; + break; case KITEM_HYUDORO: localpatch = kp_hyudoro[offset]; break; @@ -8628,7 +8994,7 @@ static void K_drawKartItem(void) } // pain and suffering defined below - if (splitscreen < 2) // don't change shit for THIS splitscreen. + if (r_splitscreen < 2) // don't change shit for THIS splitscreen. { fx = ITEM_X; fy = ITEM_Y; @@ -8699,6 +9065,51 @@ static void K_drawKartItem(void) // Quick Eggman numbers if (stplyr->kartstuff[k_eggmanexplode] > 1 /*&& stplyr->kartstuff[k_eggmanexplode] <= 3*TICRATE*/) V_DrawScaledPatch(fx+17, fy+13-offset, V_HUDTRANS|fflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->kartstuff[k_eggmanexplode]))]); + + if (stplyr->kartstuff[k_itemtype] == KITEM_FLAMESHIELD && stplyr->kartstuff[k_flamelength] > 0) + { + INT32 numframes = 104; + INT32 absolutemax = 16 * flameseg; + INT32 flamemax = stplyr->kartstuff[k_flamelength] * flameseg; + INT32 flamemeter = min(stplyr->kartstuff[k_flamemeter], flamemax); + + INT32 bf = 16 - stplyr->kartstuff[k_flamelength]; + INT32 ff = numframes - ((flamemeter * numframes) / absolutemax); + INT32 fmin = (8 * (bf-1)); + + INT32 xo = 6, yo = 4; + INT32 flip = 0; + + if (offset) + { + xo++; + + if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // Flip for P1 and P3 (yes, that's correct) + { + xo -= 62; + flip = V_FLIP; + } + } + + if (ff < fmin) + ff = fmin; + + if (bf >= 0 && bf < 16) + V_DrawScaledPatch(fx-xo, fy-yo, V_HUDTRANS|fflags|flip, kp_flameshieldmeter_bg[bf][offset]); + + if (ff >= 0 && ff < numframes && stplyr->kartstuff[k_flamemeter] > 0) + { + if ((stplyr->kartstuff[k_flamemeter] > flamemax) && (leveltime & 1)) + { + UINT8 *fsflash = R_GetTranslationColormap(TC_BLINK, SKINCOLOR_WHITE, GTC_CACHE); + V_DrawMappedPatch(fx-xo, fy-yo, V_HUDTRANS|fflags|flip, kp_flameshieldmeter[ff][offset], fsflash); + } + else + { + V_DrawScaledPatch(fx-xo, fy-yo, V_HUDTRANS|fflags|flip, kp_flameshieldmeter[ff][offset]); + } + } + } } void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode) @@ -8873,19 +9284,19 @@ static void K_DrawKartPositionNum(INT32 num) scale *= 2; overtake = true; // this is used for splitscreen stuff in conjunction with flipdraw. } - if (splitscreen) + if (r_splitscreen) scale /= 2; W = FixedMul(W<>FRACBITS; // pain and suffering defined below - if (!splitscreen) + if (!r_splitscreen) { fx = POSI_X; fy = BASEVIDHEIGHT - 8; fflags = V_SNAPTOBOTTOM|V_SNAPTORIGHT; } - else if (splitscreen == 1) // for this splitscreen, we'll use case by case because it's a bit different. + else if (r_splitscreen == 1) // for this splitscreen, we'll use case by case because it's a bit different. { fx = POSI_X; if (stplyr == &players[displayplayers[0]]) // for player 1: display this at the top right, above the minimap. @@ -9152,7 +9563,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I y2 = y; - if (tab[i].num == 0 && server_lagless) + if (playerconsole[tab[i].num] == 0 && server_lagless) { y2 = ( y - 4 ); @@ -9276,16 +9687,16 @@ static void K_drawKartLapsAndRings(void) { ringflip = V_FLIP; ringanim_realframe = RINGANIM_NUMFRAMES-stplyr->karthud[khud_ringframe]; - ringx += SHORT((splitscreen > 1) ? kp_smallring[ringanim_realframe]->width : kp_ring[ringanim_realframe]->width); + ringx += SHORT((r_splitscreen > 1) ? kp_smallring[ringanim_realframe]->width : kp_ring[ringanim_realframe]->width); } - if (splitscreen > 1) + if (r_splitscreen > 1) { INT32 fx = 0, fy = 0, fr = 0; INT32 flipflag = 0; // pain and suffering defined below - if (splitscreen < 2) // don't change shit for THIS splitscreen. + if (r_splitscreen < 2) // don't change shit for THIS splitscreen. { fx = LAPS_X; fy = LAPS_Y; @@ -9468,13 +9879,13 @@ static void K_drawKartBumpersOrKarma(void) UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, stplyr->skincolor, GTC_CACHE); INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT); - if (splitscreen > 1) + if (r_splitscreen > 1) { INT32 fx = 0, fy = 0; INT32 flipflag = 0; // pain and suffering defined below - if (splitscreen < 2) // don't change shit for THIS splitscreen. + if (r_splitscreen < 2) // don't change shit for THIS splitscreen. { fx = LAPS_X; fy = LAPS_Y; @@ -9614,7 +10025,7 @@ static fixed_t K_FindCheckX(fixed_t px, fixed_t py, angle_t ang, fixed_t mx, fix if (encoremode) x = 320-x; - if (splitscreen > 1) + if (r_splitscreen > 1) x /= 2; return x; @@ -9640,17 +10051,17 @@ static void K_drawKartWanted(void) return; // set X/Y coords depending on splitscreen. - if (splitscreen < 3) // 1P and 2P use the same code. + if (r_splitscreen < 3) // 1P and 2P use the same code. { basex = WANT_X; basey = WANT_Y; - if (splitscreen == 2) + if (r_splitscreen == 2) { basey += 16; // slight adjust for 3P basex -= 6; } } - else if (splitscreen == 3) // 4P splitscreen... + else if (r_splitscreen == 3) // 4P splitscreen... { basex = BASEVIDWIDTH/2 - (SHORT(kp_wantedsplit->width)/2); // center on screen basey = BASEVIDHEIGHT - 55; @@ -9659,13 +10070,13 @@ static void K_drawKartWanted(void) if (battlewanted[0] != -1) colormap = R_GetTranslationColormap(0, players[battlewanted[0]].skincolor, GTC_CACHE); - V_DrawFixedPatch(basex< 1 ? kp_wantedsplit : kp_wanted), colormap); + V_DrawFixedPatch(basex< 1 ? kp_wantedsplit : kp_wanted), colormap); /*if (basey2) V_DrawFixedPatch(basex< 1 ? 13 : 8), y = basey+(splitscreen > 1 ? 16 : 21); + INT32 x = basex+(r_splitscreen > 1 ? 13 : 8), y = basey+(r_splitscreen > 1 ? 16 : 21); fixed_t scale = FRACUNIT/2; player_t *p = &players[battlewanted[i]]; @@ -9685,7 +10096,7 @@ static void K_drawKartWanted(void) if (players[battlewanted[i]].skincolor) { colormap = R_GetTranslationColormap(TC_RAINBOW, p->skincolor, GTC_CACHE); - V_DrawFixedPatch(x<skin] : facerankprefix[p->skin]), colormap); + V_DrawFixedPatch(x<skin] : facerankprefix[p->skin]), colormap); /*if (basey2) // again with 4p stuff V_DrawFixedPatch(x<skin] : facerankprefix[p->skin]), colormap);*/ } @@ -9706,7 +10117,7 @@ static void K_drawKartPlayerCheck(void) if (stplyr->awayviewtics) return; - if (camspin[0]) + if (( stplyr->cmd.buttons & BT_LOOKBACK )) return; for (i = 0; i < MAXPLAYERS; i++) @@ -9822,7 +10233,7 @@ static void K_drawKartMinimap(void) patch_t *AutomapPic; INT32 i = 0; INT32 x, y; - INT32 minimaptrans, splitflags = (splitscreen == 3 ? 0 : V_SNAPTORIGHT); // flags should only be 0 when it's centered (4p split) + INT32 minimaptrans, splitflags = (r_splitscreen == 3 ? 0 : V_SNAPTORIGHT); // flags should only be 0 when it's centered (4p split) UINT8 skin = 0; UINT8 *colormap = NULL; SINT8 localplayers[4]; @@ -9868,7 +10279,7 @@ static void K_drawKartMinimap(void) else V_DrawScaledPatch(x, y, splitflags, AutomapPic); - if (!(splitscreen == 2)) + if (!(r_splitscreen == 2)) { splitflags &= ~minimaptrans; splitflags |= V_HUDTRANSHALF; @@ -9937,7 +10348,7 @@ static void K_drawKartMinimap(void) if (!players[i].mo || players[i].spectator) continue; - if (i != displayplayers[0] || splitscreen) + if (i != displayplayers[0] || r_splitscreen) { if (G_BattleGametype() && players[i].kartstuff[k_bumper] <= 0) continue; @@ -10047,7 +10458,7 @@ static void K_drawKartStartCountdown(void) pnum++; if ((leveltime % (2*5)) / 5) // blink pnum += 4; - if (splitscreen) // splitscreen + if (r_splitscreen) // splitscreen pnum += 8; V_DrawScaledPatch(STCD_X - (SHORT(kp_startcountdown[pnum]->width)/2), STCD_Y - (SHORT(kp_startcountdown[pnum]->height)/2), splitflags, kp_startcountdown[pnum]); @@ -10063,7 +10474,7 @@ static void K_drawKartFinish(void) if ((stplyr->karthud[khud_cardanimation] % (2*5)) / 5) // blink pnum = 1; - if (splitscreen > 1) // 3/4p, stationary FIN + if (r_splitscreen > 1) // 3/4p, stationary FIN { pnum += 2; V_DrawScaledPatch(STCD_X - (SHORT(kp_racefinish[pnum]->width)/2), STCD_Y - (SHORT(kp_racefinish[pnum]->height)/2), splitflags, kp_racefinish[pnum]); @@ -10074,14 +10485,14 @@ static void K_drawKartFinish(void) { INT32 x, xval; - if (splitscreen) // wide splitscreen + if (r_splitscreen) // wide splitscreen pnum += 4; x = ((vid.width<width)<karthud[khud_cardanimation])*(xval > x ? xval : x))/TICRATE; - if (splitscreen && stplyr == &players[displayplayers[1]]) + if (r_splitscreen && stplyr == &players[displayplayers[1]]) x = -x; V_DrawFixedPatch(x + (STCD_X<>1), @@ -10103,11 +10514,11 @@ static void K_drawBattleFullscreen(void) drawcomebacktimer = false; #endif - if (splitscreen) + if (r_splitscreen) { - if ((splitscreen == 1 && stplyr == &players[displayplayers[1]]) - || (splitscreen > 1 && (stplyr == &players[displayplayers[2]] - || (stplyr == &players[displayplayers[3]] && splitscreen > 2)))) + if ((r_splitscreen == 1 && stplyr == &players[displayplayers[1]]) + || (r_splitscreen > 1 && (stplyr == &players[displayplayers[2]] + || (stplyr == &players[displayplayers[3]] && r_splitscreen > 2)))) { y = 232-(stplyr->karthud[khud_cardanimation]/2); splitflags = V_SNAPTOBOTTOM; @@ -10115,12 +10526,12 @@ static void K_drawBattleFullscreen(void) else y = -32+(stplyr->karthud[khud_cardanimation]/2); - if (splitscreen > 1) + if (r_splitscreen > 1) { scale /= 2; if (stplyr == &players[displayplayers[1]] - || (stplyr == &players[displayplayers[3]] && splitscreen > 2)) + || (stplyr == &players[displayplayers[3]] && r_splitscreen > 2)) x = 3*BASEVIDWIDTH/4; else x = BASEVIDWIDTH/4; @@ -10160,7 +10571,7 @@ static void K_drawBattleFullscreen(void) else if (stplyr->kartstuff[k_bumper] <= 0 && stplyr->kartstuff[k_comebacktimer] && comeback && !stplyr->spectator && drawcomebacktimer) { UINT16 t = stplyr->kartstuff[k_comebacktimer]/(10*TICRATE); - INT32 txoff, adjust = (splitscreen > 1) ? 4 : 6; // normal string is 8, kart string is 12, half of that for ease + 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; txoff = adjust; @@ -10171,13 +10582,13 @@ static void K_drawBattleFullscreen(void) t /= 10; } - if (splitscreen) + if (r_splitscreen) { - if (splitscreen > 1) + if (r_splitscreen > 1) ty = (BASEVIDHEIGHT/4)+33; - if ((splitscreen == 1 && stplyr == &players[displayplayers[1]]) - || (stplyr == &players[displayplayers[2]] && splitscreen > 1) - || (stplyr == &players[displayplayers[3]] && splitscreen > 2)) + if ((r_splitscreen == 1 && stplyr == &players[displayplayers[1]]) + || (stplyr == &players[displayplayers[2]] && r_splitscreen > 1) + || (stplyr == &players[displayplayers[3]] && r_splitscreen > 2)) ty += (BASEVIDHEIGHT/2); } else @@ -10188,7 +10599,7 @@ static void K_drawBattleFullscreen(void) else V_DrawFixedPatch(x< 1) + if (r_splitscreen > 1) V_DrawString(x-txoff, ty, 0, va("%d", stplyr->kartstuff[k_comebacktimer]/TICRATE)); else { @@ -10230,24 +10641,24 @@ static void K_drawKartFirstPerson(void) if (stplyr->spectator || !stplyr->mo || (stplyr->mo->flags2 & MF2_DONTDRAW)) return; - if (stplyr == &players[displayplayers[1]] && splitscreen) + if (stplyr == &players[displayplayers[1]] && r_splitscreen) { pn = pnum[1]; tn = turn[1]; dr = drift[1]; } - else if (stplyr == &players[displayplayers[2]] && splitscreen > 1) + else if (stplyr == &players[displayplayers[2]] && r_splitscreen > 1) { pn = pnum[2]; tn = turn[2]; dr = drift[2]; } - else if (stplyr == &players[displayplayers[3]] && splitscreen > 2) + else if (stplyr == &players[displayplayers[3]] && r_splitscreen > 2) { pn = pnum[3]; tn = turn[3]; dr = drift[3]; } else { pn = pnum[0]; tn = turn[0]; dr = drift[0]; } - if (splitscreen) + if (r_splitscreen) { y >>= 1; - if (splitscreen > 1) + if (r_splitscreen > 1) x >>= 1; } { - if (stplyr->speed < (20*stplyr->mo->scale) && (leveltime & 1) && !splitscreen) + if (stplyr->speed < (20*stplyr->mo->scale) && (leveltime & 1) && !r_splitscreen) y++; // the following isn't EXPLICITLY right, it just gets the result we want, but i'm too lazy to look up the right way to do it if (stplyr->mo->flags2 & MF2_SHADOW) @@ -10291,12 +10702,12 @@ static void K_drawKartFirstPerson(void) if (dr != stplyr->kartstuff[k_drift]*16) dr -= (dr - (stplyr->kartstuff[k_drift]*16))/8; - if (splitscreen == 1) + if (r_splitscreen == 1) { scale = (2*FRACUNIT)/3; y += FRACUNIT/(vid.dupx < vid.dupy ? vid.dupx : vid.dupy); // correct a one-pixel gap on the screen view (not the basevid view) } - else if (splitscreen) + else if (r_splitscreen) scale = FRACUNIT/2; else scale = FRACUNIT; @@ -10309,7 +10720,7 @@ static void K_drawKartFirstPerson(void) fixed_t xoffs = -P_ReturnThrustY(stplyr->mo, ang, (BASEVIDWIDTH<<(FRACBITS-2))/2); fixed_t yoffs = -(P_ReturnThrustX(stplyr->mo, ang, 4*FRACUNIT) - 4*FRACUNIT); - if (splitscreen) + if (r_splitscreen) xoffs = FixedMul(xoffs, scale); xoffs -= (tn)*scale; @@ -10322,7 +10733,7 @@ static void K_drawKartFirstPerson(void) if (mag < FRACUNIT) { xoffs = FixedMul(xoffs, mag); - if (!splitscreen) + if (!r_splitscreen) yoffs = FixedMul(yoffs, mag); } } @@ -10334,7 +10745,7 @@ static void K_drawKartFirstPerson(void) x -= xoffs; else x += xoffs; - if (!splitscreen) + if (!r_splitscreen) y += yoffs; @@ -10346,11 +10757,11 @@ static void K_drawKartFirstPerson(void) V_DrawFixedPatch(x, y, scale, splitflags, kp_fpview[target], colmap); - if (stplyr == &players[displayplayers[1]] && splitscreen) + if (stplyr == &players[displayplayers[1]] && r_splitscreen) { pnum[1] = pn; turn[1] = tn; drift[1] = dr; } - else if (stplyr == &players[displayplayers[2]] && splitscreen > 1) + else if (stplyr == &players[displayplayers[2]] && r_splitscreen > 1) { pnum[2] = pn; turn[2] = tn; drift[2] = dr; } - else if (stplyr == &players[displayplayers[3]] && splitscreen > 2) + else if (stplyr == &players[displayplayers[3]] && r_splitscreen > 2) { pnum[3] = pn; turn[3] = tn; drift[3] = dr; } else { pnum[0] = pn; turn[0] = tn; drift[0] = dr; } @@ -10537,6 +10948,35 @@ void K_drawKartFreePlay(UINT32 flashtime) LAPS_Y+3, V_HUDTRANS|V_SNAPTOBOTTOM|V_SNAPTORIGHT, "FREE PLAY"); } +static void +Draw_party_ping (int ss, INT32 snap) +{ + HU_drawMiniPing(0, 0, playerpingtable[displayplayers[ss]], V_HUDTRANS|snap); +} + +static void +K_drawMiniPing (void) +{ + if (cv_showping.value) + { + switch (r_splitscreen) + { + case 3: + Draw_party_ping(3, V_SNAPTORIGHT|V_SPLITSCREEN); + /*FALLTHRU*/ + case 2: + Draw_party_ping(2, V_SPLITSCREEN); + Draw_party_ping(1, V_SNAPTORIGHT); + Draw_party_ping(0, 0); + break; + case 1: + Draw_party_ping(1, V_SNAPTORIGHT|V_SPLITSCREEN); + Draw_party_ping(0, V_SNAPTORIGHT); + break; + } + } +} + static void K_drawDistributionDebugger(void) { patch_t *items[NUMKARTRESULTS] = { @@ -10554,6 +10994,8 @@ static void K_drawDistributionDebugger(void) kp_grow[1], kp_shrink[1], kp_thundershield[1], + kp_bubbleshield[1], + kp_flameshield[1], kp_hyudoro[1], kp_pogospring[1], kp_superring[1], @@ -10684,7 +11126,7 @@ void K_drawKartHUD(void) K_initKartHUD(); // Draw that fun first person HUD! Drawn ASAP so it looks more "real". - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (stplyr == &players[displayplayers[i]] && !camera[i].chase) K_drawKartFirstPerson(); @@ -10704,10 +11146,10 @@ void K_drawKartHUD(void) && comeback && stplyr->playerstate == PST_LIVE))); - if (!demo.title && (!battlefullscreen || splitscreen)) + if (!demo.title && (!battlefullscreen || r_splitscreen)) { // Draw the CHECK indicator before the other items, so it's overlapped by everything else - if (cv_kartcheck.value && !splitscreen && !players[displayplayers[0]].exiting) + if (cv_kartcheck.value && !r_splitscreen && !players[displayplayers[0]].exiting) K_drawKartPlayerCheck(); // Draw WANTED status @@ -10744,7 +11186,7 @@ void K_drawKartHUD(void) K_drawKartItem(); // If not splitscreen, draw... - if (!splitscreen && !demo.title) + if (!r_splitscreen && !demo.title) { // Draw the timestamp #ifdef HAVE_BLUA @@ -10765,7 +11207,7 @@ void K_drawKartHUD(void) if (!stplyr->spectator) // Bottom of the screen elements, don't need in spectate mode { // Draw the speedometer - if (cv_kartspeedometer.value && !splitscreen) + if (cv_kartspeedometer.value && !r_splitscreen) { #ifdef HAVE_BLUA if (LUA_HudEnabled(hud_speedometer)) @@ -10777,7 +11219,7 @@ void K_drawKartHUD(void) { INT32 x = BASEVIDWIDTH - 32, y = 128, offs; - if (splitscreen == 3) + if (r_splitscreen == 3) { x = BASEVIDWIDTH/2 + 10; y = BASEVIDHEIGHT/2 - 30; @@ -10836,11 +11278,11 @@ void K_drawKartHUD(void) if (leveltime >= starttime-(3*TICRATE) && leveltime < starttime+TICRATE) K_drawKartStartCountdown(); - else if (countdown && (!splitscreen || !stplyr->exiting)) + else if (countdown && (!r_splitscreen || !stplyr->exiting)) { char *countstr = va("%d", countdown/TICRATE); - if (splitscreen > 1) + if (r_splitscreen > 1) V_DrawCenteredString(BASEVIDWIDTH/4, LAPS_Y+1, K_calcSplitFlags(0), countstr); else { @@ -10854,14 +11296,14 @@ void K_drawKartHUD(void) { if (stplyr->exiting) K_drawKartFinish(); - else if (stplyr->karthud[khud_lapanimation] && !splitscreen) + else if (stplyr->karthud[khud_lapanimation] && !r_splitscreen) K_drawLapStartAnim(); } if (modeattacking) // everything after here is MP and debug only return; - if (G_BattleGametype() && !splitscreen && (stplyr->karthud[khud_yougotem] % 2)) // * YOU GOT EM * + if (G_BattleGametype() && !r_splitscreen && (stplyr->karthud[khud_yougotem] % 2)) // * YOU GOT EM * V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem); // Draw FREE PLAY. @@ -10873,11 +11315,16 @@ void K_drawKartHUD(void) K_drawKartFreePlay(leveltime); } - if (splitscreen == 0 && stplyr->kartstuff[k_wrongway] && ((leveltime / 8) & 1)) + if (r_splitscreen == 0 && stplyr->kartstuff[k_wrongway] && ((leveltime / 8) & 1)) { V_DrawCenteredString(BASEVIDWIDTH>>1, 176, V_REDMAP|V_SNAPTOBOTTOM, "WRONG WAY"); } + if (netgame && r_splitscreen) + { + K_drawMiniPing(); + } + if (cv_kartdebugdistribution.value) K_drawDistributionDebugger(); diff --git a/src/k_kart.h b/src/k_kart.h index d5f84a7af..273d8bcb1 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -8,6 +8,7 @@ #include "doomdef.h" #include "d_player.h" // Need for player_t +#include "command.h" // Need for player_t #define KART_FULLTURN 800 @@ -22,6 +23,10 @@ void K_RegisterKartStuff(void); boolean K_IsPlayerLosing(player_t *player); fixed_t K_GetKartGameSpeedScalar(SINT8 value); + +extern consvar_t *KartItemCVars[NUMKARTRESULTS-1]; + +INT32 K_GetShieldFromItem(INT32 item); void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); void K_KartPainEnergyFling(player_t *player); void K_FlipFromObject(mobj_t *mo, mobj_t *master); diff --git a/src/k_pwrlv.c b/src/k_pwrlv.c index d753d4daa..b8d78e0ee 100644 --- a/src/k_pwrlv.c +++ b/src/k_pwrlv.c @@ -48,7 +48,7 @@ INT16 K_CalculatePowerLevelInc(INT16 diff) diff = -MAXDIFF; #undef MAXDIFF - x = ((diff-2)< 1) // 3P : bottom right + if (r_splitscreen > 1) // 3P : bottom right { MM_X = (3*BASEVIDWIDTH/4); MM_Y = (3*BASEVIDHEIGHT/4); - if (splitscreen > 2) // 4P: centered + if (r_splitscreen > 2) // 4P: centered { MM_X = (BASEVIDWIDTH/2); MM_Y = (BASEVIDHEIGHT/2); @@ -453,7 +453,7 @@ static int libd_drawOnMinimap(lua_State *L) } // splitscreen flags - splitflags = (splitscreen == 3 ? 0 : V_SNAPTORIGHT); // flags should only be 0 when it's centered (4p split) + splitflags = (r_splitscreen == 3 ? 0 : V_SNAPTORIGHT); // flags should only be 0 when it's centered (4p split) // translucency: if (timeinmap > 105) @@ -471,7 +471,7 @@ static int libd_drawOnMinimap(lua_State *L) minimaptrans = ((10-minimaptrans)< 2 && stplayr == &players[displayplayers[3]]) + if (r_splitscreen > 2 && stplayr == &players[displayplayers[3]]) { LUA_PushUserdata(gL, &camera[3], META_CAMERA); camnum = 4; } - else if (splitscreen > 1 && stplayr == &players[displayplayers[2]]) + else if (r_splitscreen > 1 && stplayr == &players[displayplayers[2]]) { LUA_PushUserdata(gL, &camera[2], META_CAMERA); camnum = 3; } - else if (splitscreen && stplayr == &players[displayplayers[1]]) + else if (r_splitscreen && stplayr == &players[displayplayers[1]]) { LUA_PushUserdata(gL, &camera[1], META_CAMERA); camnum = 2; diff --git a/src/m_argv.c b/src/m_argv.c index e8bfdd3db..e1046f8a7 100644 --- a/src/m_argv.c +++ b/src/m_argv.c @@ -16,6 +16,7 @@ #include "doomdef.h" #include "command.h" #include "m_argv.h" +#include "m_misc.h" /** \brief number of arg */ @@ -166,7 +167,7 @@ void M_FindResponseFile(void) if (!file) I_Error("No more free memory for the response file"); if (fread(file, size, 1, handle) != 1) - I_Error("Couldn't read response file because %s", strerror(ferror(handle))); + I_Error("Couldn't read response file because %s", M_FileError(handle)); fclose(handle); // keep all the command line arguments following @responsefile diff --git a/src/m_menu.c b/src/m_menu.c index 4bbaa1205..267dbe07f 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5727,9 +5727,9 @@ static void M_DrawPlaybackMenu(void) { PlaybackMenu[playback_viewcount].status = IT_ARROWS|IT_STRING; - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) PlaybackMenu[playback_view1+i].status = IT_ARROWS|IT_STRING; - for (i = splitscreen+1; i < 4; i++) + for (i = r_splitscreen+1; i < 4; i++) PlaybackMenu[playback_view1+i].status = IT_DISABLED; //PlaybackMenu[playback_moreoptions].alphaKey = 156; @@ -5752,7 +5752,7 @@ static void M_DrawPlaybackMenu(void) { if (modeattacking) continue; - if (splitscreen >= i - playback_view1) + if (r_splitscreen >= i - playback_view1) { INT32 ply = displayplayers[i - playback_view1]; @@ -5788,18 +5788,18 @@ static void M_DrawPlaybackMenu(void) { char *str; - if (!(i == playback_viewcount && splitscreen == 3)) + if (!(i == playback_viewcount && r_splitscreen == 3)) V_DrawCharacter(BASEVIDWIDTH/2 - 4, currentMenu->y + 28 - (skullAnimCounter/5), '\x1A' | V_SNAPTOTOP|highlightflags, false); // up arrow - if (!(i == playback_viewcount && splitscreen == 0)) + if (!(i == playback_viewcount && r_splitscreen == 0)) V_DrawCharacter(BASEVIDWIDTH/2 - 4, currentMenu->y + 48 + (skullAnimCounter/5), '\x1B' | V_SNAPTOTOP|highlightflags, false); // down arrow switch (i) { case playback_viewcount: - str = va("%d", splitscreen+1); + str = va("%d", r_splitscreen+1); break; case playback_view1: @@ -5892,12 +5892,12 @@ static void M_PlaybackSetViews(INT32 choice) { if (choice > 0) { - if (splitscreen < 3) - G_AdjustView(splitscreen + 2, 0, true); + if (r_splitscreen < 3) + G_AdjustView(r_splitscreen + 2, 0, true); } - else if (splitscreen) + else if (r_splitscreen) { - splitscreen--; + r_splitscreen--; R_ExecuteSetViewSize(); } } @@ -9488,7 +9488,7 @@ static void M_SetupMultiPlayer2(INT32 choice) strcpy (setupm_name, cv_playername2.string); // set for splitscreen secondary player - setupm_player = &players[displayplayers[1]]; + setupm_player = &players[g_localplayers[1]]; setupm_cvskin = &cv_skin2; setupm_cvcolor = &cv_playercolor2; setupm_cvname = &cv_playername2; @@ -9500,7 +9500,7 @@ static void M_SetupMultiPlayer2(INT32 choice) setupm_fakecolor = setupm_cvcolor->value; // disable skin changes if we can't actually change skins - if (splitscreen && !CanChangeSkin(displayplayers[1])) + if (splitscreen && !CanChangeSkin(g_localplayers[1])) MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); else MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); @@ -9519,7 +9519,7 @@ static void M_SetupMultiPlayer3(INT32 choice) strcpy(setupm_name, cv_playername3.string); // set for splitscreen third player - setupm_player = &players[displayplayers[2]]; + setupm_player = &players[g_localplayers[2]]; setupm_cvskin = &cv_skin3; setupm_cvcolor = &cv_playercolor3; setupm_cvname = &cv_playername3; @@ -9531,7 +9531,7 @@ static void M_SetupMultiPlayer3(INT32 choice) setupm_fakecolor = setupm_cvcolor->value; // disable skin changes if we can't actually change skins - if (splitscreen > 1 && !CanChangeSkin(displayplayers[2])) + if (splitscreen > 1 && !CanChangeSkin(g_localplayers[2])) MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); else MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); @@ -9550,7 +9550,7 @@ static void M_SetupMultiPlayer4(INT32 choice) strcpy(setupm_name, cv_playername4.string); // set for splitscreen fourth player - setupm_player = &players[displayplayers[3]]; + setupm_player = &players[g_localplayers[3]]; setupm_cvskin = &cv_skin4; setupm_cvcolor = &cv_playercolor4; setupm_cvname = &cv_playername4; @@ -9562,7 +9562,7 @@ static void M_SetupMultiPlayer4(INT32 choice) setupm_fakecolor = setupm_cvcolor->value; // disable skin changes if we can't actually change skins - if (splitscreen > 2 && !CanChangeSkin(displayplayers[3])) + if (splitscreen > 2 && !CanChangeSkin(g_localplayers[3])) MP_PlayerSetupMenu[2].status = (IT_GRAYEDOUT); else MP_PlayerSetupMenu[2].status = (IT_KEYHANDLER | IT_STRING); @@ -10633,31 +10633,6 @@ static void M_HandleVideoMode(INT32 ch) // =============== // Monitor Toggles // =============== -static consvar_t *kartitemcvs[NUMKARTRESULTS-1] = { - &cv_sneaker, - &cv_rocketsneaker, - &cv_invincibility, - &cv_banana, - &cv_eggmanmonitor, - &cv_orbinaut, - &cv_jawz, - &cv_mine, - &cv_ballhog, - &cv_selfpropelledbomb, - &cv_grow, - &cv_shrink, - &cv_thundershield, - &cv_hyudoro, - &cv_pogospring, - &cv_superring, - &cv_kitchensink, - &cv_triplesneaker, - &cv_triplebanana, - &cv_decabanana, - &cv_tripleorbinaut, - &cv_quadorbinaut, - &cv_dualjawz -}; static tic_t shitsfree = 0; @@ -10726,7 +10701,7 @@ static void M_DrawMonitorToggles(void) continue; } - cv = kartitemcvs[currentMenu->menuitems[thisitem].alphaKey-1]; + cv = KartItemCVars[currentMenu->menuitems[thisitem].alphaKey-1]; translucent = (cv->value ? 0 : V_TRANSLUCENT); switch (currentMenu->menuitems[thisitem].alphaKey) @@ -10795,7 +10770,7 @@ static void M_DrawMonitorToggles(void) } else { - cv = kartitemcvs[currentMenu->menuitems[itemOn].alphaKey-1]; + cv = KartItemCVars[currentMenu->menuitems[itemOn].alphaKey-1]; translucent = (cv->value ? 0 : V_TRANSLUCENT); switch (currentMenu->menuitems[itemOn].alphaKey) @@ -10911,14 +10886,14 @@ static void M_HandleMonitorToggles(INT32 choice) S_StartSound(NULL, sfx_s1b4); for (i = 0; i < NUMKARTRESULTS-1; i++) { - if (kartitemcvs[i]->value == v) - CV_AddValue(kartitemcvs[i], 1); + if (KartItemCVars[i]->value == v) + CV_AddValue(KartItemCVars[i], 1); } } else { S_StartSound(NULL, sfx_s1ba); - CV_AddValue(kartitemcvs[currentMenu->menuitems[itemOn].alphaKey-1], 1); + CV_AddValue(KartItemCVars[currentMenu->menuitems[itemOn].alphaKey-1], 1); } break; diff --git a/src/m_misc.c b/src/m_misc.c index 800d34e79..2de64d589 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -23,6 +23,8 @@ #include #endif +#include + // Extended map support. #include @@ -110,6 +112,9 @@ consvar_t cv_screenshot_colorprofile = {"screenshot_colorprofile", "Yes", CV_SAV static CV_PossibleValue_t moviemode_cons_t[] = {{MM_GIF, "GIF"}, {MM_APNG, "aPNG"}, {MM_SCREENSHOT, "Screenshots"}, {0, NULL}}; consvar_t cv_moviemode = {"moviemode_mode", "GIF", CV_SAVE|CV_CALL, moviemode_cons_t, Moviemode_mode_Onchange, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_movie_option = {"movie_option", "Default", CV_SAVE, screenshot_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_movie_folder = {"movie_folder", "", CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; + static CV_PossibleValue_t zlib_mem_level_t[] = { {1, "(Min Memory) 1"}, {2, "2"}, {3, "3"}, {4, "4"}, {5, "5"}, {6, "6"}, {7, "7"}, @@ -764,12 +769,12 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png else snprintf(lvlttltext, 48, "Unknown"); - if (gamestate == GS_LEVEL && &players[displayplayers[0]] && players[displayplayers[0]].mo) + if (gamestate == GS_LEVEL && &players[g_localplayers[0]] && players[g_localplayers[0]].mo) snprintf(locationtxt, 40, "X:%d Y:%d Z:%d A:%d", - players[displayplayers[0]].mo->x>>FRACBITS, - players[displayplayers[0]].mo->y>>FRACBITS, - players[displayplayers[0]].mo->z>>FRACBITS, - FixedInt(AngleFixed(players[displayplayers[0]].mo->angle))); + players[g_localplayers[0]].mo->x>>FRACBITS, + players[g_localplayers[0]].mo->y>>FRACBITS, + players[g_localplayers[0]].mo->z>>FRACBITS, + FixedInt(AngleFixed(players[g_localplayers[0]].mo->angle))); else snprintf(locationtxt, 40, "Unknown"); @@ -1100,19 +1105,25 @@ static inline moviemode_t M_StartMovieGIF(const char *pathname) void M_StartMovie(void) { #if NUMSCREENS > 2 - const char *pathname = "."; + char pathname[MAX_WADPATH]; if (moviemode) return; - if (cv_screenshot_option.value == 0) - pathname = usehome ? srb2home : srb2path; - else if (cv_screenshot_option.value == 1) - pathname = srb2home; - else if (cv_screenshot_option.value == 2) - pathname = srb2path; - else if (cv_screenshot_option.value == 3 && *cv_screenshot_folder.string != '\0') - pathname = cv_screenshot_folder.string; + if (cv_movie_option.value == 0) + strcpy(pathname, usehome ? srb2home : srb2path); + else if (cv_movie_option.value == 1) + strcpy(pathname, srb2home); + else if (cv_movie_option.value == 2) + strcpy(pathname, srb2path); + else if (cv_movie_option.value == 3 && *cv_movie_folder.string != '\0') + strcpy(pathname, cv_movie_folder.string); + + if (cv_movie_option.value != 3) + { + strcat(pathname, PATHSEP"movies"PATHSEP); + I_mkdir(pathname, 0755); + } if (rendermode == render_none) I_Error("Can't make a movie without a render system\n"); @@ -1449,7 +1460,8 @@ void M_ScreenShot(void) void M_DoScreenShot(void) { #if NUMSCREENS > 2 - const char *freename = NULL, *pathname = "."; + const char *freename = NULL; + char pathname[MAX_WADPATH]; boolean ret = false; UINT8 *linear = NULL; @@ -1461,13 +1473,19 @@ void M_DoScreenShot(void) return; if (cv_screenshot_option.value == 0) - pathname = usehome ? srb2home : srb2path; + strcpy(pathname, usehome ? srb2home : srb2path); else if (cv_screenshot_option.value == 1) - pathname = srb2home; + strcpy(pathname, srb2home); else if (cv_screenshot_option.value == 2) - pathname = srb2path; + strcpy(pathname, srb2path); else if (cv_screenshot_option.value == 3 && *cv_screenshot_folder.string != '\0') - pathname = cv_screenshot_folder.string; + strcpy(pathname, cv_screenshot_folder.string); + + if (cv_screenshot_option.value != 3) + { + strcat(pathname, PATHSEP"screenshots"PATHSEP); + I_mkdir(pathname, 0755); + } #ifdef USE_PNG freename = Newsnapshotfile(pathname,"png"); @@ -2379,3 +2397,104 @@ void M_SetupMemcpy(void) M_Memcpy = cpu_cpy; #endif } + +/** Return the appropriate message for a file error or end of file. +*/ +const char *M_FileError(FILE *fp) +{ + if (ferror(fp)) + return strerror(errno); + else + return "end-of-file"; +} + +/** Return the number of parts of this path. +*/ +int M_PathParts(const char *path) +{ + int n; + const char *p; + const char *t; + if (path == NULL) + return 0; + for (n = 0, p = path ;; ++n) + { + t = p; + if (( p = strchr(p, PATHSEP[0]) )) + p += strspn(p, PATHSEP); + else + { + if (*t)/* there is something after the final delimiter */ + n++; + break; + } + } + return n; +} + +/** Check whether a path is an absolute path. +*/ +boolean M_IsPathAbsolute(const char *path) +{ +#ifdef _WIN32 + return ( strncmp(&path[1], ":\\", 2) == 0 ); +#else + return ( path[0] == '/' ); +#endif +} + +/** I_mkdir for each part of the path. +*/ +void M_MkdirEachUntil(const char *cpath, int start, int end, int mode) +{ + char path[MAX_WADPATH]; + char *p; + char *t; + + if (end > 0 && end <= start) + return; + + strlcpy(path, cpath, sizeof path); +#ifdef _WIN32 + if (strncmp(&path[1], ":\\", 2) == 0) + p = &path[3]; + else +#endif + p = path; + + if (end > 0) + end -= start; + + for (; start > 0; --start) + { + p += strspn(p, PATHSEP); + if (!( p = strchr(p, PATHSEP[0]) )) + return; + } + p += strspn(p, PATHSEP); + for (;;) + { + if (end > 0 && !--end) + break; + + t = p; + if (( p = strchr(p, PATHSEP[0]) )) + { + *p = '\0'; + I_mkdir(path, mode); + *p = PATHSEP[0]; + p += strspn(p, PATHSEP); + } + else + { + if (*t) + I_mkdir(path, mode); + break; + } + } +} + +void M_MkdirEach(const char *path, int start, int mode) +{ + M_MkdirEachUntil(path, start, -1, mode); +} diff --git a/src/m_misc.h b/src/m_misc.h index 3d42b4244..456aa0a4f 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -30,7 +30,7 @@ typedef enum { extern moviemode_t moviemode; extern consvar_t cv_screenshot_option, cv_screenshot_folder, cv_screenshot_colorprofile; -extern consvar_t cv_moviemode; +extern consvar_t cv_moviemode, cv_movie_folder, cv_movie_option; extern consvar_t cv_zlib_memory, cv_zlib_level, cv_zlib_strategy, cv_zlib_window_bits; extern consvar_t cv_zlib_memorya, cv_zlib_levela, cv_zlib_strategya, cv_zlib_window_bitsa; extern consvar_t cv_apng_delay; @@ -100,6 +100,13 @@ void strcatbf(char *s1, const char *s2, const char *s3); void M_SetupMemcpy(void); +const char *M_FileError(FILE *handle); + +int M_PathParts (const char *path); +boolean M_IsPathAbsolute (const char *path); +void M_MkdirEach (const char *path, int start, int mode); +void M_MkdirEachUntil (const char *path, int start, int end, int mode); + // counting bits, for weapon ammo code, usually FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size); diff --git a/src/p_ceilng.c b/src/p_ceilng.c index 757edebae..a2db42b2d 100644 --- a/src/p_ceilng.c +++ b/src/p_ceilng.c @@ -484,7 +484,7 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) } // chained linedef executing ability - if (line->flags & ML_BLOCKMONSTERS) + if (line->flags & ML_BLOCKPLAYERS) { // only set it on ONE of the moving sectors (the smallest numbered) // and front side x offset must be positive diff --git a/src/p_enemy.c b/src/p_enemy.c index a7a5d4cef..1b6556eca 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -203,6 +203,7 @@ void A_MayonakaArrow(mobj_t *actor); //SRB2kart void A_ReaperThinker(mobj_t *actor); //SRB2kart void A_MementosTPParticles(mobj_t *actor); //SRB2kart void A_FlameParticle(mobj_t *actor); // SRB2kart +void A_FlameShieldPaper(mobj_t *actor); // SRB2kart void A_OrbitNights(mobj_t *actor); void A_GhostMe(mobj_t *actor); void A_SetObjectState(mobj_t *actor); @@ -3678,7 +3679,7 @@ void A_AttractChase(mobj_t *actor) if (actor->tracer && actor->tracer->player && actor->tracer->health //&& P_CheckSight(actor, actor->tracer) && actor->tracer->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD - && (actor->tracer->player->kartstuff[k_rings]+actor->tracer->player->kartstuff[k_pickuprings]) < 20 + && RINGTOTAL(actor->tracer->player) < 20 && !actor->tracer->player->kartstuff[k_ringlock]) { fixed_t dist; @@ -4198,7 +4199,7 @@ void A_OverlayThink(mobj_t *actor) if (!actor->target) return; - if (!splitscreen && rendermode != render_soft) + if (!r_splitscreen && rendermode != render_soft) { angle_t viewingangle; @@ -9328,6 +9329,52 @@ void A_FlameParticle(mobj_t *actor) par->momz = actor->scale<<1; } +void A_FlameShieldPaper(mobj_t *actor) +{ + INT32 framea = 0; + INT32 frameb = 0; + INT32 locvar1 = var1; + INT32 locvar2 = var2; + UINT8 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_FlameShieldPaper", actor)) + return; +#endif + + framea = (locvar1 & FF_FRAMEMASK); + frameb = (locvar2 & FF_FRAMEMASK); + + for (i = 0; i < 2; i++) + { + INT32 perpendicular = ((i & 1) ? -ANGLE_90 : ANGLE_90); + fixed_t newx = actor->x + P_ReturnThrustX(NULL, actor->angle + perpendicular, 8*actor->scale); + fixed_t newy = actor->y + P_ReturnThrustY(NULL, actor->angle + perpendicular, 8*actor->scale); + mobj_t *paper = P_SpawnMobj(newx, newy, actor->z, MT_FLAMESHIELDPAPER); + + P_SetTarget(&paper->target, actor); + P_SetScale(paper, actor->scale); + paper->destscale = actor->destscale; + + P_SetMobjState(paper, S_FLAMESHIELDPAPER); + paper->frame &= ~FF_FRAMEMASK; + + paper->angle = actor->angle + ANGLE_45; + + if (i & 1) + { + paper->angle -= ANGLE_90; + paper->frame |= frameb; + } + else + { + paper->frame |= framea; + } + + paper->extravalue1 = i; + } +} + //} // Function: A_OrbitNights diff --git a/src/p_floor.c b/src/p_floor.c index 737a8810b..11ffe270d 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2537,9 +2537,9 @@ void T_CameraScanner(elevator_t *elevator) lastleveltime = leveltime; } - if (players[displayplayers[0]].mo) + if (players[g_localplayers[0]].mo) { - if (players[displayplayers[0]].mo->subsector->sector == elevator->actionsector) + if (players[g_localplayers[0]].mo->subsector->sector == elevator->actionsector) { if (t_cam_dist == -42) t_cam_dist = cv_cam_dist.value; @@ -2565,9 +2565,9 @@ void T_CameraScanner(elevator_t *elevator) } } - if (splitscreen && players[displayplayers[1]].mo) + if (splitscreen && players[g_localplayers[1]].mo) { - if (players[displayplayers[1]].mo->subsector->sector == elevator->actionsector) + if (players[g_localplayers[1]].mo->subsector->sector == elevator->actionsector) { if (t_cam2_rotate == -42) t_cam2_dist = cv_cam2_dist.value; @@ -2593,9 +2593,9 @@ void T_CameraScanner(elevator_t *elevator) } } - if (splitscreen > 1 && players[displayplayers[2]].mo) + if (splitscreen > 1 && players[g_localplayers[2]].mo) { - if (players[displayplayers[2]].mo->subsector->sector == elevator->actionsector) + if (players[g_localplayers[2]].mo->subsector->sector == elevator->actionsector) { if (t_cam3_rotate == -42) t_cam3_dist = cv_cam3_dist.value; @@ -2621,9 +2621,9 @@ void T_CameraScanner(elevator_t *elevator) } } - if (splitscreen > 2 && players[displayplayers[3]].mo) + if (splitscreen > 2 && players[g_localplayers[3]].mo) { - if (players[displayplayers[3]].mo->subsector->sector == elevator->actionsector) + if (players[g_localplayers[3]].mo->subsector->sector == elevator->actionsector) { if (t_cam4_rotate == -42) t_cam4_dist = cv_cam4_dist.value; @@ -2747,7 +2747,7 @@ INT32 EV_DoFloor(line_t *line, floor_e floortype) dofloor->direction = -1; // down // chained linedef executing ability - if (line->flags & ML_BLOCKMONSTERS) + if (line->flags & ML_BLOCKPLAYERS) { // Only set it on one of the moving sectors (the // smallest numbered) and only if the front side diff --git a/src/p_inter.c b/src/p_inter.c index e83315a12..8cc307571 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -64,11 +64,11 @@ void P_ForceConstant(const BasicFF_t *FFInfo) ConstantQuake.Magnitude = FFInfo->Magnitude; if (FFInfo->player == &players[consoleplayer]) I_Tactile(ConstantForce, &ConstantQuake); - else if (splitscreen && FFInfo->player == &players[displayplayers[1]]) + else if (splitscreen && FFInfo->player == &players[g_localplayers[1]]) I_Tactile2(ConstantForce, &ConstantQuake); - else if (splitscreen > 1 && FFInfo->player == &players[displayplayers[2]]) + else if (splitscreen > 1 && FFInfo->player == &players[g_localplayers[2]]) I_Tactile3(ConstantForce, &ConstantQuake); - else if (splitscreen > 2 && FFInfo->player == &players[displayplayers[3]]) + else if (splitscreen > 2 && FFInfo->player == &players[g_localplayers[3]]) I_Tactile4(ConstantForce, &ConstantQuake); } void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End) @@ -85,11 +85,11 @@ void P_RampConstant(const BasicFF_t *FFInfo, INT32 Start, INT32 End) RampQuake.End = End; if (FFInfo->player == &players[consoleplayer]) I_Tactile(ConstantForce, &RampQuake); - else if (splitscreen && FFInfo->player == &players[displayplayers[1]]) + else if (splitscreen && FFInfo->player == &players[g_localplayers[1]]) I_Tactile2(ConstantForce, &RampQuake); - else if (splitscreen > 1 && FFInfo->player == &players[displayplayers[2]]) + else if (splitscreen > 1 && FFInfo->player == &players[g_localplayers[2]]) I_Tactile3(ConstantForce, &RampQuake); - else if (splitscreen > 2 && FFInfo->player == &players[displayplayers[3]]) + else if (splitscreen > 2 && FFInfo->player == &players[g_localplayers[3]]) I_Tactile4(ConstantForce, &RampQuake); } @@ -109,7 +109,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) return false; /*if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) // No bumpers in Match - return false;*/ + return false;*/ if (weapon) { @@ -117,12 +117,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) if (weapon == 2) { // Invulnerable - if (player->powers[pw_flashing] > 0 - || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinouttype] != 2) - || player->kartstuff[k_squishedtimer] > 0 - || player->kartstuff[k_invincibilitytimer] > 0 - || player->kartstuff[k_growshrinktimer] > 0 - || player->kartstuff[k_hyudorotimer] > 0) + if (player->powers[pw_flashing] > 0) return false; // Already have fake @@ -134,7 +129,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) { // Item-specific timer going off if (player->kartstuff[k_stealingtimer] || player->kartstuff[k_stolentimer] - || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_rocketsneakertimer] + || player->kartstuff[k_rocketsneakertimer] || player->kartstuff[k_eggmanexplode]) return false; @@ -144,8 +139,8 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon) || player->kartstuff[k_itemheld]) return false; - if (weapon == 3 && player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) - return false; // No stacking thunder shields! + if (weapon == 3 && K_GetShieldFromItem(player->kartstuff[k_itemtype]) != KSHIELD_NONE) + return false; // No stacking shields! } } @@ -391,58 +386,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetTarget(&special->target, toucher); P_KillMobj(special, toucher, toucher); break; - case MT_EGGMANITEM_SHIELD: // SRB2kart - case MT_EGGMANITEM: - if ((special->target == toucher || special->target == toucher->target) && (special->threshold > 0)) - return; - - if (special->health <= 0 || toucher->health <= 0) - return; - - if (!P_CanPickupItem(player, 2)) - return; - - if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) - { - if (player->kartstuff[k_comebackmode] || player->kartstuff[k_comebacktimer]) - return; - player->kartstuff[k_comebackmode] = 2; - } - else - { - K_DropItems(player); //K_StripItems(player); - //K_StripOther(player); - player->kartstuff[k_itemroulette] = 1; - player->kartstuff[k_roulettetype] = 2; - } - -#if 0 - // Eggbox snipe! - if (special->type == MT_EGGMANITEM && special->health > 1) - S_StartSound(toucher, sfx_bsnipe); -#endif - - { - mobj_t *poof = P_SpawnMobj(special->x, special->y, special->z, MT_EXPLODE); - S_StartSound(poof, special->info->deathsound); - } - - if (special->target && special->target->player) - { - if (G_RaceGametype() || special->target->player->kartstuff[k_bumper] > 0) - player->kartstuff[k_eggmanblame] = special->target->player-players; - else - player->kartstuff[k_eggmanblame] = player-players; - - if (special->target->hnext == special) - { - P_SetTarget(&special->target->hnext, NULL); - special->target->player->kartstuff[k_eggmanheld] = 0; - } - } - - P_RemoveMobj(special); - return; case MT_KARMAHITBOX: if (!special->target->player) return; @@ -597,11 +540,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) { mobj_t *spbexplode; - if (player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0) + if (player->kartstuff[k_bubbleblowup] > 0) { - //player->powers[pw_flashing] = 0; K_DropHnextList(player); - K_StripItems(player); + special->extravalue1 = 2; // WAIT... + special->extravalue2 = 52; // Slightly over the respawn timer length + return; } S_StopSound(special); // Don't continue playing the gurgle or the siren @@ -631,7 +575,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // kill - if (player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0) + if (player->kartstuff[k_invincibilitytimer] > 0 + || player->kartstuff[k_growshrinktimer] > 0 + || player->kartstuff[k_flamedash] > 0) { P_KillMobj(special, toucher, toucher); return; @@ -675,6 +621,25 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) case MT_BALLOON: // SRB2kart P_SetObjectMomZ(toucher, 20<target == toucher || special->target == toucher->target) && (special->threshold > 0)) + return; + + if (special->tracer && !P_MobjWasRemoved(special->tracer)) + return; + + if (special->health <= 0 || toucher->health <= 0) + return; + + if (!player->mo || player->spectator) + return; + + // attach to player! + P_SetTarget(&special->tracer, toucher); + toucher->flags |= MF_NOGRAVITY; + toucher->momz = (8*toucher->scale) * P_MobjFlip(toucher); + S_StartSound(toucher, sfx_s1b2); + return; // ***************************************** // // Rings, coins, spheres, weapon panels, etc // @@ -706,7 +671,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // Reached the cap, don't waste 'em! - if ((player->kartstuff[k_rings] + player->kartstuff[k_pickuprings]) >= 20) + if (RINGTOTAL(player) >= 20) return; special->momx = special->momy = special->momz = 0; @@ -3332,8 +3297,8 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) if (!player) return; - // Has a shield? Don't lose your rings! - if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + // Have a shield? You get hit, but don't lose your rings! + if (K_GetShieldFromItem(player->kartstuff[k_itemtype]) != KSHIELD_NONE) return; // 20 is the ring cap in kart diff --git a/src/p_map.c b/src/p_map.c index fbe8ff5e2..9a3864f2c 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -841,7 +841,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return K_SMKIceBlockCollide(thing, tmthing); } - if (tmthing->type == MT_EGGMANITEM) + if (tmthing->type == MT_EGGMANITEM || tmthing->type == MT_EGGMANITEM_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -849,10 +849,9 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - K_EggItemCollide(tmthing, thing); - return true; + return K_EggItemCollide(tmthing, thing); } - else if (thing->type == MT_EGGMANITEM) + else if (thing->type == MT_EGGMANITEM || thing->type == MT_EGGMANITEM_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -860,13 +859,134 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - K_EggItemCollide(thing, tmthing); - return true; + return K_EggItemCollide(thing, tmthing); } if (tmthing->type == MT_RANDOMITEM) return true; + // Bubble Shield reflect + if (((thing->type == MT_BUBBLESHIELD && thing->target->player && thing->target->player->kartstuff[k_bubbleblowup]) + || (thing->player && thing->player->kartstuff[k_bubbleblowup])) + && (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD + || tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG + || tmthing->type == MT_SSMINE || tmthing->type == MT_SINK + || (tmthing->type == MT_PLAYER && thing->target != tmthing))) + { + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + if (tmthing->type == MT_PLAYER) + { + // Counter desyncs + /*mobj_t *oldthing = thing; + mobj_t *oldtmthing = tmthing; + + P_Thrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y), 4*thing->scale); + + thing = oldthing; + P_SetTarget(&tmthing, oldtmthing);*/ + + if (tmthing->player->kartstuff[k_spinouttimer] || tmthing->player->kartstuff[k_squishedtimer] + || tmthing->player->powers[pw_flashing] || tmthing->player->kartstuff[k_hyudorotimer] + || tmthing->player->kartstuff[k_justbumped] || tmthing->scale > thing->scale + (mapobjectscale/8)) + return true; + + // Player Damage + K_SpinPlayer(tmthing->player, thing, 0, ((thing->type == MT_BUBBLESHIELD) ? thing->target : thing), false); + S_StartSound(thing, sfx_s3k44); + } + else + { + if (!tmthing->threshold) + { + if (!tmthing->momx && !tmthing->momy) + { + tmthing->momz += (24*tmthing->scale) * P_MobjFlip(tmthing); + } + else + { + tmthing->momx = -tmthing->momx; + tmthing->momy = -tmthing->momy; + tmthing->momz = -tmthing->momz; + tmthing->angle += ANGLE_180; + } + if (tmthing->type == MT_JAWZ) + P_SetTarget(&tmthing->tracer, tmthing->target); // Back to the source! + tmthing->threshold = 10; + S_StartSound(thing, sfx_s3k44); + } + } + + // no interaction + return true; + } + else if (((tmthing->type == MT_BUBBLESHIELD && tmthing->target->player && tmthing->target->player->kartstuff[k_bubbleblowup]) + || (tmthing->player && tmthing->player->kartstuff[k_bubbleblowup])) + && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD + || thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG + || thing->type == MT_SSMINE || thing->type == MT_SINK + || (thing->type == MT_PLAYER && tmthing->target != thing))) + { + // see if it went over / under + if (tmthing->z > thing->z + thing->height) + return true; // overhead + if (tmthing->z + tmthing->height < thing->z) + return true; // underneath + + if (thing->type == MT_PLAYER) + { + // Counter desyncs + /*mobj_t *oldthing = thing; + mobj_t *oldtmthing = tmthing; + + P_Thrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y), 4*tmthing->scale); + + thing = oldthing; + P_SetTarget(&tmthing, oldtmthing);*/ + + if (thing->player->kartstuff[k_spinouttimer] || thing->player->kartstuff[k_squishedtimer] + || thing->player->powers[pw_flashing] || thing->player->kartstuff[k_hyudorotimer] + || thing->player->kartstuff[k_justbumped] || thing->scale > tmthing->scale + (mapobjectscale/8)) + return true; + + // Player Damage + K_SpinPlayer(thing->player, tmthing, 0, ((tmthing->type == MT_BUBBLESHIELD) ? tmthing->target : tmthing), false); + S_StartSound(tmthing, sfx_s3k44); + } + else + { + if (!thing->threshold) + { + if (!thing->momx && !thing->momy) + { + thing->momz += (24*thing->scale) * P_MobjFlip(thing); + } + else + { + thing->momx = -thing->momx; + thing->momy = -thing->momy; + thing->momz = -thing->momz; + thing->angle += ANGLE_180; + } + if (thing->type == MT_JAWZ) + P_SetTarget(&thing->tracer, thing->target); // Back to the source! + thing->threshold = 10; + S_StartSound(tmthing, sfx_s3k44); + } + } + + // no interaction + return true; + } + + // double make sure bubbles won't collide with anything else + if (thing->type == MT_BUBBLESHIELD || tmthing->type == MT_BUBBLESHIELD) + return true; + if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD || tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD) { @@ -1296,7 +1416,6 @@ static boolean PIT_CheckThing(mobj_t *thing) // Make sure they aren't able to damage you ANYWHERE along the Z axis, you have to be TOUCHING the person. && !(thing->z + thing->height < tmthing->z || thing->z > tmthing->z + tmthing->height)) { - if (tmthing->scale > thing->scale + (mapobjectscale/8)) // SRB2kart - Handle squishes first! K_SquishPlayer(thing->player, tmthing, tmthing); else if (thing->scale > tmthing->scale + (mapobjectscale/8)) @@ -1305,6 +1424,12 @@ static boolean PIT_CheckThing(mobj_t *thing) P_DamageMobj(thing, tmthing, tmthing, 1); else if (thing->player->kartstuff[k_invincibilitytimer] && !tmthing->player->kartstuff[k_invincibilitytimer]) P_DamageMobj(tmthing, thing, thing, 1); + 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); + 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)) // SRB2kart - Then flame shield! + P_DamageMobj(tmthing, thing, thing, 1); /*if (G_BattleGametype() && (!G_GametypeHasTeams() || tmthing->player->ctfteam != thing->player->ctfteam)) { @@ -1814,10 +1939,10 @@ static boolean PIT_CheckLine(line_t *ld) // missiles can cross uncrossable lines if (!(tmthing->flags & MF_MISSILE)) { - if (ld->flags & ML_IMPASSIBLE) // block objects from moving through this linedef. + if (ld->flags & ML_IMPASSABLE) // block objects from moving through this linedef. return false; - if ((tmthing->flags & (MF_ENEMY|MF_BOSS)) && ld->flags & ML_BLOCKMONSTERS) - return false; // block monsters only + if (tmthing->player && ld->flags & ML_BLOCKPLAYERS) + return false; // SRB2Kart: Only block players, not items } // set openrange, opentop, openbottom @@ -2385,7 +2510,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) itsatwodlevel = true; else { - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (thiscam == &camera[i] && players[displayplayers[i]].mo && (players[displayplayers[i]].mo->flags2 & MF2_TWOD)) @@ -2401,7 +2526,7 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) fixed_t tryx = thiscam->x; fixed_t tryy = thiscam->y; - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { #ifndef NOCLIPCAM if ((thiscam == &camera[i] && (players[displayplayers[i]].pflags & PF_NOCLIP)) || (leveltime < introtime)) // Noclipping player camera noclips too!! @@ -3179,10 +3304,10 @@ static boolean PTR_SlideTraverse(intercept_t *in) if (!(slidemo->flags & MF_MISSILE)) { - if (li->flags & ML_IMPASSIBLE) + if (li->flags & ML_IMPASSABLE) goto isblocking; - if ((slidemo->flags & (MF_ENEMY|MF_BOSS)) && li->flags & ML_BLOCKMONSTERS) + if (slidemo->player && li->flags & ML_BLOCKPLAYERS) goto isblocking; } diff --git a/src/p_mobj.c b/src/p_mobj.c index d962317ea..666818ef3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1172,7 +1172,7 @@ static void P_PlayerFlip(mobj_t *mo) mo->player->aiming = InvAngle(mo->player->aiming); - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (mo->player-players == displayplayers[i]) { @@ -1722,6 +1722,10 @@ void P_XYMovement(mobj_t *mo) P_InstaThrust(mo, R_PointToAngle2(mo->x, mo->y, mo->x + xmove, mo->y + ymove)+ANGLE_90, 16*FRACUNIT); } } + + // Bubble bounce + if (mo->type == MT_BUBBLESHIELDTRAP) + S_StartSound(mo, sfx_s3k44); //} // Bounce ring algorithm @@ -1933,7 +1937,7 @@ void P_XYMovement(mobj_t *mo) #endif //{ SRB2kart stuff - if (mo->type == MT_BALLHOG || mo->type == MT_FLINGRING) //(mo->type == MT_JAWZ && !mo->tracer)) + if (mo->type == MT_FLINGRING || mo->type == MT_BALLHOG || mo->type == MT_BUBBLESHIELDTRAP) return; if (mo->player && (mo->player->kartstuff[k_spinouttimer] && !mo->player->kartstuff[k_wipeoutslow]) && mo->player->speed <= K_GetKartSpeed(mo->player, false)/2) @@ -2174,7 +2178,7 @@ boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover) *rover->topheight; if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3 - && !(rover->master->flags & ML_BLOCKMONSTERS) + && !(rover->master->flags & ML_BLOCKPLAYERS) && ((rover->master->flags & ML_EFFECT3) || mo->z-mo->momz > topheight - FixedMul(16*FRACUNIT, mo->scale))) return true; } @@ -2270,6 +2274,7 @@ static boolean P_ZMovement(mobj_t *mo) case MT_JAWZ_DUD: case MT_BALLHOG: case MT_SSMINE: + case MT_BUBBLESHIELDTRAP: // Remove stuff from death pits. if (P_CheckDeathPitCollide(mo)) { @@ -3556,7 +3561,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled itsatwodlevel = true; else { - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (thiscam == &camera[i] && players[displayplayers[i]].mo && (players[displayplayers[i]].mo->flags2 & MF2_TWOD)) @@ -3597,7 +3602,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled if (postimg != postimg_none) { - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (player == &players[displayplayers[i]]) postimgtype[i] = postimg; @@ -3650,11 +3655,11 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled fixed_t cam_height = cv_cam_height.value; thiscam->z = thiscam->floorz; - if (player == &players[displayplayers[1]]) + if (player == &players[g_localplayers[1]]) cam_height = cv_cam2_height.value; - if (player == &players[displayplayers[2]]) + if (player == &players[g_localplayers[2]]) cam_height = cv_cam3_height.value; - if (player == &players[displayplayers[3]]) + if (player == &players[g_localplayers[3]]) cam_height = cv_cam4_height.value; if (thiscam->z > player->mo->z + player->mo->height + FixedMul(cam_height*FRACUNIT + 16*FRACUNIT, player->mo->scale)) { @@ -6184,7 +6189,7 @@ void P_RunOverlays(void) if (!mo->target) continue; - if (!splitscreen /*&& rendermode != render_soft*/) + if (!r_splitscreen /*&& rendermode != render_soft*/) { angle_t viewingangle; @@ -6675,7 +6680,7 @@ void P_MobjThinker(mobj_t *mobj) mobj->angle = R_PointToAngle(mobj->x, mobj->y) + ANGLE_90; // literally only happened because i wanted to ^L^R the SPR_ITEM's - if (!splitscreen && players[displayplayers[0]].mo) + if (!r_splitscreen && players[displayplayers[0]].mo) { scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); @@ -6767,17 +6772,6 @@ void P_MobjThinker(mobj_t *mobj) else mobj->tracer->flags2 |= MF2_DONTDRAW; } - else if (mobj->target->player->kartstuff[k_growshrinktimer] > 0) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_GROW; - - if (leveltime & 1) - mobj->tracer->flags2 &= ~MF2_DONTDRAW; - else - mobj->tracer->flags2 |= MF2_DONTDRAW; - } else if (mobj->target->player->kartstuff[k_itemtype] && mobj->target->player->kartstuff[k_itemamount] > 0) { P_SetMobjState(mobj, S_PLAYERARROW_BOX); @@ -6863,7 +6857,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->target && mobj->target->health && mobj->tracer && mobj->target->player && !mobj->target->player->spectator && mobj->target->player->health && mobj->target->player->playerstate != PST_DEAD - && players[displayplayers[0]].mo && !players[displayplayers[0]].spectator) + && players[g_localplayers[0]].mo && !players[g_localplayers[0]].spectator) { fixed_t scale = 3*mobj->target->scale; @@ -6883,7 +6877,7 @@ void P_MobjThinker(mobj_t *mobj) mobj->x = mobj->target->x; mobj->y = mobj->target->y; - if (!splitscreen && players[displayplayers[0]].mo) + if (!r_splitscreen && players[displayplayers[0]].mo) { scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); @@ -7909,6 +7903,13 @@ void P_MobjThinker(mobj_t *mobj) case MT_ORBINAUT: { boolean grounded = P_IsObjectOnGround(mobj); + + if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true)) + { + P_RemoveMobj(mobj); + return; + } + if (mobj->flags2 & MF2_AMBUSH) { if (grounded && (mobj->flags & MF_NOCLIPTHING)) @@ -7979,6 +7980,12 @@ void P_MobjThinker(mobj_t *mobj) { mobj_t *ghost = P_SpawnGhostMobj(mobj); + if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true)) + { + P_RemoveMobj(mobj); + return; + } + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) { ghost->color = mobj->target->player->skincolor; @@ -8002,6 +8009,13 @@ void P_MobjThinker(mobj_t *mobj) case MT_JAWZ_DUD: { boolean grounded = P_IsObjectOnGround(mobj); + + if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true)) + { + P_RemoveMobj(mobj); + return; + } + if (mobj->flags2 & MF2_AMBUSH) { if (grounded && (mobj->flags & MF_NOCLIPTHING)) @@ -8062,6 +8076,12 @@ void P_MobjThinker(mobj_t *mobj) case MT_EGGMANITEM: mobj->friction = ORIG_FRICTION/4; + if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true)) + { + P_RemoveMobj(mobj); + return; + } + if (mobj->momx || mobj->momy) { mobj_t *ghost = P_SpawnGhostMobj(mobj); @@ -8091,6 +8111,12 @@ void P_MobjThinker(mobj_t *mobj) mobj_t *ghost = P_SpawnGhostMobj(mobj); ghost->fuse = 3; + if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true)) + { + P_RemoveMobj(mobj); + return; + } + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) { ghost->color = mobj->target->player->skincolor; @@ -8123,6 +8149,12 @@ void P_MobjThinker(mobj_t *mobj) mobj->threshold--; break; case MT_SSMINE: + if (P_MobjTouchingSectorSpecial(mobj, 4, 7, true)) + { + P_RemoveMobj(mobj); + return; + } + if (mobj->target && mobj->target->player) mobj->color = mobj->target->player->skincolor; else @@ -8376,6 +8408,30 @@ void P_MobjThinker(mobj_t *mobj) mobj->target->y + FINESINE(mobj->angle >> ANGLETOFINESHIFT), mobj->z + mobj->target->height * P_MobjFlip(mobj)); break; + case MT_FLAMESHIELDPAPER: + if (!mobj->target || P_MobjWasRemoved(mobj->target)) + { + P_RemoveMobj(mobj); + return; + } + + mobj->z = mobj->target->z; + + K_MatchGenericExtraFlags(mobj, mobj->target); + + { + INT32 perpendicular = ((mobj->extravalue1 & 1) ? -ANGLE_90 : ANGLE_90); + fixed_t newx = mobj->target->x + P_ReturnThrustX(NULL, mobj->target->angle + perpendicular, 8*mobj->target->scale); + fixed_t newy = mobj->target->y + P_ReturnThrustY(NULL, mobj->target->angle + perpendicular, 8*mobj->target->scale); + + P_TeleportMove(mobj, newx, newy, mobj->target->z); + + if (mobj->extravalue1 & 1) + mobj->angle = mobj->target->angle - ANGLE_45; + else + mobj->angle = mobj->target->angle + ANGLE_45; + } + break; case MT_TIREGREASE: if (!mobj->target || P_MobjWasRemoved(mobj->target) || !mobj->target->player || !mobj->target->player->kartstuff[k_tiregrease]) @@ -8429,14 +8485,15 @@ void P_MobjThinker(mobj_t *mobj) case MT_THUNDERSHIELD: { fixed_t destx, desty; - if (!mobj->target || !mobj->target->health || (mobj->target->player && mobj->target->player->kartstuff[k_curshield] != 1)) + if (!mobj->target || !mobj->target->health || !mobj->target->player + || mobj->target->player->kartstuff[k_curshield] != KSHIELD_THUNDER) { P_RemoveMobj(mobj); return; } - P_SetScale(mobj, (mobj->destscale = (5*mobj->target->destscale)>>2)); + P_SetScale(mobj, (mobj->destscale = (5*mobj->target->scale)>>2)); - if (!splitscreen /*&& rendermode != render_soft*/) + if (!r_splitscreen /*&& rendermode != render_soft*/) { angle_t viewingangle; statenum_t curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states))); @@ -8448,8 +8505,9 @@ void P_MobjThinker(mobj_t *mobj) else viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, camera[0].x, camera[0].y); - if (curstate > S_THUNDERSHIELD15) + if (curstate > S_THUNDERSHIELD15 && curstate <= S_THUNDERSHIELD24) viewingangle += ANGLE_180; + destx = mobj->target->x + P_ReturnThrustX(mobj->target, viewingangle, mobj->scale>>4); desty = mobj->target->y + P_ReturnThrustY(mobj->target, viewingangle, mobj->scale>>4); } @@ -8462,6 +8520,250 @@ void P_MobjThinker(mobj_t *mobj) P_TeleportMove(mobj, destx, desty, mobj->target->z); break; } + case MT_BUBBLESHIELD: + { + fixed_t destx, desty; + fixed_t scale; + statenum_t curstate; + + if (!mobj->target || !mobj->target->health || !mobj->target->player + || mobj->target->player->kartstuff[k_curshield] != KSHIELD_BUBBLE) + { + P_RemoveMobj(mobj); + return; + } + + scale = (5*mobj->target->scale)>>2; + curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states))); + + if (mobj->target->player->kartstuff[k_bubbleblowup]) + { + INT32 blow = mobj->target->player->kartstuff[k_bubbleblowup]; + if (blow > bubbletime) + blow = bubbletime; + + if (curstate != S_BUBBLESHIELDBLOWUP) + P_SetMobjState(mobj, S_BUBBLESHIELDBLOWUP); + + mobj->angle += ANGLE_22h; + mobj->flags2 &= ~MF2_SHADOW; + scale += (blow * (3*scale)) / bubbletime; + + mobj->frame = (states[S_BUBBLESHIELDBLOWUP].frame + mobj->extravalue1); + if ((mobj->target->player->kartstuff[k_bubbleblowup] > bubbletime) && (leveltime & 1)) + mobj->frame = (states[S_BUBBLESHIELDBLOWUP].frame + 5); + + if (mobj->extravalue1 < 4 && mobj->extravalue2 < blow && !mobj->cvmem && (leveltime & 1)) // Growing + { + mobj->extravalue1++; + if (mobj->extravalue1 >= 4) + mobj->cvmem = 1; // shrink back down + } + else if ((mobj->extravalue1 > -4 && mobj->extravalue2 > blow) + || (mobj->cvmem && mobj->extravalue1 > 0)) // Shrinking + mobj->extravalue1--; + + if (P_IsObjectOnGround(mobj->target)) + { + UINT8 i; + + for (i = 0; i < 2; i++) + { + angle_t a = mobj->angle + ((i & 1) ? ANGLE_180 : 0); + fixed_t ws = (mobj->target->scale>>1); + mobj_t *wave; + + ws += (blow * ws) / bubbletime; + + wave = P_SpawnMobj( + (mobj->target->x - mobj->target->momx) + P_ReturnThrustX(NULL, a, mobj->radius - (21*ws)), + (mobj->target->y - mobj->target->momy) + P_ReturnThrustY(NULL, a, mobj->radius - (21*ws)), + (mobj->target->z - mobj->target->momz), MT_THOK); + + wave->flags &= ~(MF_NOCLIPHEIGHT|MF_NOGRAVITY); + P_SetScale(wave, (wave->destscale = ws)); + + P_SetMobjState(wave, S_BUBBLESHIELDWAVE1); + + wave->momx = mobj->target->momx; + wave->momy = mobj->target->momy; + wave->momz = mobj->target->momz; + } + } + } + else + { + mobj->cvmem = 0; + mobj->angle = mobj->target->angle; + + if (curstate == S_BUBBLESHIELDBLOWUP) + { + if (mobj->extravalue1 != 0) + { + mobj->frame = (states[S_BUBBLESHIELDBLOWUP].frame + mobj->extravalue1); + + if (mobj->extravalue1 < 0 && (leveltime & 1)) + mobj->extravalue1++; + else if (mobj->extravalue1 > 0) + mobj->extravalue1--; + } + else + { + P_SetMobjState(mobj, S_BUBBLESHIELD1); + mobj->extravalue1 = 0; + } + } + else + { + if (mobj->target->player->kartstuff[k_bubblecool] && ((curstate-S_BUBBLESHIELD1) & 1)) + mobj->flags2 |= MF2_SHADOW; + else + mobj->flags2 &= ~MF2_SHADOW; + } + } + + mobj->extravalue2 = mobj->target->player->kartstuff[k_bubbleblowup]; + P_SetScale(mobj, (mobj->destscale = scale)); + + if (!splitscreen /*&& rendermode != render_soft*/) + { + angle_t viewingangle; + + if (players[displayplayers[0]].awayviewtics) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y); + else if (!camera[0].chase && players[displayplayers[0]].mo) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y); + else + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, camera[0].x, camera[0].y); + + destx = mobj->target->x + P_ReturnThrustX(mobj->target, viewingangle, mobj->scale>>4); + desty = mobj->target->y + P_ReturnThrustY(mobj->target, viewingangle, mobj->scale>>4); + } + else + { + destx = mobj->target->x; + desty = mobj->target->y; + } + + P_TeleportMove(mobj, destx, desty, mobj->target->z); + break; + } + case MT_FLAMESHIELD: + { + fixed_t destx, desty; + statenum_t curstate; + statenum_t underlayst = S_NULL; + INT32 flamemax = mobj->target->player->kartstuff[k_flamelength] * flameseg; + + if (!mobj->target || !mobj->target->health || !mobj->target->player + || mobj->target->player->kartstuff[k_curshield] != KSHIELD_FLAME) + { + P_RemoveMobj(mobj); + return; + } + P_SetScale(mobj, (mobj->destscale = (5*mobj->target->scale)>>2)); + + curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states))); + + if (mobj->target->player->kartstuff[k_flamedash]) + { + if (!(curstate >= S_FLAMESHIELDDASH1 && curstate <= S_FLAMESHIELDDASH12)) + P_SetMobjState(mobj, S_FLAMESHIELDDASH1); + + if (curstate == S_FLAMESHIELDDASH2) + underlayst = S_FLAMESHIELDDASH2_UNDERLAY; + else if (curstate == S_FLAMESHIELDDASH5) + underlayst = S_FLAMESHIELDDASH5_UNDERLAY; + else if (curstate == S_FLAMESHIELDDASH8) + underlayst = S_FLAMESHIELDDASH8_UNDERLAY; + else if (curstate == S_FLAMESHIELDDASH11) + underlayst = S_FLAMESHIELDDASH11_UNDERLAY; + + if (leveltime & 1) + { + UINT8 i; + UINT8 nl = 2; + + if (mobj->target->player->kartstuff[k_flamedash] > mobj->extravalue1) + nl = 3; + + for (i = 0; i < nl; i++) + { + mobj_t *fast = P_SpawnMobj(mobj->x + (P_RandomRange(-36,36) * mobj->scale), + mobj->y + (P_RandomRange(-36,36) * mobj->scale), + mobj->z + (mobj->height/2) + (P_RandomRange(-20,20) * mobj->scale), + MT_FASTLINE); + + fast->angle = mobj->angle; + fast->momx = 3*mobj->target->momx/4; + fast->momy = 3*mobj->target->momy/4; + fast->momz = 3*mobj->target->momz/4; + + K_MatchGenericExtraFlags(fast, mobj); + P_SetMobjState(fast, S_FLAMESHIELDLINE1 + i); + } + } + } + else + { + if (curstate >= S_FLAMESHIELDDASH1 && curstate <= S_FLAMESHIELDDASH12) + P_SetMobjState(mobj, S_FLAMESHIELD1); + } + + mobj->extravalue1 = mobj->target->player->kartstuff[k_flamedash]; + + if (mobj->target->player->kartstuff[k_flamemeter] > flamemax) + { + mobj_t *flash = P_SpawnMobj(mobj->x + mobj->target->momx, mobj->y + mobj->target->momy, mobj->z + mobj->target->momz, MT_THOK); + P_SetMobjState(flash, S_FLAMESHIELDFLASH); + + if (leveltime & 1) + { + flash->frame |= 2 + ((leveltime / 2) % 4); + } + else + { + flash->frame |= ((leveltime / 2) % 2); + } + } + + if (!splitscreen /*&& rendermode != render_soft*/) + { + angle_t viewingangle; + + if (players[displayplayers[0]].awayviewtics) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].awayviewmobj->x, players[displayplayers[0]].awayviewmobj->y); + else if (!camera[0].chase && players[displayplayers[0]].mo) + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y); + else + viewingangle = R_PointToAngle2(mobj->target->x, mobj->target->y, camera[0].x, camera[0].y); + + if (curstate >= S_FLAMESHIELD1 && curstate < S_FLAMESHIELDDASH1 && ((curstate-S_FLAMESHIELD1) & 1)) + viewingangle += ANGLE_180; + + destx = mobj->target->x + P_ReturnThrustX(mobj->target, viewingangle, mobj->scale>>4); + desty = mobj->target->y + P_ReturnThrustY(mobj->target, viewingangle, mobj->scale>>4); + } + else + { + destx = mobj->target->x; + desty = mobj->target->y; + } + + 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; + + if (underlayst != S_NULL) + { + mobj_t *underlay = P_SpawnMobj(mobj->target->x, mobj->target->y, mobj->target->z, MT_FLAMESHIELDUNDERLAY); + underlay->angle = mobj->angle; + P_SetMobjState(underlay, underlayst); + } + break; + } case MT_ROCKETSNEAKER: if (!mobj->target || !mobj->target->health) { @@ -9200,6 +9502,154 @@ void P_MobjThinker(mobj_t *mobj) } } break; + case MT_BUBBLESHIELDTRAP: + if (leveltime % 180 == 0) + S_StartSound(mobj, sfx_s3kbfl); + + if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer) && mobj->tracer->player) + { + player_t *player = mobj->tracer->player; + fixed_t destx, desty, curfz, destfz; + boolean blockmove = false; + + mobj->flags = MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP; + mobj->extravalue1 = 1; + + mobj->cvmem /= 2; + mobj->momz = 0; + mobj->destscale = ((5*mobj->tracer->scale)>>2) + (mobj->tracer->scale>>3); + + mobj->tracer->momz = (8*mobj->tracer->scale) * P_MobjFlip(mobj->tracer); + + mobj->tracer->momx = (31*mobj->tracer->momx)/32; + mobj->tracer->momy = (31*mobj->tracer->momy)/32; + + destx = mobj->x + mobj->tracer->momx; + desty = mobj->y + mobj->tracer->momy; + + if (mobj->tracer->eflags & MFE_VERTICALFLIP) + { + curfz = P_GetCeilingZ(mobj->tracer, mobj->tracer->subsector->sector, mobj->tracer->x, mobj->tracer->y, NULL); + destfz = P_GetCeilingZ(mobj->tracer, R_PointInSubsector(destx, desty)->sector, destx, desty, NULL); + blockmove = (curfz - destfz >= 24*mobj->scale); + } + else + { + curfz = P_GetFloorZ(mobj->tracer, mobj->tracer->subsector->sector, mobj->tracer->x, mobj->tracer->y, NULL); + destfz = P_GetFloorZ(mobj->tracer, R_PointInSubsector(destx, desty)->sector, destx, desty, NULL); + blockmove = (destfz - curfz >= 24*mobj->scale); + } + + if (blockmove) + { + mobj->tracer->momx = mobj->tracer->momy = 0; + } + + P_TeleportMove(mobj, + mobj->tracer->x + P_ReturnThrustX(NULL, mobj->tracer->angle+ANGLE_90, (mobj->cvmem)<tracer->y + P_ReturnThrustY(NULL, mobj->tracer->angle+ANGLE_90, (mobj->cvmem)<tracer->z - (4*mobj->tracer->scale) + (P_RandomRange(-abs(mobj->cvmem), abs(mobj->cvmem))<movecount > 4*TICRATE) + { + S_StartSound(mobj->tracer, sfx_s3k77); + mobj->tracer->flags &= ~MF_NOGRAVITY; + P_KillMobj(mobj, mobj->tracer, mobj->tracer); + break; + } + + if (abs(player->cmd.driftturn) > 100) + { + INT32 lastsign = 0; + if (mobj->lastlook > 0) + lastsign = 1; + else if (mobj->lastlook < 0) + lastsign = -1; + + if ((player->cmd.driftturn > 0 && lastsign < 0) + || (player->cmd.driftturn < 0 && lastsign > 0)) + { + mobj->movecount += (TICRATE/2); + mobj->cvmem = 8*lastsign; + S_StartSound(mobj, sfx_s3k7a); + } + + mobj->lastlook = player->cmd.driftturn; + } + + mobj->movecount++; + } + else if (mobj->extravalue1) // lost your player somehow, DIE + { + P_KillMobj(mobj, NULL, NULL); + break; + } + else + { + mobj->destscale = (5*mapobjectscale)>>2; + + if (mobj->threshold > 0) + mobj->threshold--; + + if (abs(mobj->momx) < 8*mobj->destscale && abs(mobj->momy) < 8*mobj->destscale) + { + // Stop, give light gravity + mobj->momx = mobj->momy = 0; + mobj->momz = -(mobj->scale * P_MobjFlip(mobj)); + } + else + { + UINT8 i; + mobj_t *ghost = P_SpawnGhostMobj(mobj); + + if (mobj->target && !P_MobjWasRemoved(mobj->target) && mobj->target->player) + { + ghost->color = mobj->target->player->skincolor; + ghost->colorized = true; + } + + mobj->momx = (23*mobj->momx)/24; + mobj->momy = (23*mobj->momy)/24; + + mobj->angle = R_PointToAngle2(0,0,mobj->momx,mobj->momy); + + if ((mobj->z - mobj->floorz) < (24*mobj->scale) && (leveltime % 3 != 0)) + { + // Cool wave effects! + for (i = 0; i < 2; i++) + { + angle_t aoff; + SINT8 sign = 1; + mobj_t *wave; + + if (i & 1) + sign = -1; + else + sign = 1; + + aoff = (mobj->angle + ANGLE_180) + (ANGLE_45 * sign); + + wave = P_SpawnMobj(mobj->x + FixedMul(mobj->radius, FINECOSINE(aoff>>ANGLETOFINESHIFT)), + mobj->y + FixedMul(mobj->radius, FINESINE(aoff>>ANGLETOFINESHIFT)), + mobj->z, MT_THOK); + + wave->flags &= ~(MF_NOCLIPHEIGHT|MF_NOGRAVITY); + P_SetScale(wave, (wave->destscale = mobj->scale/2)); + + P_SetMobjState(wave, S_BUBBLESHIELDWAVE1); + if (leveltime & 1) + wave->tics++; + + P_SetTarget(&wave->target, mobj); + wave->angle = mobj->angle - (ANGLE_90 * sign); // point completely perpendicular from the bubble + K_FlipFromObject(wave, mobj); + + P_Thrust(wave, wave->angle, 4*mobj->scale); + } + } + } + } + break; case MT_KARMAFIREWORK: if (mobj->flags & MF_NOGRAVITY) break; @@ -10144,7 +10594,6 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) case MT_SSMINE_SHIELD: case MT_BALLHOG: case MT_SINK: - case MT_THUNDERSHIELD: case MT_ROCKETSNEAKER: case MT_SPB: thing->shadowscale = 3*FRACUNIT/2; @@ -10164,6 +10613,12 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) thing->shadowscale = 3*FRACUNIT/2; thing->whiteshadow = false; break; + case MT_THUNDERSHIELD: + case MT_BUBBLESHIELD: + case MT_BUBBLESHIELDTRAP: + case MT_FLAMESHIELD: + thing->shadowscale = FRACUNIT; + break; case MT_RING: case MT_FLOATINGITEM: thing->shadowscale = FRACUNIT/2; @@ -10976,13 +11431,13 @@ void P_PrecipitationEffects(void) // Local effects from here on out! // If we're not in game fully yet, we don't worry about them. - if (!playeringame[displayplayers[0]] || !players[displayplayers[0]].mo) + if (!playeringame[g_localplayers[0]] || !players[g_localplayers[0]].mo) return; if (sound_disabled) return; // Sound off? D'aw, no fun. - if (players[displayplayers[0]].mo->subsector->sector->ceilingpic == skyflatnum) + if (players[g_localplayers[0]].mo->subsector->sector->ceilingpic == skyflatnum) volume = 255; // Sky above? We get it full blast. else { @@ -10990,17 +11445,17 @@ void P_PrecipitationEffects(void) fixed_t closedist, newdist; // Essentially check in a 1024 unit radius of the player for an outdoor area. - yl = players[displayplayers[0]].mo->y - 1024*FRACUNIT; - yh = players[displayplayers[0]].mo->y + 1024*FRACUNIT; - xl = players[displayplayers[0]].mo->x - 1024*FRACUNIT; - xh = players[displayplayers[0]].mo->x + 1024*FRACUNIT; + yl = players[g_localplayers[0]].mo->y - 1024*FRACUNIT; + yh = players[g_localplayers[0]].mo->y + 1024*FRACUNIT; + xl = players[g_localplayers[0]].mo->x - 1024*FRACUNIT; + xh = players[g_localplayers[0]].mo->x + 1024*FRACUNIT; closedist = 2048*FRACUNIT; for (y = yl; y <= yh; y += FRACUNIT*64) for (x = xl; x <= xh; x += FRACUNIT*64) { if (R_PointInSubsector(x, y)->sector->ceilingpic == skyflatnum) // Found the outdoors! { - newdist = S_CalculateSoundDistance(players[displayplayers[0]].mo->x, players[displayplayers[0]].mo->y, 0, x, y, 0); + newdist = S_CalculateSoundDistance(players[g_localplayers[0]].mo->x, players[g_localplayers[0]].mo->y, 0, x, y, 0); if (newdist < closedist) closedist = newdist; } @@ -11015,7 +11470,7 @@ void P_PrecipitationEffects(void) volume = 255; if (rainsfx != sfx_None && (!leveltime || leveltime % rainfreq == 1)) - S_StartSoundAtVolume(players[displayplayers[0]].mo, rainsfx, volume); + S_StartSoundAtVolume(players[g_localplayers[0]].mo, rainsfx, volume); if (!sounds_thunder) return; @@ -11023,7 +11478,7 @@ void P_PrecipitationEffects(void) if (effects_lightning && lightningStrike && volume) { // Large, close thunder sounds to go with our lightning. - S_StartSoundAtVolume(players[displayplayers[0]].mo, sfx_litng1 + M_RandomKey(4), volume); + S_StartSoundAtVolume(players[g_localplayers[0]].mo, sfx_litng1 + M_RandomKey(4), volume); } else if (thunderchance < 20) { @@ -11031,7 +11486,7 @@ void P_PrecipitationEffects(void) if (volume < 80) volume = 80; - S_StartSoundAtVolume(players[displayplayers[0]].mo, sfx_athun1 + M_RandomKey(2), volume); + S_StartSoundAtVolume(players[g_localplayers[0]].mo, sfx_athun1 + M_RandomKey(2), volume); } } @@ -11368,9 +11823,9 @@ void P_AfterPlayerSpawn(INT32 playernum) if (playernum == consoleplayer) localangle[0] = mobj->angle; - else if (splitscreen) + else if (r_splitscreen) { - for (i = 1; i <= splitscreen; i++) + for (i = 1; i <= r_splitscreen; i++) { if (playernum == displayplayers[i]) { @@ -11400,7 +11855,7 @@ void P_AfterPlayerSpawn(INT32 playernum) SV_SpawnPlayer(playernum, mobj->x, mobj->y, mobj->angle); - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (camera[i].chase) { diff --git a/src/p_saveg.c b/src/p_saveg.c index ee2dc62ea..ccae035ee 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2018,7 +2018,7 @@ static void LoadMobjThinker(actionf_p1 thinker) CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type %d\n", mobj->spawnpoint->type); else CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing type NULL\n"); - I_Error("Savegame corrupted"); + I_Error("Netsave corrupted"); } mobj->type = i; } diff --git a/src/p_setup.c b/src/p_setup.c index 08e94bd46..40ea643b7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2580,29 +2580,29 @@ static void P_ForceCharacter(const char *forcecharskin) { if (splitscreen) { - SetPlayerSkin(displayplayers[1], forcecharskin); - if ((unsigned)cv_playercolor2.value != skins[players[displayplayers[1]].skin].prefcolor && !modeattacking) + SetPlayerSkin(g_localplayers[1], forcecharskin); + if ((unsigned)cv_playercolor2.value != skins[players[g_localplayers[1]].skin].prefcolor && !modeattacking) { - CV_StealthSetValue(&cv_playercolor2, skins[players[displayplayers[1]].skin].prefcolor); - players[displayplayers[1]].skincolor = skins[players[displayplayers[1]].skin].prefcolor; + CV_StealthSetValue(&cv_playercolor2, skins[players[g_localplayers[1]].skin].prefcolor); + players[g_localplayers[1]].skincolor = skins[players[g_localplayers[1]].skin].prefcolor; } if (splitscreen > 1) { - SetPlayerSkin(displayplayers[2], forcecharskin); - if ((unsigned)cv_playercolor3.value != skins[players[displayplayers[2]].skin].prefcolor && !modeattacking) + SetPlayerSkin(g_localplayers[2], forcecharskin); + if ((unsigned)cv_playercolor3.value != skins[players[g_localplayers[2]].skin].prefcolor && !modeattacking) { - CV_StealthSetValue(&cv_playercolor3, skins[players[displayplayers[2]].skin].prefcolor); - players[displayplayers[2]].skincolor = skins[players[displayplayers[2]].skin].prefcolor; + CV_StealthSetValue(&cv_playercolor3, skins[players[g_localplayers[2]].skin].prefcolor); + players[g_localplayers[2]].skincolor = skins[players[g_localplayers[2]].skin].prefcolor; } if (splitscreen > 2) { - SetPlayerSkin(displayplayers[3], forcecharskin); - if ((unsigned)cv_playercolor4.value != skins[players[displayplayers[3]].skin].prefcolor && !modeattacking) + SetPlayerSkin(g_localplayers[3], forcecharskin); + if ((unsigned)cv_playercolor4.value != skins[players[g_localplayers[3]].skin].prefcolor && !modeattacking) { - CV_StealthSetValue(&cv_playercolor4, skins[players[displayplayers[3]].skin].prefcolor); - players[displayplayers[3]].skincolor = skins[players[displayplayers[3]].skin].prefcolor; + CV_StealthSetValue(&cv_playercolor4, skins[players[g_localplayers[3]].skin].prefcolor); + players[g_localplayers[3]].skincolor = skins[players[g_localplayers[3]].skin].prefcolor; } } } @@ -2840,7 +2840,7 @@ boolean P_SetupLevel(boolean skipprecip) P_LevelInitStuff(); - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) postimgtype[i] = postimg_none; if (mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0') @@ -3216,7 +3216,7 @@ boolean P_SetupLevel(boolean skipprecip) if (!dedicated) { - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) P_SetupCamera(displayplayers[i], &camera[i]); // Salt: CV_ClearChangedFlags() messes with your settings :( @@ -3258,7 +3258,7 @@ boolean P_SetupLevel(boolean skipprecip) /*if (rendermode != render_none) CV_Set(&cv_fov, cv_fov.defaultvalue);*/ - displayplayers[0] = consoleplayer; // Start with your OWN view, please! + g_localplayers[0] = consoleplayer; // Start with your OWN view, please! } /*if (cv_useranalog.value) diff --git a/src/p_spec.c b/src/p_spec.c index 64c0df789..425d1c779 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -1651,7 +1651,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (rings > dist) return false; } - else if (triggerline->flags & ML_BLOCKMONSTERS) + else if (triggerline->flags & ML_BLOCKPLAYERS) { if (rings < dist) return false; @@ -1705,6 +1705,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (!(ALL7EMERALDS(emeralds))) return false; } + // If we were not triggered by a sector type especially for the purpose, // a Linedef Executor linedef trigger is not handling sector triggers properly, return. @@ -2162,7 +2163,7 @@ static void K_HandleLapIncrement(player_t *player) if (lap < (sides[lines[i].sidenum[0]].textureoffset >> FRACBITS)) continue; } - else if (lines[i].flags & ML_BLOCKMONSTERS) // Need lower than or equal to + else if (lines[i].flags & ML_BLOCKPLAYERS) // Need lower than or equal to { if (lap > (sides[lines[i].sidenum[0]].textureoffset >> FRACBITS)) continue; @@ -2425,7 +2426,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (bot) // This might put poor Tails in a wall if he's too far behind! D: But okay, whatever! >:3 P_TeleportMove(bot, bot->x + x, bot->y + y, bot->z + z); - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (mo->player == &players[displayplayers[i]] && camera[i].chase) { @@ -2448,8 +2449,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) return; if (bot) - P_Teleport(bot, dest->x, dest->y, dest->z, (line->flags & ML_NOCLIMB) ? mo->angle : dest->angle, (line->flags & ML_BLOCKMONSTERS) == 0, (line->flags & ML_EFFECT4) == ML_EFFECT4); - if (line->flags & ML_BLOCKMONSTERS) + P_Teleport(bot, dest->x, dest->y, dest->z, (line->flags & ML_NOCLIMB) ? mo->angle : dest->angle, (line->flags & ML_BLOCKPLAYERS) == 0, (line->flags & ML_EFFECT4) == ML_EFFECT4); + if (line->flags & ML_BLOCKPLAYERS) P_Teleport(mo, dest->x, dest->y, dest->z, (line->flags & ML_NOCLIMB) ? mo->angle : dest->angle, false, (line->flags & ML_EFFECT4) == ML_EFFECT4); else { @@ -2511,7 +2512,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) mapmusname[6] = 0; mapmusflags = tracknum & MUSIC_TRACKMASK; - if (!(line->flags & ML_BLOCKMONSTERS)) + if (!(line->flags & ML_BLOCKPLAYERS)) mapmusflags |= MUSIC_RELOADRESET; if (line->flags & ML_BOUNCY) mapmusflags |= MUSIC_FORCERESET; @@ -2531,7 +2532,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } } - // Except, you can use the ML_BLOCKMONSTERS flag to change this behavior. + // Except, you can use the ML_BLOCKPLAYERS flag to change this behavior. // if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn. } break; @@ -2601,7 +2602,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // play the sound from nowhere S_StartSound(NULL, sfxnum); } - else if (line->flags & ML_BLOCKMONSTERS) + else if (line->flags & ML_BLOCKPLAYERS) { // play the sound from calling sector's soundorg if (callsec) @@ -2950,7 +2951,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) var1 = sides[line->sidenum[0]].toptexture; //(line->dx>>FRACBITS)-1; - if (line->sidenum[1] != 0xffff && line->flags & ML_BLOCKMONSTERS) // read power from back sidedef + if (line->sidenum[1] != 0xffff && line->flags & ML_BLOCKPLAYERS) // read power from back sidedef var2 = sides[line->sidenum[1]].toptexture; else if (line->flags & ML_NOCLIMB) // 'Infinite' var2 = UINT16_MAX; @@ -3551,6 +3552,97 @@ sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number, b return rover->master->frontsector; } +#ifdef POLYOBJECTS + // Allow sector specials to be applied to polyobjects! + if (mo->subsector->polyList) + { + polyobj_t *po = mo->subsector->polyList; + sector_t *polysec; + boolean touching = false; + boolean inside = false; + + while (po) + { + if (po->flags & POF_NOSPECIALS) + { + po = (polyobj_t *)(po->link.next); + continue; + } + + polysec = po->lines[0]->backsector; + + if (GETSECSPECIAL(polysec->special, section) != number) + { + po = (polyobj_t *)(po->link.next); + continue; + } + + if ((polysec->flags & SF_TRIGGERSPECIAL_TOUCH)) + touching = P_MobjTouchingPolyobj(po, mo); + else + touching = false; + + inside = P_MobjInsidePolyobj(po, mo); + + if (!(inside || touching)) + { + po = (polyobj_t *)(po->link.next); + continue; + } + + topheight = polysec->ceilingheight; + bottomheight = polysec->floorheight; + + // We're inside it! Yess... + if (!(po->flags & POF_TESTHEIGHT)) // Don't do height checking + { + } + else if (po->flags & POF_SOLID) + { + // Thing must be on top of the floor to be affected... + if ((polysec->flags & SF_FLIPSPECIAL_FLOOR) + && !(polysec->flags & SF_FLIPSPECIAL_CEILING)) + { + if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != topheight) + { + po = (polyobj_t *)(po->link.next); + continue; + } + } + else if ((polysec->flags & SF_FLIPSPECIAL_CEILING) + && !(polysec->flags & SF_FLIPSPECIAL_FLOOR)) + { + if (!(mo->eflags & MFE_VERTICALFLIP) || mo->z + mo->height != bottomheight) + { + po = (polyobj_t *)(po->link.next); + continue; + } + } + else if (polysec->flags & SF_FLIPSPECIAL_BOTH) + { + if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottomheight) + || (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == topheight))) + { + po = (polyobj_t *)(po->link.next); + continue; + } + } + } + else + { + // Water and DEATH FOG!!! heh + if (mo->z > topheight || (mo->z + mo->height) < bottomheight) + { + po = (polyobj_t *)(po->link.next); + continue; + } + } + + return polysec; + } + } +#endif + for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) { if (GETSECSPECIAL(node->m_sector->special, section) == number) @@ -3611,8 +3703,7 @@ sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number, b else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)) { - if (!(mo->eflags & MFE_VERTICALFLIP) - || mo->z + mo->height != bottomheight) + if (!(mo->eflags & MFE_VERTICALFLIP) || mo->z + mo->height != bottomheight) continue; } else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH) @@ -4106,7 +4197,7 @@ DoneSection2: if (gametype == GT_COOP && lineindex != -1) // Custom exit! { // Special goodies with the block monsters flag depending on emeralds collected - if ((lines[lineindex].flags & ML_BLOCKMONSTERS) && ALL7EMERALDS(emeralds)) + if ((lines[lineindex].flags & ML_BLOCKPLAYERS) && ALL7EMERALDS(emeralds)) nextmapoverride = (INT16)(lines[lineindex].frontsector->ceilingheight>>FRACBITS); else nextmapoverride = (INT16)(lines[lineindex].frontsector->floorheight>>FRACBITS); @@ -4205,11 +4296,7 @@ DoneSection2: } break; - case 7: // SRB2kart 190117 - Oil Slick (deprecated) - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) - { - K_SpinPlayer(player, NULL, 0, NULL, false); - } + case 7: // SRB2Kart: Destroy items break; case 8: // Zoom Tube Start @@ -5394,7 +5481,7 @@ static void P_AddRaiseThinker(sector_t *sec, line_t *sourceline) raise->thinker.function.acp1 = (actionf_p1)T_RaiseSector; - if (sourceline->flags & ML_BLOCKMONSTERS) + if (sourceline->flags & ML_BLOCKPLAYERS) raise->vars[0] = 1; else raise->vars[0] = 0; @@ -5453,7 +5540,7 @@ static void P_AddOldAirbob(sector_t *sec, line_t *sourceline, boolean noadjust) airbob->vars[3] = airbob->vars[2]; - if (sourceline->flags & ML_BLOCKMONSTERS) + if (sourceline->flags & ML_BLOCKPLAYERS) airbob->vars[0] = 1; else airbob->vars[0] = 0; @@ -6037,7 +6124,7 @@ void P_SpawnSpecials(INT32 fromnetsave) break; case 64: // Appearing/Disappearing FOF option - if (lines[i].flags & ML_BLOCKMONSTERS) { // Find FOFs by control sector tag + if (lines[i].flags & ML_BLOCKPLAYERS) { // Find FOFs by control sector tag for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) for (j = 0; (unsigned)j < sectors[s].linecount; j++) if (sectors[s].lines[j]->special >= 100 && sectors[s].lines[j]->special < 300) @@ -6265,7 +6352,7 @@ void P_SpawnSpecials(INT32 fromnetsave) case 150: // Air bobbing platform case 151: // Adjustable air bobbing platform P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - lines[i].flags |= ML_BLOCKMONSTERS; + lines[i].flags |= ML_BLOCKPLAYERS; P_AddOldAirbob(lines[i].frontsector, lines + i, (lines[i].special != 151)); break; case 152: // Adjustable air bobbing platform in reverse @@ -6320,14 +6407,14 @@ void P_SpawnSpecials(INT32 fromnetsave) case 176: // Air bobbing platform that will crumble and bob on the water when it falls and hits P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_FLOATBOB|FF_CRUMBLE, secthinkers); - lines[i].flags |= ML_BLOCKMONSTERS; + lines[i].flags |= ML_BLOCKPLAYERS; P_AddOldAirbob(lines[i].frontsector, lines + i, true); break; case 177: // Air bobbing platform that will crumble and bob on // the water when it falls and hits, then never return P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB|FF_CRUMBLE|FF_NORETURN, secthinkers); - lines[i].flags |= ML_BLOCKMONSTERS; + lines[i].flags |= ML_BLOCKPLAYERS; P_AddOldAirbob(lines[i].frontsector, lines + i, true); break; @@ -6341,7 +6428,7 @@ void P_SpawnSpecials(INT32 fromnetsave) case 180: // Air bobbing platform that will crumble P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE, secthinkers); - lines[i].flags |= ML_BLOCKMONSTERS; + lines[i].flags |= ML_BLOCKPLAYERS; P_AddOldAirbob(lines[i].frontsector, lines + i, true); break; diff --git a/src/p_telept.c b/src/p_telept.c index 74f9d462c..8c2f8ed70 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -66,9 +66,9 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, // absolute angle position if (thing == players[consoleplayer].mo) localangle[0] = angle; - else if (splitscreen) + else if (r_splitscreen) { - for (i = 1; i <= splitscreen; i++) + for (i = 1; i <= r_splitscreen; i++) { if (thing == players[displayplayers[i]].mo) { @@ -79,7 +79,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, } // move chasecam at new player location - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (thing->player == &players[displayplayers[i]] && camera[i].chase) P_ResetCamera(thing->player, &camera[i]); @@ -151,9 +151,9 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle // absolute angle position if (thing == players[consoleplayer].mo) localangle[0] = angle; - else if (splitscreen) + else if (r_splitscreen) { - for (i = 1; i <= splitscreen; i++) + for (i = 1; i <= r_splitscreen; i++) { if (thing == players[displayplayers[i]].mo) { @@ -164,7 +164,7 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle } // move chasecam at new player location - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (thing->player == &players[displayplayers[i]] && camera[i].chase) P_ResetCamera(thing->player, &camera[i]); diff --git a/src/p_tick.c b/src/p_tick.c index 2284cbc12..d7359b307 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -594,7 +594,7 @@ void P_Ticker(boolean run) return; } - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) postimgtype[i] = postimg_none; P_MapStart(); @@ -751,7 +751,7 @@ void P_Ticker(boolean run) } // Always move the camera. - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (camera[i].chase) P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false); @@ -771,7 +771,7 @@ void P_PreTicker(INT32 frames) INT32 i,framecnt; ticcmd_t temptic; - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) postimgtype[i] = postimg_none; for (framecnt = 0; framecnt < frames; ++framecnt) diff --git a/src/p_user.c b/src/p_user.c index 757354631..16038fade 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1083,7 +1083,7 @@ void P_PlayLivesJingle(player_t *player) void P_PlayRinglossSound(mobj_t *source) { - if (source->player && source->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD) + if (source->player && K_GetShieldFromItem(source->player->kartstuff[k_itemtype]) != KSHIELD_NONE) S_StartSound(source, sfx_s1a3); // Shield hit (no ring loss) else if (source->player && source->player->kartstuff[k_rings] <= 0) S_StartSound(source, sfx_s1a6); // Ring debt (lessened ring loss) @@ -1122,12 +1122,12 @@ boolean P_EndingMusic(player_t *player) // Event - Level Finish // Check for if this is valid or not - if (splitscreen) + if (r_splitscreen) { if (!((players[displayplayers[0]].exiting || (players[displayplayers[0]].pflags & PF_TIMEOVER)) || (players[displayplayers[1]].exiting || (players[displayplayers[1]].pflags & PF_TIMEOVER)) - || ((splitscreen < 2) && (players[displayplayers[2]].exiting || (players[displayplayers[2]].pflags & PF_TIMEOVER))) - || ((splitscreen < 3) && (players[displayplayers[3]].exiting || (players[displayplayers[3]].pflags & PF_TIMEOVER))))) + || ((r_splitscreen < 2) && (players[displayplayers[2]].exiting || (players[displayplayers[2]].pflags & PF_TIMEOVER))) + || ((r_splitscreen < 3) && (players[displayplayers[3]].exiting || (players[displayplayers[3]].pflags & PF_TIMEOVER))))) return false; bestlocalplayer = &players[displayplayers[0]]; @@ -1139,9 +1139,9 @@ boolean P_EndingMusic(player_t *player) bestlocalpos = ((players[p].pflags & PF_TIMEOVER) ? MAXPLAYERS+1 : players[p].kartstuff[k_position]); \ } setbests(displayplayers[1]); - if (splitscreen > 1) + if (r_splitscreen > 1) setbests(displayplayers[2]); - if (splitscreen > 2) + if (r_splitscreen > 2) setbests(displayplayers[3]); #undef setbests } @@ -1211,23 +1211,23 @@ void P_RestoreMusic(player_t *player) { INT32 wantedmus = 0; // 0 is level music, 1 is invincibility, 2 is grow - if (splitscreen) + if (r_splitscreen) { INT32 bestlocaltimer = 1; #define setbests(p) \ if (players[p].playerstate == PST_LIVE) \ { \ - if (players[p].kartstuff[k_growshrinktimer] > bestlocaltimer) \ - { wantedmus = 2; bestlocaltimer = players[p].kartstuff[k_growshrinktimer]; } \ - else if (players[p].kartstuff[k_invincibilitytimer] > bestlocaltimer) \ + if (players[p].kartstuff[k_invincibilitytimer] > bestlocaltimer) \ { wantedmus = 1; bestlocaltimer = players[p].kartstuff[k_invincibilitytimer]; } \ + else if (players[p].kartstuff[k_growshrinktimer] > bestlocaltimer) \ + { wantedmus = 2; bestlocaltimer = players[p].kartstuff[k_growshrinktimer]; } \ } setbests(displayplayers[0]); setbests(displayplayers[1]); - if (splitscreen > 1) + if (r_splitscreen > 1) setbests(displayplayers[2]); - if (splitscreen > 2) + if (r_splitscreen > 2) setbests(displayplayers[3]); #undef setbests } @@ -1235,10 +1235,10 @@ void P_RestoreMusic(player_t *player) { if (player->playerstate == PST_LIVE) { - if (player->kartstuff[k_growshrinktimer] > 1) - wantedmus = 2; - else if (player->kartstuff[k_invincibilitytimer] > 1) + if (player->kartstuff[k_invincibilitytimer] > 1) wantedmus = 1; + else if (player->kartstuff[k_growshrinktimer] > 1) + wantedmus = 2; } } @@ -1488,7 +1488,15 @@ boolean P_IsLocalPlayer(player_t *player) { UINT8 i; - if (player == &players[consoleplayer]) + if (r_splitscreen > splitscreen) + { + for (i = 0; i <= r_splitscreen; ++i) + { + if (player == &players[displayplayers[i]]) + return true; + } + } + else if (player == &players[consoleplayer]) return true; else if (splitscreen) { @@ -1512,7 +1520,7 @@ boolean P_IsDisplayPlayer(player_t *player) { UINT8 i; - for (i = 0; i <= splitscreen; i++) // DON'T skip P1 + for (i = 0; i <= r_splitscreen; i++) // DON'T skip P1 { if (player == &players[displayplayers[i]]) return true; @@ -6134,7 +6142,8 @@ static void P_MovePlayer(player_t *player) //////////////////////////// // SRB2kart - Drifting smoke and fire - if (EITHERSNEAKER(player) && onground && (leveltime & 1)) + if ((EITHERSNEAKER(player) || player->kartstuff[k_flamedash]) + && onground && (leveltime & 1)) K_SpawnBoostTrail(player); if (player->kartstuff[k_invincibilitytimer] > 0) @@ -7255,17 +7264,17 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall focusangle = localangle[0]; focusaiming = localaiming[0]; } - else if (player == &players[displayplayers[1]]) + else if (player == &players[g_localplayers[1]]) { focusangle = localangle[1]; focusaiming = localaiming[1]; } - else if (player == &players[displayplayers[2]]) + else if (player == &players[g_localplayers[2]]) { focusangle = localangle[2]; focusaiming = localaiming[2]; } - else if (player == &players[displayplayers[3]]) + else if (player == &players[g_localplayers[3]]) { focusangle = localangle[3]; focusaiming = localaiming[3]; @@ -7279,6 +7288,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (P_CameraThinker(player, thiscam, resetcalled)) return true; + lookback = ( player->cmd.buttons & BT_LOOKBACK ); if (thiscam == &camera[1]) // Camera 2 { @@ -7288,7 +7298,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camrotate = cv_cam2_rotate.value; camdist = FixedMul(cv_cam2_dist.value, mapobjectscale); camheight = FixedMul(cv_cam2_height.value, mapobjectscale); - lookback = camspin[1]; } else if (thiscam == &camera[2]) // Camera 3 { @@ -7298,7 +7307,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camrotate = cv_cam3_rotate.value; camdist = FixedMul(cv_cam3_dist.value, mapobjectscale); camheight = FixedMul(cv_cam3_height.value, mapobjectscale); - lookback = camspin[2]; } else if (thiscam == &camera[3]) // Camera 4 { @@ -7308,7 +7316,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camrotate = cv_cam4_rotate.value; camdist = FixedMul(cv_cam4_dist.value, mapobjectscale); camheight = FixedMul(cv_cam4_height.value, mapobjectscale); - lookback = camspin[3]; } else // Camera 1 { @@ -7318,7 +7325,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall camrotate = cv_cam_rotate.value; camdist = FixedMul(cv_cam_dist.value, mapobjectscale); camheight = FixedMul(cv_cam_height.value, mapobjectscale); - lookback = camspin[0]; } if (timeover) @@ -7428,7 +7434,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall else distxy = dist; distz = -FixedMul(dist, FINESINE((pitch>>ANGLETOFINESHIFT) & FINEMASK)); - if (splitscreen == 1) // 2 player is weird, this helps keep players on screen + if (r_splitscreen == 1) // 2 player is weird, this helps keep players on screen distz = 3*distz/5; x = mo->x - FixedMul(FINECOSINE((angle>>ANGLETOFINESHIFT) & FINEMASK), distxy); @@ -7845,8 +7851,8 @@ boolean P_SpectatorJoinGame(player_t *player) player->playerstate = PST_REBORN; //Reset away view - if (P_IsLocalPlayer(player) && displayplayers[0] != consoleplayer) - displayplayers[0] = consoleplayer; + if (P_IsLocalPlayer(player) && g_localplayers[0] != consoleplayer) + g_localplayers[0] = consoleplayer; HU_AddChatText(va(M_GetText("\x82*%s entered the game."), player_names[player-players]), false); return true; // no more player->mo, cannot continue. @@ -7873,7 +7879,7 @@ static void P_CalcPostImg(player_t *player) pviewheight = player->awayviewmobj->z + 20*FRACUNIT; } - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (player == &players[displayplayers[i]]) { @@ -8038,7 +8044,7 @@ void P_PlayerThink(player_t *player) } #ifdef SEENAMES - if (netgame && player == &players[displayplayers[0]] && !(leveltime % (TICRATE/5)) && !splitscreen) + if (netgame && player == &players[displayplayers[0]] && !(leveltime % (TICRATE/5)) && !r_splitscreen) { seenplayer = NULL; @@ -8369,7 +8375,7 @@ void P_PlayerThink(player_t *player) // Hide the mobj from our sights if we're the displayplayer and chasecam is off. // Why not just not spawn the mobj? Well, I'd rather only flirt with // consistency so much... - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (player == &players[displayplayers[i]] && !camera[i].chase) { @@ -8599,7 +8605,7 @@ void P_PlayerAfterThink(player_t *player) P_PlayerInSpecialSector(player); #endif - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (player == &players[displayplayers[i]]) { diff --git a/src/r_bsp.c b/src/r_bsp.c index a748af51c..13240fe47 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -264,7 +264,7 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, boolean underwater; UINT8 i; - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (viewplayer == &players[displayplayers[i]] && camera[i].chase) { @@ -273,7 +273,7 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, } } - if (i > splitscreen && viewmobj) + if (i > r_splitscreen && viewmobj) heightsec = R_PointInSubsector(viewmobj->x, viewmobj->y)->sector->heightsec; else return sec; diff --git a/src/r_defs.h b/src/r_defs.h index 52a3be80e..c8a72044d 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -406,6 +406,8 @@ typedef enum ST_NEGATIVE } slopetype_t; +#define HORIZONSPECIAL 41 + typedef struct line_s { // Vertices, from v1 to v2. diff --git a/src/r_draw.c b/src/r_draw.c index 1931ce6ee..70e487342 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -299,7 +299,7 @@ void R_InitViewBuffer(INT32 width, INT32 height) for (i = 0; i < height; i++) { ylookup[i] = ylookup1[i] = screens[0] + i*vid.width*bytesperpixel; - if (splitscreen == 1) + if (r_splitscreen == 1) ylookup2[i] = screens[0] + (i+viewheight)*vid.width*bytesperpixel; else ylookup2[i] = screens[0] + i*vid.width*bytesperpixel + (viewwidth*bytesperpixel); diff --git a/src/r_main.c b/src/r_main.c index 06d53a2f5..5afda93f7 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -73,6 +73,8 @@ boolean skyVisiblePerPlayer[MAXSPLITSCREENPLAYERS]; // saved values of skyVisibl sector_t *viewsector; player_t *viewplayer; +int r_splitscreen; + // PORTALS! // You can thank and/or curse JTE for these. UINT8 portalrender; @@ -191,6 +193,12 @@ void SplitScreen_OnChange(void) { UINT8 i; + /* + local splitscreen is updated before you're in a game, + so this is the first value for renderer splitscreen + */ + r_splitscreen = splitscreen; + // recompute screen size R_ExecuteSetViewSize(); @@ -658,12 +666,12 @@ void R_ExecuteSetViewSize(void) scaledviewwidth = vid.width; viewheight = vid.height; - if (splitscreen) + if (r_splitscreen) viewheight >>= 1; viewwidth = scaledviewwidth; - if (splitscreen > 1) + if (r_splitscreen > 1) { viewwidth >>= 1; scaledviewwidth >>= 1; @@ -676,7 +684,7 @@ void R_ExecuteSetViewSize(void) fov = FixedAngle(cv_fov.value/2) + ANGLE_90; fovtan = FINETANGENT(fov >> ANGLETOFINESHIFT); - if (splitscreen == 1) // Splitscreen FOV should be adjusted to maintain expected vertical view + if (r_splitscreen == 1) // Splitscreen FOV should be adjusted to maintain expected vertical view fovtan = 17*fovtan/10; projection = projectiony = FixedDiv(centerxfrac, fovtan); @@ -847,9 +855,9 @@ void R_SkyboxFrame(player_t *player) camera_t *thiscam = &camera[0]; UINT8 i; - if (splitscreen) + if (r_splitscreen) { - for (i = 1; i <= splitscreen; i++) + for (i = 1; i <= r_splitscreen; i++) { if (player == &players[displayplayers[i]]) { @@ -894,7 +902,7 @@ void R_SkyboxFrame(player_t *player) { for (i = 1; i <= splitscreen; i++) { - if (player == &players[displayplayers[i]]) + if (player == &players[g_localplayers[i]]) { viewangle = localangle[i]; aimingangle = localaiming[i]; @@ -1079,17 +1087,17 @@ void R_SetupFrame(player_t *player, boolean skybox) camera_t *thiscam; boolean chasecam = false; - if (splitscreen > 2 && player == &players[displayplayers[3]]) + if (r_splitscreen > 2 && player == &players[displayplayers[3]]) { thiscam = &camera[3]; chasecam = (cv_chasecam4.value != 0); } - else if (splitscreen > 1 && player == &players[displayplayers[2]]) + else if (r_splitscreen > 1 && player == &players[displayplayers[2]]) { thiscam = &camera[2]; chasecam = (cv_chasecam3.value != 0); } - else if (splitscreen && player == &players[displayplayers[1]]) + else if (r_splitscreen && player == &players[displayplayers[1]]) { thiscam = &camera[1]; chasecam = (cv_chasecam2.value != 0); @@ -1154,7 +1162,7 @@ void R_SetupFrame(player_t *player, boolean skybox) UINT8 i; for (i = 1; i <= splitscreen; i++) { - if (player == &players[displayplayers[i]]) + if (player == &players[g_localplayers[i]]) { viewangle = localangle[i]; aimingangle = localaiming[i]; @@ -1333,7 +1341,7 @@ void R_RenderPlayerView(player_t *player) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 32+(timeinmap&15)); } // Draw over the fourth screen so you don't have to stare at a HOM :V - else if (splitscreen == 2 && player == &players[displayplayers[2]]) + else if (r_splitscreen == 2 && player == &players[displayplayers[2]]) #if 1 { // V_DrawPatchFill, but for the fourth screen only @@ -1352,7 +1360,7 @@ void R_RenderPlayerView(player_t *player) #endif // load previous saved value of skyVisible for the player - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (player == &players[displayplayers[i]]) { @@ -1462,7 +1470,7 @@ void R_RenderPlayerView(player_t *player) // save value to skyVisiblePerPlayer // this is so that P1 can't affect whether P2 can see a skybox or not, or vice versa - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { if (player == &players[displayplayers[i]]) { diff --git a/src/r_plane.c b/src/r_plane.c index ec105bf75..08a449e6c 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -883,12 +883,12 @@ void R_DrawSinglePlane(visplane_t *pl) if (bottom > vid.height) bottom = vid.height; - if (splitscreen > 2 && viewplayer == &players[displayplayers[3]]) // Only copy the part of the screen we need + if (r_splitscreen > 2 && viewplayer == &players[displayplayers[3]]) // Only copy the part of the screen we need scr = (screens[0] + (top+(viewheight))*vid.width + viewwidth); - else if ((splitscreen == 1 && viewplayer == &players[displayplayers[1]]) - || (splitscreen > 1 && viewplayer == &players[displayplayers[2]])) + else if ((r_splitscreen == 1 && viewplayer == &players[displayplayers[1]]) + || (r_splitscreen > 1 && viewplayer == &players[displayplayers[2]])) scr = (screens[0] + (top+(viewheight))*vid.width); - else if (splitscreen > 1 && viewplayer == &players[displayplayers[1]]) + else if (r_splitscreen > 1 && viewplayer == &players[displayplayers[1]]) scr = (screens[0] + ((top)*vid.width) + viewwidth); else scr = (screens[0] + ((top)*vid.width)); diff --git a/src/r_segs.c b/src/r_segs.c index 399f514bc..2304540fe 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -2687,7 +2687,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) worldbottomslope >>= 4; #endif - if (linedef->special == 41) { // HORIZON LINES + if (linedef->special == HORIZONSPECIAL) { // HORIZON LINES topstep = bottomstep = 0; topfrac = bottomfrac = (centeryfrac>>4); topfrac++; // Prevent 1px HOM @@ -2817,12 +2817,23 @@ void R_StoreWallRange(INT32 start, INT32 stop) ffloor[i].f_pos >>= 4; #ifdef ESLOPE ffloor[i].f_pos_slope >>= 4; - ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); - ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(range); -#else - ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos); - ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); #endif + if (linedef->special == HORIZONSPECIAL) // Horizon lines extend FOFs in contact with them too. + { + ffloor[i].f_step = 0; + ffloor[i].f_frac = (centeryfrac>>4); + topfrac++; // Prevent 1px HOM + } + else + { +#ifdef ESLOPE + ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); + ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(range); +#else + ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos); + ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale); +#endif + } } } diff --git a/src/r_sky.c b/src/r_sky.c index 1fe0fe0e6..3904eba3a 100644 --- a/src/r_sky.c +++ b/src/r_sky.c @@ -81,7 +81,7 @@ void R_SetSkyScale(void) { fixed_t difference = vid.fdupx-(vid.dupx< 1) + if (r_splitscreen > 1) scr *= 2; skyscale = FixedDiv(scr, vid.fdupx+difference); } diff --git a/src/r_things.c b/src/r_things.c index 4b7339c4e..587be375d 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2109,7 +2109,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) continue; - if (splitscreen) + if (r_splitscreen) { if (thing->eflags & MFE_DRAWONLYFORP1) if (viewssnum != 0) @@ -2119,11 +2119,11 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) if (viewssnum != 1) continue; - if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) + if (thing->eflags & MFE_DRAWONLYFORP3 && r_splitscreen > 1) if (viewssnum != 2) continue; - if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) + if (thing->eflags & MFE_DRAWONLYFORP4 && r_splitscreen > 2) if (viewssnum != 3) continue; } @@ -2144,7 +2144,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW) continue; - if (splitscreen) + if (r_splitscreen) { if (thing->eflags & MFE_DRAWONLYFORP1) if (viewssnum != 0) @@ -2154,11 +2154,11 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) if (viewssnum != 1) continue; - if (thing->eflags & MFE_DRAWONLYFORP3 && splitscreen > 1) + if (thing->eflags & MFE_DRAWONLYFORP3 && r_splitscreen > 1) if (viewssnum != 2) continue; - if (thing->eflags & MFE_DRAWONLYFORP4 && splitscreen > 2) + if (thing->eflags & MFE_DRAWONLYFORP4 && r_splitscreen > 2) if (viewssnum != 3) continue; } diff --git a/src/s_sound.c b/src/s_sound.c index 21b668f28..82435d3dc 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -457,19 +457,19 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) if (players[displayplayers[0]].awayviewtics) listenmobj = players[displayplayers[0]].awayviewmobj; - if (splitscreen) + if (r_splitscreen) { listenmobj2 = players[displayplayers[1]].mo; if (players[displayplayers[1]].awayviewtics) listenmobj2 = players[displayplayers[1]].awayviewmobj; - if (splitscreen > 1) + if (r_splitscreen > 1) { listenmobj3 = players[displayplayers[2]].mo; if (players[displayplayers[2]].awayviewtics) listenmobj3 = players[displayplayers[2]].awayviewmobj; - if (splitscreen > 2) + if (r_splitscreen > 2) { listenmobj4 = players[displayplayers[3]].mo; if (players[displayplayers[3]].awayviewtics) @@ -574,10 +574,10 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) pitch = NORM_PITCH; priority = NORM_PRIORITY; - if (splitscreen && origin) - volume = FixedDiv(volume<>FRACBITS; + if (r_splitscreen && origin) + volume = FixedDiv(volume<>FRACBITS; - if (splitscreen && listenmobj2) // Copy the sound for the split player + if (r_splitscreen && listenmobj2) // Copy the sound for the split player { // Check to see if it is audible, and if not, modify the params if (origin && origin != listenmobj2) @@ -633,7 +633,7 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) dontplay: - if (splitscreen > 1 && listenmobj3) // Copy the sound for the third player + if (r_splitscreen > 1 && listenmobj3) // Copy the sound for the third player { // Check to see if it is audible, and if not, modify the params if (origin && origin != listenmobj3) @@ -689,7 +689,7 @@ dontplay: dontplay3: - if (splitscreen > 2 && listenmobj4) // Copy the sound for the split player + if (r_splitscreen > 2 && listenmobj4) // Copy the sound for the split player { // Check to see if it is audible, and if not, modify the params if (origin && origin != listenmobj4) @@ -942,19 +942,19 @@ void S_UpdateSounds(void) if (players[displayplayers[0]].awayviewtics) listenmobj = players[displayplayers[0]].awayviewmobj; - if (splitscreen) + if (r_splitscreen) { listenmobj2 = players[displayplayers[1]].mo; if (players[displayplayers[1]].awayviewtics) listenmobj2 = players[displayplayers[1]].awayviewmobj; - if (splitscreen > 1) + if (r_splitscreen > 1) { listenmobj3 = players[displayplayers[2]].mo; if (players[displayplayers[2]].awayviewtics) listenmobj3 = players[displayplayers[2]].awayviewmobj; - if (splitscreen > 2) + if (r_splitscreen > 2) { listenmobj4 = players[displayplayers[3]].mo; if (players[displayplayers[3]].awayviewtics) @@ -1058,24 +1058,24 @@ void S_UpdateSounds(void) pitch = NORM_PITCH; sep = NORM_SEP; - if (splitscreen && c->origin) - volume = FixedDiv(volume<>FRACBITS; + if (r_splitscreen && c->origin) + volume = FixedDiv(volume<>FRACBITS; // check non-local sounds for distance clipping // or modify their params - if (c->origin && ((c->origin != players[consoleplayer].mo) - || (splitscreen && c->origin != players[displayplayers[1]].mo) - || (splitscreen > 1 && c->origin != players[displayplayers[2]].mo) - || (splitscreen > 2 && c->origin != players[displayplayers[3]].mo))) + if (c->origin && ((c->origin != players[displayplayers[0]].mo) + || (r_splitscreen && c->origin != players[displayplayers[1]].mo) + || (r_splitscreen > 1 && c->origin != players[displayplayers[2]].mo) + || (r_splitscreen > 2 && c->origin != players[displayplayers[3]].mo))) { // Whomever is closer gets the sound, but only in splitscreen. - if (splitscreen) + if (r_splitscreen) { const mobj_t *soundmobj = c->origin; fixed_t recdist = -1; INT32 i, p = -1; - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { fixed_t thisdist = -1; @@ -1130,7 +1130,7 @@ void S_UpdateSounds(void) S_StopChannel(cnum); } } - else if (listenmobj && !splitscreen) + else if (listenmobj && !r_splitscreen) { // In the case of a single player, he or she always should get updated sound. audible = S_AdjustSoundParams(listenmobj, c->origin, &volume, &sep, &pitch, @@ -1258,21 +1258,21 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v listensource.z = camera[0].z; listensource.angle = camera[0].angle; } - else if (splitscreen && listener == players[displayplayers[1]].mo && camera[1].chase) + else if (r_splitscreen && listener == players[displayplayers[1]].mo && camera[1].chase) { listensource.x = camera[1].x; listensource.y = camera[1].y; listensource.z = camera[1].z; listensource.angle = camera[1].angle; } - else if (splitscreen > 1 && listener == players[displayplayers[2]].mo && camera[2].chase) + else if (r_splitscreen > 1 && listener == players[displayplayers[2]].mo && camera[2].chase) { listensource.x = camera[2].x; listensource.y = camera[2].y; listensource.z = camera[2].z; listensource.angle = camera[2].angle; } - else if (splitscreen > 2 && listener == players[displayplayers[3]].mo && camera[3].chase) + else if (r_splitscreen > 2 && listener == players[displayplayers[3]].mo && camera[3].chase) { listensource.x = camera[3].x; listensource.y = camera[3].y; @@ -1372,8 +1372,8 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v *vol = (15 * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR; } - if (splitscreen) - *vol = FixedDiv((*vol)<>FRACBITS; + if (r_splitscreen) + *vol = FixedDiv((*vol)<>FRACBITS; return (*vol > 0); } diff --git a/src/screen.c b/src/screen.c index 96a78ae8e..5b38f82db 100644 --- a/src/screen.c +++ b/src/screen.c @@ -445,7 +445,7 @@ void SCR_DisplayTicRate(void) void SCR_DisplayLocalPing(void) { UINT32 ping = playerpingtable[consoleplayer]; // consoleplayer's ping is everyone's ping in a splitnetgame :P - if (cv_showping.value == 1 || (cv_showping.value == 2 && ping > servermaxping)) // only show 2 (warning) if our ping is at a bad level + if (! r_splitscreen && ( cv_showping.value == 1 || (cv_showping.value == 2 && ping > servermaxping) )) // only show 2 (warning) if our ping is at a bad level { INT32 dispy = cv_ticrate.value ? 160 : 181; HU_drawPing(307, dispy, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM | V_HUDTRANS); diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c index 41a9d7cd6..816142d72 100644 --- a/src/sdl/i_main.c +++ b/src/sdl/i_main.c @@ -20,12 +20,19 @@ #include "../doomdef.h" #include "../m_argv.h" #include "../d_main.h" +#include "../m_misc.h"/* path shit */ #include "../i_system.h" -#ifdef __GNUC__ +#if defined (__GNUC__) || defined (__unix__) #include #endif +#ifdef __unix__ +#include +#endif + +#include "time.h" // For log timestamps + #ifdef HAVE_SDL #ifdef HAVE_TTF @@ -45,6 +52,7 @@ extern int SDL_main(int argc, char *argv[]); #ifdef LOGMESSAGES FILE *logstream = NULL; +char logfilename[1024]; #endif #ifndef DOXYGEN @@ -125,16 +133,89 @@ int main(int argc, char **argv) #endif #endif - logdir = D_Home(); - #ifdef LOGMESSAGES + if (!M_CheckParm("-nolog")) + { + time_t my_time; + struct tm * timeinfo; + const char *format; + const char *reldir; + int left; + boolean fileabs; + const char *link; + + logdir = D_Home(); + + my_time = time(NULL); + timeinfo = localtime(&my_time); + + if (M_CheckParm("-logfile") && M_IsNextParm()) + { + format = M_GetNextParm(); + fileabs = M_IsPathAbsolute(format); + } + else + { + format = "log-%Y-%m-%d_%H-%M-%S.txt"; + fileabs = false; + } + + if (fileabs) + { + strftime(logfilename, sizeof logfilename, format, timeinfo); + } + else + { + if (M_CheckParm("-logdir") && M_IsNextParm()) + reldir = M_GetNextParm(); + else + reldir = "logs"; + + if (M_IsPathAbsolute(reldir)) + { + left = snprintf(logfilename, sizeof logfilename, + "%s"PATHSEP, reldir); + } + else #ifdef DEFAULTDIR - if (logdir) - logstream = fopen(va("%s/"DEFAULTDIR"/log.txt",logdir), "wt"); - else -#endif - logstream = fopen("./log.txt", "wt"); -#endif + if (logdir) + { + left = snprintf(logfilename, sizeof logfilename, + "%s"PATHSEP DEFAULTDIR PATHSEP"%s"PATHSEP, logdir, reldir); + } + else +#endif/*DEFAULTDIR*/ + { + left = snprintf(logfilename, sizeof logfilename, + "."PATHSEP"%s"PATHSEP, reldir); + } +#endif/*LOGMESSAGES*/ + + strftime(&logfilename[left], sizeof logfilename - left, + format, timeinfo); + } + + M_MkdirEachUntil(logfilename, + M_PathParts(logdir) - 1, + M_PathParts(logfilename) - 1, 0755); + +#ifdef __unix__ + logstream = fopen(logfilename, "w"); +#ifdef DEFAULTDIR + if (logdir) + link = va("%s/"DEFAULTDIR"/latest-log.txt", logdir); + else +#endif/*DEFAULTDIR*/ + link = "latest-log.txt"; + unlink(link); + if (symlink(logfilename, link) == -1) + { + I_OutputMsg("Error symlinking latest-log.txt: %s\n", strerror(errno)); + } +#else/*__unix__*/ + logstream = fopen("latest-log.txt", "wt+"); +#endif/*__unix__*/ + } //I_OutputMsg("I_StartupSystem() ...\n"); I_StartupSystem(); @@ -160,6 +241,10 @@ int main(int argc, char **argv) // startup SRB2 CONS_Printf("Setting up SRB2Kart...\n"); D_SRB2Main(); +#ifdef LOGMESSAGES + if (!M_CheckParm("-nolog")) + CONS_Printf("Logfile: %s\n", logfilename); +#endif CONS_Printf("Entering main game loop...\n"); // never return D_SRB2Loop(); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index f75a42117..2ccdec5c4 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -3268,6 +3268,48 @@ void I_RemoveExitFunc(void (*func)()) } } +#ifndef __unix__ +static void Shittycopyerror(const char *name) +{ + I_OutputMsg( + "Error copying log file: %s: %s\n", + name, + strerror(errno) + ); +} + +static void Shittylogcopy(void) +{ + char buf[8192]; + FILE *fp; + int n; + if (fseek(logstream, 0, SEEK_SET) == -1) + { + Shittycopyerror("fseek"); + } + else if (( fp = fopen(logfilename, "wt") )) + { + while (( n = fread(buf, 1, sizeof buf, logstream) )) + { + if (fwrite(buf, 1, n, fp) < n) + { + Shittycopyerror("fwrite"); + break; + } + } + if (ferror(logstream)) + { + Shittycopyerror("fread"); + } + fclose(fp); + } + else + { + Shittycopyerror(logfilename); + } +} +#endif/*__unix__*/ + // // Closes down everything. This includes restoring the initial // palette and video mode, and removing whatever mouse, keyboard, and @@ -3286,6 +3328,9 @@ void I_ShutdownSystem(void) if (logstream) { I_OutputMsg("I_ShutdownSystem(): end of logstream.\n"); +#ifndef __unix__ + Shittylogcopy(); +#endif fclose(logstream); logstream = NULL; } diff --git a/src/sdl12/sdl_sound.c b/src/sdl12/sdl_sound.c index ed1afd8e2..1a7525fee 100644 --- a/src/sdl12/sdl_sound.c +++ b/src/sdl12/sdl_sound.c @@ -1435,7 +1435,7 @@ static boolean LoadSong(void *data, size_t lumplength, size_t selectpos) if (fwrite(data, lumplength, 1, midfile) == 0) { - CONS_Printf(M_GetText("Couldn't write music into file %s because %s\n"), tempname, strerror(ferror(midfile))); + CONS_Printf(M_GetText("Couldn't write music into file %s because %s\n"), tempname, M_FileError(midfile)); Z_Free(data); fclose(midfile); return false; diff --git a/src/sounds.c b/src/sounds.c index adae99df5..b64dda5cb 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -408,13 +408,13 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k3b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k3c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k3d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart Flame Shield spawned + {"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart Bubble Shield spawned {"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart Thunder Shield spawned - {"s3k43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, - {"s3k44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart Thunder Shield spawned + {"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, + {"s3k43", false, 96, 48, -1, NULL, 0, -1, -1, LUMPERROR}, + {"s3k44", false, 96, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart Bubble Shield reflect {"s3k45", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k46", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, {"s3k47", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR}, // Kart AIZ dust diff --git a/src/st_stuff.c b/src/st_stuff.c index 8ac6e89a0..5da057045 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -230,7 +230,7 @@ void ST_doPaletteStuff(void) if (rendermode != render_none) { //V_SetPaletteLump(GetPalette()); // Reset the palette -- is this needed? - if (!splitscreen) + if (!r_splitscreen) V_SetPalette(palette); } } @@ -515,9 +515,9 @@ static INT32 SCR(INT32 r) #define ST_DrawNumFromHud(h,n) V_DrawTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART|V_HUDTRANS, n) #define ST_DrawPadNumFromHud(h,n,q) V_DrawPaddedTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART|V_HUDTRANS, n, q) #define ST_DrawPatchFromHud(h,p) V_DrawScaledPatch(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART|V_HUDTRANS, p) -#define ST_DrawNumFromHudWS(h,n) V_DrawTallNum(SCX(hudinfo[h+!!splitscreen].x), SCY(hudinfo[h+!!splitscreen].y), V_NOSCALESTART|V_HUDTRANS, n) -#define ST_DrawPadNumFromHudWS(h,n,q) V_DrawPaddedTallNum(SCX(hudinfo[h+!!splitscreen].x), SCY(hudinfo[h+!!splitscreen].y), V_NOSCALESTART|V_HUDTRANS, n, q) -#define ST_DrawPatchFromHudWS(h,p) V_DrawScaledPatch(SCX(hudinfo[h+!!splitscreen].x), SCY(hudinfo[h+!!splitscreen].y), V_NOSCALESTART|V_HUDTRANS, p) +#define ST_DrawNumFromHudWS(h,n) V_DrawTallNum(SCX(hudinfo[h+!!r_splitscreen].x), SCY(hudinfo[h+!!r_splitscreen].y), V_NOSCALESTART|V_HUDTRANS, n) +#define ST_DrawPadNumFromHudWS(h,n,q) V_DrawPaddedTallNum(SCX(hudinfo[h+!!r_splitscreen].x), SCY(hudinfo[h+!!r_splitscreen].y), V_NOSCALESTART|V_HUDTRANS, n, q) +#define ST_DrawPatchFromHudWS(h,p) V_DrawScaledPatch(SCX(hudinfo[h+!!r_splitscreen].x), SCY(hudinfo[h+!!r_splitscreen].y), V_NOSCALESTART|V_HUDTRANS, p) /* // Draw a number, scaled, over the view, maybe with set translucency @@ -757,7 +757,7 @@ static void ST_drawLevelTitle(void) INT32 dupcalc = (vid.width/vid.dupx); UINT8 gtc = G_GetGametypeColor(gametype); INT32 sub = 0; - INT32 bary = (splitscreen) + INT32 bary = (r_splitscreen) ? BASEVIDHEIGHT/2 : 163; INT32 lvlw; @@ -1911,12 +1911,12 @@ static void ST_overlayDrawer(void) } else if (!demo.title) { - if (!splitscreen) + if (!r_splitscreen) { V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-40, V_HUDTRANSHALF, M_GetText("VIEWPOINT:")); V_DrawCenteredString((BASEVIDWIDTH/2), BASEVIDHEIGHT-32, V_HUDTRANSHALF|V_ALLOWLOWERCASE, player_names[stplyr-players]); } - else if (splitscreen == 1) + else if (r_splitscreen == 1) { char name[MAXPLAYERNAME+12]; @@ -1924,7 +1924,7 @@ static void ST_overlayDrawer(void) sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]); V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT), name); } - else if (splitscreen) + else if (r_splitscreen) { V_DrawCenteredThinString((vid.width/vid.dupx)/4, BASEVIDHEIGHT/2 - 12, V_HUDTRANSHALF|V_ALLOWLOWERCASE|K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT), player_names[stplyr-players]); } @@ -2000,7 +2000,7 @@ static void ST_overlayDrawer(void) } // SRB2kart: changed positions & text - if (splitscreen) + if (r_splitscreen) { INT32 splitflags = K_calcSplitFlags(0); V_DrawThinString(2, (BASEVIDHEIGHT/2)-20, V_YELLOWMAP|V_HUDTRANSHALF|splitflags, M_GetText("- SPECTATING -")); @@ -2091,7 +2091,7 @@ void ST_Drawer(void) UINT8 i; #ifdef SEENAMES - if (cv_seenames.value && cv_allowseenames.value && displayplayers[0] == consoleplayer && seenplayer && seenplayer->mo && !mapreset) + if (cv_seenames.value && cv_allowseenames.value && g_localplayers[0] == consoleplayer && seenplayer && seenplayer->mo && !mapreset) { if (cv_seenames.value == 1) V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 + 15, V_HUDTRANSHALF, player_names[seenplayer-players]); @@ -2125,7 +2125,7 @@ void ST_Drawer(void) if (st_overlay) { // No deadview! - for (i = 0; i <= splitscreen; i++) + for (i = 0; i <= r_splitscreen; i++) { stplyr = &players[displayplayers[i]]; ST_overlayDrawer(); diff --git a/src/v_video.c b/src/v_video.c index d7e8b64c1..67e7963f9 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -2678,15 +2678,15 @@ void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param) return; #endif - if (view < 0 || view > 3 || view > splitscreen) + if (view < 0 || view > 3 || view > r_splitscreen) return; - if ((view == 1 && splitscreen == 1) || view >= 2) + if ((view == 1 && r_splitscreen == 1) || view >= 2) yoffset = viewheight; else yoffset = 0; - if ((view == 1 || view == 3) && splitscreen > 1) + if ((view == 1 || view == 3) && r_splitscreen > 1) xoffset = viewwidth; else xoffset = 0; diff --git a/src/w_wad.c b/src/w_wad.c index da82a276d..734308956 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -366,7 +366,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen // read the header if (fread(&header, 1, sizeof header, handle) < sizeof header) { - CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header because %s\n"), strerror(ferror(handle))); + CONS_Alert(CONS_ERROR, M_GetText("Can't read wad header because %s\n"), M_FileError(handle)); return NULL; } @@ -389,7 +389,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen if (fseek(handle, header.infotableofs, SEEK_SET) == -1 || fread(fileinfo, 1, i, handle) < i) { - CONS_Alert(CONS_ERROR, M_GetText("Corrupt wadfile directory (%s)\n"), strerror(ferror(handle))); + CONS_Alert(CONS_ERROR, M_GetText("Corrupt wadfile directory (%s)\n"), M_FileError(handle)); free(fileinfov); return NULL; } @@ -410,7 +410,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen handle) < sizeof realsize) { I_Error("corrupt compressed file: %s; maybe %s", /// \todo Avoid the bailout? - filename, strerror(ferror(handle))); + filename, M_FileError(handle)); } realsize = LONG(realsize); if (realsize != 0) @@ -548,7 +548,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) fseek(handle, -4, SEEK_CUR); if (fread(&zend, 1, sizeof zend, handle) < sizeof zend) { - CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", strerror(ferror(handle))); + CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", M_FileError(handle)); return NULL; } numlumps = zend.entries; @@ -565,7 +565,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) if (fread(zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t)) { - CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", strerror(ferror(handle))); + CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle)); Z_Free(lumpinfo); free(zentry); return NULL; @@ -585,7 +585,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) fullname = malloc(zentry->namelen + 1); if (fgets(fullname, zentry->namelen + 1, handle) != fullname) { - CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", strerror(ferror(handle))); + CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle)); Z_Free(lumpinfo); free(zentry); free(fullname); diff --git a/src/y_inter.c b/src/y_inter.c index 94f454496..e9e243b04 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -367,7 +367,7 @@ void Y_IntermissionDrawer(void) if (usebuffer) // Fade everything out V_DrawFadeScreen(0xFF00, 22); - if (!splitscreen) + if (!r_splitscreen) whiteplayer = demo.playback ? displayplayers[0] : consoleplayer; if (cons_menuhighlight.value) @@ -496,7 +496,7 @@ void Y_IntermissionDrawer(void) y2 = y; - if (data.match.num[i] == 0 && server_lagless) + if (playerconsole[data.match.num[i]] == 0 && server_lagless) { static int alagles_timer = 0; patch_t *alagles; @@ -1316,19 +1316,19 @@ void Y_VoteDrawer(void) { case 1: thiscurs = cursor2; - p = displayplayers[1]; + p = g_localplayers[1]; break; case 2: thiscurs = cursor3; - p = displayplayers[2]; + p = g_localplayers[2]; break; case 3: thiscurs = cursor4; - p = displayplayers[3]; + p = g_localplayers[3]; break; default: thiscurs = cursor1; - p = displayplayers[0]; + p = g_localplayers[0]; break; } @@ -1616,13 +1616,13 @@ void Y_VoteTicker(void) switch (i) { case 1: - p = displayplayers[1]; + p = g_localplayers[1]; break; case 2: - p = displayplayers[2]; + p = g_localplayers[2]; break; case 3: - p = displayplayers[3]; + p = g_localplayers[3]; break; default: p = consoleplayer;