More finished power level

broken, can't finish
This commit is contained in:
TehRealSalt 2019-01-16 14:49:42 -05:00
parent a14c5c3381
commit 3246ca6b33
14 changed files with 428 additions and 131 deletions

View file

@ -1461,7 +1461,7 @@ static void SV_SendPlayerInfo(INT32 node)
*/
static boolean SV_SendServerConfig(INT32 node)
{
INT32 i;
INT32 i, j;
UINT8 *p, *op;
boolean waspacketsent;
@ -1485,9 +1485,15 @@ static boolean SV_SendServerConfig(INT32 node)
memset(netbuffer->u.servercfg.adminplayers, -1, sizeof(netbuffer->u.servercfg.adminplayers));
for (i = 0; i < MAXPLAYERS; i++)
for (j = 0; j < 2; j++)
netbuffer->u.servercfg.powerlevels[i][j] = 0; // Not sure if memset works on something like this
for (i = 0; i < MAXPLAYERS; i++)
{
netbuffer->u.servercfg.adminplayers[i] = (SINT8)adminplayers[i];
for (j = 0; j < 2; j++)
netbuffer->u.servercfg.powerlevels[i][j] = clientpowerlevels[i][j];
if (!playeringame[i])
continue;
@ -2163,6 +2169,7 @@ static void CL_ConnectToServer(boolean viams)
wipegamestate = GS_WAITINGPLAYERS;
ClearAdminPlayers();
ClearClientPowerLevels();
pnumnodes = 1;
oldtic = I_GetTime() - 1;
#ifndef NONET
@ -2971,6 +2978,21 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
break;
}
// SRB2Kart: kicks count as forfeit
switch (kickreason)
{
case KR_KICK:
case KR_BAN:
case KR_LEAVE:
// Intentional removals should be hit with a true forfeit.
K_PlayerForfeit(pnum, true);
break;
default:
// Otherwise, give remaining players the point compensation, but doesn't penalize who left.
K_PlayerForfeit(pnum, false);
break;
}
if (playernode[pnum] == playernode[consoleplayer])
{
#ifdef DUMPCONSISTENCY
@ -3145,6 +3167,7 @@ void SV_ResetServer(void)
playernode[i] = UINT8_MAX;
sprintf(player_names[i], "Player %d", i + 1);
adminplayers[i] = -1; // Populate the entire adminplayers array with -1.
ClearClientPowerLevels();
}
mynode = 0;
@ -3220,6 +3243,7 @@ void D_QuitNetGame(void)
D_CloseConnection();
ClearAdminPlayers();
ClearClientPowerLevels();
DEBFILE("===========================================================================\n"
" Log finish\n"
@ -3247,8 +3271,7 @@ static inline void SV_AddNode(INT32 node)
// Xcmd XD_ADDPLAYER
static void Got_AddPlayer(UINT8 **p, INT32 playernum)
{
INT16 node, newplayernum;
UINT8 splitscreenplayer = 0;
UINT8 node, newplayernum, splitscreenplayer;
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{
@ -3265,11 +3288,12 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
return;
}
node = READUINT8(*p);
newplayernum = READUINT8(*p);
splitscreenplayer = newplayernum/MAXPLAYERS;
newplayernum %= MAXPLAYERS;
node = (UINT8)READUINT8(*p);
newplayernum = (UINT8)READUINT8(*p);
splitscreenplayer = (UINT8)READUINT8(*p);
CONS_Printf("addplayer: %d %d %d\n", node, newplayernum, splitscreenplayer);
// Clear player before joining, lest some things get set incorrectly
CL_ClearPlayer(newplayernum);
@ -3282,28 +3306,8 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
if (node == mynode)
{
playernode[newplayernum] = 0; // for information only
if (splitscreenplayer)
{
if (splitscreenplayer == 1)
{
secondarydisplayplayer = newplayernum;
DEBFILE("spawning my brother\n");
if (botingame)
players[newplayernum].bot = 1;
// Same goes for player 2 when relevant
}
else if (splitscreenplayer == 2)
{
thirddisplayplayer = newplayernum;
DEBFILE("spawning my sister\n");
}
else if (splitscreenplayer == 3)
{
fourthdisplayplayer = newplayernum;
DEBFILE("spawning my trusty pet dog\n");
}
}
else
if (splitscreenplayer == 0)
{
consoleplayer = newplayernum;
displayplayer = newplayernum;
@ -3312,6 +3316,25 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
fourthdisplayplayer = newplayernum;
DEBFILE("spawning me\n");
}
else if (splitscreenplayer == 1)
{
secondarydisplayplayer = newplayernum;
DEBFILE("spawning my brother\n");
if (botingame)
players[newplayernum].bot = 1;
// Same goes for player 2 when relevant
}
else if (splitscreenplayer == 2)
{
thirddisplayplayer = newplayernum;
DEBFILE("spawning my sister\n");
}
else if (splitscreenplayer == 3)
{
fourthdisplayplayer = newplayernum;
DEBFILE("spawning my trusty pet dog\n");
}
D_SendPlayerConfig();
addedtogame = true;
}
@ -3365,8 +3388,9 @@ static void Got_RemovePlayer(UINT8 **p, INT32 playernum)
static boolean SV_AddWaitingPlayers(void)
{
INT32 node, n, newplayer = false;
XBOXSTATIC UINT8 buf[2];
UINT8 newplayernum = 0;
static UINT8 buf[3];
static UINT8 *buf_p = buf;
// What is the reason for this? Why can't newplayernum always be 0?
// Sal: Because the dedicated player is stupidly forced into players[0].....
@ -3385,8 +3409,10 @@ static boolean SV_AddWaitingPlayers(void)
for (; newplayernum < MAXPLAYERS; newplayernum++)
{
for (n = 0; n < MAXNETNODES; n++)
if (nodetoplayer[n] == newplayernum || nodetoplayer2[n] == newplayernum
|| nodetoplayer3[n] == newplayernum || nodetoplayer4[n] == newplayernum)
if (nodetoplayer[n] == newplayernum
|| nodetoplayer2[n] == newplayernum
|| nodetoplayer3[n] == newplayernum
|| nodetoplayer4[n] == newplayernum)
break;
if (n == MAXNETNODES)
break;
@ -3398,28 +3424,23 @@ static boolean SV_AddWaitingPlayers(void)
playernode[newplayernum] = (UINT8)node;
buf[0] = (UINT8)node;
buf[1] = newplayernum;
WRITEUINT8(buf_p, (UINT8)node);
WRITEUINT8(buf_p, newplayernum);
if (playerpernode[node] < 1)
nodetoplayer[node] = newplayernum;
else if (playerpernode[node] < 2)
{
nodetoplayer2[node] = newplayernum;
buf[1] += MAXPLAYERS;
}
else if (playerpernode[node] < 3)
{
nodetoplayer3[node] = newplayernum;
buf[1] += MAXPLAYERS*2;
}
else
{
else if (playerpernode[node] < 4)
nodetoplayer4[node] = newplayernum;
buf[1] += MAXPLAYERS*3;
}
WRITEUINT8(buf_p, playerpernode[node]); // splitscreen num
playerpernode[node]++;
SendNetXCmd(XD_ADDPLAYER, &buf, 2);
SendNetXCmd(XD_ADDPLAYER, buf, buf_p - buf);
DEBFILE(va("Server added player %d node %d\n", newplayernum, node));
// use the next free slot (we can't put playeringame[newplayernum] = true here)
@ -3775,7 +3796,7 @@ static void HandlePacketFromAwayNode(SINT8 node)
case PT_SERVERCFG: // Positive response of client join request
{
INT32 j;
INT32 j, k;
UINT8 *scp;
if (server && serverrunning && node != servernode)
@ -3795,7 +3816,11 @@ static void HandlePacketFromAwayNode(SINT8 node)
I_Error("Bad gametype in cliserv!");
modifiedgame = netbuffer->u.servercfg.modifiedgame;
for (j = 0; j < MAXPLAYERS; j++)
{
adminplayers[j] = netbuffer->u.servercfg.adminplayers[j];
for (k = 0; k < 2; k++)
clientpowerlevels[j][k] = netbuffer->u.servercfg.powerlevels[j][k];
}
memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
}

View file

@ -328,6 +328,7 @@ typedef struct
UINT8 gametype;
UINT8 modifiedgame;
SINT8 adminplayers[MAXPLAYERS]; // Needs to be signed
UINT16 powerlevels[MAXPLAYERS][2]; // SRB2kart: player power levels
char server_context[8]; // Unique context id, generated at server startup.

View file

@ -61,6 +61,7 @@
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_Mapcmd(UINT8 **cp, INT32 playernum);
static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum);
static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum);
@ -455,6 +456,7 @@ boolean deferencoremode = false;
UINT8 splitscreen = 0;
boolean circuitmap = true; // SRB2kart
INT32 adminplayers[MAXPLAYERS];
UINT16 clientpowerlevels[MAXPLAYERS][2];
/// \warning Keep this up-to-date if you add/remove/rename net text commands
const char *netxcmdnames[MAXNETXCMD - 1] =
@ -483,6 +485,8 @@ const char *netxcmdnames[MAXNETXCMD - 1] =
"SETUPVOTE",
"MODIFYVOTE",
"PICKVOTE",
"REMOVEPLAYER",
"POWERLEVEL",
#ifdef HAVE_BLUA
"LUACMD",
"LUAVAR"
@ -502,6 +506,7 @@ void D_RegisterServerCommands(void)
{
RegisterNetXCmd(XD_NAMEANDCOLOR, Got_NameAndColor);
RegisterNetXCmd(XD_WEAPONPREF, Got_WeaponPref);
RegisterNetXCmd(XD_POWERLEVEL, Got_PowerLevel);
RegisterNetXCmd(XD_MAP, Got_Mapcmd);
RegisterNetXCmd(XD_EXITLEVEL, Got_ExitLevelcmd);
RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd);
@ -1864,6 +1869,16 @@ static void Got_WeaponPref(UINT8 **cp,INT32 playernum)
players[playernum].pflags |= PF_ANALOGMODE;
}
static void Got_PowerLevel(UINT8 **cp,INT32 playernum)
{
UINT16 race = (UINT16)READUINT16(*cp);
UINT16 battle = (UINT16)READUINT16(*cp);
clientpowerlevels[playernum][0] = min(9999, race);
clientpowerlevels[playernum][1] = min(9999, battle);
CONS_Printf("set player %d to power %d\n", playernum, race);
}
void D_SendPlayerConfig(void)
{
SendNameAndColor();
@ -1880,6 +1895,31 @@ void D_SendPlayerConfig(void)
SendWeaponPref3();
if (splitscreen > 2)
SendWeaponPref4();
{
UINT8 buf[4];
UINT8 *buf_p = buf;
WRITEUINT16(buf_p, vspowerlevel[0]);
WRITEUINT16(buf_p, vspowerlevel[1]);
SendNetXCmd(XD_POWERLEVEL, buf, 4);
}
if (splitscreen)
{
UINT8 buf[4];
UINT8 *buf_p = buf;
WRITEUINT16(buf_p, 0);
WRITEUINT16(buf_p, 0);
SendNetXCmd2(XD_POWERLEVEL, buf, 4);
if (splitscreen > 1)
SendNetXCmd3(XD_POWERLEVEL, buf, 4);
if (splitscreen > 2)
SendNetXCmd4(XD_POWERLEVEL, buf, 4);
}
}
// Only works for displayplayer, sorry!
@ -3373,6 +3413,8 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
if (K_IsPlayerWanted(&players[playernum]))
K_CalculateBattleWanted();
}
K_PlayerForfeit(playernum, true);
players[playernum].health = 1;
if (players[playernum].mo)
players[playernum].mo->health = 1;
@ -3521,6 +3563,14 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
#endif
}
void ClearClientPowerLevels(void)
{
INT32 i, j;
for (i = 0; i < MAXPLAYERS; i++)
for (j = 0; j < 2; j++)
clientpowerlevels[i][j] = 0;
}
boolean IsPlayerAdmin(INT32 playernum)
{
INT32 i;

View file

@ -176,9 +176,10 @@ typedef enum
XD_MODIFYVOTE, // 23
XD_PICKVOTE, // 24
XD_REMOVEPLAYER,// 25
XD_POWERLEVEL, // 26
#ifdef HAVE_BLUA
XD_LUACMD, // 26
XD_LUAVAR, // 27
XD_LUACMD, // 27
XD_LUAVAR, // 28
#endif
MAXNETXCMD
} netxcmd_t;
@ -237,6 +238,7 @@ void D_SetupVote(void);
void D_ModifyClientVote(SINT8 voted, UINT8 splitplayer);
void D_PickVote(void);
void ObjectPlace_OnChange(void);
void ClearClientPowerLevels(void);
boolean IsPlayerAdmin(INT32 playernum);
void SetAdminPlayer(INT32 playernum);
void ClearAdminPlayers(void);

