diff --git a/src/Makefile b/src/Makefile index 16cb8912d..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 \ @@ -494,6 +495,8 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/y_inter.o \ $(OBJDIR)/st_stuff.o \ $(OBJDIR)/k_kart.o \ + $(OBJDIR)/k_collide.o\ + $(OBJDIR)/k_battle.o \ $(OBJDIR)/k_pwrlv.o \ $(OBJDIR)/k_waypoint.o\ $(OBJDIR)/k_pathfind.o\ diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 308eb2616..084a6fd81 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -47,6 +47,7 @@ #include "lua_script.h" #include "lua_hook.h" #include "k_kart.h" +#include "k_battle.h" #include "k_pwrlv.h" #ifdef CLIENT_LOADINGSCREEN @@ -84,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]; @@ -1507,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; @@ -1526,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++) { @@ -1537,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; } @@ -2621,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! @@ -2628,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)); } @@ -2703,6 +2733,8 @@ void CL_RemovePlayer(INT32 playernum, INT32 reason) (void)reason; #endif + G_RemovePartyMember(playernum); + // Reset player data CL_ClearPlayer(playernum); @@ -2720,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]); @@ -3353,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; @@ -3457,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; @@ -3477,10 +3513,11 @@ 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); - + // Clear player before joining, lest some things get set incorrectly CL_ClearPlayer(newplayernum); @@ -3497,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; @@ -3505,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"); } @@ -3515,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) @@ -3576,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; @@ -3613,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]++; @@ -3719,7 +3768,11 @@ void SV_StartSinglePlayerServer(void) server = true; netgame = false; multiplayer = false; - gametype = GT_RACE; //srb2kart + + if (modeattacking == ATTACKING_CAPSULES) + gametype = GT_MATCH; //srb2kart + else + gametype = GT_RACE; //srb2kart // no more tic the game with this settings! SV_StopServer(); @@ -4139,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); } @@ -5450,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 283deecb4..80bc1c72c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -416,7 +416,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 +443,7 @@ static void D_Display(void) switch (i) { case 1: - if (splitscreen > 1) + if (r_splitscreen > 1) { viewwindowx = viewwidth; viewwindowy = 0; @@ -468,7 +468,7 @@ static void D_Display(void) break; } - + topleft = screens[0] + viewwindowy*vid.width + viewwindowx; } @@ -482,7 +482,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 +780,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 diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 404d7f181..e3435b39f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -47,6 +47,7 @@ #include "m_cond.h" #include "m_anigif.h" #include "k_kart.h" // SRB2kart +#include "k_battle.h" #include "k_pwrlv.h" #include "y_inter.h" @@ -63,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); @@ -136,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 @@ -552,6 +563,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); @@ -763,6 +778,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); @@ -1190,11 +1211,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)); @@ -1302,16 +1323,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 @@ -1441,8 +1496,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; @@ -1530,14 +1585,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) @@ -1564,8 +1619,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; @@ -1645,14 +1700,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) @@ -1679,8 +1734,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; @@ -1768,14 +1823,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) @@ -1806,11 +1861,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 @@ -1833,8 +1888,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; @@ -1871,11 +1926,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 @@ -1942,6 +1997,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(); @@ -1988,7 +2230,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 */ @@ -2144,7 +2386,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 ",) } @@ -2169,7 +2411,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); @@ -2177,11 +2419,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 @@ -2426,7 +2814,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); @@ -3080,11 +3468,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 @@ -3171,11 +3559,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 @@ -3262,11 +3650,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 @@ -3663,8 +4051,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()) { @@ -5309,7 +5697,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. @@ -5504,7 +5914,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(); @@ -5515,7 +5925,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(); @@ -5526,7 +5936,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(); @@ -5567,12 +5977,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); } } @@ -5581,12 +5991,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); } } @@ -5595,12 +6005,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); } } @@ -5641,7 +6051,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(); @@ -5649,7 +6059,7 @@ static void Color2_OnChange(void) else { CV_StealthSetValue(&cv_playercolor2, - players[displayplayers[1]].skincolor); + players[g_localplayers[1]].skincolor); } } @@ -5658,7 +6068,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(); @@ -5666,7 +6076,7 @@ static void Color3_OnChange(void) else { CV_StealthSetValue(&cv_playercolor3, - players[displayplayers[2]].skincolor); + players[g_localplayers[2]].skincolor); } } @@ -5675,7 +6085,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(); @@ -5683,7 +6093,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..8238dea2b 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -182,9 +182,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_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 a9d46b2a4..468f3aae0 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2473,10 +2473,10 @@ static void readunlockable(MYFILE *f, INT32 num) unlockables[num].type = SECRET_PANDORA; else if (fastcmp(word2, "CREDITS")) unlockables[num].type = SECRET_CREDITS; - else if (fastcmp(word2, "RECORDATTACK")) - unlockables[num].type = SECRET_RECORDATTACK; - else if (fastcmp(word2, "NIGHTSMODE")) - unlockables[num].type = SECRET_NIGHTSMODE; + else if (fastcmp(word2, "TIMEATTACK")) + unlockables[num].type = SECRET_TIMEATTACK; + else if (fastcmp(word2, "BREAKTHECAPSULES")) + unlockables[num].type = SECRET_BREAKTHECAPSULES; else if (fastcmp(word2, "HEADER")) unlockables[num].type = SECRET_HEADER; else if (fastcmp(word2, "LEVELSELECT")) @@ -7219,6 +7219,13 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_OVERTIMEORB", "S_OVERTIMEBEAM", + "S_BATTLECAPSULE_SIDE1", + "S_BATTLECAPSULE_SIDE2", + "S_BATTLECAPSULE_TOP", + "S_BATTLECAPSULE_BUTTON", + "S_BATTLECAPSULE_SUPPORT", + "S_BATTLECAPSULE_SUPPORTFLY", + #ifdef SEENAMES "S_NAMECHECK", #endif @@ -8018,6 +8025,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_OVERTIMEORB", "MT_OVERTIMEBEAM", + "MT_BATTLECAPSULE", + "MT_BATTLECAPSULE_PIECE", + #ifdef SEENAMES "MT_NAMECHECK", #endif @@ -8193,8 +8203,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", diff --git a/src/djgppdos/internal.h b/src/djgppdos/internal.h index 94c1a052b..b34b5ebb7 100644 --- a/src/djgppdos/internal.h +++ b/src/djgppdos/internal.h @@ -1,6 +1,6 @@ -/* ______ ___ ___ - * /\ _ \ /\_ \ /\_ \ - * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ +/* ______ ___ ___ + * /\ _ \ /\_ \ /\_ \ + * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ @@ -22,9 +22,9 @@ #include "allegro.h" -/* ______ ___ ___ - * /\ _ \ /\_ \ /\_ \ - * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ +/* ______ ___ ___ + * /\ _ \ /\_ \ /\_ \ + * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ @@ -57,7 +57,7 @@ #define FILE_CREATE(filename, handle) handle = open(filename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR) #define FILE_CLOSE(handle) close(handle) #define FILE_READ(handle, buf, size, sz) sz = read(handle, buf, size) -#define FILE_WRITE(handle, buf, size, sz) sz = write(handle, buf, size) +#define FILE_WRITE(handle, buf, size, sz) sz = write(handle, buf, size) #define FILE_SEARCH_STRUCT struct ffblk #define FILE_FINDFIRST(filename, attrib, dta) findfirst(filename, dta, attrib) #define FILE_FINDNEXT(dta) findnext(dta) @@ -73,11 +73,11 @@ #define ENABLE() asm volatile ("sti") -__INLINE__ void enter_critical(void) +__INLINE__ void enter_critical(void) { if (windows_version >= 3) { __dpmi_regs r; - r.x.ax = 0x1681; + r.x.ax = 0x1681; __dpmi_int(0x2F, &r); } @@ -85,11 +85,11 @@ __INLINE__ void enter_critical(void) } -__INLINE__ void exit_critical(void) +__INLINE__ void exit_critical(void) { if (windows_version >= 3) { __dpmi_regs r; - r.x.ax = 0x1682; + r.x.ax = 0x1682; __dpmi_int(0x2F, &r); } @@ -176,9 +176,9 @@ extern int _fm_port; extern int _mpu_port; extern int _mpu_irq; extern int _sb_freq; -extern int _sb_port; -extern int _sb_dma; -extern int _sb_irq; +extern int _sb_port; +extern int _sb_dma; +extern int _sb_irq; int _sb_read_dsp_version(void); int _sb_reset_dsp(int data); @@ -238,8 +238,8 @@ extern volatile int _retrace_hpp_value; /* caches and tables for svga bank switching */ -extern int _last_bank_1, _last_bank_2; -extern int *_gfx_bank; +extern int _last_bank_1, _last_bank_2; +extern int *_gfx_bank; /* bank switching routines */ @@ -282,7 +282,7 @@ extern int _crtc; __INLINE__ int _read_vga_register(int port, int index) { if (port==0x3C0) - inportb(_crtc+6); + inportb(_crtc+6); outportb(port, index); return inportb(port+1); @@ -292,7 +292,7 @@ __INLINE__ int _read_vga_register(int port, int index) /* _write_vga_register: * Writes a byte to a VGA register. */ -__INLINE__ void _write_vga_register(int port, int index, int v) +__INLINE__ void _write_vga_register(int port, int index, int v) { if (port==0x3C0) { inportb(_crtc+6); @@ -345,7 +345,7 @@ __INLINE__ void _vsync_out_v(void) __INLINE__ void _vsync_in(void) { if (_timer_use_retrace) { - int t = retrace_count; + int t = retrace_count; do { } while (t == retrace_count); @@ -555,7 +555,7 @@ typedef struct POLYGON_SEGMENT /* an active polygon edge */ -typedef struct POLYGON_EDGE +typedef struct POLYGON_EDGE { int top; /* top y position */ int bottom; /* bottom y position */ @@ -673,7 +673,7 @@ void _poly_scanline_ptex_mask_lit32d(unsigned long addr, int w, POLYGON_SEGMENT /* sound lib stuff */ extern int _digi_volume; extern int _midi_volume; -extern int _flip_pan; +extern int _flip_pan; extern int _sound_hq; extern int (*_midi_init)(void); 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..288c8e7ad 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -242,6 +242,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 f4f7acfd0..3a89e8d28 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -82,7 +82,7 @@ extern boolean metalrecording; #define ATTACKING_NONE 0 #define ATTACKING_RECORD 1 -//#define ATTACKING_NIGHTS 2 +#define ATTACKING_CAPSULES 2 extern UINT8 modeattacking; // menu demo things @@ -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; @@ -371,7 +385,7 @@ extern UINT16 emeralds; #define EMERALD7 64 #define ALL7EMERALDS(v) ((v & (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) == (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) -extern INT32 nummaprings, nummapboxes, numgotboxes; //keep track of spawned rings/coins/battle mode items +extern INT32 nummaprings; // keep track of spawned rings/coins /** Time attack information, currently a very small structure. */ @@ -504,15 +518,6 @@ extern INT16 votelevels[5][2]; extern SINT8 votes[MAXPLAYERS]; extern SINT8 pickedvote; -/** Battle overtime information - */ -extern struct battleovertime -{ - UINT16 enabled; ///< Has this been initalized yet? - fixed_t radius, minradius; ///< Radius of kill field - fixed_t x, y, z; ///< Position to center on -} battleovertime; - extern tic_t hidetime; extern UINT32 timesBeaten; // # of times the game has been beaten. diff --git a/src/f_wipe.c b/src/f_wipe.c index 8d73c1fe7..e42042516 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -204,7 +204,7 @@ static void F_DoWipe(fademask_t *fademask, lighttable_t *fadecolormap, boolean r // --- // Sal: I kinda destroyed some of this code by introducing Genesis-style fades. // A colormap can be provided in F_RunWipe, which the white/black values will be - // remapped to the appropriate entry in the fade colormap. + // remapped to the appropriate entry in the fade colormap. { // wipe screen, start, end UINT8 *w = wipe_scr; @@ -434,7 +434,7 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean r reverse = false; } - paldiv = FixedDiv(257<>16, 50<>16}; static fixed_t sidemove[2] = {2<>16, 4<>16}; @@ -1269,7 +1263,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]); @@ -1468,6 +1462,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; @@ -1588,7 +1587,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. @@ -1608,7 +1606,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; } @@ -1761,12 +1759,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; @@ -1774,10 +1772,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 @@ -1889,8 +1887,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); @@ -2154,7 +2152,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; @@ -2225,7 +2223,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) @@ -2236,7 +2234,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) @@ -2309,14 +2307,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(); } @@ -2635,7 +2633,7 @@ void G_PlayerReborn(INT32 player) itemtype = 0; itemamount = 0; growshrinktimer = 0; - bumper = (G_BattleGametype() ? cv_kartbumpers.value : 0); + bumper = (G_BattleGametype() ? K_StartingBumperCount() : 0); rings = (G_BattleGametype() ? 0 : 5); comebackpoints = 0; wanted = 0; @@ -2860,9 +2858,13 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost) return; } + // -- Record Attack -- + if (modeattacking || battlecapsules) + spawnpoint = playerstarts[0]; + // -- CTF -- // Order: CTF->DM->Coop - if (gametype == GT_CTF && players[playernum].ctfteam) + else if (gametype == GT_CTF && players[playernum].ctfteam) { if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start && !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start @@ -2894,18 +2896,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. } @@ -3000,17 +3002,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; } @@ -3098,17 +3100,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; } @@ -3723,7 +3725,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) @@ -4801,8 +4803,8 @@ char *G_BuildMapTitle(INT32 mapnum) #define DEMOHEADER "\xF0" "KartReplay" "\x0F" #define DF_GHOST 0x01 // This demo contains ghost data too! -#define DF_RECORDATTACK 0x02 // This demo is from record attack and contains its final completion time! -#define DF_NIGHTSATTACK 0x04 // This demo is from NiGHTS attack and contains its time left, score, and mares! +#define DF_TIMEATTACK 0x02 // This demo is from Time Attack and contains its final completion time & best lap! +#define DF_BREAKTHECAPSULES 0x04 // This demo is from Break the Capsules and contains its final completion time! #define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ??? #define DF_ATTACKSHIFT 1 #define DF_ENCORE 0x40 @@ -4840,7 +4842,6 @@ static ticcmd_t oldcmd[MAXPLAYERS]; // Not used for Metal Sonic #define GZT_SPRITE 0x10 // Animation frame #define GZT_EXTRA 0x20 -#define GZT_NIGHTS 0x40 // NiGHTS Mode stuff! // GZT_EXTRA flags #define EZT_THOK 0x01 // Spawned a thok object @@ -5346,13 +5347,6 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) if (!(demoflags & DF_GHOST)) return; // No ghost data to write. - if (ghost->player && ghost->player->pflags & PF_NIGHTSMODE && ghost->tracer) - { - // We're talking about the NiGHTS thing, not the normal platforming thing! - ziptic |= GZT_NIGHTS; - ghost = ghost->tracer; - } - ziptic_p = demo_p++; // the ziptic, written at the end of this function #define MAXMOM (0x7FFF<<8) @@ -5569,12 +5563,6 @@ void G_ConsGhostTic(INT32 playernum) demo_p++; if (ziptic & GZT_SPRITE) demo_p++; - if(ziptic & GZT_NIGHTS) { - if (!testmo || !testmo->player || !(testmo->player->pflags & PF_NIGHTSMODE) || !testmo->tracer) - nightsfail = true; - else - testmo = testmo->tracer; - } if (ziptic & GZT_EXTRA) { // But wait, there's more! @@ -6405,6 +6393,10 @@ void G_BeginRecording(void) WRITEUINT32(demo_p,UINT32_MAX); // time WRITEUINT32(demo_p,UINT32_MAX); // lap break; + case ATTACKING_CAPSULES: // 2 + demotime_p = demo_p; + WRITEUINT32(demo_p,UINT32_MAX); // time + break; default: // 3 break; } @@ -6547,13 +6539,18 @@ void G_SetDemoTime(UINT32 ptime, UINT32 plap) { if (!demo.recording || !demotime_p) return; - - if (demoflags & DF_RECORDATTACK) + if (demoflags & DF_TIMEATTACK) { WRITEUINT32(demotime_p, ptime); WRITEUINT32(demotime_p, plap); demotime_p = NULL; } + else if (demoflags & DF_BREAKTHECAPSULES) + { + WRITEUINT32(demotime_p, ptime); + (void)plap; + demotime_p = NULL; + } } static void G_LoadDemoExtraFiles(UINT8 **pp) @@ -6729,6 +6726,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) UINT8 c; UINT16 s ATTRUNUSED; UINT8 aflags = 0; + boolean uselaps = false; // load the new file FIL_DefaultExtension(newname, ".lmp"); @@ -6755,20 +6753,17 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p++; // gametype G_SkipDemoExtraFiles(&p); - aflags = flags & (DF_RECORDATTACK|DF_NIGHTSATTACK); + aflags = flags & (DF_TIMEATTACK|DF_BREAKTHECAPSULES); I_Assert(aflags); - if (flags & DF_RECORDATTACK) - { - newtime = READUINT32(p); + + if (flags & DF_TIMEATTACK) + uselaps = true; // get around uninitalized error + + newtime = READUINT32(p); + if (uselaps) newlap = READUINT32(p); - } - /*else if (flags & DF_NIGHTSATTACK) - { - newtime = READUINT32(p); - newscore = READUINT32(p); - }*/ - else // appease compiler - return 0; + else + newlap = UINT32_MAX; Z_Free(buffer); @@ -6820,28 +6815,32 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) Z_Free(buffer); return UINT8_MAX; } - if (flags & DF_RECORDATTACK) - { - oldtime = READUINT32(p); + + oldtime = READUINT32(p); + if (uselaps) oldlap = READUINT32(p); - } - /*else if (flags & DF_NIGHTSATTACK) - { - oldtime = READUINT32(p); - oldscore = READUINT32(p); - }*/ - else // appease compiler - return UINT8_MAX; + else + oldlap = 0; Z_Free(buffer); c = 0; - if (newtime < oldtime - || (newtime == oldtime && (newlap < oldlap))) - c |= 1; // Better time - if (newlap < oldlap - || (newlap == oldlap && newtime < oldtime)) - c |= 1<<1; // Better lap time + + if (uselaps) + { + if (newtime < oldtime + || (newtime == oldtime && (newlap < oldlap))) + c |= 1; // Better time + if (newlap < oldlap + || (newlap == oldlap && newtime < oldtime)) + c |= 1<<1; // Better lap time + } + else + { + if (newtime < oldtime) + c |= 1; // Better time + } + return c; } @@ -7216,19 +7215,18 @@ void G_DoPlayDemo(char *defdemoname) switch (modeattacking) { - case ATTACKING_NONE: // 0 - break; - case ATTACKING_RECORD: // 1 - hu_demotime = READUINT32(demo_p); - hu_demolap = READUINT32(demo_p); - break; - /*case ATTACKING_NIGHTS: // 2 - hu_demotime = READUINT32(demo_p); - hu_demoscore = READUINT32(demo_p); - break;*/ - default: // 3 - modeattacking = ATTACKING_NONE; - break; + case ATTACKING_NONE: // 0 + break; + case ATTACKING_RECORD: // 1 + hu_demotime = READUINT32(demo_p); + hu_demolap = READUINT32(demo_p); + break; + case ATTACKING_CAPSULES: // 2 + hu_demotime = READUINT32(demo_p); + break; + default: // 3 + modeattacking = ATTACKING_NONE; + break; } // Random seed @@ -7523,16 +7521,16 @@ void G_AddGhost(char *defdemoname) switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { - case ATTACKING_NONE: // 0 - break; - case ATTACKING_RECORD: // 1 - p += 8; // demo time, lap - break; - /*case ATTACKING_NIGHTS: // 2 - p += 8; // demo time left, score - break;*/ - default: // 3 - break; + case ATTACKING_NONE: // 0 + break; + case ATTACKING_RECORD: // 1 + p += 8; // demo time, lap + break; + case ATTACKING_CAPSULES: // 2 + p += 4; // demo time + break; + default: // 3 + break; } p += 4; // random seed @@ -7724,6 +7722,9 @@ void G_UpdateStaffGhostName(lumpnum_t l) case ATTACKING_RECORD: // 1 p += 8; // demo time, lap break; + case ATTACKING_CAPSULES: // 2 + p += 4; // demo time + break; default: // 3 break; } @@ -8055,7 +8056,7 @@ void G_SaveDemo(void) free(demobuffer); demo.recording = false; - if (modeattacking != ATTACKING_RECORD) + if (!modeattacking) { if (demo.savemode == DSM_SAVED) CONS_Printf(M_GetText("Demo %s recorded\n"), demoname); 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 73e65cceb..b7675a21b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -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 76b85dd01..91d200cf2 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 cdccdb420..ab9dd44eb 100644 --- a/src/info.c +++ b/src/info.c @@ -3460,6 +3460,13 @@ state_t states[NUMSTATES] = {SPR_OTFG, 2|FF_FULLBRIGHT|FF_PAPERSPRITE, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEORB {SPR_OTFG, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEBEAM + {SPR_CAPS, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SIDE1 + {SPR_CAPS, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SIDE2 + {SPR_CAPS, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_TOP + {SPR_CAPS, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_BUTTON + {SPR_CAPS, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SUPPORT + {SPR_CAPS, FF_ANIMATE|5, -1, {NULL}, 3, 1, S_NULL}, // S_BATTLECAPSULE_SUPPORTFLY + #ifdef SEENAMES {SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK #endif @@ -20441,6 +20448,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_BATTLECAPSULE + 2333, // doomednum + S_INVISIBLE, // spawnstate + 1, // 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_INVISIBLE, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 28< bestbumper) + { + bestbumper = players[i].kartstuff[k_bumper]; + bestbumperplayer = i; + } + else if (players[i].kartstuff[k_bumper] == bestbumper) + bestbumperplayer = -1; // Tie, no one has best bumper. + + for (j = 0; j < MAXPLAYERS; j++) + { + if (!playeringame[j] || players[j].spectator) + continue; + if (players[j].kartstuff[k_bumper] <= 0) + continue; + if (j == i) + continue; + if (players[j].kartstuff[k_wanted] == players[i].kartstuff[k_wanted] && players[j].marescore > players[i].marescore) + position++; + else if (players[j].kartstuff[k_wanted] > players[i].kartstuff[k_wanted]) + position++; + } + + position--; // Make zero based + + while (camppos[position] != -1) // Port priority! + position++; + + camppos[position] = i; + } + + if (numplaying <= 2 || (numingame <= 2 && bestbumper == 1)) // In 1v1s then there's no need for WANTED. In bigger netgames, don't show anyone as WANTED when they're equally matched. + numwanted = 0; + else + numwanted = min(4, 1 + ((numingame-2) / 4)); + + for (i = 0; i < 4; i++) + { + if (i+1 > numwanted) // Not enough players for this slot to be wanted! + battlewanted[i] = -1; + else if (bestbumperplayer != -1 && !setbumper) // If there's a player who has an untied bumper lead over everyone else, they are the first to be wanted. + { + battlewanted[i] = bestbumperplayer; + setbumper = true; // Don't set twice + } + else + { + // Don't accidentally set the same player, if the bestbumperplayer is also a huge camper. + while (bestbumperplayer != -1 && camppos[nextcamppos] != -1 + && bestbumperplayer == camppos[nextcamppos]) + nextcamppos++; + + // Do not add *any* more people if there's too many times that are tied with others. + // This could theoretically happen very easily if people don't hit each other for a while after the start of a match. + // (I will be sincerely impressed if more than 2 people tie after people start hitting each other though) + + if (camppos[nextcamppos] == -1 // Out of entries + || ties >= (numwanted-i)) // Already counted ties + { + battlewanted[i] = -1; + continue; + } + + if (ties < (numwanted-i)) + { + ties = 0; // Reset + for (j = 0; j < 2; j++) + { + if (camppos[nextcamppos+(j+1)] == -1) // Nothing beyond, cancel + break; + if (players[camppos[nextcamppos]].kartstuff[k_wanted] == players[camppos[nextcamppos+(j+1)]].kartstuff[k_wanted]) + ties++; + } + } + + if (ties < (numwanted-i)) // Is it still low enough after counting? + { + battlewanted[i] = camppos[nextcamppos]; + nextcamppos++; + } + else + battlewanted[i] = -1; + } + } +} + +void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount) +{ + statenum_t st; + mobj_t *pt; + + if (!source || !source->mo) + return; + + if (amount == 1) + st = S_BATTLEPOINT1A; + else if (amount == 2) + st = S_BATTLEPOINT2A; + else if (amount == 3) + st = S_BATTLEPOINT3A; + else + return; // NO STATE! + + pt = P_SpawnMobj(source->mo->x, source->mo->y, source->mo->z, MT_BATTLEPOINT); + P_SetTarget(&pt->target, source->mo); + P_SetMobjState(pt, st); + if (victim && victim->skincolor) + pt->color = victim->skincolor; + else + pt->color = source->skincolor; +} + +void K_CheckBumpers(void) +{ + UINT8 i; + UINT8 numingame = 0; + SINT8 winnernum = -1; + INT32 winnerscoreadd = 0; + boolean nobumpers = false; + + if (!G_BattleGametype()) + return; + + if (gameaction == ga_completed) + return; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) // not even in-game + continue; + + if (players[i].exiting) // we're already exiting! stop! + return; + + numingame++; + winnerscoreadd += players[i].marescore; + + if (players[i].kartstuff[k_bumper] <= 0) // if you don't have any bumpers, you're probably not a winner + { + nobumpers = true; + continue; + } + else if (winnernum != -1) // TWO winners? that's dumb :V + return; + + winnernum = i; + winnerscoreadd -= players[i].marescore; + } + + if (numingame <= 1) + { + if (!battlecapsules) + { + // Reset map to turn on battle capsules + D_MapChange(gamemap, gametype, encoremode, true, 0, false, false); + } + else + { + if (nobumpers) + { + for (i = 0; i < MAXPLAYERS; i++) + { + players[i].pflags |= PF_TIMEOVER; + //players[i].lives = 0; + P_DoPlayerExit(&players[i]); + } + } + } + + return; + } + + if (winnernum > -1 && playeringame[winnernum]) + { + players[winnernum].marescore += winnerscoreadd; + CONS_Printf(M_GetText("%s recieved %d point%s for winning!\n"), player_names[winnernum], winnerscoreadd, (winnerscoreadd == 1 ? "" : "s")); + } + + for (i = 0; i < MAXPLAYERS; i++) // This can't go in the earlier loop because winning adds points + K_KartUpdatePosition(&players[i]); + + for (i = 0; i < MAXPLAYERS; i++) // and it can't be merged with this loop because it needs to be all updated before exiting... multi-loops suck... + P_DoPlayerExit(&players[i]); +} + +#define MAXPLANESPERSECTOR (MAXFFLOORS+1)*2 + +static void K_SpawnOvertimeParticles(fixed_t x, fixed_t y, fixed_t scale, mobjtype_t type, boolean ceiling) +{ + UINT8 i; + fixed_t flatz[MAXPLANESPERSECTOR]; + boolean flip[MAXPLANESPERSECTOR]; + UINT8 numflats = 0; + mobj_t *mo; + subsector_t *ss = R_IsPointInSubsector(x, y); + sector_t *sec; + + if (!ss) + return; + sec = ss->sector; + + // convoluted stuff JUST to get all of the planes we need to draw orbs on :V + + for (i = 0; i < MAXPLANESPERSECTOR; i++) + flip[i] = false; + + if (sec->floorpic != skyflatnum) + { +#ifdef ESLOPE + flatz[numflats] = (sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->floorheight); +#else + flatz[numflats] = (sec->floorheight); +#endif + numflats++; + } + if (sec->ceilingpic != skyflatnum && ceiling) + { +#ifdef ESLOPE + flatz[numflats] = (sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : sec->ceilingheight) - FixedMul(mobjinfo[type].height, scale); +#else + flatz[numflats] = (sec->ceilingheight) - FixedMul(mobjinfo[type].height, scale); +#endif + flip[numflats] = true; + numflats++; + } + + if (sec->ffloors) + { + ffloor_t *rover; + for (rover = sec->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) + continue; + if (*rover->toppic != skyflatnum) + { +#ifdef ESLOPE + flatz[numflats] = (*rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) : *rover->topheight); +#else + flatz[numflats] = (*rover->topheight); +#endif + numflats++; + } + if (*rover->bottompic != skyflatnum && ceiling) + { +#ifdef ESLOPE + flatz[numflats] = (*rover->b_slope ? P_GetZAt(*rover->b_slope, x, y) : *rover->bottomheight) - FixedMul(mobjinfo[type].height, scale); +#else + flatz[numflats] = (*rover->bottomheight) - FixedMul(mobjinfo[type].height, scale); +#endif + flip[numflats] = true; + numflats++; + } + } + } + + if (numflats <= 0) // no flats + return; + + for (i = 0; i < numflats; i++) + { + mo = P_SpawnMobj(x, y, flatz[i], type); + + // Lastly, if this can see the skybox mobj, then... we just wasted our time :V + if (skyboxmo[0] && !P_MobjWasRemoved(skyboxmo[0])) + { + const fixed_t sbz = skyboxmo[0]->z; + fixed_t checkz = sec->floorheight; + + while (checkz < sec->ceilingheight) + { + P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, checkz); + if (P_CheckSight(skyboxmo[0], mo)) + { + P_RemoveMobj(mo); + break; + } + else + checkz += 32*mapobjectscale; + } + + P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, sbz); + + if (P_MobjWasRemoved(mo)) + continue; + } + + P_SetScale(mo, scale); + + if (flip[i]) + { + mo->flags2 |= MF2_OBJECTFLIP; + mo->eflags |= MFE_VERTICALFLIP; + } + + switch(type) + { + case MT_OVERTIMEFOG: + mo->destscale = 8*mo->scale; + mo->momz = P_RandomRange(1,8)*mo->scale; + break; + case MT_OVERTIMEORB: + //mo->destscale = mo->scale/4; + mo->frame += ((leveltime/4) % 8); + /*if (battleovertime.enabled < 10*TICRATE) + mo->flags2 |= MF2_SHADOW;*/ + mo->angle = R_PointToAngle2(mo->x, mo->y, battleovertime.x, battleovertime.y) + ANGLE_90; + mo->z += P_RandomRange(0,48) * mo->scale; + break; + default: + break; + } + } +} + +#undef MAXPLANESPERSECTOR + +void K_RunBattleOvertime(void) +{ + UINT16 i, j; + + if (battleovertime.enabled < 10*TICRATE) + { + battleovertime.enabled++; + if (battleovertime.enabled == TICRATE) + S_StartSound(NULL, sfx_bhurry); + if (battleovertime.enabled == 10*TICRATE) + S_StartSound(NULL, sfx_kc40); + } + else + { + if (battleovertime.radius > battleovertime.minradius) + battleovertime.radius -= mapobjectscale; + else + battleovertime.radius = battleovertime.minradius; + } + + if (leveltime & 1) + { + UINT8 transparency = tr_trans50; + + if (!splitscreen && players[displayplayers[0]].mo) + { + INT32 dist = P_AproxDistance(battleovertime.x-players[displayplayers[0]].mo->x, battleovertime.y-players[displayplayers[0]].mo->y); + transparency = max(0, NUMTRANSMAPS - ((256 + (dist>>FRACBITS)) / 256)); + } + + if (transparency < NUMTRANSMAPS) + { + mobj_t *beam = P_SpawnMobj(battleovertime.x, battleovertime.y, battleovertime.z + (mobjinfo[MT_RANDOMITEM].height/2), MT_OVERTIMEBEAM); + P_SetScale(beam, beam->scale*2); + if (transparency > 0) + beam->frame |= transparency<>FRACBITS / 2));*/ + + for (i = 0; i < 16; i++) + { + j = 0; + while (j < 32) // max attempts + { + fixed_t x = battleovertime.x + ((P_RandomRange(-64,64) * 128)<extrainfo-1; + fixed_t speed = (FRACUNIT >> 3) * mt->angle; + boolean backandforth = (mt->options & MTF_AMBUSH); + boolean reverse = (mt->options & MTF_OBJECTSPECIAL); + mobj_t *mo2; + mobj_t *target = NULL; + thinker_t *th; + + // Find the inital target + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type != MT_TUBEWAYPOINT) + continue; + + if (mo2->threshold == sequence) + { + if (reverse) // Use the highest waypoint number as first + { + if (mo2->health != 0) + { + if (target == NULL) + target = mo2; + else if (mo2->health > target->health) + target = mo2; + } + } + else // Use the lowest waypoint number as first + { + if (mo2->health == 0) + target = mo2; + } + } + } + + if (!target) + { + CONS_Alert(CONS_WARNING, "No target waypoint found for moving capsule (seq: #%d)\n", sequence); + return; + } + + P_SetTarget(&mobj->target, target); + mobj->lastlook = sequence; + mobj->movecount = target->health; + mobj->movefactor = speed; + + if (backandforth) { + mobj->flags2 |= MF2_AMBUSH; + } else { + mobj->flags2 &= ~MF2_AMBUSH; + } + + if (reverse) { + mobj->cvmem = -1; + } else { + mobj->cvmem = 1; + } +} + +void K_SpawnBattleCapsules(void) +{ + mapthing_t *mt; + size_t i; + + if (battlecapsules) + return; + + if (!G_BattleGametype()) + return; + + if (modeattacking != ATTACKING_CAPSULES) + { + UINT8 n = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator) + n++; + if (players[i].exiting) + return; + if (n > 1) + break; + } + + if (n > 1) + return; + } + + mt = mapthings; + for (i = 0; i < nummapthings; i++, mt++) + { + if (mt->type == mobjinfo[MT_BATTLECAPSULE].doomednum) + { + sector_t *mtsector, *sec; + fixed_t x, y, z; + fixed_t floorheights[MAXFFLOORS+1]; + UINT8 numfloors = 1; + mobj_t *mobj = NULL; + boolean fly = true; + UINT8 j; + + mt->mobj = NULL; + + mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector; + mt->z = (INT16)( +#ifdef ESLOPE + mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) : +#endif + mtsector->floorheight)>>FRACBITS; + + x = mt->x << FRACBITS; + y = mt->y << FRACBITS; + + sec = R_PointInSubsector(x, y)->sector; + + if (mt->options & MTF_OBJECTFLIP) + { + z = ( +#ifdef ESLOPE + sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : +#endif + sec->ceilingheight) - mobjinfo[MT_BATTLECAPSULE].height; + + floorheights[0] = z; + + if (mt->options >> ZSHIFT) + z -= ((mt->options >> ZSHIFT) << FRACBITS); + } + else + { + z = +#ifdef ESLOPE + sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : +#endif + sec->floorheight; + + floorheights[0] = z; + + if (mt->options >> ZSHIFT) + z += ((mt->options >> ZSHIFT) << FRACBITS); + } + + + if (sec->ffloors) + { + ffloor_t *rover; + for (rover = sec->ffloors; rover; rover = rover->next) + { + if ((rover->flags & FF_EXISTS) && (rover->flags & FF_BLOCKOTHERS)) + { + if (mt->options & MTF_OBJECTFLIP) + { + floorheights[numfloors] = ( +#ifdef ESLOPE + *rover->b_slope ? P_GetZAt(*rover->b_slope, x, y) : +#endif + *rover->bottomheight) - mobjinfo[MT_BATTLECAPSULE].height; + } + else + { + floorheights[numfloors] = ( +#ifdef ESLOPE + *rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) : +#endif + *rover->topheight); + } + + numfloors++; + } + } + } + + mt->z = (INT16)(z>>FRACBITS); + + mobj = P_SpawnMobj(x, y, z, MT_BATTLECAPSULE); + mobj->spawnpoint = mt; + + if (mt->options & MTF_OBJECTFLIP) + { + mobj->eflags |= MFE_VERTICALFLIP; + mobj->flags2 |= MF2_OBJECTFLIP; + } + + for (j = 0; j < numfloors; j++) + { + if (z == floorheights[j]) + { + fly = false; + break; + } + } + + // Flying capsules + if (fly) + { + mobj->flags |= MF_NOGRAVITY; + mobj->extravalue1 = 1; // Set extravalue1 for later reference + } + + // Moving capsules! + if (mt->extrainfo && mt->angle) + K_SetupMovingCapsule(mt, mobj); + + // Moved from P_SpawnMobj due to order of operations mumbo jumbo + { + mobj_t *cur, *prev = mobj; + + // Init hnext list + // Spherical top + cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE); + P_SetMobjState(cur, S_BATTLECAPSULE_TOP); + + P_SetTarget(&cur->target, mobj); + P_SetTarget(&cur->hprev, prev); + P_SetTarget(&prev->hnext, cur); + prev = cur; + + // Tippity-top decorational button + cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE); + P_SetMobjState(cur, S_BATTLECAPSULE_BUTTON); + + P_SetTarget(&cur->target, mobj); + P_SetTarget(&cur->hprev, prev); + P_SetTarget(&prev->hnext, cur); + prev = cur; + + // Supports on the bottom + for (j = 0; j < 4; j++) + { + cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE); + cur->extravalue1 = j; + + if (mobj->extravalue1) // Flying capsule, moving or not + P_SetMobjState(cur, S_BATTLECAPSULE_SUPPORTFLY); + else if (mobj->target && !P_MobjWasRemoved(mobj->target)) // Grounded, moving capsule + P_SetMobjState(cur, S_KARMAWHEEL); + else + P_SetMobjState(cur, S_BATTLECAPSULE_SUPPORT); // Grounded, stationary capsule + + P_SetTarget(&cur->target, mobj); + P_SetTarget(&cur->hprev, prev); + P_SetTarget(&prev->hnext, cur); + prev = cur; + } + + // Side paneling + for (j = 0; j < 8; j++) + { + cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE); + cur->extravalue1 = j; + + if (j & 1) + P_SetMobjState(cur, S_BATTLECAPSULE_SIDE2); + else + P_SetMobjState(cur, S_BATTLECAPSULE_SIDE1); + + P_SetTarget(&cur->target, mobj); + P_SetTarget(&cur->hprev, prev); + P_SetTarget(&prev->hnext, cur); + prev = cur; + } + } + + mt->mobj = mobj; + } + } + + battlecapsules = true; +} diff --git a/src/k_battle.h b/src/k_battle.h new file mode 100644 index 000000000..b69938d39 --- /dev/null +++ b/src/k_battle.h @@ -0,0 +1,26 @@ +#ifndef __K_BATTLE__ +#define __K_BATTLE__ + +#include "doomtype.h" +#include "d_player.h" + +extern struct battleovertime +{ + UINT16 enabled; ///< Has this been initalized yet? + fixed_t radius, minradius; ///< Radius of kill field + fixed_t x, y, z; ///< Position to center on +} battleovertime; + +extern boolean battlecapsules; +extern INT32 nummapboxes, numgotboxes; // keep track of spawned battle mode items +extern UINT8 maptargets, numtargets; + +INT32 K_StartingBumperCount(void); +boolean K_IsPlayerWanted(player_t *player); +void K_CalculateBattleWanted(void); +void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount); +void K_CheckBumpers(void); +void K_RunBattleOvertime(void); +void K_SpawnBattleCapsules(void); + +#endif diff --git a/src/k_collide.c b/src/k_collide.c new file mode 100644 index 000000000..7edbe3e87 --- /dev/null +++ b/src/k_collide.c @@ -0,0 +1,319 @@ +/// \file k_collide.c +/// \brief SRB2Kart item collision hooks + +#include "k_collide.h" +#include "doomtype.h" +#include "p_mobj.h" +#include "k_kart.h" +#include "p_local.h" +#include "s_sound.h" +#include "r_main.h" // R_PointToAngle2, R_PointToDist2 +#include "hu_stuff.h" // Sink snipe print +#include "doomdef.h" // Sink snipe print +#include "g_game.h" // Sink snipe print + +boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2) +{ + boolean damageitem = false; + + if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0))) + return true; + + if (t1->health <= 0 || t2->health <= 0) + return true; + + if ((t1->type == MT_ORBINAUT_SHIELD || t1->type == MT_JAWZ_SHIELD) && t1->lastlook + && (t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD) && t2->lastlook + && (t1->target == t2->target)) // Don't hit each other if you have the same target + return true; + + if (t2->player) + { + if (t2->player->powers[pw_flashing] + && !(t1->type == MT_ORBINAUT || t1->type == MT_JAWZ || t1->type == MT_JAWZ_DUD)) + return true; + + if (t2->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); + + damageitem = true; + } + else if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD + || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD + || t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD + || t2->type == MT_BALLHOG) + { + // Other Item Damage + if (t2->eflags & MFE_VERTICALFLIP) + t2->z -= t2->height; + else + t2->z += t2->height; + + S_StartSound(t2, t2->info->deathsound); + P_KillMobj(t2, t1, t1); + + P_SetObjectMomZ(t2, 8*FRACUNIT, false); + P_InstaThrust(t2, R_PointToAngle2(t1->x, t1->y, t2->x, t2->y)+ANGLE_90, 16*FRACUNIT); + + P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH); + + damageitem = true; + } + else if (t2->type == MT_SSMINE_SHIELD || t2->type == MT_SSMINE) + { + damageitem = true; + // Bomb death + P_KillMobj(t2, t1, t1); + } + else if (t2->flags & MF_SPRING && (t1->type != MT_ORBINAUT_SHIELD && t1->type != MT_JAWZ_SHIELD)) + { + // Let thrown items hit springs! + P_DoSpring(t2, t1); + } + else if (t2->flags & MF_SHOOTABLE) + { + // Shootable damage + P_DamageMobj(t2, t2, t1->target, 1); + damageitem = true; + } + + if (damageitem) + { + // This Item Damage + if (t1->eflags & MFE_VERTICALFLIP) + t1->z -= t1->height; + else + t1->z += t1->height; + + S_StartSound(t1, t1->info->deathsound); + P_KillMobj(t1, t2, t2); + + P_SetObjectMomZ(t1, 8*FRACUNIT, false); + P_InstaThrust(t1, R_PointToAngle2(t2->x, t2->y, t1->x, t1->y)+ANGLE_90, 16*FRACUNIT); + } + + return true; +} + +boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2) +{ + boolean damageitem = false; + + if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0))) + return true; + + if (t1->health <= 0 || t2->health <= 0) + return true; + + if (((t1->type == MT_BANANA_SHIELD) && (t2->type == MT_BANANA_SHIELD)) + && (t1->target == t2->target)) // Don't hit each other if you have the same target + return true; + + if (t1->type == MT_BALLHOG && t2->type == MT_BALLHOG) + return true; // Ballhogs don't collide with eachother + + if (t2->player) + { + if (t2->player->powers[pw_flashing]) + return true; + + // Banana snipe! + 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)); + + damageitem = true; + } + else if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD + || t2->type == MT_ORBINAUT || t2->type == MT_ORBINAUT_SHIELD + || t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD || t2->type == MT_JAWZ_SHIELD + || t2->type == MT_BALLHOG) + { + // Other Item Damage + if (t2->eflags & MFE_VERTICALFLIP) + t2->z -= t2->height; + else + t2->z += t2->height; + + S_StartSound(t2, t2->info->deathsound); + P_KillMobj(t2, t1, t1); + + P_SetObjectMomZ(t2, 8*FRACUNIT, false); + P_InstaThrust(t2, R_PointToAngle2(t1->x, t1->y, t2->x, t2->y)+ANGLE_90, 16*FRACUNIT); + + P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH); + + damageitem = true; + } + else if (t2->flags & MF_SHOOTABLE) + { + // Shootable damage + P_DamageMobj(t2, t2, t1->target, 1); + damageitem = true; + } + + if (damageitem) + { + // This Item Damage + if (t1->eflags & MFE_VERTICALFLIP) + t1->z -= t1->height; + else + t1->z += t1->height; + + S_StartSound(t1, t1->info->deathsound); + P_KillMobj(t1, t2, t2); + + P_SetObjectMomZ(t1, 8*FRACUNIT, false); + P_InstaThrust(t1, R_PointToAngle2(t2->x, t2->y, t1->x, t1->y)+ANGLE_90, 16*FRACUNIT); + } + + return true; +} + +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); + + // Player collision is handled by TouchSpecial + return true; +} + +boolean K_MineCollide(mobj_t *t1, mobj_t *t2) +{ + if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0))) + return true; + + if (t1->health <= 0 || t2->health <= 0) + return true; + + if (t2->player) + { + if (t2->player->powers[pw_flashing]) + return true; + + // Bomb punting + if ((t1->state >= &states[S_SSMINE1] && t1->state <= &states[S_SSMINE4]) + || (t1->state >= &states[S_SSMINE_DEPLOY8] && t1->state <= &states[S_SSMINE_DEPLOY13])) + P_KillMobj(t1, t2, t2); + else + K_PuntMine(t1, t2); + } + else if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD + || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD) + { + // Bomb death + P_KillMobj(t1, t2, t2); + + // Other Item Damage + if (t2->eflags & MFE_VERTICALFLIP) + t2->z -= t2->height; + else + t2->z += t2->height; + + S_StartSound(t2, t2->info->deathsound); + P_KillMobj(t2, t1, t1); + + P_SetObjectMomZ(t2, 8*FRACUNIT, false); + P_InstaThrust(t2, R_PointToAngle2(t1->x, t1->y, t2->x, t2->y)+ANGLE_90, 16*FRACUNIT); + } + else if (t2->flags & MF_SHOOTABLE) + { + // Bomb death + P_KillMobj(t1, t2, t2); + // Shootable damage + P_DamageMobj(t2, t2, t1->target, 1); + } + + return true; +} + +boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2) +{ + if (t2->player) + { + if (t2->player->powers[pw_flashing]) + return true; + + if (t1->state == &states[S_MINEEXPLOSION1]) + K_ExplodePlayer(t2->player, t1->target, t1); + else + K_SpinPlayer(t2->player, t1->target, 0, t1, false); + } + else if (t2->flags & MF_SHOOTABLE) + { + // Shootable damage + P_DamageMobj(t2, t2, t1->target, 1); + } + + return true; +} + +boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2) +{ + if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0))) + return true; + + if (t2->player) + { + if (t2->player->powers[pw_flashing]) + return true; + + S_StartSound(NULL, sfx_bsnipe); // let all players hear it. + HU_SetCEchoFlags(0); + HU_SetCEchoDuration(5); + HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[t2->player-players])); + I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[t2->player-players]); + P_DamageMobj(t2, t1, t1->target, 10000); + P_KillMobj(t1, t2, t2); + } + else if (t2->flags & MF_SHOOTABLE) + { + // Shootable damage + P_KillMobj(t2, t2, t1->target); + // This item damage + P_KillMobj(t1, t2, t2); + } + + return true; +} + +boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2) +{ + if (t2->player || t2->type == MT_FALLINGROCK) + K_KartBouncing(t2, t1, false, false); + return true; +} + +boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2) +{ + if (!(t2->flags & MF_SOLID || t2->flags & MF_SHOOTABLE || t2->flags & MF_BOUNCE)) + return true; + + if (!(t2->health)) + return true; + + if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD + || t2->type == MT_EGGMANITEM || t2->type == MT_EGGMANITEM_SHIELD + || t2->type == MT_SSMINE || t2->type == MT_SSMINE_SHIELD + || t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD) + return false; + + if (t1->health) + P_KillMobj(t1, t2, t2); + + /*if (t2->player && (t2->player->kartstuff[k_invincibilitytimer] > 0 + || t2->player->kartstuff[k_growshrinktimer] > 0)) + return true;*/ + + K_KartBouncing(t2, t1, false, true); + return false; +} diff --git a/src/k_collide.h b/src/k_collide.h new file mode 100644 index 000000000..86f643b3f --- /dev/null +++ b/src/k_collide.h @@ -0,0 +1,16 @@ +#ifndef __K_COLLIDE__ +#define __K_COLLIDE__ + +#include "doomtype.h" +#include "p_mobj.h" + +boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2); +boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2); +boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2); +boolean K_MineCollide(mobj_t *t1, mobj_t *t2); +boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2); +boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2); +boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2); +boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2); + +#endif diff --git a/src/k_kart.c b/src/k_kart.c index 29579ad50..3badb2d68 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -5,6 +5,7 @@ /// All of the SRB2kart-unique stuff. #include "k_kart.h" +#include "k_battle.h" #include "k_pwrlv.h" #include "doomdef.h" #include "hu_stuff.h" @@ -604,6 +605,9 @@ boolean K_IsPlayerLosing(player_t *player) INT32 winningpos = 1; UINT8 i, pcount = 0; + if (battlecapsules && player->kartstuff[k_bumper] <= 0) + return true; // DNF in break the capsules + if (player->kartstuff[k_position] == 1) return false; @@ -625,21 +629,6 @@ boolean K_IsPlayerLosing(player_t *player) return (player->kartstuff[k_position] > winningpos); } -boolean K_IsPlayerWanted(player_t *player) -{ - UINT8 i; - if (!(G_BattleGametype())) - return false; - for (i = 0; i < 4; i++) - { - if (battlewanted[i] == -1) - break; - if (player == &players[battlewanted[i]]) - return true; - } - return false; -} - fixed_t K_GetKartGameSpeedScalar(SINT8 value) { // Easy = 81.25% @@ -1065,7 +1054,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; @@ -1179,8 +1168,8 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) } else { - if (modeattacking || cv_orbinaut.value) // Waited patiently? You get an orbinaut! - K_KartGetItemResult(player, KITEM_ORBINAUT); + if (modeattacking || cv_tripleorbinaut.value) // Waited patiently? You get Orbinaut x3! + K_KartGetItemResult(player, KRITEM_TRIPLEORBINAUT); else // Default to sad if nothing's enabled... K_KartGetItemResult(player, KITEM_SAD); player->karthud[khud_itemblinkmode] = 0; @@ -2059,9 +2048,20 @@ void K_RespawnChecker(player_t *player) destz = (player->starpostz << FRACBITS); if (player->kartstuff[k_starpostflip]) + { + // This variable is set from the settings of the best waypoint, thus this waypoint is FLIPPED as well. + // So we should flip the player in advance for it as well. + player->mo->flags2 |= MF2_OBJECTFLIP; + player->mo->eflags |= MFE_VERTICALFLIP; destz -= (128 * mapobjectscale) + (player->mo->height); + } else + { + // Ditto, but this waypoint isn't flipped, so make sure the player also isn't flipped! + player->mo->flags2 &= ~MF2_OBJECTFLIP; + player->mo->eflags &= ~MFE_VERTICALFLIP; destz += (128 * mapobjectscale); + } if (player->mo->x != destx || player->mo->y != desty || player->mo->z != destz) { @@ -2196,7 +2196,7 @@ void K_RespawnChecker(player_t *player) // Sal: The old behavior was stupid and prone to accidental usage. // Let's rip off Mania instead, and turn this into a Drop Dash! - if (cmd->buttons & BT_ACCELERATE) + if (cmd->buttons & BT_ACCELERATE && !player->kartstuff[k_spinouttimer]) // Lat: Since we're letting players spin out on respawn, don't let them charge a dropdash in this state. (It wouldn't work anyway) player->kartstuff[k_dropdash]++; else player->kartstuff[k_dropdash] = 0; @@ -2619,32 +2619,6 @@ void K_DoInstashield(player_t *player) P_SetTarget(&layerb->target, player->mo); } -void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount) -{ - statenum_t st; - mobj_t *pt; - - if (!source || !source->mo) - return; - - if (amount == 1) - st = S_BATTLEPOINT1A; - else if (amount == 2) - st = S_BATTLEPOINT2A; - else if (amount == 3) - st = S_BATTLEPOINT3A; - else - return; // NO STATE! - - pt = P_SpawnMobj(source->mo->x, source->mo->y, source->mo->z, MT_BATTLEPOINT); - P_SetTarget(&pt->target, source->mo); - P_SetMobjState(pt, st); - if (victim && victim->skincolor) - pt->color = victim->skincolor; - else - pt->color = source->skincolor; -} - void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflictor, boolean trapitem) { UINT8 scoremultiply = 1; @@ -3065,7 +3039,7 @@ void K_StealBumper(player_t *player, player_t *victim, boolean force) if (!force) { - if (victim->kartstuff[k_bumper] <= 0) // || player->kartstuff[k_bumper] >= cv_kartbumpers.value+2 + if (victim->kartstuff[k_bumper] <= 0) // || player->kartstuff[k_bumper] >= K_StartingBumperCount()+2 return; if (player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0) @@ -4308,7 +4282,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); } } @@ -6215,6 +6189,7 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player) (bestwaypoint != NULL) && (bestwaypoint != player->nextwaypoint) && (player->kartstuff[k_respawn] == 0) && + (K_GetWaypointIsSpawnpoint(bestwaypoint)) && // Don't try to respawn on waypoints that are marked with no respawn (K_GetWaypointIsShortcut(bestwaypoint) == false) && (K_GetWaypointIsEnabled(bestwaypoint) == true)) { size_t i = 0U; @@ -6492,12 +6467,11 @@ static void K_KartDrift(player_t *player, boolean onground) // Holding the Jump button will enable drifting. // Drift Release (Moved here so you can't "chain" drifts) - if ((player->kartstuff[k_drift] != -5 && player->kartstuff[k_drift] != 5) - // || (player->kartstuff[k_drift] >= 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] <= -1 && player->kartstuff[k_turndir] != -1)) - && onground) + if (player->kartstuff[k_drift] != -5 && player->kartstuff[k_drift] != 5) { if (player->kartstuff[k_driftcharge] < 0 || player->kartstuff[k_driftcharge] >= dsone) { + angle_t pushdir = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); //mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_DRIFTEXPLODE); //P_SetTarget(&overlay->target, player->mo); //P_SetScale(overlay, (overlay->destscale = player->mo->scale)); @@ -6509,6 +6483,9 @@ static void K_KartDrift(player_t *player, boolean onground) if (player->kartstuff[k_driftcharge] < 0) { // Stage 0: Yellow sparks + if (!onground) + P_Thrust(player->mo, pushdir, player->speed / 8); + if (player->kartstuff[k_driftboost] < 15) player->kartstuff[k_driftboost] = 15; @@ -6518,6 +6495,9 @@ static void K_KartDrift(player_t *player, boolean onground) else if (player->kartstuff[k_driftcharge] >= dsone && player->kartstuff[k_driftcharge] < dstwo) { // Stage 1: Red sparks + if (!onground) + P_Thrust(player->mo, pushdir, player->speed / 4); + if (player->kartstuff[k_driftboost] < 20) player->kartstuff[k_driftboost] = 20; @@ -6527,6 +6507,9 @@ static void K_KartDrift(player_t *player, boolean onground) else if (player->kartstuff[k_driftcharge] < dsthree) { // Stage 2: Blue sparks + if (!onground) + P_Thrust(player->mo, pushdir, player->speed / 3); + if (player->kartstuff[k_driftboost] < 50) player->kartstuff[k_driftboost] = 50; @@ -6536,6 +6519,9 @@ static void K_KartDrift(player_t *player, boolean onground) else if (player->kartstuff[k_driftcharge] >= dsthree) { // Stage 3: Rainbow sparks + if (!onground) + P_Thrust(player->mo, pushdir, player->speed / 2); + if (player->kartstuff[k_driftboost] < 125) player->kartstuff[k_driftboost] = 125; @@ -7429,7 +7415,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (player->kartstuff[k_hyudorotimer] > 0) { - if (splitscreen) + if (r_splitscreen) { if (leveltime & 1) player->mo->flags2 |= MF2_DONTDRAW; @@ -7440,9 +7426,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground) { 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; @@ -7560,7 +7546,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); @@ -7642,181 +7628,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground) } } -void K_CalculateBattleWanted(void) -{ - UINT8 numingame = 0, numplaying = 0, numwanted = 0; - SINT8 bestbumperplayer = -1, bestbumper = -1; - SINT8 camppos[MAXPLAYERS]; // who is the biggest camper - UINT8 ties = 0, nextcamppos = 0; - boolean setbumper = false; - UINT8 i, j; - - if (!G_BattleGametype()) - { - for (i = 0; i < 4; i++) - battlewanted[i] = -1; - return; - } - - wantedcalcdelay = wantedfrequency; - - for (i = 0; i < MAXPLAYERS; i++) - camppos[i] = -1; // initialize - - for (i = 0; i < MAXPLAYERS; i++) - { - UINT8 position = 1; - - if (!playeringame[i] || players[i].spectator) // Not playing - continue; - - if (players[i].exiting) // We're done, don't calculate. - return; - - numplaying++; - - if (players[i].kartstuff[k_bumper] <= 0) // Not alive, so don't do anything else - continue; - - numingame++; - - if (bestbumper == -1 || players[i].kartstuff[k_bumper] > bestbumper) - { - bestbumper = players[i].kartstuff[k_bumper]; - bestbumperplayer = i; - } - else if (players[i].kartstuff[k_bumper] == bestbumper) - bestbumperplayer = -1; // Tie, no one has best bumper. - - for (j = 0; j < MAXPLAYERS; j++) - { - if (!playeringame[j] || players[j].spectator) - continue; - if (players[j].kartstuff[k_bumper] <= 0) - continue; - if (j == i) - continue; - if (players[j].kartstuff[k_wanted] == players[i].kartstuff[k_wanted] && players[j].marescore > players[i].marescore) - position++; - else if (players[j].kartstuff[k_wanted] > players[i].kartstuff[k_wanted]) - position++; - } - - position--; // Make zero based - - while (camppos[position] != -1) // Port priority! - position++; - - camppos[position] = i; - } - - if (numplaying <= 2 || (numingame <= 2 && bestbumper == 1)) // In 1v1s then there's no need for WANTED. In bigger netgames, don't show anyone as WANTED when they're equally matched. - numwanted = 0; - else - numwanted = min(4, 1 + ((numingame-2) / 4)); - - for (i = 0; i < 4; i++) - { - if (i+1 > numwanted) // Not enough players for this slot to be wanted! - battlewanted[i] = -1; - else if (bestbumperplayer != -1 && !setbumper) // If there's a player who has an untied bumper lead over everyone else, they are the first to be wanted. - { - battlewanted[i] = bestbumperplayer; - setbumper = true; // Don't set twice - } - else - { - // Don't accidentally set the same player, if the bestbumperplayer is also a huge camper. - while (bestbumperplayer != -1 && camppos[nextcamppos] != -1 - && bestbumperplayer == camppos[nextcamppos]) - nextcamppos++; - - // Do not add *any* more people if there's too many times that are tied with others. - // This could theoretically happen very easily if people don't hit each other for a while after the start of a match. - // (I will be sincerely impressed if more than 2 people tie after people start hitting each other though) - - if (camppos[nextcamppos] == -1 // Out of entries - || ties >= (numwanted-i)) // Already counted ties - { - battlewanted[i] = -1; - continue; - } - - if (ties < (numwanted-i)) - { - ties = 0; // Reset - for (j = 0; j < 2; j++) - { - if (camppos[nextcamppos+(j+1)] == -1) // Nothing beyond, cancel - break; - if (players[camppos[nextcamppos]].kartstuff[k_wanted] == players[camppos[nextcamppos+(j+1)]].kartstuff[k_wanted]) - ties++; - } - } - - if (ties < (numwanted-i)) // Is it still low enough after counting? - { - battlewanted[i] = camppos[nextcamppos]; - nextcamppos++; - } - else - battlewanted[i] = -1; - } - } -} - -void K_CheckBumpers(void) -{ - UINT8 i; - UINT8 numingame = 0; - SINT8 winnernum = -1; - INT32 winnerscoreadd = 0; - - if (!multiplayer) - return; - - if (!G_BattleGametype()) - return; - - if (gameaction == ga_completed) - return; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) // not even in-game - continue; - - if (players[i].exiting) // we're already exiting! stop! - return; - - numingame++; - winnerscoreadd += players[i].marescore; - - if (players[i].kartstuff[k_bumper] <= 0) // if you don't have any bumpers, you're probably not a winner - continue; - else if (winnernum > -1) // TWO winners? that's dumb :V - return; - - winnernum = i; - winnerscoreadd -= players[i].marescore; - } - - if (numingame <= 1) - return; - - if (winnernum > -1 && playeringame[winnernum]) - { - players[winnernum].marescore += winnerscoreadd; - CONS_Printf(M_GetText("%s recieved %d point%s for winning!\n"), player_names[winnernum], winnerscoreadd, (winnerscoreadd == 1 ? "" : "s")); - } - - for (i = 0; i < MAXPLAYERS; i++) // This can't go in the earlier loop because winning adds points - K_KartUpdatePosition(&players[i]); - - for (i = 0; i < MAXPLAYERS; i++) // and it can't be merged with this loop because it needs to be all updated before exiting... multi-loops suck... - P_DoPlayerExit(&players[i]); -} - void K_CheckSpectateStatus(void) { UINT8 respawnlist[MAXPLAYERS]; @@ -7930,6 +7741,8 @@ static patch_t *kp_lapstickernarrow; static patch_t *kp_splitlapflag; static patch_t *kp_bumpersticker; static patch_t *kp_bumperstickerwide; +static patch_t *kp_capsulesticker; +static patch_t *kp_capsulestickerwide; static patch_t *kp_karmasticker; static patch_t *kp_splitkarmabomb; static patch_t *kp_timeoutsticker; @@ -7960,6 +7773,7 @@ static patch_t *kp_speedometerlabel[4]; static patch_t *kp_rankbumper; static patch_t *kp_tinybumper[2]; static patch_t *kp_ranknobumpers; +static patch_t *kp_rankcapsule; static patch_t *kp_battlewin; static patch_t *kp_battlecool; @@ -8032,6 +7846,8 @@ void K_LoadKartHUDGraphics(void) kp_splitlapflag = W_CachePatchName("K_SPTLAP", PU_HUDGFX); kp_bumpersticker = W_CachePatchName("K_STBALN", PU_HUDGFX); kp_bumperstickerwide = W_CachePatchName("K_STBALW", PU_HUDGFX); + kp_capsulesticker = W_CachePatchName("K_STCAPN", PU_HUDGFX); + kp_capsulestickerwide = W_CachePatchName("K_STCAPW", PU_HUDGFX); kp_karmasticker = W_CachePatchName("K_STKARM", PU_HUDGFX); kp_splitkarmabomb = W_CachePatchName("K_SPTKRM", PU_HUDGFX); kp_timeoutsticker = W_CachePatchName("K_STTOUT", PU_HUDGFX); @@ -8158,6 +7974,7 @@ void K_LoadKartHUDGraphics(void) kp_tinybumper[0] = W_CachePatchName("K_BLNA", PU_HUDGFX); kp_tinybumper[1] = W_CachePatchName("K_BLNB", PU_HUDGFX); kp_ranknobumpers = W_CachePatchName("K_NOBLNS", PU_HUDGFX); + kp_rankcapsule = W_CachePatchName("K_CAPICO", PU_HUDGFX); // Battle graphics kp_battlewin = W_CachePatchName("K_BWIN", PU_HUDGFX); @@ -8467,7 +8284,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; @@ -8480,7 +8297,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; @@ -8509,7 +8326,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); @@ -8529,20 +8346,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; } } @@ -8552,7 +8369,7 @@ INT32 K_calcSplitFlags(INT32 snapflags) else snapflags &= ~V_SNAPTOBOTTOM; - if (splitscreen > 1) + if (r_splitscreen > 1) { if (splitflags & V_HORZSCREEN) snapflags &= ~V_SNAPTOLEFT; @@ -8570,7 +8387,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]); @@ -8579,7 +8396,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; @@ -8811,7 +8628,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; @@ -9056,19 +8873,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. @@ -9335,7 +9152,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 ); @@ -9459,16 +9276,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; @@ -9501,8 +9318,8 @@ static void K_drawKartLapsAndRings(void) if (cv_numlaps.value >= 10) { UINT8 ln[2]; - ln[0] = ((abs(stplyr->laps) / 10) % 10); - ln[1] = (abs(stplyr->laps) % 10); + ln[0] = ((stplyr->laps / 10) % 10); + ln[1] = (stplyr->laps % 10); V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]); V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]); @@ -9651,13 +9468,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; @@ -9682,52 +9499,95 @@ static void K_drawKartBumpersOrKarma(void) V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[1]->width) - 3) : 0), fy, V_HUDTRANS|splitflags|flipflag, kp_ringstickersplit[0]); V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|splitflags, frameslash); - if (stplyr->kartstuff[k_bumper] <= 0) + if (battlecapsules) { - V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_splitkarmabomb, colormap); - V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->kartstuff[k_comebackpoints]) % 10]); - V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[2]); - } - else - { - V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_rankbumper, colormap); + V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_rankcapsule, NULL); - if (stplyr->kartstuff[k_bumper] > 9 || cv_kartbumpers.value > 9) + if (numtargets > 9 || maptargets > 9) { UINT8 ln[2]; - ln[0] = ((abs(stplyr->kartstuff[k_bumper]) / 10) % 10); - ln[1] = (abs(stplyr->kartstuff[k_bumper]) % 10); + ln[0] = ((numtargets / 10) % 10); + ln[1] = (numtargets % 10); V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]); V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]); - ln[0] = ((abs(cv_kartbumpers.value) / 10) % 10); - ln[1] = (abs(cv_kartbumpers.value) % 10); + ln[0] = ((maptargets / 10) % 10); + ln[1] = (maptargets % 10); V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]); V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]); } else { - V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->kartstuff[k_bumper]) % 10]); - V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[(cv_kartbumpers.value) % 10]); + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[numtargets % 10]); + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[maptargets % 10]); + } + } + else + { + if (stplyr->kartstuff[k_bumper] <= 0) + { + V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_splitkarmabomb, colormap); + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->kartstuff[k_comebackpoints]) % 10]); + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[2]); + } + else + { + INT32 maxbumper = K_StartingBumperCount(); + V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_rankbumper, colormap); + + if (stplyr->kartstuff[k_bumper] > 9 || maxbumper > 9) + { + UINT8 ln[2]; + ln[0] = ((abs(stplyr->kartstuff[k_bumper]) / 10) % 10); + ln[1] = (abs(stplyr->kartstuff[k_bumper]) % 10); + + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]); + V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]); + + ln[0] = ((abs(maxbumper) / 10) % 10); + ln[1] = (abs(maxbumper) % 10); + + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]); + V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]); + } + else + { + V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->kartstuff[k_bumper]) % 10]); + V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[(maxbumper) % 10]); + } } } } else { - if (stplyr->kartstuff[k_bumper] <= 0) + if (battlecapsules) { - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_karmasticker, colormap); - V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/2", stplyr->kartstuff[k_comebackpoints])); + if (numtargets > 9 && maptargets > 9) + V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_capsulestickerwide, NULL); + else + V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_capsulesticker, NULL); + V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", numtargets, maptargets)); } else { - if (stplyr->kartstuff[k_bumper] > 9 && cv_kartbumpers.value > 9) - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumperstickerwide, colormap); + if (stplyr->kartstuff[k_bumper] <= 0) + { + V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_karmasticker, colormap); + V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/2", stplyr->kartstuff[k_comebackpoints])); + } else - V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumpersticker, colormap); - V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->kartstuff[k_bumper], cv_kartbumpers.value)); + { + INT32 maxbumper = K_StartingBumperCount(); + + if (stplyr->kartstuff[k_bumper] > 9 && maxbumper > 9) + V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumperstickerwide, colormap); + else + V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumpersticker, colormap); + + V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->kartstuff[k_bumper], maxbumper)); + } } } } @@ -9754,7 +9614,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; @@ -9780,17 +9640,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; @@ -9799,13 +9659,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]]; @@ -9825,7 +9685,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);*/ } @@ -9846,7 +9706,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++) @@ -9962,7 +9822,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]; @@ -10008,7 +9868,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; @@ -10077,7 +9937,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; @@ -10187,7 +10047,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]); @@ -10203,7 +10063,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]); @@ -10214,14 +10074,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), @@ -10243,11 +10103,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; @@ -10255,12 +10115,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; @@ -10285,10 +10145,14 @@ static void K_drawBattleFullscreen(void) V_DrawFadeScreen(0xFF00, 16); if (stplyr->exiting < 6*TICRATE && !stplyr->spectator) { - if (stplyr->kartstuff[k_position] == 1) - V_DrawFixedPatch(x<kartstuff[k_position] == 1) + p = kp_battlewin; + + V_DrawFixedPatch(x<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; @@ -10307,13 +10171,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 @@ -10324,7 +10188,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 { @@ -10366,24 +10230,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) @@ -10427,12 +10291,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; @@ -10445,7 +10309,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; @@ -10458,7 +10322,7 @@ static void K_drawKartFirstPerson(void) if (mag < FRACUNIT) { xoffs = FixedMul(xoffs, mag); - if (!splitscreen) + if (!r_splitscreen) yoffs = FixedMul(yoffs, mag); } } @@ -10470,7 +10334,7 @@ static void K_drawKartFirstPerson(void) x -= xoffs; else x += xoffs; - if (!splitscreen) + if (!r_splitscreen) y += yoffs; @@ -10482,11 +10346,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; } @@ -10673,6 +10537,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] = { @@ -10820,7 +10713,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(); @@ -10840,10 +10733,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 @@ -10880,7 +10773,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 @@ -10901,7 +10794,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)) @@ -10913,7 +10806,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; @@ -10972,11 +10865,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 { @@ -10990,14 +10883,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. @@ -11009,11 +10902,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 891834f26..d5f84a7af 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -21,7 +21,6 @@ UINT8 K_GetKartColorByName(const char *name); void K_RegisterKartStuff(void); boolean K_IsPlayerLosing(player_t *player); -boolean K_IsPlayerWanted(player_t *player); fixed_t K_GetKartGameSpeedScalar(SINT8 value); void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid); void K_KartPainEnergyFling(player_t *player); @@ -34,7 +33,6 @@ void K_KartPlayerHUDUpdate(player_t *player); void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); void K_KartPlayerAfterThink(player_t *player); void K_DoInstashield(player_t *player); -void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount); void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflictor, boolean trapitem); void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor); void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor); @@ -68,8 +66,6 @@ fixed_t K_GetKartAccel(player_t *player); UINT16 K_GetKartFlashing(player_t *player); fixed_t K_3dKartMovement(player_t *player, boolean onground, fixed_t forwardmove); void K_MoveKartPlayer(player_t *player, boolean onground); -void K_CalculateBattleWanted(void); -void K_CheckBumpers(void); void K_CheckSpectateStatus(void); // sound stuff for lua diff --git a/src/k_pwrlv.c b/src/k_pwrlv.c index b219043c0..b8d78e0ee 100644 --- a/src/k_pwrlv.c +++ b/src/k_pwrlv.c @@ -19,7 +19,7 @@ UINT16 clientpowerlevels[MAXPLAYERS][PWRLV_NUMTYPES]; // Which players spec-scummed, and their power level before scumming. // On race finish, everyone is considered to have "won" against these people. -INT16 nospectategrief[MAXPLAYERS]; +INT16 nospectategrief[MAXPLAYERS]; // Game setting scrambles based on server Power Level SINT8 speedscramble = -1; diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 3288219cd..a9b02aa5f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -26,6 +26,7 @@ #include "hu_stuff.h" // HU_AddChatText #include "console.h" #include "k_kart.h" // SRB2Kart +#include "k_battle.h" #include "d_netcmd.h" // IsPlayerAdmin #include "lua_script.h" diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 299870e00..4e75ca8f7 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -125,7 +125,7 @@ void COM_Lua_f(void) lua_pop(gL, 1); // pop command info table return; // can't execute splitscreen command without player 2! } - playernum = displayplayers[1]; + playernum = g_localplayers[1]; } if (netgame) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 2fe8c33a2..4ef61704b 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -436,15 +436,15 @@ static int libd_drawOnMinimap(lua_State *L) // first, check what position the mmap is supposed to be in (pasted from k_kart.c): MM_X = BASEVIDWIDTH - 50; // 270 MM_Y = (BASEVIDHEIGHT/2)-16; // 84 - if (splitscreen) + if (r_splitscreen) { MM_Y = (BASEVIDHEIGHT/2); - if (splitscreen > 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_cond.c b/src/m_cond.c index b56882c90..e91ac1273 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -172,7 +172,8 @@ unlockable_t unlockables[MAXUNLOCKABLES] = /* 05 */ {"Encore Mode", "", 4, 5, SECRET_ENCORE, 0, false, false, 0}, /* 06 */ {"Hell Attack", "", 6, 6, SECRET_HELLATTACK, 0, false, false, 0}, - /* 07 */ {"Record Attack", "", -1, -1, SECRET_RECORDATTACK, 0, true, true, 0}, + /* 07 */ {"Time Attack", "", -1, -1, SECRET_TIMEATTACK, 0, true, true, 0}, + /* 08 */ {"Break the Capsules", "", -1, -1, SECRET_BREAKTHECAPSULES, 0, true, true, 0}, }; // Default number of emblems and extra emblems diff --git a/src/m_cond.h b/src/m_cond.h index c6362ec5d..82e776632 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -118,8 +118,8 @@ typedef struct #define SECRET_ITEMFINDER -5 // Enables Item Finder/Emblem Radar #define SECRET_EMBLEMHINTS -4 // Enables Emblem Hints #define SECRET_PANDORA -3 // Enables Pandora's Box -#define SECRET_RECORDATTACK -2 // Enables Record Attack on the main menu -#define SECRET_NIGHTSMODE -1 // Enables NiGHTS Mode on the main menu +#define SECRET_TIMEATTACK -2 // Enables Time Attack on the main menu +#define SECRET_BREAKTHECAPSULES -1 // Enables Break the Capsules on the main menu #define SECRET_HEADER 0 // Does nothing on its own, just serves as a header for the menu #define SECRET_LEVELSELECT 1 // Selectable level select #define SECRET_WARP 2 // Selectable warp diff --git a/src/m_menu.c b/src/m_menu.c index d5084dff2..897db4709 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -138,8 +138,8 @@ typedef enum { LLM_CREATESERVER, LLM_LEVELSELECT, - LLM_RECORDATTACK, - LLM_NIGHTSATTACK + LLM_TIMEATTACK, + LLM_BREAKTHECAPSULES } levellist_mode_t; levellist_mode_t levellistmode = LLM_CREATESERVER; @@ -205,9 +205,7 @@ static char *M_GetConditionString(condition_t cond); menu_t SR_MainDef, SR_UnlockChecklistDef; // Misc. Main Menu -#if 0 // Bring this back when we have actual single-player static void M_SinglePlayerMenu(INT32 choice); -#endif static void M_Options(INT32 choice); static void M_Manual(INT32 choice); static void M_SelectableClearMenus(INT32 choice); @@ -230,7 +228,7 @@ menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef, MISC_ChangeSpectateDef; //static void M_LoadGame(INT32 choice); static void M_TimeAttack(INT32 choice); static boolean M_QuitTimeAttackMenu(void); -//static void M_NightsAttack(INT32 choice); +static void M_BreakTheCapsules(INT32 choice); static void M_Statistics(INT32 choice); static void M_HandleStaffReplay(INT32 choice); static void M_ReplayTimeAttack(INT32 choice); @@ -482,11 +480,10 @@ static consvar_t cv_dummystaff = {"dummystaff", "0", CV_HIDEN|CV_CALL, dummystaf static menuitem_t MainMenu[] = { {IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_MainDef, 76}, - //{IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, #ifdef TESTERS - {IT_GRAYEDOUT, NULL, "Time Attack", NULL, 84}, + {IT_GRAYEDOUT, NULL, "1 Player", NULL, 84}, #else - {IT_CALL |IT_STRING, NULL, "Time Attack", M_TimeAttack, 84}, + {IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84}, #endif {IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92}, {IT_CALL |IT_STRING, NULL, "Options", M_Options, 100}, @@ -806,18 +803,16 @@ static menuitem_t SR_EmblemHintMenu[] = // Single Player Main static menuitem_t SP_MainMenu[] = { - //{IT_CALL | IT_STRING, NULL, "Start Game", M_LoadGame, 92}, - {IT_SECRET, NULL, "Record Attack", M_TimeAttack, 100}, - //{IT_SECRET, NULL, "NiGHTS Mode", M_NightsAttack, 108}, - {IT_CALL | IT_STRING | IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 108}, + //{IT_CALL | IT_STRING, NULL, "Grand Prix", M_LoadGame, 92}, + {IT_SECRET, NULL, "Time Attack", M_TimeAttack, 100}, + {IT_SECRET, NULL, "Break the Capsules", M_BreakTheCapsules, 108}, }; enum { - //sploadgame, - sprecordattack, - //spnightsmode, - spstatistics + //spgrandprix, + sptimeattack, + spbreakthecapsules }; // Single Player Load Game @@ -1879,52 +1874,6 @@ static menu_t SP_GhostDef = NULL }; -/*static menu_t SP_NightsAttackDef = -{ - "M_NIGHTS", - sizeof (SP_NightsAttackMenu)/sizeof (menuitem_t), - &MainDef, // Doesn't matter. - SP_NightsAttackMenu, - M_DrawNightsAttackMenu, - 32, 40, - 0, - NULL -}; -static menu_t SP_NightsReplayDef = -{ - "M_NIGHTS", - sizeof(SP_NightsReplayMenu)/sizeof(menuitem_t), - &SP_NightsAttackDef, - SP_NightsReplayMenu, - M_DrawNightsAttackMenu, - 32, 120, - 0, - NULL -}; -static menu_t SP_NightsGuestReplayDef = -{ - "M_NIGHTS", - sizeof(SP_NightsGuestReplayMenu)/sizeof(menuitem_t), - &SP_NightsAttackDef, - SP_NightsGuestReplayMenu, - M_DrawNightsAttackMenu, - 32, 120, - 0, - NULL -}; -static menu_t SP_NightsGhostDef = -{ - "M_NIGHTS", - sizeof(SP_NightsGhostMenu)/sizeof(menuitem_t), - &SP_NightsAttackDef, - SP_NightsGhostMenu, - M_DrawNightsAttackMenu, - 32, 120, - 0, - NULL -};*/ - - /*menu_t SP_PlayerDef = { "M_PICKP", @@ -2163,7 +2112,7 @@ static void Nextmap_OnChange(void) CV_StealthSetValue(&cv_dummystaff, 0); - active = false; + active = 0; SP_TimeAttackMenu[taguest].status = IT_DISABLED; SP_TimeAttackMenu[tareplay].status = IT_DISABLED; //SP_TimeAttackMenu[taghost].status = IT_DISABLED; @@ -2184,11 +2133,15 @@ static void Nextmap_OnChange(void) SP_GuestReplayMenu[0].status = IT_WHITESTRING|IT_CALL; active |= 3; } - if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, cv_chooseskin.string))) { - SP_ReplayMenu[1].status = IT_WHITESTRING|IT_CALL; - SP_GuestReplayMenu[1].status = IT_WHITESTRING|IT_CALL; - active |= 3; + + if (levellistmode != LLM_BREAKTHECAPSULES) { + if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, cv_chooseskin.string))) { + SP_ReplayMenu[1].status = IT_WHITESTRING|IT_CALL; + SP_GuestReplayMenu[1].status = IT_WHITESTRING|IT_CALL; + active |= 3; + } } + if (FIL_FileExists(va("%s-%s-last.lmp", gpath, cv_chooseskin.string))) { SP_ReplayMenu[2].status = IT_WHITESTRING|IT_CALL; SP_GuestReplayMenu[2].status = IT_WHITESTRING|IT_CALL; @@ -4263,11 +4216,13 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt) return false; // not unlocked return true;*/ - case LLM_RECORDATTACK: + case LLM_TIMEATTACK: + case LLM_BREAKTHECAPSULES: /*if (!(mapheaderinfo[mapnum]->menuflags & LF2_RECORDATTACK)) return false;*/ - if (!(mapheaderinfo[mapnum]->typeoflevel & TOL_RACE)) + if ((levellistmode == LLM_TIMEATTACK && !(mapheaderinfo[mapnum]->typeoflevel & TOL_RACE)) + || (levellistmode == LLM_BREAKTHECAPSULES && !(mapheaderinfo[mapnum]->typeoflevel & TOL_MATCH))) return false; if (M_MapLocked(mapnum+1)) @@ -4286,20 +4241,6 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt) return false;*/ return true; - /*case LLM_NIGHTSATTACK: - if (!(mapheaderinfo[mapnum]->menuflags & LF2_NIGHTSATTACK)) - return false; - - if (M_MapLocked(mapnum+1)) - return false; // not unlocked - - if (mapheaderinfo[mapnum]->menuflags & LF2_NOVISITNEEDED) - return true; - - if (!mapvisited[mapnum]) - return false; - - return true;*/ default: return false; } @@ -5789,9 +5730,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; @@ -5814,7 +5755,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]; @@ -5850,18 +5791,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: @@ -5954,12 +5895,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(); } } @@ -6627,18 +6568,16 @@ static void M_Credits(INT32 choice) // SINGLE PLAYER MENU // ================== -#if 0 // Bring this back when we have actual single-player static void M_SinglePlayerMenu(INT32 choice) { (void)choice; - SP_MainMenu[sprecordattack].status = - (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET; - /*SP_MainMenu[spnightsmode].status = - (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;*/ + SP_MainMenu[sptimeattack].status = + (M_SecretUnlocked(SECRET_TIMEATTACK)) ? IT_CALL|IT_STRING : IT_SECRET; + SP_MainMenu[spbreakthecapsules].status = + (M_SecretUnlocked(SECRET_BREAKTHECAPSULES)) ? IT_CALL|IT_STRING : IT_SECRET; M_SetupNextMenu(&SP_MainDef); } -#endif /*static void M_LoadGameLevelSelect(INT32 choice) { @@ -7624,8 +7563,11 @@ void M_DrawTimeAttackMenu(void) V_DrawFill((BASEVIDWIDTH - dupadjust)>>1, 78, dupadjust, 36, 159); - V_DrawRightAlignedString(149, 80, highlightflags, "BEST LAP:"); - K_drawKartTimestamp(lap, 19, 86, 0, 2); + if (levellistmode != LLM_BREAKTHECAPSULES) + { + V_DrawRightAlignedString(149, 80, highlightflags, "BEST LAP:"); + K_drawKartTimestamp(lap, 19, 86, 0, 2); + } V_DrawRightAlignedString(292, 80, highlightflags, "BEST TIME:"); K_drawKartTimestamp(time, 162, 86, cv_nextmap.value, 1); @@ -7714,11 +7656,43 @@ static void M_TimeAttack(INT32 choice) memset(skins_cons_t, 0, sizeof (skins_cons_t)); - levellistmode = LLM_RECORDATTACK; // Don't be dependent on cv_newgametype + levellistmode = LLM_TIMEATTACK; // Don't be dependent on cv_newgametype if (M_CountLevelsToShowInList() == 0) { - M_StartMessage(M_GetText("No record-attackable levels found.\n"),NULL,MM_NOTHING); + M_StartMessage(M_GetText("No levels found for Time Attack.\n"),NULL,MM_NOTHING); + return; + } + + M_PatchSkinNameTable(); + + M_PrepareLevelSelect(); + M_SetupNextMenu(&SP_TimeAttackDef); + + G_SetGamestate(GS_TIMEATTACK); + + if (cv_nextmap.value) + Nextmap_OnChange(); + else + CV_AddValue(&cv_nextmap, 1); + + itemOn = tastart; // "Start" is selected. + + S_ChangeMusicInternal("racent", true); +} + +// Same as above, but sets a different levellistmode. Should probably be merged... +static void M_BreakTheCapsules(INT32 choice) +{ + (void)choice; + + memset(skins_cons_t, 0, sizeof (skins_cons_t)); + + levellistmode = LLM_BREAKTHECAPSULES; // Don't be dependent on cv_newgametype + + if (M_CountLevelsToShowInList() == 0) + { + M_StartMessage(M_GetText("No levels found for Break the Capsules.\n"),NULL,MM_NOTHING); return; } @@ -7852,13 +7826,13 @@ static boolean M_QuitTimeAttackMenu(void) }*/ // Going to Nights Attack menu... -/*static void M_NightsAttack(INT32 choice) +/*static void M_BreakTheCapsules(INT32 choice) { (void)choice; memset(skins_cons_t, 0, sizeof (skins_cons_t)); - levellistmode = LLM_NIGHTSATTACK; // Don't be dependent on cv_newgametype + levellistmode = LLM_BREAKTHECAPSULES; // Don't be dependent on cv_newgametype if (M_CountLevelsToShowInList() == 0) { @@ -7886,7 +7860,7 @@ static boolean M_QuitTimeAttackMenu(void) (void)choice; emeralds = 0; M_ClearMenus(true); - modeattacking = ATTACKING_NIGHTS; + modeattacking = ATTACKING_CAPSULES; I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); @@ -7910,7 +7884,7 @@ static void M_ChooseTimeAttack(INT32 choice) (void)choice; emeralds = 0; M_ClearMenus(true); - modeattacking = ATTACKING_RECORD; + modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD); I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755); I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755); @@ -7960,7 +7934,7 @@ static void M_HandleStaffReplay(INT32 choice) if (l == LUMPERROR) break; M_ClearMenus(true); - modeattacking = ATTACKING_RECORD; + modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD); demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed G_DoPlayDemo(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value)); break; @@ -7981,7 +7955,7 @@ static void M_ReplayTimeAttack(INT32 choice) { const char *which; M_ClearMenus(true); - modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows + modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD); // set modeattacking before G_DoPlayDemo so the map loader knows demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed if (currentMenu == &SP_ReplayDef) @@ -8128,10 +8102,8 @@ static void M_ModeAttackRetry(INT32 choice) { (void)choice; G_CheckDemoStatus(); // Cancel recording - if (modeattacking == ATTACKING_RECORD) + if (modeattacking) M_ChooseTimeAttack(0); - /*else if (modeattacking == ATTACKING_NIGHTS) - M_ChooseNightsAttack(0);*/ } static void M_ModeAttackEndGame(INT32 choice) @@ -8143,16 +8115,10 @@ static void M_ModeAttackEndGame(INT32 choice) Command_ExitGame_f(); M_StartControlPanel(); - switch(modeattacking) - { - default: - case ATTACKING_RECORD: + + if (modeattacking) currentMenu = &SP_TimeAttackDef; - break; - /*case ATTACKING_NIGHTS: - currentMenu = &SP_NightsAttackDef; - break;*/ - } + itemOn = currentMenu->lastOn; G_SetGamestate(GS_TIMEATTACK); modeattacking = ATTACKING_NONE; @@ -9525,7 +9491,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; @@ -9537,7 +9503,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); @@ -9556,7 +9522,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; @@ -9568,7 +9534,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); @@ -9587,7 +9553,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; @@ -9599,7 +9565,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); diff --git a/src/m_misc.c b/src/m_misc.c index f4a4ec291..c3b8776b0 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -743,12 +743,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"); 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 df20cb6f1..49416aec4 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -25,6 +25,7 @@ #include "lua_hook.h" #include "k_kart.h" // SRB2kart #include "k_waypoint.h" +#include "k_battle.h" #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -4197,7 +4198,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; 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 905cf1c1f..a1f507445 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -27,6 +27,7 @@ #include "m_misc.h" #include "v_video.h" // video flags for CEchos #include "k_kart.h" // SRB2kart +#include "k_battle.h" #include "k_pwrlv.h" // CTF player names @@ -63,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) @@ -84,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); } @@ -1785,7 +1786,7 @@ void P_CheckTimeLimit(void) if (!(multiplayer || netgame)) return; - if (G_RaceGametype()) + if (G_RaceGametype() || battlecapsules) return; if (leveltime < (timelimitintics + starttime)) @@ -2516,6 +2517,45 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source) S_StartSound(target, sfx_s3k80); } break; + case MT_BATTLECAPSULE: + { + mobj_t *cur; + + numtargets++; + target->fuse = 16; + target->flags |= MF_NOCLIP|MF_NOCLIPTHING; + + cur = target->hnext; + + while (cur && !P_MobjWasRemoved(cur)) + { + // Shoot every piece outward + if (!(cur->x == target->x && cur->y == target->y)) + { + P_InstaThrust(cur, + R_PointToAngle2(target->x, target->y, cur->x, cur->y), + R_PointToDist2(target->x, target->y, cur->x, cur->y) / 12 + ); + } + + cur->momz = 8 * target->scale * P_MobjFlip(target); + + cur->flags &= ~MF_NOGRAVITY; + cur->tics = TICRATE; + cur->frame &= ~FF_ANIMATE; // Stop animating the propellers + + cur = cur->hnext; + } + + // All targets busted! + if (numtargets >= maptargets) + { + UINT8 i; + for (i = 0; i < MAXPLAYERS; i++) + P_DoPlayerExit(&players[i]); + } + } + break; default: break; diff --git a/src/p_local.h b/src/p_local.h index a4e661bfc..0d7d3ec3e 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -227,7 +227,6 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state); boolean P_SetMobjState(mobj_t *mobj, statenum_t state); //void P_RunShields(void); void P_RunOverlays(void); -void P_RunBattleOvertime(void); void P_MobjThinker(mobj_t *mobj); boolean P_RailThinker(mobj_t *mobj); void P_PushableThinker(mobj_t *mobj); diff --git a/src/p_map.c b/src/p_map.c index adedd581f..559b9a461 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -25,6 +25,7 @@ #include "s_sound.h" #include "w_wad.h" #include "k_kart.h" // SRB2kart 011617 +#include "k_collide.h" #include "hu_stuff.h" // SRB2kart #include "i_system.h" // SRB2kart @@ -819,7 +820,7 @@ static boolean PIT_CheckThing(mobj_t *thing) // SRB2kart 011617 - Colission[sic] code for kart items //{ - if (thing->type == MT_SMK_ICEBLOCK) + if (tmthing->type == MT_SMK_ICEBLOCK) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -827,31 +828,20 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (!(tmthing->flags & MF_SOLID || tmthing->flags & MF_SHOOTABLE || tmthing->flags & MF_BOUNCE)) - return true; + return K_SMKIceBlockCollide(tmthing, thing); + } + else if (thing->type == MT_SMK_ICEBLOCK) + { + // 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->health)) - return true; - - if (tmthing->type == MT_BANANA || tmthing->type == MT_BANANA_SHIELD - || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_EGGMANITEM_SHIELD - || tmthing->type == MT_SSMINE || tmthing->type == MT_SSMINE_SHIELD - || tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD) - return false; - - if (thing->health) - P_KillMobj(thing, tmthing, tmthing); - - /*if (tmthing->player && (tmthing->player->kartstuff[k_invincibilitytimer] > 0 - || tmthing->player->kartstuff[k_growshrinktimer] > 0)) - return true;*/ - - K_KartBouncing(tmthing, thing, false, true); - return false; + return K_SMKIceBlockCollide(thing, tmthing); } - // Push fakes out of other items - if (tmthing->type == MT_EGGMANITEM && (thing->type == MT_RANDOMITEM || thing->type == MT_EGGMANITEM)) + if (tmthing->type == MT_EGGMANITEM) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -859,10 +849,10 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y), thing->radius/4); + K_EggItemCollide(tmthing, thing); return true; } - else if (thing->type == MT_EGGMANITEM && (tmthing->type == MT_RANDOMITEM || tmthing->type == MT_EGGMANITEM)) + else if (thing->type == MT_EGGMANITEM) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -870,7 +860,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y), tmthing->radius/4); + K_EggItemCollide(thing, tmthing); return true; } @@ -886,97 +876,10 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0))) - return true; - - if (tmthing->health <= 0 || thing->health <= 0) - return true; - - if ((tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD) && tmthing->lastlook - && (thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD) && thing->lastlook - && (tmthing->target == thing->target)) // Don't hit each other if you have the same target - return true; - - if (thing->player && thing->player->powers[pw_flashing] - && !(tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD)) - return true; - - if (thing->player && thing->player->kartstuff[k_hyudorotimer]) - return true; // no interaction - - if (thing->type == MT_PLAYER) - { - // Player Damage - P_DamageMobj(thing, tmthing, tmthing->target, 1); - K_KartBouncing(thing, tmthing, false, false); - S_StartSound(thing, sfx_s3k7b); - - // This Item Damage - if (tmthing->eflags & MFE_VERTICALFLIP) - tmthing->z -= tmthing->height; - else - tmthing->z += tmthing->height; - - S_StartSound(tmthing, tmthing->info->deathsound); - P_KillMobj(tmthing, thing, thing); - - P_SetObjectMomZ(tmthing, 12*FRACUNIT, false); - P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); - } - else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD - || thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD - || thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD - || thing->type == MT_BALLHOG) - { - // Other Item Damage - if (thing->eflags & MFE_VERTICALFLIP) - thing->z -= thing->height; - else - thing->z += thing->height; - - S_StartSound(thing, thing->info->deathsound); - P_KillMobj(thing, tmthing, tmthing); - - P_SetObjectMomZ(thing, 12*FRACUNIT, false); - P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); - - P_SpawnMobj(thing->x/2 + tmthing->x/2, thing->y/2 + tmthing->y/2, thing->z/2 + tmthing->z/2, MT_ITEMCLASH); - - // This Item Damage - if (tmthing->eflags & MFE_VERTICALFLIP) - tmthing->z -= tmthing->height; - else - tmthing->z += tmthing->height; - - S_StartSound(tmthing, tmthing->info->deathsound); - P_KillMobj(tmthing, thing, thing); - - P_SetObjectMomZ(tmthing, 12*FRACUNIT, false); - P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); - } - else if (thing->type == MT_SSMINE_SHIELD || thing->type == MT_SSMINE) - { - // This Item Damage - if (tmthing->eflags & MFE_VERTICALFLIP) - tmthing->z -= tmthing->height; - else - tmthing->z += tmthing->height; - - S_StartSound(tmthing, tmthing->info->deathsound); - P_KillMobj(tmthing, thing, thing); - - P_SetObjectMomZ(tmthing, 12*FRACUNIT, false); - P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); - - // Bomb death - P_KillMobj(thing, tmthing, tmthing); - } - else if (thing->flags & MF_SPRING && (tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD || tmthing->type == MT_ORBINAUT)) - P_DoSpring(thing, tmthing); - - return true; + return K_OrbinautJawzCollide(tmthing, thing); } - else if (tmthing->flags & MF_SPRING && (thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD || thing->type == MT_ORBINAUT)) + else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD + || thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -984,14 +887,10 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (thing->health <= 0) - return true; - - P_DoSpring(tmthing, thing); - - return true; + return K_OrbinautJawzCollide(thing, tmthing); } - else if (tmthing->type == MT_SINK) + + if (tmthing->type == MT_BANANA || tmthing->type == MT_BANANA_SHIELD || tmthing->type == MT_BALLHOG) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -999,34 +898,9 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0))) - return true; - - if (thing->player && thing->player->powers[pw_flashing]) - return true; - - if (thing->type == MT_PLAYER) - { - mobj_t *explosion; - - S_StartSound(NULL, sfx_bsnipe); // let all players hear it. - - HU_SetCEchoFlags(0); - HU_SetCEchoDuration(5); - HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[thing->player-players])); - I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[thing->player-players]); - - explosion = P_SpawnMobj(thing->x, thing->y, thing->z, MT_SPBEXPLOSION); - explosion->extravalue1 = 1; // Tell K_ExplodePlayer to use extra knockback - if (tmthing->target && !P_MobjWasRemoved(tmthing->target)) - P_SetTarget(&explosion->target, tmthing->target); - - P_KillMobj(tmthing, thing, thing); - } - - return true; + return K_BananaBallhogCollide(tmthing, thing); } - else if (tmthing->type == MT_MINEEXPLOSION) + else if (thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD || thing->type == MT_BALLHOG) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -1034,24 +908,10 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (!(thing->type == MT_PLAYER)) - return true; - - if (thing->player && thing->player->powers[pw_flashing]) - return true; - - if (thing->type == MT_PLAYER && thing->player) - { - if (tmthing->state == &states[S_MINEEXPLOSION1]) - K_ExplodePlayer(thing->player, tmthing->target, tmthing); - else - K_SpinPlayer(thing->player, tmthing->target, 0, tmthing, false); - } - - return true; // This doesn't collide with anything, but we want it to effect the player anyway. + return K_BananaBallhogCollide(thing, tmthing); } - else if (tmthing->type == MT_BANANA_SHIELD || tmthing->type == MT_BANANA - || tmthing->type == MT_BALLHOG) + + if (tmthing->type == MT_SSMINE || tmthing->type == MT_SSMINE_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -1059,78 +919,9 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0))) - return true; - - if (tmthing->health <= 0 || thing->health <= 0) - return true; - - if (((tmthing->type == MT_BANANA_SHIELD) && (thing->type == MT_BANANA_SHIELD)) - && (tmthing->target == thing->target)) // Don't hit each other if you have the same target - return true; - - if (tmthing->type == MT_BALLHOG && thing->type == MT_BALLHOG) - return true; // Ballhogs don't collide with eachother - - if (thing->player && thing->player->powers[pw_flashing]) - return true; - - if (thing->type == MT_PLAYER) - { - // Banana snipe! - if (tmthing->type == MT_BANANA && tmthing->health > 1) - S_StartSound(thing, sfx_bsnipe); - - // Player Damage - K_SpinPlayer(thing->player, tmthing->target, 0, tmthing, (tmthing->type == MT_BANANA || tmthing->type == MT_BANANA_SHIELD)); - - // This Item Damage - if (tmthing->eflags & MFE_VERTICALFLIP) - tmthing->z -= tmthing->height; - else - tmthing->z += tmthing->height; - - S_StartSound(tmthing, tmthing->info->deathsound); - P_KillMobj(tmthing, thing, thing); - - P_SetObjectMomZ(tmthing, 12*FRACUNIT, false); - P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); - } - else if (thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD - || thing->type == MT_ORBINAUT || thing->type == MT_ORBINAUT_SHIELD - || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD || thing->type == MT_JAWZ_SHIELD - || thing->type == MT_BALLHOG) - { - // Other Item Damage - if (thing->eflags & MFE_VERTICALFLIP) - thing->z -= thing->height; - else - thing->z += thing->height; - - S_StartSound(thing, thing->info->deathsound); - P_KillMobj(thing, tmthing, tmthing); - - P_SetObjectMomZ(thing, 12*FRACUNIT, false); - P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); - - P_SpawnMobj(thing->x/2 + tmthing->x/2, thing->y/2 + tmthing->y/2, thing->z/2 + tmthing->z/2, MT_ITEMCLASH); - - // This Item Damage - if (tmthing->eflags & MFE_VERTICALFLIP) - tmthing->z -= tmthing->height; - else - tmthing->z += tmthing->height; - - S_StartSound(tmthing, tmthing->info->deathsound); - P_KillMobj(tmthing, thing, thing); - - P_SetObjectMomZ(tmthing, 12*FRACUNIT, false); - P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT); - } - - return true; + return K_MineCollide(tmthing, thing); } - else if (tmthing->type == MT_SSMINE_SHIELD || tmthing->type == MT_SSMINE) + else if (thing->type == MT_SSMINE || thing->type == MT_SSMINE_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -1138,52 +929,10 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0))) - return true; - - if (tmthing->health <= 0 || thing->health <= 0) - return true; - - if (thing->player && thing->player->powers[pw_flashing]) - return true; - - if (thing->type == MT_PLAYER) - { - // Bomb punting - if ((tmthing->state >= &states[S_SSMINE1] && tmthing->state <= &states[S_SSMINE4]) - || (tmthing->state >= &states[S_SSMINE_DEPLOY8] && tmthing->state <= &states[S_SSMINE_DEPLOY13])) - P_KillMobj(tmthing, thing, thing); - else - K_PuntMine(tmthing, thing); - } - else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD - || thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD) - { - P_KillMobj(tmthing, thing, thing); - - // Other Item Damage - if (thing->eflags & MFE_VERTICALFLIP) - thing->z -= thing->height; - else - thing->z += thing->height; - - S_StartSound(thing, thing->info->deathsound); - P_KillMobj(thing, tmthing, tmthing); - - P_SetObjectMomZ(thing, 12*FRACUNIT, false); - P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); - } - - return true; + return K_MineCollide(thing, tmthing); } - else if (tmthing->type == MT_PLAYER && - (thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_ORBINAUT - || thing->type == MT_JAWZ_SHIELD || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD - || thing->type == MT_BANANA_SHIELD || thing->type == MT_BANANA - || thing->type == MT_SSMINE_SHIELD || thing->type == MT_SSMINE - || thing->type == MT_MINEEXPLOSION - || thing->type == MT_SINK || thing->type == MT_BALLHOG - )) + + if (tmthing->type == MT_MINEEXPLOSION) { // see if it went over / under if (tmthing->z > thing->z + thing->height) @@ -1191,130 +940,63 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if (tmthing->player && tmthing->player->powers[pw_flashing] - && !(thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD)) - return true; + return K_MineExplosionCollide(tmthing, thing); + } + else if (thing->type == MT_MINEEXPLOSION) + { + // 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->player && tmthing->player->kartstuff[k_hyudorotimer]) // I thought about doing this for just the objects below but figured it should apply to everything. - return true; // no interaction + return K_MineExplosionCollide(thing, tmthing); + } - if (thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD - || thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD) - { - if ((thing->target == tmthing) && (thing->threshold > 0)) - return true; + if (tmthing->type == MT_SINK) + { + // 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->health <= 0 || thing->health <= 0) - return true; + return K_KitchenSinkCollide(tmthing, thing); + } + else if (thing->type == MT_SINK) + { + // 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 - // Player Damage - P_DamageMobj(tmthing, thing, thing->target, 1); - K_KartBouncing(tmthing, thing, false, false); - S_StartSound(tmthing, sfx_s3k7b); + return K_KitchenSinkCollide(thing, tmthing); + } - // Other Item Damage - if (thing->eflags & MFE_VERTICALFLIP) - thing->z -= thing->height; - else - thing->z += thing->height; + if (tmthing->type == MT_FALLINGROCK) + { + // 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 - S_StartSound(thing, thing->info->deathsound); - P_KillMobj(thing, tmthing, tmthing); + return K_FallingRockCollide(tmthing, thing); + } + else if (thing->type == MT_FALLINGROCK) + { + // 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 - P_SetObjectMomZ(thing, 12*FRACUNIT, false); - P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); - } - else if (thing->type == MT_BANANA_SHIELD || thing->type == MT_BANANA - || thing->type == MT_BALLHOG) - { - if ((thing->target == tmthing) && (thing->threshold > 0)) - return true; - - if (tmthing->health <= 0 || thing->health <= 0) - return true; - - // Banana snipe! - if (thing->type == MT_BANANA && thing->health > 1) - S_StartSound(tmthing, sfx_bsnipe); - - // Player Damage - K_SpinPlayer(tmthing->player, thing->target, 0, thing, (thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD)); - - // Other Item Damage - if (thing->eflags & MFE_VERTICALFLIP) - thing->z -= thing->height; - else - thing->z += thing->height; - - S_StartSound(thing, thing->info->deathsound); - P_KillMobj(thing, tmthing, tmthing); - - P_SetObjectMomZ(thing, 12*FRACUNIT, false); - P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT); - } - else if (thing->type == MT_SSMINE_SHIELD || thing->type == MT_SSMINE) - { - if ((thing->target == tmthing) && (thing->threshold > 0)) - return true; - - if (tmthing->health <= 0 || thing->health <= 0) - return true; - - // Bomb punting - if ((thing->state >= &states[S_SSMINE1] && thing->state <= &states[S_SSMINE4]) - || (thing->state >= &states[S_SSMINE_DEPLOY8] && thing->state <= &states[S_SSMINE_DEPLOY13])) - P_KillMobj(thing, tmthing, tmthing); - else - K_PuntMine(thing, tmthing); - } - else if (thing->type == MT_MINEEXPLOSION && tmthing->player) - { - // Player Damage - if (thing->state == &states[S_MINEEXPLOSION1]) - K_ExplodePlayer(tmthing->player, thing->target, thing); - else - K_SpinPlayer(tmthing->player, thing->target, 0, thing, false); - - return true; - } - else if (thing->type == MT_SINK) - { - mobj_t *explosion; - - if ((thing->target == tmthing) && (thing->threshold > 0)) - return true; - - S_StartSound(NULL, sfx_bsnipe); // let all players hear it. - - HU_SetCEchoFlags(0); - HU_SetCEchoDuration(5); - HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[tmthing->player-players])); - I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[tmthing->player-players]); - - explosion = P_SpawnMobj(tmthing->x, tmthing->y, tmthing->z, MT_SPBEXPLOSION); - explosion->extravalue1 = 1; // Tell K_ExplodePlayer to use extra knockback - if (thing->target && !P_MobjWasRemoved(thing->target)) - P_SetTarget(&explosion->target, thing->target); - - P_KillMobj(thing, tmthing, tmthing); - } - - return true; + return K_FallingRockCollide(thing, tmthing); } //} - if ((thing->type == MT_FALLINGROCK && (tmthing->player || tmthing->type == MT_FALLINGROCK)) - || (tmthing->type == MT_FALLINGROCK && (thing->player || thing->type == MT_FALLINGROCK))) - { - // 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 - K_KartBouncing(thing, tmthing, false, false); - } - if ((thing->type == MT_SPRINGSHELL || thing->type == MT_YELLOWSHELL) && thing->health > 0 && (tmthing->player || (tmthing->flags & MF_PUSHABLE)) && tmthing->health > 0) { @@ -2132,10 +1814,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 @@ -2703,7 +2385,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)) @@ -2719,7 +2401,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!! @@ -3497,10 +3179,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 118e5b0bc..a1ac18dc9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -36,6 +36,7 @@ #endif #include "k_kart.h" +#include "k_battle.h" // protos. //static CV_PossibleValue_t viewheight_cons_t[] = {{16, "MIN"}, {56, "MAX"}, {0, NULL}}; @@ -1171,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]) { @@ -2173,7 +2174,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; } @@ -3555,7 +3556,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)) @@ -3596,7 +3597,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; @@ -3614,12 +3615,15 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled dummy.y = thiscam->y; dummy.z = thiscam->z; dummy.height = thiscam->height; - if (player->pflags & PF_TIMEOVER) + + if ((player->pflags & PF_TIMEOVER) && G_RaceGametype()) player->karthud[khud_timeovercam] = (2*TICRATE)+1; + if (!resetcalled && !(player->pflags & PF_NOCLIP || leveltime < introtime) && !P_CheckSight(&dummy, player->mo)) // TODO: "P_CheckCameraSight" instead. P_ResetCamera(player, thiscam); else P_SlideCameraMove(thiscam); + if (resetcalled) // Okay this means the camera is fully reset. return true; } @@ -3646,11 +3650,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)) { @@ -6180,7 +6184,7 @@ void P_RunOverlays(void) if (!mo->target) continue; - if (!splitscreen /*&& rendermode != render_soft*/) + if (!r_splitscreen /*&& rendermode != render_soft*/) { angle_t viewingangle; @@ -6268,216 +6272,6 @@ static void P_RemoveOverlay(mobj_t *thing) } } -// SAL'S KART BATTLE MODE OVERTIME HANDLER -#define MAXPLANESPERSECTOR (MAXFFLOORS+1)*2 -static void P_SpawnOvertimeParticles(fixed_t x, fixed_t y, fixed_t scale, mobjtype_t type, boolean ceiling) -{ - UINT8 i; - fixed_t flatz[MAXPLANESPERSECTOR]; - boolean flip[MAXPLANESPERSECTOR]; - UINT8 numflats = 0; - mobj_t *mo; - subsector_t *ss = R_IsPointInSubsector(x, y); - sector_t *sec; - - if (!ss) - return; - sec = ss->sector; - - // convoluted stuff JUST to get all of the planes we need to draw orbs on :V - - for (i = 0; i < MAXPLANESPERSECTOR; i++) - flip[i] = false; - - if (sec->floorpic != skyflatnum) - { -#ifdef ESLOPE - flatz[numflats] = (sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->floorheight); -#else - flatz[numflats] = (sec->floorheight); -#endif - numflats++; - } - if (sec->ceilingpic != skyflatnum && ceiling) - { -#ifdef ESLOPE - flatz[numflats] = (sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : sec->ceilingheight) - FixedMul(mobjinfo[type].height, scale); -#else - flatz[numflats] = (sec->ceilingheight) - FixedMul(mobjinfo[type].height, scale); -#endif - flip[numflats] = true; - numflats++; - } - - if (sec->ffloors) - { - ffloor_t *rover; - for (rover = sec->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER)) - continue; - if (*rover->toppic != skyflatnum) - { -#ifdef ESLOPE - flatz[numflats] = (*rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) : *rover->topheight); -#else - flatz[numflats] = (*rover->topheight); -#endif - numflats++; - } - if (*rover->bottompic != skyflatnum && ceiling) - { -#ifdef ESLOPE - flatz[numflats] = (*rover->b_slope ? P_GetZAt(*rover->b_slope, x, y) : *rover->bottomheight) - FixedMul(mobjinfo[type].height, scale); -#else - flatz[numflats] = (*rover->bottomheight) - FixedMul(mobjinfo[type].height, scale); -#endif - flip[numflats] = true; - numflats++; - } - } - } - - if (numflats <= 0) // no flats - return; - - for (i = 0; i < numflats; i++) - { - mo = P_SpawnMobj(x, y, flatz[i], type); - - // Lastly, if this can see the skybox mobj, then... we just wasted our time :V - if (skyboxmo[0] && !P_MobjWasRemoved(skyboxmo[0])) - { - const fixed_t sbz = skyboxmo[0]->z; - fixed_t checkz = sec->floorheight; - - while (checkz < sec->ceilingheight) - { - P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, checkz); - if (P_CheckSight(skyboxmo[0], mo)) - { - P_RemoveMobj(mo); - break; - } - else - checkz += 32*mapobjectscale; - } - - P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, sbz); - - if (P_MobjWasRemoved(mo)) - continue; - } - - P_SetScale(mo, scale); - - if (flip[i]) - { - mo->flags2 |= MF2_OBJECTFLIP; - mo->eflags |= MFE_VERTICALFLIP; - } - - switch(type) - { - case MT_OVERTIMEFOG: - mo->destscale = 8*mo->scale; - mo->momz = P_RandomRange(1,8)*mo->scale; - break; - case MT_OVERTIMEORB: - //mo->destscale = mo->scale/4; - mo->frame += ((leveltime/4) % 8); - /*if (battleovertime.enabled < 10*TICRATE) - mo->flags2 |= MF2_SHADOW;*/ - mo->angle = R_PointToAngle2(mo->x, mo->y, battleovertime.x, battleovertime.y) + ANGLE_90; - mo->z += P_RandomRange(0,48) * mo->scale; - break; - default: - break; - } - } -} -#undef MAXPLANESPERSECTOR - -void P_RunBattleOvertime(void) -{ - UINT16 i, j; - - if (battleovertime.enabled < 10*TICRATE) - { - battleovertime.enabled++; - if (battleovertime.enabled == TICRATE) - S_StartSound(NULL, sfx_bhurry); - if (battleovertime.enabled == 10*TICRATE) - S_StartSound(NULL, sfx_kc40); - } - else - { - if (battleovertime.radius > battleovertime.minradius) - battleovertime.radius -= mapobjectscale; - else - battleovertime.radius = battleovertime.minradius; - } - - if (leveltime & 1) - { - UINT8 transparency = tr_trans50; - - if (!splitscreen && players[displayplayers[0]].mo) - { - INT32 dist = P_AproxDistance(battleovertime.x-players[displayplayers[0]].mo->x, battleovertime.y-players[displayplayers[0]].mo->y); - transparency = max(0, NUMTRANSMAPS - ((256 + (dist>>FRACBITS)) / 256)); - } - - if (transparency < NUMTRANSMAPS) - { - mobj_t *beam = P_SpawnMobj(battleovertime.x, battleovertime.y, battleovertime.z + (mobjinfo[MT_RANDOMITEM].height/2), MT_OVERTIMEBEAM); - P_SetScale(beam, beam->scale*2); - if (transparency > 0) - beam->frame |= transparency<>FRACBITS / 2));*/ - - for (i = 0; i < 16; i++) - { - j = 0; - while (j < 32) // max attempts - { - fixed_t x = battleovertime.x + ((P_RandomRange(-64,64) * 128)<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); @@ -7069,7 +6863,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; @@ -7089,7 +6883,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); @@ -7124,6 +6918,18 @@ void P_MobjThinker(mobj_t *mobj) P_SetMobjStateNF(smok, smok->info->painstate); // same function, diff sprite } break; + case MT_BATTLECAPSULE_PIECE: + if (mobj->extravalue2) + mobj->frame |= FF_VERTICALFLIP; + else + mobj->frame &= ~FF_VERTICALFLIP; + + if (mobj->flags2 & MF2_OBJECTFLIP) + mobj->eflags |= MFE_VERTICALFLIP; + + if (mobj->tics > 0) + mobj->flags2 ^= MF2_DONTDRAW; + break; //} case MT_WATERDROP: P_SceneryCheckWater(mobj); @@ -7571,6 +7377,27 @@ void P_MobjThinker(mobj_t *mobj) return; } break; + case MT_BATTLECAPSULE: + if (!(mobj->fuse & 1)) + { + const SINT8 amt = 96; + mobj_t *dust; + UINT8 i; + + for (i = 0; i < 2; i++) + { + fixed_t xoffset = P_RandomRange(-amt, amt) * mobj->scale; + fixed_t yoffset = P_RandomRange(-amt, amt) * mobj->scale; + fixed_t zoffset = P_RandomRange(-(amt >> 1), (amt >> 1)) * mobj->scale; + + dust = P_SpawnMobj(mobj->x + xoffset, mobj->y + yoffset, + mobj->z + (mobj->height >> 1) + zoffset, MT_EXPLODE); + } + + if (dust && !P_MobjWasRemoved(dust)) // Only do for 1 explosion + S_StartSound(dust, sfx_s3k3d); + } + break; //} default: break; @@ -8082,6 +7909,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)) @@ -8152,6 +7986,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; @@ -8175,6 +8015,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)) @@ -8235,6 +8082,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); @@ -8264,6 +8117,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; @@ -8296,6 +8155,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 @@ -8609,7 +8474,7 @@ void P_MobjThinker(mobj_t *mobj) } P_SetScale(mobj, (mobj->destscale = (5*mobj->target->destscale)>>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))); @@ -9392,6 +9257,229 @@ void P_MobjThinker(mobj_t *mobj) trail->color = mobj->color; } break; + case MT_BATTLECAPSULE: + { + SINT8 realflip = P_MobjFlip(mobj); + SINT8 flip = realflip; // Flying capsules needs flipped sprites, but not flipped gravity + fixed_t bottom; + mobj_t *cur; + + if (mobj->extravalue1) + { + const INT32 speed = 6*TICRATE; // longer is slower + const fixed_t pi = 22*FRACUNIT/7; // Inaccurate, but is close enough for our usage + fixed_t sine = FINESINE((((2*pi*speed) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK) * flip; + + // Flying capsules are flipped upside-down, like S3K + flip = -flip; + + // ALL CAPSULE MOVEMENT NEEDS TO HAPPEN AFTER THIS & ADD TO MOMENTUM FOR BOBBING TO BE ACCURATE + mobj->momz = sine/2; + } + + // Moving capsules + if (mobj->target && !P_MobjWasRemoved(mobj->target)) + { + fixed_t speed = mobj->movefactor; + UINT8 sequence = mobj->lastlook; + UINT8 num = mobj->movecount; + boolean backandforth = (mobj->flags2 & MF2_AMBUSH); + SINT8 direction = mobj->cvmem; + mobj_t *next = NULL; + thinker_t *th; + fixed_t dist, momx, momy, momz; + + dist = P_AproxDistance(mobj->target->x - mobj->x, mobj->target->y - mobj->y); + if (mobj->extravalue1) + dist = P_AproxDistance(dist, mobj->target->z - mobj->z); + if (dist < 1) + dist = 1; + + if (speed <= dist) + { + momx = FixedMul(FixedDiv(mobj->target->x - mobj->x, dist), speed); + momy = FixedMul(FixedDiv(mobj->target->y - mobj->y, dist), speed); + if (mobj->extravalue1) + momz = mobj->momz + FixedMul(FixedDiv(mobj->target->z - mobj->z, dist), speed); + + mobj->momx = momx; + mobj->momy = momy; + if (mobj->extravalue1) + mobj->momz = momz; + } + else + { + mobj_t *mo2; + + speed -= dist; + + P_UnsetThingPosition(mobj); + mobj->x = mobj->target->x; + mobj->y = mobj->target->y; + mobj->z = mobj->target->z; + P_SetThingPosition(mobj); + + mobj->floorz = mobj->subsector->sector->floorheight; + mobj->ceilingz = mobj->subsector->sector->ceilingheight; + + // Onto the next waypoint! + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type != MT_TUBEWAYPOINT) + continue; + + if (mo2->threshold == sequence) + { + if (mo2->health == num + direction) + { + next = mo2; + break; + } + } + } + + // Are we at the end of the waypoint chain? + // If so, search again for the first/previous waypoint (depending on settings) + if (next == NULL) + { + if (backandforth) + { + mobj->cvmem = -mobj->cvmem; + direction = mobj->cvmem; + } + + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker + continue; + + mo2 = (mobj_t *)th; + + if (mo2->type != MT_TUBEWAYPOINT) + continue; + + if (mo2->threshold == sequence) + { + if (backandforth) + { + if (mo2->health == num + direction) + { + next = mo2; + break; + } + } + else + { + if (direction < 0) + { + if (next == NULL || mo2->health > next->health) + next = mo2; + } + else + { + if (next == NULL || mo2->health < next->health) + next = mo2; + } + } + } + } + } + + if (next && !P_MobjWasRemoved(next)) + { + P_SetTarget(&mobj->target, next); + mobj->movecount = next->health; + + dist = P_AproxDistance(mobj->target->x - mobj->x, mobj->target->y - mobj->y); + if (mobj->extravalue1) + dist = P_AproxDistance(dist, mobj->target->z - mobj->z); + if (dist < 1) + dist = 1; + + momx = FixedMul(FixedDiv(mobj->target->x - mobj->x, dist), speed); + momy = FixedMul(FixedDiv(mobj->target->y - mobj->y, dist), speed); + if (mobj->extravalue1) + momz = mobj->momz + FixedMul(FixedDiv(mobj->target->z - mobj->z, dist), speed); + + mobj->momx = momx; + mobj->momy = momy; + if (mobj->extravalue1) + mobj->momz = momz; + } + else + { + CONS_Alert(CONS_WARNING, "Moving capsule could not find next waypoint! (seq: %d)\n", sequence); + P_SetTarget(&mobj->target, NULL); + } + } + } + + if (flip == -1) + bottom = mobj->z + mobj->height; + else + bottom = mobj->z; + + cur = mobj->hnext; + + // Move each piece to the proper position + while (cur && !P_MobjWasRemoved(cur)) + { + fixed_t newx = mobj->x; + fixed_t newy = mobj->y; + fixed_t newz = bottom; + statenum_t state = (statenum_t)(cur->state-states); + + cur->scale = mobj->scale; + cur->destscale = mobj->destscale; + cur->scalespeed = mobj->scalespeed; + + cur->extravalue2 = mobj->extravalue1; + + cur->flags2 = (cur->flags2 & ~MF2_OBJECTFLIP)|(mobj->flags2 & MF2_OBJECTFLIP); + + if (state == S_BATTLECAPSULE_TOP) + newz += (80 * mobj->scale * flip); + else if (state == S_BATTLECAPSULE_BUTTON) + newz += (108 * mobj->scale * flip); + else if (state == S_BATTLECAPSULE_SUPPORT + || state == S_BATTLECAPSULE_SUPPORTFLY + || state == S_KARMAWHEEL) + { + fixed_t offx = mobj->radius; + fixed_t offy = mobj->radius; + + if (cur->extravalue1 & 1) + offx = -offx; + + if (cur->extravalue1 > 1) + offy = -offy; + + newx += offx; + newy += offy; + } + else if (state == S_BATTLECAPSULE_SIDE1 + || state == S_BATTLECAPSULE_SIDE2) + { + fixed_t offset = 48 * mobj->scale; + angle_t angle = (ANGLE_45 * cur->extravalue1); + + newx += FixedMul(offset, FINECOSINE(angle >> ANGLETOFINESHIFT)); + newy += FixedMul(offset, FINESINE(angle >> ANGLETOFINESHIFT)); + newz += (12 * mobj->scale * flip); + + cur->angle = angle + ANGLE_90; + } + + P_TeleportMove(cur, newx, newy, newz); + + cur = cur->hnext; + } + } case MT_RANDOMITEM: if (G_BattleGametype() && mobj->threshold == 70) { @@ -10926,13 +11014,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 { @@ -10940,17 +11028,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; } @@ -10965,7 +11053,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; @@ -10973,7 +11061,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) { @@ -10981,7 +11069,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); } } @@ -11276,7 +11364,7 @@ void P_SpawnPlayer(INT32 playernum) || (p->jointime <= 1 && pcount <= 1)) { if (leveltime < 1 || (p->jointime <= 1 && pcount <= 1)) // Start of the map? - p->kartstuff[k_bumper] = cv_kartbumpers.value; // Reset those bumpers! + p->kartstuff[k_bumper] = K_StartingBumperCount(); // Reset those bumpers! if (p->kartstuff[k_bumper]) { @@ -11318,9 +11406,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]) { @@ -11350,7 +11438,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 4767b09d1..ee2dc62ea 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -35,6 +35,7 @@ #endif // SRB2Kart +#include "k_battle.h" #include "k_pwrlv.h" savedata_t savedata; @@ -3320,6 +3321,8 @@ static void P_NetArchiveMisc(void) // SRB2kart WRITEINT32(save_p, numgotboxes); + WRITEUINT8(save_p, numtargets); + WRITEUINT8(save_p, battlecapsules); WRITEUINT8(save_p, gamespeed); WRITEUINT8(save_p, franticitems); @@ -3443,6 +3446,8 @@ static inline boolean P_NetUnArchiveMisc(void) // SRB2kart numgotboxes = READINT32(save_p); + numtargets = READUINT8(save_p); + battlecapsules = (boolean)READUINT8(save_p); gamespeed = READUINT8(save_p); franticitems = (boolean)READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index e0b3550dc..40ea643b7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -84,6 +84,7 @@ // SRB2Kart #include "k_kart.h" +#include "k_battle.h" // K_SpawnBattleCapsules #include "k_pwrlv.h" #include "k_waypoint.h" @@ -1026,6 +1027,12 @@ static void P_LoadThings(void) if (mt->type == mobjinfo[MT_RANDOMITEM].doomednum) nummapboxes++; + if (mt->type == mobjinfo[MT_BATTLECAPSULE].doomednum) + { + maptargets++; + continue; // These should not be spawned *yet* + } + mt->mobj = NULL; P_SpawnMapThing(mt); } @@ -1082,14 +1089,19 @@ static void P_LoadThings(void) for (i = 0; i < nummapthings; i++, mt++) { if (mt->type == 300 || mt->type == 308 || mt->type == 309 - || mt->type == 1706 || (mt->type >= 600 && mt->type <= 609) - || mt->type == 1705 || mt->type == 1713 || mt->type == 1800) + || mt->type == 1706 || (mt->type >= 600 && mt->type <= 609) + || mt->type == 1705 || mt->type == 1713 || mt->type == 1800) { + sector_t *mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector; + mt->mobj = NULL; - // Z for objects Tails 05-26-2002 - mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS) - ->sector->floorheight>>FRACBITS); + // Z for objects + mt->z = (INT16)( +#ifdef ESLOPE + mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) : +#endif + mtsector->floorheight)>>FRACBITS; P_SpawnHoopsAndRings (mt); } @@ -2297,15 +2309,13 @@ static void P_LevelInitStuff(void) memset(localaiming, 0, sizeof(localaiming)); - // map object scale - mapobjectscale = mapheaderinfo[gamemap-1]->mobj_scale; - // special stage tokens, emeralds, and ring total tokenbits = 0; runemeraldmanager = false; nummaprings = 0; - nummapboxes = 0; - numgotboxes = 0; + nummapboxes = numgotboxes = 0; + maptargets = numtargets = 0; + battlecapsules = false; // emerald hunt hunt1 = hunt2 = hunt3 = NULL; @@ -2570,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; } } } @@ -2634,15 +2644,18 @@ static void P_LoadRecordGhosts(void) } // Best Lap ghost - if (cv_ghost_bestlap.value) + if (modeattacking != ATTACKING_CAPSULES) { - for (i = 0; i < numskins; ++i) + if (cv_ghost_bestlap.value) { - if (cv_ghost_bestlap.value == 1 && players[consoleplayer].skin != i) - continue; + for (i = 0; i < numskins; ++i) + { + if (cv_ghost_bestlap.value == 1 && players[consoleplayer].skin != i) + continue; - if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, skins[i].name))) - G_AddGhost(va("%s-%s-lap-best.lmp", gpath, skins[i].name)); + if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, skins[i].name))) + G_AddGhost(va("%s-%s-lap-best.lmp", gpath, skins[i].name)); + } } } @@ -2827,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') @@ -3175,49 +3188,10 @@ boolean P_SetupLevel(boolean skipprecip) } } - if (modeattacking == ATTACKING_RECORD && !demo.playback) + if (modeattacking && !demo.playback) P_LoadRecordGhosts(); - /*else if (modeattacking == ATTACKING_NIGHTS && !demo.playback) - P_LoadNightsGhosts();*/ - if (G_TagGametype()) - { - INT32 realnumplayers = 0; - INT32 playersactive[MAXPLAYERS]; - - //I just realized how problematic this code can be. - //D_NumPlayers() will not always cover the scope of the netgame. - //What if one player is node 0 and the other node 31? - //The solution? Make a temp array of all players that are currently playing and pick from them. - //Future todo? When a player leaves, shift all nodes down so D_NumPlayers() can be used as intended? - //Also, you'd never have to loop through all 32 players slots to find anything ever again. - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].spectator) - { - playersactive[realnumplayers] = i; //stores the player's node in the array. - realnumplayers++; - } - } - - if (realnumplayers) //this should also fix the dedicated crash bug. You only pick a player if one exists to be picked. - { - i = P_RandomKey(realnumplayers); - players[playersactive[i]].pflags |= PF_TAGIT; //choose our initial tagger before map starts. - - // Taken and modified from G_DoReborn() - // Remove the player so he can respawn elsewhere. - // first dissasociate the corpse - if (players[playersactive[i]].mo) - P_RemoveMobj(players[playersactive[i]].mo); - - G_SpawnPlayer(playersactive[i], false); //respawn the lucky player in his dedicated spawn location. - } - else - CONS_Printf(M_GetText("No player currently available to become IT. Awaiting available players.\n")); - - } - else if (G_RaceGametype() && server) + if (G_RaceGametype() && server) CV_StealthSetValue(&cv_numlaps, ((netgame || multiplayer) && cv_basenumlaps.value && (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) @@ -3242,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 :( @@ -3284,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) @@ -3347,6 +3321,8 @@ boolean P_SetupLevel(boolean skipprecip) if (!(netgame || multiplayer) && !majormods) mapvisited[gamemap-1] |= MV_VISITED; + G_AddMapToBuffer(gamemap-1); + levelloading = false; P_RunCachedActions(); @@ -3384,7 +3360,8 @@ boolean P_SetupLevel(boolean skipprecip) #endif } - G_AddMapToBuffer(gamemap-1); + // NOW you can try to spawn in the Battle capsules, if there's not enough players for a match + K_SpawnBattleCapsules(); return true; } diff --git a/src/p_spec.c b/src/p_spec.c index c4070ef5c..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. @@ -1983,7 +1984,7 @@ void P_SwitchWeather(UINT8 newWeather) return; // Nothing to do. purge = true; } - else + else { if (precipprops[curWeather].type != MT_NULL) { @@ -2024,7 +2025,7 @@ void P_SwitchWeather(UINT8 newWeather) precipmobj->flags = mobjinfo[swap].flags; st = mobjinfo[swap].spawnstate; - + if (randomstates > 0) { UINT8 mrand = M_RandomByte(); @@ -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; @@ -5699,6 +5786,9 @@ static void P_RunLevelLoadExecutors(void) */ void P_InitSpecials(void) { + // Set the map object scale + mapobjectscale = mapheaderinfo[gamemap-1]->mobj_scale; + // Set the default gravity. Custom gravity overrides this setting. gravity = (FRACUNIT*8)/10; @@ -6034,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) @@ -6262,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 @@ -6317,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; @@ -6338,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 1c87218b9..d7359b307 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -23,6 +23,7 @@ #include "lua_script.h" #include "lua_hook.h" #include "k_kart.h" +#include "k_battle.h" #include "k_waypoint.h" // Object place @@ -593,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(); @@ -636,14 +637,15 @@ void P_Ticker(boolean run) if (run) { P_RunThinkers(); - if (G_BattleGametype() && battleovertime.enabled) - P_RunBattleOvertime(); // Run any "after all the other thinkers" stuff for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); + if (G_BattleGametype() && battleovertime.enabled) + K_RunBattleOvertime(); + #ifdef HAVE_BLUA LUAh_ThinkFrame(); #endif @@ -749,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); @@ -769,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) @@ -793,14 +795,15 @@ void P_PreTicker(INT32 frames) } P_RunThinkers(); - if (G_BattleGametype() && battleovertime.enabled) - P_RunBattleOvertime(); // Run any "after all the other thinkers" stuff for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); + if (G_BattleGametype() && battleovertime.enabled) + K_RunBattleOvertime(); + #ifdef HAVE_BLUA LUAh_ThinkFrame(); #endif diff --git a/src/p_user.c b/src/p_user.c index 666855f53..22149f408 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -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 } @@ -1158,10 +1158,10 @@ boolean P_EndingMusic(player_t *player) sprintf(buffer, "k*fail"); // F-Zero death results theme else { - if (bestlocalpos == 1) - sprintf(buffer, "k*win"); - else if (K_IsPlayerLosing(bestlocalplayer)) + if (K_IsPlayerLosing(bestlocalplayer)) sprintf(buffer, "k*lose"); + else if (bestlocalpos == 1) + sprintf(buffer, "k*win"); else sprintf(buffer, "k*ok"); } @@ -1211,7 +1211,7 @@ 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; @@ -1225,9 +1225,9 @@ void P_RestoreMusic(player_t *player) } 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 } @@ -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; @@ -6961,9 +6969,10 @@ static void P_DeathThink(player_t *player) if (player->bot) // don't allow bots to do any of the below, B_CheckRespawn does all they need for respawning already goto notrealplayer; - if (player->pflags & PF_TIMEOVER) + if ((player->pflags & PF_TIMEOVER) && G_RaceGametype()) { player->karthud[khud_timeovercam]++; + if (player->mo) { player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP); @@ -7178,7 +7187,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall || (leveltime < introtime)); // Kart intro cam #endif - if (player->pflags & PF_TIMEOVER) // 1 for momentum keep, 2 for turnaround + if ((player->pflags & PF_TIMEOVER) && G_RaceGametype()) // 1 for momentum keep, 2 for turnaround timeover = (player->karthud[khud_timeovercam] > 2*TICRATE ? 2 : 1); else timeover = 0; @@ -7254,17 +7263,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]; @@ -7278,6 +7287,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 { @@ -7287,7 +7297,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 { @@ -7297,7 +7306,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 { @@ -7307,7 +7315,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 { @@ -7317,7 +7324,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) @@ -7427,7 +7433,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); @@ -7844,8 +7850,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. @@ -7872,7 +7878,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]]) { @@ -8037,7 +8043,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; @@ -8368,7 +8374,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) { @@ -8598,7 +8604,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_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_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/sounds.h b/src/sounds.h index e3a8560ca..528e21a6b 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -14,6 +14,8 @@ #ifndef __SOUNDS__ #define __SOUNDS__ +#include "doomdef.h" + // Customisable sounds for Skins typedef enum { diff --git a/src/st_stuff.c b/src/st_stuff.c index b15bb568a..7e783c116 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; @@ -1272,7 +1272,7 @@ static void ST_drawNiGHTSHUD(void) // SRB2kart - unused. #endif ) { - if (modeattacking == ATTACKING_NIGHTS) + if (modeattacking == ATTACKING_CAPSULES) { INT32 maretime = max(stplyr->realtime - stplyr->marebegunat, 0); fixed_t cornerx = vid.width, cornery = vid.height-SCZ(20); @@ -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 297eae9c4..55e8e7b90 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -2503,15 +2503,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/y_inter.c b/src/y_inter.c index ff168070c..e9e243b04 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -39,6 +39,7 @@ #include "m_random.h" // M_RandomKey #include "g_input.h" // PLAYER1INPUTDOWN #include "k_kart.h" // colortranslations +#include "k_battle.h" #include "k_pwrlv.h" #include "console.h" // cons_menuhighlight #include "lua_hook.h" // IntermissionThinker hook @@ -168,7 +169,7 @@ static void Y_UnloadVoteData(void); // // SRB2Kart - Y_CalculateMatchData and ancillary functions // -static void Y_CompareRace(INT32 i) +static void Y_CompareTime(INT32 i) { UINT32 val = ((players[i].pflags & PF_TIMEOVER || players[i].realtime == UINT32_MAX) ? (UINT32_MAX-1) : players[i].realtime); @@ -180,7 +181,7 @@ static void Y_CompareRace(INT32 i) data.match.num[data.match.numplayers] = i; } -static void Y_CompareBattle(INT32 i) +static void Y_CompareScore(INT32 i) { UINT32 val = ((players[i].pflags & PF_TIMEOVER) ? (UINT32_MAX-1) : players[i].marescore); @@ -366,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) @@ -440,7 +441,7 @@ void Y_IntermissionDrawer(void) if (data.match.rankingsmode) timeheader = "PWR.LV"; else - timeheader = (intertype == int_race ? "TIME" : "SCORE"); + timeheader = ((intertype == int_race || (intertype == int_match && battlecapsules)) ? "TIME" : "SCORE"); // draw the level name V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 12, 0, data.match.levelstring); @@ -495,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; @@ -559,7 +560,7 @@ void Y_IntermissionDrawer(void) V_DrawRightAlignedThinString(x+152+gutter, y-1, (data.match.numplayers > NUMFORNEWCOLUMN ? V_6WIDTHSPACE : 0), "NO CONTEST."); else { - if (intertype == int_race) + if (intertype == int_race || (intertype == int_match && battlecapsules)) { snprintf(strtime, sizeof strtime, "%i'%02i\"%02i", G_TicsToMinutes(data.match.val[i], true), G_TicsToSeconds(data.match.val[i]), G_TicsToCentiseconds(data.match.val[i])); @@ -745,7 +746,7 @@ void Y_Ticker(void) remove = 10; // Remove 10 points at a time - data.match.increase[data.match.num[q]] -= remove; + data.match.increase[data.match.num[q]] -= remove; // Still not zero, no kaching yet if (data.match.increase[data.match.num[q]] != 0) @@ -795,11 +796,26 @@ static void Y_UpdateRecordReplays(void) if (!mainrecords[gamemap-1]) G_AllocMainRecordData(gamemap-1); - if ((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time)) - mainrecords[gamemap-1]->time = players[consoleplayer].realtime; + if (players[consoleplayer].pflags & PF_TIMEOVER) + { + players[consoleplayer].realtime = UINT32_MAX; + } - if ((mainrecords[gamemap-1]->lap == 0) || (bestlap < mainrecords[gamemap-1]->lap)) - mainrecords[gamemap-1]->lap = bestlap; + if (((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time)) + && (players[consoleplayer].realtime < UINT32_MAX)) // DNF + { + mainrecords[gamemap-1]->time = players[consoleplayer].realtime; + } + + if (modeattacking == ATTACKING_RECORD) + { + if ((mainrecords[gamemap-1]->lap == 0) || (bestlap < mainrecords[gamemap-1]->lap)) + mainrecords[gamemap-1]->lap = bestlap; + } + else + { + mainrecords[gamemap-1]->lap = 0; + } // Save demo! bestdemo[255] = '\0'; @@ -830,13 +846,16 @@ static void Y_UpdateRecordReplays(void) CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); } - snprintf(bestdemo, 255, "%s-%s-lap-best.lmp", gpath, cv_chooseskin.string); - if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)) - { // Better lap time, save this demo. - if (FIL_FileExists(bestdemo)) - remove(bestdemo); - FIL_WriteFile(bestdemo, buf, len); - CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD LAP!"), M_GetText("Saved replay as"), bestdemo); + if (modeattacking == ATTACKING_RECORD) + { + snprintf(bestdemo, 255, "%s-%s-lap-best.lmp", gpath, cv_chooseskin.string); + if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)) + { // Better lap time, save this demo. + if (FIL_FileExists(bestdemo)) + remove(bestdemo); + FIL_WriteFile(bestdemo, buf, len); + CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD LAP!"), M_GetText("Saved replay as"), bestdemo); + } } //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); @@ -1036,12 +1055,20 @@ void Y_StartIntermission(void) { timer = 0; - /* // srb2kart: time attack tally is UGLY rn - if (modeattacking) - intertype = int_timeattack; - else - */ - intertype = int_race; + if (!majormods && !multiplayer && !demo.playback) // move this once we have a proper time attack screen + { + // Update visitation flags + mapvisited[gamemap-1] |= MV_BEATEN; + if (ALL7EMERALDS(emeralds)) + mapvisited[gamemap-1] |= MV_ALLEMERALDS; + /*if (ultimatemode) + mapvisited[gamemap-1] |= MV_ULTIMATE; + if (data.coop.gotperfbonus) + mapvisited[gamemap-1] |= MV_PERFECT;*/ + + if (modeattacking) + Y_UpdateRecordReplays(); + } } else { @@ -1056,13 +1083,13 @@ void Y_StartIntermission(void) if (!timer) timer = 1; } - - if (gametype == GT_MATCH) - intertype = int_match; - else //if (gametype == GT_RACE) - intertype = int_race; } + if (gametype == GT_MATCH) + intertype = int_match; + else //if (gametype == GT_RACE) + intertype = int_race; + // We couldn't display the intermission even if we wanted to. // But we still need to give the players their score bonuses, dummy. //if (dedicated) return; @@ -1076,30 +1103,24 @@ void Y_StartIntermission(void) case int_match: { // Calculate who won - Y_CalculateMatchData(0, Y_CompareBattle); + if (battlecapsules) + { + Y_CalculateMatchData(0, Y_CompareTime); + } + else + { + Y_CalculateMatchData(0, Y_CompareScore); + } + if (cv_inttime.value > 0) S_ChangeMusicInternal("racent", true); // loop it + break; } case int_race: // (time-only race) { - if (!majormods && !multiplayer && !demo.playback) // remove this once we have a proper time attack screen - { - // Update visitation flags - mapvisited[gamemap-1] |= MV_BEATEN; - if (ALL7EMERALDS(emeralds)) - mapvisited[gamemap-1] |= MV_ALLEMERALDS; - /*if (ultimatemode) - mapvisited[gamemap-1] |= MV_ULTIMATE; - if (data.coop.gotperfbonus) - mapvisited[gamemap-1] |= MV_PERFECT;*/ - - if (modeattacking == ATTACKING_RECORD) - Y_UpdateRecordReplays(); - } - // Calculate who won - Y_CalculateMatchData(0, Y_CompareRace); + Y_CalculateMatchData(0, Y_CompareTime); break; } @@ -1295,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; } @@ -1595,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;