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.
This commit is contained in:
James R 2023-03-25 20:05:38 -07:00 committed by toaster
parent a3a3f4cd18
commit 9b5b07b03c
11 changed files with 486 additions and 304 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

318
src/g_party.cpp Normal file
View file

@ -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 <algorithm>
#include <array>
#include <cstddef>
#include <functional>
#include <iterator>
#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<Console>());
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<playernum_t, MAXSPLITSCREENPLAYERS> 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<Party, MAXPLAYERS> 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();
}

77
src/g_party.h Normal file
View file

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

View file

@ -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();
}
}

View file

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

View file

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

View file

@ -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++)
{