View file

@ -332,7 +332,7 @@ enum GameType // SRB2Kart
extern tic_t totalplaytime;
extern UINT32 matchesplayed;
extern UINT16 versusrecord[2];
extern UINT16 vspowerlevel[2];
extern UINT8 stagefailed;
@ -467,7 +467,7 @@ extern SINT8 battlewanted[4];
extern tic_t wantedcalcdelay;
extern tic_t indirectitemcooldown;
extern tic_t mapreset;
extern UINT8 nospectategrief;
extern INT16 nospectategrief[MAXPLAYERS];
extern boolean thwompsactive;
extern SINT8 spbplace;
@ -547,6 +547,7 @@ extern consvar_t cv_maxping;
extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
extern INT32 serverplayer;
extern INT32 adminplayers[MAXPLAYERS];
extern UINT16 clientpowerlevels[MAXPLAYERS][2];
/// \note put these in d_clisrv outright?

View file

@ -169,7 +169,7 @@ INT32 sstimer; // Time allotted in the special stage
tic_t totalplaytime;
UINT32 matchesplayed; // SRB2Kart
UINT16 versusrecord[2]; // SRB2Kart: Online rankings
UINT16 vspowerlevel[2]; // SRB2Kart: Online rankings for each gametype
boolean gamedataloaded = false;
// Time attack data for levels
@ -267,7 +267,7 @@ SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points
tic_t wantedcalcdelay; // Time before it recalculates WANTED
tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded
tic_t mapreset; // Map reset delay when enough players have joined an empty game
UINT8 nospectategrief; // How many players need to be in-game to eliminate last; for preventing spectate griefing
INT16 nospectategrief[MAXPLAYERS]; // Which players spec-scummed, and their power level before scumming.
boolean thwompsactive; // Thwomps activate on lap 2
SINT8 spbplace; // SPB exists, give the person behind better items
@ -3782,8 +3782,8 @@ void G_LoadGameData(void)
totalplaytime = 0; // total play time (separate from all)
matchesplayed = 0; // SRB2Kart: matches played & finished
for (i = 0; i < 2; i++) // SRB2Kart: online VR system
versusrecord[i] = 5000;
for (i = 0; i < 2; i++) // SRB2Kart: online rank system
vspowerlevel[i] = 5000;
if (M_CheckParm("-nodata"))
return; // Don't load.
@ -3816,7 +3816,7 @@ void G_LoadGameData(void)
matchesplayed = READUINT32(save_p);
for (i = 0; i < 2; i++)
versusrecord[i] = READUINT16(save_p);
vspowerlevel[i] = READUINT16(save_p);
modded = READUINT8(save_p);
@ -3967,7 +3967,7 @@ void G_SaveGameData(boolean force)
WRITEUINT32(save_p, matchesplayed);
for (i = 0; i < 2; i++)
WRITEUINT16(save_p, versusrecord[i]);
WRITEUINT16(save_p, vspowerlevel[i]);
btemp = (UINT8)(savemoddata || modifiedgame);
WRITEUINT8(save_p, btemp);

