From 9b5b07b03cb0d684d8de8a118a3540a16db26097 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 25 Mar 2023 20:05:38 -0700 Subject: [PATCH] Completely rewrite party management code Replaces g_splitscreen.c with g_party.cpp. Simplifies party management functions. Moves externs out of already bloated doomstat.h and g_game.h into g_party.h. Cuts down on globals spam. --- src/CMakeLists.txt | 2 +- src/d_clisrv.c | 15 +-- src/d_netcmd.c | 52 +++----- src/doomstat.h | 12 -- src/g_game.h | 4 - src/g_party.cpp | 318 ++++++++++++++++++++++++++++++++++++++++++++ src/g_party.h | 77 +++++++++++ src/g_splitscreen.c | 210 ----------------------------- src/k_hud.c | 3 +- src/p_saveg.c | 74 ++++++++--- src/p_user.c | 23 +--- 11 files changed, 486 insertions(+), 304 deletions(-) create mode 100644 src/g_party.cpp create mode 100644 src/g_party.h delete mode 100644 src/g_splitscreen.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c9b12a921..eb0205a43 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,7 +19,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 g_demo.c g_game.c g_input.c - g_splitscreen.c + g_party.cpp am_map.c command.c console.c diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f8c419d85..7a03ea576 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -59,6 +59,7 @@ #include "doomstat.h" #include "s_sound.h" // sfx_syfail #include "m_cond.h" // netUnlocked +#include "g_party.h" // cl loading screen #include "v_video.h" @@ -2759,10 +2760,9 @@ void CL_ClearPlayer(INT32 playernum) splitscreen_invitations[i] = -1; } splitscreen_invitations[playernum] = -1; - splitscreen_party_size[playernum] = 0; - splitscreen_original_party_size[playernum] = 0; playerconsole[playernum] = playernum; + G_DestroyParty(playernum); // Wipe the struct. memset(&players[playernum], 0, sizeof (player_t)); @@ -2804,7 +2804,7 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) LUA_HookPlayerQuit(&players[playernum], reason); // Lua hook for player quitting - G_RemovePartyMember(playernum); + G_LeaveParty(playernum); // Reset player data CL_ClearPlayer(playernum); @@ -3657,9 +3657,9 @@ void SV_ResetServer(void) Schedule_Clear(); Automate_Clear(); K_ClearClientPowerLevels(); + G_ObliterateParties(); memset(splitscreen_invitations, -1, sizeof splitscreen_invitations); - memset(splitscreen_partied, 0, sizeof splitscreen_partied); memset(player_name_changes, 0, sizeof player_name_changes); mynode = 0; @@ -3753,6 +3753,7 @@ void D_QuitNetGame(void) Schedule_Clear(); Automate_Clear(); K_ClearClientPowerLevels(); + G_ObliterateParties(); DEBFILE("===========================================================================\n" " Log finish\n" @@ -3847,7 +3848,6 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) displayplayers[i] = newplayernum; g_localplayers[i] = newplayernum; } - splitscreen_partied[newplayernum] = true; DEBFILE("spawning me\n"); } @@ -3861,10 +3861,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) players[newplayernum].bot = false; playerconsole[newplayernum] = console; - splitscreen_original_party_size[console] = - ++splitscreen_party_size[console]; - splitscreen_original_party[console][splitscreenplayer] = - splitscreen_party[console][splitscreenplayer] = newplayernum; + G_BuildLocalSplitscreenParty(newplayernum); if (netgame) { diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b64a7fbd2..ae51b5e01 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -63,6 +63,7 @@ #include "m_perfstats.h" #include "k_specialstage.h" #include "k_race.h" +#include "g_party.h" #ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES #include "m_avrecorder.h" @@ -1405,14 +1406,12 @@ static void ForceAllSkins(INT32 forcedskin) } static const char * -VaguePartyDescription (int playernum, int *party_sizes, int default_color) +VaguePartyDescription (int playernum, int size, 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"!!! @@ -1855,7 +1854,7 @@ static void Got_PartyInvite(UINT8 **cp,INT32 playernum) HU_AddChatText(va( "\x82*You have been invited to join %s.", VaguePartyDescription( - playernum, splitscreen_party_size, '\x82') + playernum, G_PartySize(playernum), '\x82') ), true); } } @@ -1864,8 +1863,6 @@ static void Got_PartyInvite(UINT8 **cp,INT32 playernum) static void Got_AcceptPartyInvite(UINT8 **cp,INT32 playernum) { int invitation; - int old_party_size; - int views; (void)cp; @@ -1881,12 +1878,12 @@ static void Got_AcceptPartyInvite(UINT8 **cp,INT32 playernum) if (invitation >= 0) { - if (splitscreen_partied[invitation]) + if (G_IsPartyLocal(invitation)) { HU_AddChatText(va( "\x82*%s joined your party!", VaguePartyDescription( - playernum, splitscreen_original_party_size, '\x82') + playernum, G_LocalSplitscreenPartySize(playernum), '\x82') ), true); } else if (playernum == consoleplayer) @@ -1894,18 +1891,11 @@ static void Got_AcceptPartyInvite(UINT8 **cp,INT32 playernum) HU_AddChatText(va( "\x82*You joined %s's party!", VaguePartyDescription( - invitation, splitscreen_party_size, '\x82') + invitation, G_PartySize(invitation), '\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); - } + G_JoinParty(invitation, playernum); splitscreen_invitations[playernum] = -1; } @@ -1963,21 +1953,16 @@ static void Got_LeaveParty(UINT8 **cp,INT32 playernum) splitscreen_invitations[playernum] = -1; - if (splitscreen_party_size[playernum] > - splitscreen_original_party_size[playernum]) + if (G_IsPartyLocal(playernum) && playernum != consoleplayer) { - 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); + HU_AddChatText(va( + "\x85*%s left your party.", + VaguePartyDescription( + playernum, G_LocalSplitscreenPartySize(playernum), '\x85') + ), true); } + + G_LeaveParty(playernum); } void D_SendPlayerConfig(UINT8 n) @@ -2319,8 +2304,7 @@ Command_Invite_f (void) return; } - if (( splitscreen_party_size[consoleplayer] + - splitscreen_original_party_size[invitee] ) > MAXSPLITSCREENPLAYERS) + if ((G_PartySize(consoleplayer) + G_LocalSplitscreenPartySize(invitee)) > MAXSPLITSCREENPLAYERS) { CONS_Alert(CONS_WARNING, "That player joined with too many " @@ -2331,7 +2315,7 @@ Command_Invite_f (void) CONS_Printf( "Inviting %s...\n", VaguePartyDescription( - invitee, splitscreen_original_party_size, '\x80') + invitee, G_LocalSplitscreenPartySize(invitee), '\x80') ); buffer[0] = invitee; @@ -2375,7 +2359,7 @@ Command_CancelInvite_f (void) CONS_Printf( "Rescinding invite to %s...\n", VaguePartyDescription( - invitee, splitscreen_original_party_size, '\x80') + invitee, G_LocalSplitscreenPartySize(invitee), '\x80') ); buffer[0] = invitee; diff --git a/src/doomstat.h b/src/doomstat.h index a0f28098f..d72ef266b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -218,18 +218,6 @@ extern INT32 displayplayers[MAXSPLITSCREENPLAYERS]; /* g_localplayers[0] = consoleplayer */ extern INT32 g_localplayers[MAXSPLITSCREENPLAYERS]; -/* spitscreen players sync */ -extern INT32 splitscreen_original_party_size[MAXPLAYERS]; -extern INT32 splitscreen_original_party[MAXPLAYERS][MAXSPLITSCREENPLAYERS]; - -/* parties */ -extern INT32 splitscreen_invitations[MAXPLAYERS]; -extern INT32 splitscreen_party_size[MAXPLAYERS]; -extern INT32 splitscreen_party[MAXPLAYERS][MAXSPLITSCREENPLAYERS]; - -/* the only local one */ -extern boolean splitscreen_partied[MAXPLAYERS]; - extern char * titlemap; extern boolean hidetitlepics; extern char * bootmap; //bootmap for loading a map on startup diff --git a/src/g_game.h b/src/g_game.h index 3f122f6c4..2ef74e230 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -229,10 +229,6 @@ 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_party.cpp b/src/g_party.cpp new file mode 100644 index 000000000..2e56d97ec --- /dev/null +++ b/src/g_party.cpp @@ -0,0 +1,318 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by James Robert Roman +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#include +#include +#include +#include +#include + +#include "core/static_vec.hpp" +#include "cxxutil.hpp" + +#include "d_clisrv.h" // playerconsole +#include "doomdef.h" // MAXPLAYERS +#include "doomstat.h" // consoleplayer +#include "g_game.h" // localangle +#include "g_party.h" +#include "g_state.h" +#include "p_local.h" +#include "r_fps.h" +#include "r_main.h" // R_ExecuteSetViewSize + +namespace +{ + +using playernum_t = uint8_t; + +class Party +{ +public: + class Console + { + public: + // The Console class is basically analogous to + // a playernum except local splitscreen players only + // resolve to one playernum. + // + // Local splitscreen players are always joined with + // each other, so this lets just one party to refer to + // that group. + + Console(playernum_t player) + { + SRB2_ASSERT(player >= 0 && player < MAXPLAYERS); + + console_ = playerconsole[player]; + + SRB2_ASSERT(console_ >= 0 && console_ < MAXPLAYERS); + } + + operator playernum_t() const { return console_; } + + private: + playernum_t console_; + }; + + // + // Write Access Methods + // + + // Add a single player. + void add(playernum_t player) { vec_.push_back(player); } + + // Add every player from another party. + void add(const Party& party) { std::copy(party.vec_.begin(), party.vec_.end(), std::back_inserter(vec_)); } + + // Remove every player whose console is the same. + void remove(Console console) + { + auto it = std::remove_if(vec_.begin(), vec_.end(), [console](Console other) { return other == console; }); + + while (it < vec_.end()) + { + vec_.pop_back(); + } + } + + // + // Read Access Methods + // + + std::size_t size() const { return vec_.size(); } + + // The player at this position in the party. + playernum_t at(std::size_t i) const { return vec_[i]; } + playernum_t operator[](std::size_t i) const { return at(i); } + + // C array access to the raw player numbers. + const playernum_t* data() const { return &vec_[0]; } + + // True if the player is a member of this party. + bool contains(playernum_t player) const { return std::find(vec_.begin(), vec_.end(), player) != vec_.end(); } + + // True if the consoleplayer is a member of this party. + bool local() const + { + // consoleplayer is not valid yet. + if (!addedtogame) + { + return false; + } + + return contains(consoleplayer); + } + + // Returns a party composed of only the unique consoles + // from this party. + Party consoles() const + { + Party party; + + std::unique_copy(vec_.begin(), vec_.end(), std::back_inserter(party.vec_), std::equal_to()); + + return party; + } + + // If the party is local, set the correct viewports. + void rebuild_displayplayers() const + { + if (!local()) + { + return; + } + + // Rendering stuff is not valid outside of levels. + if (!G_GamestateUsesLevel()) + { + return; + } + + for (std::size_t i = 0; i < size(); ++i) + { + const playernum_t player = at(i); + + displayplayers[i] = player; + + // The order of displayplayers can change, which + // would make localangle invalid now. + localangle[i] = players[player].angleturn; + + P_ResetCamera(&players[player], &camera[i]); + + // Make sure the viewport doesn't interpolate at + // all into its new position -- just snap + // instantly into place. + R_ResetViewInterpolation(1 + i); + R_ResetViewInterpolation(1 + i); // (Why does it need to be called twice?) + } + + r_splitscreen = size() - 1; + + R_ExecuteSetViewSize(); // present viewport + } + + // + // Iterators + // + + // Returns an iterator to the player within this party if + // they are a member. Else returns the end() iterator. + auto find(playernum_t player) const + { + return std::find(vec_.begin(), vec_.end(), player); + } + + // Iterator to the beginning of the party. + auto begin() const { return vec_.begin(); } + + // Iterator to the end of the party. + auto end() const { return vec_.end(); } + +private: + srb2::StaticVec vec_; +}; + +class PartyManager +{ +public: + // To avoid copying the same party to each local + // splitscreen player, all lookups will use the + // consoleplayer. + Party& operator [](Party::Console console) { return pool_[console]; } + +protected: + std::array pool_; +} +local_party; + +class FinalPartyManager : public PartyManager +{ +public: + // Adds guest's entire local splitscreen party to the + // host's party. If the operation succeeds, host and guest + // parties are guaranteed to be identical and the + // viewports are updated for every player involved. + bool join(Party::Console host, Party::Console guest) + { + Party &party = pool_[host]; + + // Already in the same party. + if (party.contains(guest)) + { + return false; + } + + // Parties do not fit when merged. + if (party.size() + local_party[guest].size() > MAXSPLITSCREENPLAYERS) + { + return false; + } + + // If the host party includes players from a local + // party, iterating the unique consoles avoids + // duplicate insertions of the guest. + for (Party::Console other : party.consoles()) + { + pool_[other].add(local_party[guest]); + } + + pool_[guest] = party; + + party.rebuild_displayplayers(); + + return true; + } + + // Removes player from another party and restores their + // local splitscreen party. Viewports are updated for + // every player involved. + void leave(Party::Console player) + { + Party &party = pool_[player]; + + // Iterate a COPY of party because this very party + // could be modified. + for (Party::Console member : Party(party)) + { + pool_[member].remove(player); + } + + party.rebuild_displayplayers(); // restore viewports for left behind party + party = local_party[player]; + party.rebuild_displayplayers(); // restore local viewports + } +} +final_party; + +}; // namespace + +INT32 splitscreen_invitations[MAXPLAYERS]; + +void G_ObliterateParties(void) +{ + final_party = {}; + local_party = {}; +} + +void G_DestroyParty(UINT8 player) +{ + local_party[player] = {}; + final_party[player] = {}; +} + +void G_BuildLocalSplitscreenParty(UINT8 player) +{ + local_party[player].add(player); + final_party[player] = local_party[player]; +} + +void G_JoinParty(UINT8 host, UINT8 guest) +{ + final_party.join(host, guest); +} + +void G_LeaveParty(UINT8 player) +{ + final_party.leave(player); +} + +UINT8 G_LocalSplitscreenPartySize(UINT8 player) +{ + return local_party[player].size(); +} + +UINT8 G_PartySize(UINT8 player) +{ + return final_party[player].size(); +} + +boolean G_IsPartyLocal(UINT8 player) +{ + return final_party[player].local(); +} + +UINT8 G_PartyMember(UINT8 player, UINT8 index) +{ + SRB2_ASSERT(index < final_party[player].size()); + + return final_party[player][index]; +} + +const UINT8* G_PartyArray(UINT8 player) +{ + return final_party[player].data(); +} + +UINT8 G_PartyPosition(UINT8 player) +{ + const Party& party = final_party[player]; + + return party.find(player) - party.begin(); +} diff --git a/src/g_party.h b/src/g_party.h new file mode 100644 index 000000000..8937545e8 --- /dev/null +++ b/src/g_party.h @@ -0,0 +1,77 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by James Robert Roman +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#ifndef __G_PARTY_H__ +#define __G_PARTY_H__ + +#include "doomdef.h" // MAXPLAYERS + +#ifdef __cplusplus +extern "C" { +#endif + +// +// Functions +// + +// Frees all party resources. +void G_ObliterateParties(void); + +// Wipes all party data for this player slot. +void G_DestroyParty(UINT8 player); + +// Adds player to their local party. +void G_BuildLocalSplitscreenParty(UINT8 player); + +// Join guest's entire local party to the host. All checks are +// performed, so this is a no-op if the parties are already +// joined, or if either party is too big for the other, etc. +// +// Resets viewports for all players involved. +void G_JoinParty(UINT8 host, UINT8 guest); + +// Removes guest from an online party and restores their +// initial local party. +void G_LeaveParty(UINT8 guest); + +// Size of the player's initial local party. +UINT8 G_LocalSplitscreenPartySize(UINT8 player); + +// Ultimate size of this player's party. Includes any joined +// parties, else the same as G_LocalSplitscreenPartySize. +UINT8 G_PartySize(UINT8 player); + +// True if this player is a member of the consoleplayer's +// party. +boolean G_IsPartyLocal(UINT8 player); + +// Returns the player slot present at a certain position +// within this player's party. Do not call this function with +// an index beyond G_PartySize() - 1. +UINT8 G_PartyMember(UINT8 player, UINT8 index); + +// C array access to the same data as G_PartyMember. +const UINT8 *G_PartyArray(UINT8 player); + +// Suitable index to G_PartyMember and G_PartyArray. +UINT8 G_PartyPosition(UINT8 player); + +// +// Globals +// + +// Whether this player has been invited to join anyone's party +// and who invited them. -1 if no invitation. +extern INT32 splitscreen_invitations[MAXPLAYERS]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __G_PARTY_H__ diff --git a/src/g_splitscreen.c b/src/g_splitscreen.c deleted file mode 100644 index e510a474c..000000000 --- a/src/g_splitscreen.c +++ /dev/null @@ -1,210 +0,0 @@ -// 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" -#include "doomstat.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/k_hud.c b/src/k_hud.c index 710c28058..64c504745 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -39,6 +39,7 @@ #include "k_roulette.h" #include "k_bot.h" #include "k_rank.h" +#include "g_party.h" //{ Patch Definitions static patch_t *kp_nodraw; @@ -4779,7 +4780,7 @@ static void K_DrawDirectorButton(INT32 idx, const char *label, patch_t *kp[2], I static void K_drawDirectorHUD(void) { - const INT32 p = (splitscreen_partied[consoleplayer] ? splitscreen_party[consoleplayer] : g_localplayers)[R_GetViewNumber()]; + const INT32 p = G_PartyMember(consoleplayer, R_GetViewNumber()); const char *itemtxt = "Join"; UINT8 offs = 0; diff --git a/src/p_saveg.c b/src/p_saveg.c index 4770f0602..17ac43a4f 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -42,6 +42,7 @@ #include "k_pwrlv.h" #include "k_terrain.h" #include "acs/interface.h" +#include "g_party.h" savedata_t savedata; @@ -49,6 +50,7 @@ savedata_t savedata; // being sent and received #define ARCHIVEBLOCK_MISC 0x7FEEDEED #define ARCHIVEBLOCK_PLAYERS 0x7F448008 +#define ARCHIVEBLOCK_PARTIES 0x7F87AF0C #define ARCHIVEBLOCK_WORLD 0x7F8C08C0 #define ARCHIVEBLOCK_POBJS 0x7F928546 #define ARCHIVEBLOCK_THINKERS 0x7F37037C @@ -123,14 +125,6 @@ static void P_NetArchivePlayers(savebuffer_t *save) WRITEUINT8(save->p, playerconsole[i]); WRITEINT32(save->p, splitscreen_invitations[i]); - WRITEINT32(save->p, splitscreen_party_size[i]); - WRITEINT32(save->p, splitscreen_original_party_size[i]); - - for (j = 0; j < MAXSPLITSCREENPLAYERS; ++j) - { - WRITEINT32(save->p, splitscreen_party[i][j]); - WRITEINT32(save->p, splitscreen_original_party[i][j]); - } WRITEINT16(save->p, players[i].steering); WRITEANGLE(save->p, players[i].angleturn); @@ -528,14 +522,6 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) playerconsole[i] = READUINT8(save->p); splitscreen_invitations[i] = READINT32(save->p); - splitscreen_party_size[i] = READINT32(save->p); - splitscreen_original_party_size[i] = READINT32(save->p); - - for (j = 0; j < MAXSPLITSCREENPLAYERS; ++j) - { - splitscreen_party[i][j] = READINT32(save->p); - splitscreen_original_party[i][j] = READINT32(save->p); - } players[i].steering = READINT16(save->p); players[i].angleturn = READANGLE(save->p); @@ -892,6 +878,59 @@ static void P_NetUnArchivePlayers(savebuffer_t *save) } } +static void P_NetArchiveParties(savebuffer_t *save) +{ + INT32 i, k; + UINT8 partySize; + + WRITEUINT32(save->p, ARCHIVEBLOCK_PARTIES); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + partySize = G_PartySize(i); + + WRITEUINT8(save->p, partySize); + + for (k = 0; k < partySize; ++k) + { + WRITEUINT8(save->p, G_PartyMember(i, k)); + } + } +} + +static void P_NetUnArchiveParties(savebuffer_t *save) +{ + INT32 i, k; + UINT8 partySize; + + if (READUINT32(save->p) != ARCHIVEBLOCK_PARTIES) + I_Error("Bad $$$.sav at archive block Parties"); + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + G_BuildLocalSplitscreenParty(i); + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + partySize = READUINT8(save->p); + + for (k = 0; k < partySize; ++k) + { + G_JoinParty(i, READUINT8(save->p)); + } + } +} + /// /// Colormaps /// @@ -5355,6 +5394,8 @@ void P_SaveNetGame(savebuffer_t *save, boolean resending) } P_NetArchivePlayers(save); + P_NetArchiveParties(save); + if (gamestate == GS_LEVEL) { P_NetArchiveWorld(save); @@ -5403,6 +5444,7 @@ boolean P_LoadNetGame(savebuffer_t *save, boolean reloading) return false; P_NetUnArchivePlayers(save); + P_NetUnArchiveParties(save); if (gamestate == GS_LEVEL) { diff --git a/src/p_user.c b/src/p_user.c index 7529c12ad..442fa0767 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -61,6 +61,7 @@ #include "k_battle.h" #include "k_rank.h" #include "k_director.h" +#include "g_party.h" #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -754,7 +755,7 @@ boolean P_EndingMusic(player_t *player) if (r_splitscreen) { - INT32 *localplayertable = (splitscreen_partied[consoleplayer] ? splitscreen_party[consoleplayer] : g_localplayers); + const UINT8 *localplayertable = G_PartyArray(consoleplayer); if (!((players[localplayertable[0]].exiting || (players[localplayertable[0]].pflags & PF_NOCONTEST)) || (players[localplayertable[1]].exiting || (players[localplayertable[1]].pflags & PF_NOCONTEST)) @@ -856,7 +857,7 @@ void P_RestoreMusic(player_t *player) if (r_splitscreen) { INT32 bestlocaltimer = 1; - INT32 *localplayertable = (splitscreen_partied[consoleplayer] ? splitscreen_party[consoleplayer] : g_localplayers); + const UINT8 *localplayertable = G_PartyArray(consoleplayer); #define setbests(p) \ if (players[p].playerstate == PST_LIVE) \ @@ -1146,8 +1147,6 @@ boolean P_IsMachineLocalPlayer(player_t *player) // boolean P_IsLocalPlayer(player_t *player) { - UINT8 i; - if (player == NULL) { return false; @@ -1157,18 +1156,8 @@ boolean P_IsLocalPlayer(player_t *player) if (demo.playback) return false; - // parties - treat everyone as if it's couch co-op - if (splitscreen_partied[consoleplayer]) - { - for (i = 0; i < splitscreen_party_size[consoleplayer]; i++) - { - if (splitscreen_party[consoleplayer][i] == (player-players)) - return true; - } - return false; - } - - return P_IsMachineLocalPlayer(player); + // handles both online parties and local players (no need to call P_IsMachineLocalPlayer here) + return G_IsPartyLocal(consoleplayer); } // @@ -3640,7 +3629,7 @@ boolean P_SpectatorJoinGame(player_t *player) // Reset away view (some code referenced from Got_Teamchange) { UINT8 i = 0; - INT32 *localplayertable = (splitscreen_partied[consoleplayer] ? splitscreen_party[consoleplayer] : g_localplayers); + const UINT8 *localplayertable = G_PartyArray(consoleplayer); for (i = 0; i <= r_splitscreen; i++) {