View file

@ -31,7 +31,7 @@
// battlewanted is an array of the WANTED player nums, -1 for no player in that slot
// indirectitemcooldown is timer before anyone's allowed another Shrink/SPB
// mapreset is set when enough players fill an empty server
// nospectategrief is the players in-game needed to eliminate the person in last
// nospectategrief is a list of griefers' power levels
//{ SRB2kart Color Code
@ -5741,6 +5741,115 @@ void K_CheckBumpers(void)
P_DoPlayerExit(&players[i]);
}
// Adapted from this: http://wiki.tockdom.com/wiki/Player_Rating
INT16 K_CalculatePowerLevelInc(INT16 diff)
{
INT16 control[10] = {0,0,0,1,8,50,125,125,125,125};
fixed_t increment = 0;
fixed_t x;
UINT8 j;
#define MAXDIFF 9998
if (diff > MAXDIFF)
diff = MAXDIFF;
if (diff < -MAXDIFF)
diff = -MAXDIFF;
#undef MAXDIFF
x = ((diff-2)<<FRACBITS) / 5000;
for (j = 3; j < 10; j++) // Just skipping to 3 since 0 thru 2 will always just add 0...
{
fixed_t f = abs(x - ((j-4)<<FRACBITS));
fixed_t add;
if (f >= (2<<FRACBITS))
{
continue; //add = 0;
}
else if (f >= (1<<FRACBITS))
{
fixed_t f2 = (2<<FRACBITS) - f;
add = FixedMul(FixedMul(f2, f2), f2) / 6;
}
else
{
add = ((3*FixedMul(FixedMul(f, f), f)) - (6*FixedMul(f, f)) + (4<<FRACBITS)) / 6;
}
increment += (add * control[j]);
}
return (INT16)(increment >> FRACBITS);
}
void K_PlayerForfeit(UINT8 playernum, boolean nopointloss)
{
INT32 powertype = -1;
UINT16 yourpower = 5000;
UINT16 theirpower = 5000;
INT16 diff = 0; // Loser PWR.LV - Winner PWR.LV
INT16 inc = 0;
UINT8 i;
// power level is netgames only
if (!netgame)
return;
// 20 sec into the match counts as a forfeit -- automatic loss against every other player in the match.
if (gamestate != GS_LEVEL || leveltime <= starttime+(20*TICRATE))
return;
if (G_RaceGametype())
powertype = 0;
else if (G_BattleGametype())
powertype = 1;
if (powertype == -1) // Not using power levels
return;
if (clientpowerlevels[playernum][powertype] == 0) // splitscreen guests don't record power level changes
return;
yourpower = clientpowerlevels[playernum][powertype];
// Set up the point compensation.
nospectategrief[playernum] = yourpower;
if (nopointloss) // This is set for stuff like sync-outs, which shouldn't be so harsh on the victim!
return;
for (i = 0; i < MAXPLAYERS; i++)
{
if (i == playernum)
continue;
theirpower = 5000;
if (clientpowerlevels[i][powertype] != 0) // No power level acts as 5000 (used for splitscreen guests)
theirpower = clientpowerlevels[i][powertype];
diff = yourpower - theirpower;
inc -= K_CalculatePowerLevelInc(diff);
}
if (inc == 0) // No change.
return;
if (yourpower + inc > 9999) // I mean... we're subtracting... but y'know how it is :V
inc -= ((yourpower + inc) - 9999);
if (yourpower + inc < 1)
inc -= ((yourpower + inc) - 1);
clientpowerlevels[playernum][powertype] += inc;
if (playernum == consoleplayer)
{
vspowerlevel[powertype] = clientpowerlevels[playernum][powertype];
if (M_UpdateUnlockablesAndExtraEmblems(true))
S_StartSound(NULL, sfx_ncitem);
G_SaveGameData(true); // save your punishment!
}
}
void K_CheckSpectateStatus(void)
{
UINT8 respawnlist[MAXPLAYERS];

View file

@ -63,6 +63,8 @@ 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);
INT16 K_CalculatePowerLevelInc(INT16 diff);
void K_PlayerForfeit(UINT8 playernum, boolean nopointloss);
void K_CheckSpectateStatus(void);
const char *K_GetItemPatch(UINT8 item, boolean tiny);

View file

@ -6252,7 +6252,7 @@ static void M_Statistics(INT32 choice)
static void M_DrawStatsMaps(int location)
{
INT32 y = 80, i = -1;
INT32 y = 88, i = -1;
INT16 mnum;
extraemblem_t *exemblem;
boolean dotopname = true, dobottomarrow = (location < statsMax);
@ -6365,11 +6365,9 @@ static void M_DrawLevelStats(void)
V_DrawString(20, 42, highlightflags, "Total Matches:");
V_DrawRightAlignedString(BASEVIDWIDTH-16, 42, 0, va("%i played", matchesplayed));
V_DrawString(20, 50, highlightflags, "Race Versus Record:");
V_DrawRightAlignedString(BASEVIDWIDTH-16, 50, 0, va("%i", versusrecord[0]));
V_DrawString(20, 58, highlightflags, "Battle Versus Record:");
V_DrawRightAlignedString(BASEVIDWIDTH-16, 58, 0, va("%i", versusrecord[1]));
V_DrawString(20, 52, highlightflags, "Online Power Level:");
V_DrawRightAlignedString(BASEVIDWIDTH-16, 52, 0, va("Race: %i", vspowerlevel[0]));
V_DrawRightAlignedString(BASEVIDWIDTH-16, 60, 0, va("Battle: %i", vspowerlevel[1]));
for (i = 0; i < NUMMAPS; i++)
{
@ -6385,18 +6383,18 @@ static void M_DrawLevelStats(void)
besttime += mainrecords[i]->time;
}
V_DrawString(20, 62, highlightflags, "Combined time records:");
V_DrawString(20, 70, highlightflags, "Combined time records:");
sprintf(beststr, "%i:%02i:%02i.%02i", G_TicsToHours(besttime), G_TicsToMinutes(besttime, false), G_TicsToSeconds(besttime), G_TicsToCentiseconds(besttime));
V_DrawRightAlignedString(BASEVIDWIDTH-16, 62, (mapsunfinished ? warningflags : 0), beststr);
V_DrawRightAlignedString(BASEVIDWIDTH-16, 70, (mapsunfinished ? warningflags : 0), beststr);
if (mapsunfinished)
V_DrawRightAlignedString(BASEVIDWIDTH-16, 70, warningflags, va("(%d unfinished)", mapsunfinished));
V_DrawRightAlignedString(BASEVIDWIDTH-16, 78, warningflags, va("(%d unfinished)", mapsunfinished));
else
V_DrawRightAlignedString(BASEVIDWIDTH-16, 70, recommendedflags, "(complete)");
V_DrawRightAlignedString(BASEVIDWIDTH-16, 78, recommendedflags, "(complete)");
V_DrawString(32, 70, 0, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems));
V_DrawSmallScaledPatch(20, 70, 0, W_CachePatchName("GOTITA", PU_STATIC));
V_DrawString(32, 78, V_ALLOWLOWERCASE, va("x %d/%d", M_CountEmblems(), numemblems+numextraemblems));
V_DrawSmallScaledPatch(20, 78, 0, W_CachePatchName("GOTITA", PU_STATIC));
M_DrawStatsMaps(statsLocation);
}
@ -8515,7 +8513,7 @@ static void M_EraseDataResponse(INT32 ch)
totalplaytime = 0;
matchesplayed = 0;
for (i = 0; i < 2; i++)
versusrecord[i] = 5000;
vspowerlevel[i] = 5000;
F_StartIntro();
}
if (erasecontext != 1)

View file

@ -2010,7 +2010,8 @@ void P_CheckPointLimit(void)
// Checks whether or not to end a race netgame.
boolean P_CheckRacers(void)
{
INT32 i, j, numplayersingame = 0;
INT32 i, j, numplayersingame = 0, numexiting = 0;
boolean griefed = false;
// Check if all the players in the race have finished. If so, end the level.
for (i = 0; i < MAXPLAYERS; i++)
@ -2027,57 +2028,53 @@ boolean P_CheckRacers(void)
return true;
}
if (cv_karteliminatelast.value)
for (j = 0; j < MAXPLAYERS; j++)
{
for (j = 0; j < MAXPLAYERS; j++)
if (nospectategrief[j] != -1) // prevent spectate griefing
griefed = true;
if (!playeringame[j] || players[j].spectator)
continue;
numplayersingame++;
if (players[j].exiting)
numexiting++;
}
if (cv_karteliminatelast.value && numplayersingame > 1 && !griefed)
{
// check if we just got unlucky and there was only one guy who was a problem
for (j = i+1; j < MAXPLAYERS; j++)
{
if (!playeringame[j] || players[j].spectator)
if (!playeringame[j] || players[j].spectator || players[j].exiting || !players[j].lives)
continue;
numplayersingame++;
break;
}
if (numplayersingame > 1 && nospectategrief > 0 && numplayersingame >= nospectategrief) // prevent spectate griefing
if (j == MAXPLAYERS) // finish anyways, force a time over
{
// check if we just got unlucky and there was only one guy who was a problem
for (j = i+1; j < MAXPLAYERS; j++)
{
if (!playeringame[j] || players[j].spectator || players[j].exiting || !players[j].lives)
continue;
break;
}
if (j == MAXPLAYERS) // finish anyways, force a time over
{
P_DoTimeOver(&players[i]);
countdown = countdown2 = 0;
return true;
}
P_DoTimeOver(&players[i]);
countdown = countdown2 = 0;
return true;
}
}
if (!countdown) // Check to see if the winners have finished, to set countdown.
{
UINT8 numingame = 0, numexiting = 0;
UINT8 winningpos = 1;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
numingame++;
if (players[i].exiting)
numexiting++;
}
winningpos = max(1, numingame/2);
if (numingame % 2) // any remainder?
winningpos = max(1, numplayersingame/2);
if (numplayersingame % 2) // any remainder?
winningpos++;
if (numexiting >= winningpos)
countdown = (((netgame || multiplayer) ? cv_countdowntime.value : 30)*TICRATE) + 1; // 30 seconds to finish, get going!
}
if (numplayersingame < 2) // reset nospectategrief in free play
{
for (j = 0; j < MAXPLAYERS; j++)
nospectategrief[j] = -1;
}
return false;
}

View file

@ -3314,7 +3314,10 @@ static void P_NetArchiveMisc(void)
WRITEUINT32(save_p, wantedcalcdelay);
WRITEUINT32(save_p, indirectitemcooldown);
WRITEUINT32(save_p, mapreset);
WRITEUINT8(save_p, nospectategrief);
for (i = 0; i < MAXPLAYERS; i++)
WRITEINT16(save_p, nospectategrief[i]);
WRITEUINT8(save_p, thwompsactive);
WRITESINT8(save_p, spbplace);
@ -3422,7 +3425,10 @@ static inline boolean P_NetUnArchiveMisc(void)
wantedcalcdelay = READUINT32(save_p);
indirectitemcooldown = READUINT32(save_p);
mapreset = READUINT32(save_p);
nospectategrief = READUINT8(save_p);
for (i = 0; i < MAXPLAYERS; i++)
nospectategrief[i] = READINT16(save_p);
thwompsactive = (boolean)READUINT8(save_p);
spbplace = READSINT8(save_p);

View file

@ -3242,7 +3242,10 @@ boolean P_SetupLevel(boolean skipprecip)
wantedcalcdelay = wantedfrequency*2;
indirectitemcooldown = 0;
mapreset = 0;
nospectategrief = 0;
for (i = 0; i < MAXPLAYERS; i++)
nospectategrief[i] = -1;
thwompsactive = false;
spbplace = -1;

View file

@ -4278,10 +4278,6 @@ DoneSection2:
// Play the starpost sound for 'consistency'
// S_StartSound(player->mo, sfx_strpst);
// Figure out how many are playing on the last lap, to prevent spectate griefing
if (!nospectategrief && player->laps >= (UINT8)(cv_numlaps.value - 1))
nospectategrief = nump;
thwompsactive = true; // Lap 2 effects
}
else if (player->starpostnum)

View file

@ -89,7 +89,7 @@ typedef union
INT32 numplayers; // Number of players being displayed
char levelstring[64]; // holds levelnames up to 64 characters
// SRB2kart
UINT8 increase[MAXPLAYERS]; // how much did the score increase by?
INT16 increase[MAXPLAYERS]; // how much did the score increase by?
UINT8 jitter[MAXPLAYERS]; // wiggle
UINT32 val[MAXPLAYERS]; // Gametype-specific value
UINT8 pos[MAXPLAYERS]; // player positions. used for ties
@ -109,6 +109,7 @@ static boolean usetile;
boolean usebuffer = false;
static boolean useinterpic;
static INT32 timer;
static INT32 powertype = 0;
static INT32 intertic;
static INT32 endtic = -1;
@ -192,11 +193,16 @@ static void Y_CompareBattle(INT32 i)
static void Y_CompareRank(INT32 i)
{
UINT8 increase = ((data.match.increase[i] == UINT8_MAX) ? 0 : data.match.increase[i]);
if (!(data.match.val[data.match.numplayers] == UINT32_MAX || (players[i].score - increase) > data.match.val[data.match.numplayers]))
INT16 increase = ((data.match.increase[i] == INT16_MIN) ? 0 : data.match.increase[i]);
UINT32 score = (powertype != -1 ? clientpowerlevels[i][powertype] : players[i].score);
if (!(data.match.val[data.match.numplayers] == UINT32_MAX))
return;
data.match.val[data.match.numplayers] = (players[i].score - increase);
if (powertype == -1 && (players[i].score - increase) > data.match.val[data.match.numplayers])
return;
data.match.val[data.match.numplayers] = (score - increase);
data.match.num[data.match.numplayers] = i;
}
@ -204,7 +210,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
{
INT32 i, j;
boolean completed[MAXPLAYERS];
INT32 numplayersingame = 0;
INT32 numplayersingame = 0, numgriefers = 0;
// Initialize variables
if (rankingsmode > 1)
@ -256,14 +262,17 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
{
data.match.val[i] = UINT32_MAX;
if (nospectategrief[i] != -1)
numgriefers++;
if (!playeringame[i] || players[i].spectator)
{
data.match.increase[i] = UINT8_MAX;
data.match.increase[i] = INT16_MIN;
continue;
}
if (!rankingsmode)
data.match.increase[i] = UINT8_MAX;
data.match.increase[i] = INT16_MIN;
numplayersingame++;
}
@ -275,8 +284,6 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
for (j = 0; j < numplayersingame; j++)
{
INT32 nump = ((G_RaceGametype() && nospectategrief > 0) ? nospectategrief : numplayersingame);
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || completed[i])
@ -298,14 +305,98 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
else
data.match.pos[data.match.numplayers] = data.match.numplayers+1;
if (!rankingsmode && !(players[i].pflags & PF_TIMEOVER) && (data.match.pos[data.match.numplayers] < nump))
if ((!rankingsmode && powertype == -1) // Single player rankings (grand prix). Online rank is handled below.
&& !(players[i].pflags & PF_TIMEOVER) && (data.match.pos[data.match.numplayers] < (numplayersingame + numgriefers)))
{
data.match.increase[i] = nump - data.match.pos[data.match.numplayers];
data.match.increase[i] = (numplayersingame + numgriefers) - data.match.pos[data.match.numplayers];
players[i].score += data.match.increase[i];
}
data.match.numplayers++;
}
// Compare every single player against each other for power level increases.
// Every player you won against gives you more points, and vice versa.
// The amount of points won per match-up depends on the difference between the loser's power and the winner's power.
// See K_CalculatePowerLevelInc for more info.
// (I'm bad at understanding this code, so I had no idea how to incorporate it with the above loop properly.)
if (!rankingsmode && powertype != -1)
{
for (i = 0; i < data.match.numplayers; i++)
{
UINT16 yourpower = 5000;
UINT16 theirpower = 5000;
INT16 diff = 0; // Loser PWR.LV - Winner PWR.LV
INT16 inc = 0; // Total pt increment
if (clientpowerlevels[i][powertype] == 0) // splitscreen guests don't record power level changes
continue;
yourpower = clientpowerlevels[i][powertype];
for (j = 0; j < data.match.numplayers; j++)
{
if (i == j || data.match.pos[i] == data.match.pos[j]) // Tie -- neither get any points for this match up.
continue;
theirpower = 5000;
if (clientpowerlevels[j][powertype] != 0) // No power level acts as 5000 (used for splitscreen guests)
theirpower = clientpowerlevels[j][powertype];
if (data.match.pos[i] > data.match.pos[j]) // This player won!
{
diff = theirpower - yourpower;
inc += K_CalculatePowerLevelInc(diff);
}
else if (data.match.pos[i] < data.match.pos[j]) // This player lost...
{
diff = yourpower - theirpower;
inc -= K_CalculatePowerLevelInc(diff);
}
}
if (numgriefers != 0) // Automatic win against quitters.
{
for (j = 0; j < MAXPLAYERS; j++)
{
if (nospectategrief[j] == -1) // Empty slot
continue;
if (i == j) // Yourself??
continue;
theirpower = 5000;
if (nospectategrief[j] != 0) // No power level acts as 5000 (used for splitscreen guests)
theirpower = nospectategrief[j];
diff = theirpower - yourpower;
inc += K_CalculatePowerLevelInc(diff);
}
}
if (inc == 0)
{
data.match.increase[i] = INT16_MIN;
continue;
}
if (yourpower + inc > 9999)
inc -= ((yourpower + inc) - 9999);
if (yourpower + inc < 1)
inc -= ((yourpower + inc) - 1);
data.match.increase[i] = inc;
clientpowerlevels[i][powertype] += data.match.increase[i];
if (i == consoleplayer)
{
vspowerlevel[powertype] = clientpowerlevels[i][powertype];
if (M_UpdateUnlockablesAndExtraEmblems(true))
S_StartSound(NULL, sfx_ncitem);
G_SaveGameData(true);
}
}
}
}
//
@ -421,7 +512,7 @@ void Y_IntermissionDrawer(void)
const char *timeheader;
if (data.match.rankingsmode)
timeheader = "RANK";
timeheader = "PWR.LV";
else
timeheader = (intertype == int_race ? "TIME" : "SCORE");
@ -487,18 +578,23 @@ void Y_IntermissionDrawer(void)
if (data.match.rankingsmode)
{
if (data.match.increase[data.match.num[i]] != UINT8_MAX)
if (!clientpowerlevels[i][powertype]) // No power level (splitscreen guests)
STRBUFCPY(strtime, "----");
else
{
if (data.match.increase[data.match.num[i]] > 9)
snprintf(strtime, sizeof strtime, "(+%02d)", data.match.increase[data.match.num[i]]);
else
snprintf(strtime, sizeof strtime, "(+ %d)", data.match.increase[data.match.num[i]]);
if (data.match.increase[data.match.num[i]] != INT16_MIN)
{
if (data.match.increase[data.match.num[i]] > 9)
snprintf(strtime, sizeof strtime, "(+%02d)", data.match.increase[data.match.num[i]]);
else
snprintf(strtime, sizeof strtime, "(+ %d)", data.match.increase[data.match.num[i]]);
V_DrawRightAlignedString(x+120+gutter, y, 0, strtime);
V_DrawRightAlignedString(x+118+gutter, y, 0, strtime);
}
snprintf(strtime, sizeof strtime, "%d", data.match.val[i]);
}
snprintf(strtime, sizeof strtime, "%d", data.match.val[i]);
V_DrawRightAlignedString(x+152+gutter, y, 0, strtime);
}
else
@ -617,7 +713,7 @@ void Y_Ticker(void)
{
if (data.match.num[q] == MAXPLAYERS
|| !data.match.increase[data.match.num[q]]
|| data.match.increase[data.match.num[q]] == UINT8_MAX)
|| data.match.increase[data.match.num[q]] == INT16_MIN)
continue;
r++;
@ -737,6 +833,17 @@ void Y_StartIntermission(void)
I_Error("endtic is dirty");
#endif
// set player Power Level type
powertype = -1;
if (netgame)
{
if (G_RaceGametype())
powertype = 0;
else if (G_BattleGametype())
powertype = 1;
}
if (!multiplayer)
{
timer = 0;