...
 
Commits (5)
......@@ -644,6 +644,10 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
rsp->onconveyor = LONG(players[i].onconveyor);
rsp->jointime = (tic_t)LONG(players[i].jointime);
rsp->spectatorreentry = (tic_t)LONG(players[i].spectatorreentry);
rsp->grieftime = (tic_t)LONG(players[i].grieftime);
rsp->griefstrikes = players[i].griefstrikes;
rsp->splitscreenindex = players[i].splitscreenindex;
......@@ -767,6 +771,10 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].onconveyor = LONG(rsp->onconveyor);
players[i].jointime = (tic_t)LONG(rsp->jointime);
players[i].spectatorreentry = (tic_t)LONG(rsp->spectatorreentry);
players[i].grieftime = (tic_t)LONG(rsp->grieftime);
players[i].griefstrikes = rsp->griefstrikes;
players[i].splitscreenindex = rsp->splitscreenindex;
......
......@@ -282,6 +282,10 @@ typedef struct
INT32 onconveyor;
tic_t jointime;
tic_t spectatorreentry;
tic_t grieftime;
UINT8 griefstrikes;
UINT8 splitscreenindex;
......
......@@ -247,6 +247,12 @@ consvar_t cv_allowteamchange = {"allowteamchange", "Yes", CV_NETVAR, CV_YesNo, N
static CV_PossibleValue_t ingamecap_cons_t[] = {{0, "MIN"}, {MAXPLAYERS-1, "MAX"}, {0, NULL}};
consvar_t cv_ingamecap = {"ingamecap", "0", CV_NETVAR, ingamecap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t spectatorreentry_cons_t[] = {{0, "MIN"}, {10*60, "MAX"}, {0, NULL}};
consvar_t cv_spectatorreentry = {"spectatorreentry", "60", CV_NETVAR, spectatorreentry_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t antigrief_cons_t[] = {{20, "MIN"}, {60, "MAX"}, {0, "Off"}, {0, NULL}};
consvar_t cv_antigrief = {"antigrief", "30", CV_NETVAR, antigrief_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_startinglives = {"startinglives", "3", CV_NETVAR|CV_CHEAT|CV_NOSHOWHELP, startingliveslimit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t respawntime_cons_t[] = {{0, "MIN"}, {30, "MAX"}, {0, NULL}};
......@@ -679,6 +685,8 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_restrictskinchange);
CV_RegisterVar(&cv_allowteamchange);
CV_RegisterVar(&cv_ingamecap);
CV_RegisterVar(&cv_spectatorreentry);
CV_RegisterVar(&cv_antigrief);
CV_RegisterVar(&cv_respawntime);
CV_RegisterVar(&cv_killingdead);
......@@ -3703,12 +3711,15 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
// Clear player score and rings if a spectator.
if (players[playernum].spectator)
{
players[playernum].spectatorreentry = (cv_spectatorreentry.value * TICRATE);
if (G_BattleGametype()) // SRB2kart
{
players[playernum].marescore = 0;
if (K_IsPlayerWanted(&players[playernum]))
K_CalculateBattleWanted();
}
players[playernum].health = 1;
if (players[playernum].mo)
players[playernum].mo->health = 1;
......
......@@ -94,6 +94,7 @@ extern consvar_t cv_killingdead;
extern consvar_t cv_pause;
extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_ingamecap, cv_respawntime;
extern consvar_t cv_spectatorreentry, cv_antigrief;
/*extern consvar_t cv_teleporters, cv_superring, cv_supersneakers, cv_invincibility;
extern consvar_t cv_jumpshield, cv_watershield, cv_ringshield, cv_forceshield, cv_bombshield;
......
......@@ -520,6 +520,10 @@ typedef struct player_s
UINT8 bot;
tic_t jointime; // Timer when player joins game to change skin/color
tic_t spectatorreentry;
tic_t grieftime;
UINT8 griefstrikes;
UINT8 splitscreenindex;
#ifdef HWRENDER
......
......@@ -2603,6 +2603,9 @@ void G_PlayerReborn(INT32 player)
INT32 wanted;
INT32 respawnflip;
boolean songcredit = false;
tic_t spectatorreentry;
tic_t grieftime;
UINT8 griefstrikes;
score = players[player].score;
marescore = players[player].marescore;
......@@ -2644,7 +2647,7 @@ void G_PlayerReborn(INT32 player)
pity = players[player].pity;
// SRB2kart
if (leveltime <= starttime)
if (leveltime <= starttime || spectator == true)
{
itemroulette = 0;
roulettetype = 0;
......@@ -2655,6 +2658,14 @@ void G_PlayerReborn(INT32 player)
comebackpoints = 0;
wanted = 0;
starpostwp = 0;
starposttime = 0;
starpostx = 0;
starposty = 0;
starpostz = 0;
starpostnum = 0;
respawnflip = 0;
starpostangle = 0;
}
else
{
......@@ -2685,6 +2696,11 @@ void G_PlayerReborn(INT32 player)
wanted = players[player].kartstuff[k_wanted];
}
spectatorreentry = players[player].spectatorreentry;
grieftime = players[player].grieftime;
griefstrikes = players[player].griefstrikes;
p = &players[player];
memset(p, 0, sizeof (*p));
......@@ -2738,6 +2754,10 @@ void G_PlayerReborn(INT32 player)
p->kartstuff[k_eggmanblame] = -1;
p->kartstuff[k_starpostflip] = respawnflip;
p->spectatorreentry = spectatorreentry;
p->grieftime = grieftime;
p->griefstrikes = griefstrikes;
// Don't do anything immediately
p->pflags |= PF_USEDOWN;
p->pflags |= PF_ATTACKDOWN;
......
......@@ -759,7 +759,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
char *tempchar = NULL;
// player is a spectator?
if (players[playernum].spectator)
if (players[playernum].spectator)
{
cstart = "\x86"; // grey name
textcolor = "\x86";
......
......@@ -6219,16 +6219,23 @@ void K_CheckSpectateStatus(void)
{
UINT8 respawnlist[MAXPLAYERS];
UINT8 i, j, numingame = 0, numjoiners = 0;
UINT8 previngame = 0;
// Maintain spectate wait timer
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (players[i].spectator && (players[i].pflags & PF_WANTSTOJOIN))
players[i].kartstuff[k_spectatewait]++;
else
players[i].kartstuff[k_spectatewait] = 0;
if (gamestate != GS_LEVEL)
players[i].spectatorreentry = 0;
else if (players[i].spectatorreentry > 0)
players[i].spectatorreentry--;
}
// No one's allowed to join
......@@ -6244,22 +6251,38 @@ void K_CheckSpectateStatus(void)
if (!players[i].spectator)
{
numingame++;
if (cv_ingamecap.value && numingame >= cv_ingamecap.value) // DON'T allow if you've hit the in-game player cap
// DON'T allow if you've hit the in-game player cap
if (cv_ingamecap.value && numingame >= cv_ingamecap.value)
return;
if (gamestate != GS_LEVEL) // Allow if you're not in a level
// Allow if you're not in a level
if (gamestate != GS_LEVEL)
continue;
if (players[i].exiting) // DON'T allow if anyone's exiting
// DON'T allow if anyone's exiting
if (players[i].exiting)
return;
if (numingame < 2 || leveltime < starttime || mapreset) // Allow if the match hasn't started yet
// Allow if the match hasn't started yet
if (numingame < 2 || leveltime < starttime || mapreset)
continue;
if (leveltime > (starttime + 20*TICRATE)) // DON'T allow if the match is 20 seconds in
// DON'T allow if the match is 20 seconds in
if (leveltime > (starttime + 20*TICRATE))
return;
if (G_RaceGametype() && players[i].laps) // DON'T allow if the race is at 2 laps
// DON'T allow if the race is on the second lap
if (G_RaceGametype() && players[i].laps)
return;
continue;
}
else if (!(players[i].pflags & PF_WANTSTOJOIN))
{
// This spectator does not want to join.
continue;
}
respawnlist[numjoiners++] = i;
}
......@@ -6269,7 +6292,9 @@ void K_CheckSpectateStatus(void)
return;
// Organize by spectate wait timer
#if 0
if (cv_ingamecap.value)
#endif
{
UINT8 oldrespawnlist[MAXPLAYERS];
memcpy(oldrespawnlist, respawnlist, numjoiners);
......@@ -6293,16 +6318,25 @@ void K_CheckSpectateStatus(void)
}
}
// Finally, we can de-spectate everyone!
// Finally, we can de-spectate everyone in the list!
previngame = numingame;
for (i = 0; i < numjoiners; i++)
{
if (cv_ingamecap.value && numingame+i >= cv_ingamecap.value) // Hit the in-game player cap while adding people?
// Hit the in-game player cap while adding people? Get out of here
if (cv_ingamecap.value > 0 && numingame >= cv_ingamecap.value)
break;
// This person has their reentry cooldown active.
if (players[i].spectatorreentry > 0 && numingame > 0)
continue;
P_SpectatorJoinGame(&players[respawnlist[i]]);
numingame++;
}
// Reset the match if you're in an empty server
if (!mapreset && gamestate == GS_LEVEL && leveltime >= starttime && (numingame < 2 && numingame+i >= 2)) // use previous i value
if (!mapreset && gamestate == GS_LEVEL && leveltime >= starttime && (previngame < 2 && numingame >= 2))
{
S_ChangeMusicInternal("chalng", false); // COME ON
mapreset = 3*TICRATE; // Even though only the server uses this for game logic, set for everyone for HUD
......
......@@ -382,6 +382,12 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->bot);
else if (fastcmp(field,"jointime"))
lua_pushinteger(L, plr->jointime);
else if (fastcmp(field,"spectatorreentry"))
lua_pushinteger(L, plr->spectatorreentry);
else if (fastcmp(field,"grieftime"))
lua_pushinteger(L, plr->grieftime);
else if (fastcmp(field,"griefstrikes"))
lua_pushinteger(L, plr->griefstrikes);
else if (fastcmp(field,"splitscreenindex"))
lua_pushinteger(L, plr->splitscreenindex);
#ifdef HWRENDER
......@@ -646,6 +652,12 @@ static int player_set(lua_State *L)
return NOSET;
else if (fastcmp(field,"jointime"))
plr->jointime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"spectatorreentry"))
plr->spectatorreentry = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"grieftime"))
plr->grieftime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"griefstrikes"))
plr->griefstrikes = (UINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"splitscreenindex"))
return NOSET;
#ifdef HWRENDER
......
......@@ -1454,7 +1454,15 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
{
// blatant reuse of a variable that's normally unused in circuit
if (!player->tossdelay)
{
S_StartSound(toucher, sfx_s26d);
if (netgame && cv_antigrief.value)
{
player->grieftime += TICRATE;
}
}
player->tossdelay = 3;
return;
}
......@@ -1478,6 +1486,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
player->starpostangle = special->angle;
player->starpostnum = special->health;
player->kartstuff[k_starpostflip] = special->spawnpoint->options & MTF_OBJECTFLIP; // store flipping
player->grieftime = 0;
//S_StartSound(toucher, special->info->painsound);
return;
......
......@@ -10650,10 +10650,7 @@ void P_SpawnPlayer(INT32 playernum)
else if (netgame && p->jointime <= 1 && pcount)
{
p->spectator = true;
// Oni doesn't want this
/*if (pcount == 1 || leveltime < starttime)
p->pflags |= PF_WANTSTOJOIN;
p->jointime = 2;*/
p->spectatorreentry = (cv_spectatorreentry.value * TICRATE);
}
else if (multiplayer && !netgame)
{
......@@ -10667,6 +10664,8 @@ void P_SpawnPlayer(INT32 playernum)
// Spawn as a spectator,
// yes even in splitscreen mode
p->spectator = true;
p->spectatorreentry = (cv_spectatorreentry.value * TICRATE);
if (playernum&1) p->skincolor = skincolor_redteam;
else p->skincolor = skincolor_blueteam;
......@@ -10686,7 +10685,10 @@ void P_SpawnPlayer(INT32 playernum)
{
// Fix stupid non spectator spectators.
if (!p->spectator && !p->ctfteam)
{
p->spectator = true;
p->spectatorreentry = (cv_spectatorreentry.value * TICRATE);
}
// Fix team colors.
// This code isn't being done right somewhere else. Oh well.
......@@ -10728,6 +10730,8 @@ void P_SpawnPlayer(INT32 playernum)
// Spawn with a pity shield if necessary.
//P_DoPityCheck(p);
p->grieftime = 0;
if (G_BattleGametype()) // SRB2kart
{
mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + P_GetPlayerHeight(p)+16*FRACUNIT, MT_PLAYERARROW);
......
......@@ -246,6 +246,10 @@ static void P_NetArchivePlayers(void)
WRITEINT32(save_p, players[i].onconveyor);
WRITEUINT32(save_p, players[i].jointime);
WRITEUINT32(save_p, players[i].spectatorreentry);
WRITEUINT32(save_p, players[i].grieftime);
WRITEUINT8(save_p, players[i].griefstrikes);
WRITEUINT8(save_p, players[i].splitscreenindex);
......@@ -411,6 +415,10 @@ static void P_NetUnArchivePlayers(void)
players[i].onconveyor = READINT32(save_p);
players[i].jointime = READUINT32(save_p);
players[i].spectatorreentry = READUINT32(save_p);
players[i].grieftime = READUINT32(save_p);
players[i].griefstrikes = READUINT8(save_p);
players[i].splitscreenindex = READUINT8(save_p);
......
......@@ -4316,12 +4316,21 @@ DoneSection2:
nospectategrief = nump;
thwompsactive = true; // Lap 2 effects
player->grieftime = 0;
}
else if (player->starpostnum)
{
// blatant reuse of a variable that's normally unused in circuit
if (!player->tossdelay)
{
S_StartSound(player->mo, sfx_s26d);
if (netgame && cv_antigrief.value)
{
player->grieftime += TICRATE;
}
}
player->tossdelay = 3;
}
......
......@@ -1698,6 +1698,9 @@ void P_DoPlayerExit(player_t *player)
if (P_IsLocalPlayer(player) && (!player->spectator && !demo.playback))
legitimateexit = true;
if (player->griefstrikes > 0)
player->griefstrikes--; // Remove a strike for finishing a race normally
if (G_RaceGametype()) // If in Race Mode, allow
{
player->exiting = raceexittime+2;
......@@ -8489,6 +8492,55 @@ void P_PlayerThink(player_t *player)
}
}
if (netgame && cv_antigrief.value != 0)
{
if (!player->spectator && !player->exiting && !(player->pflags & PF_TIMEOVER))
{
const tic_t griefval = cv_antigrief.value * TICRATE;
const UINT8 n = player - players;
if (n != serverplayer && !IsPlayerAdmin(n))
{
if (player->grieftime > griefval)
{
player->griefstrikes++;
player->grieftime = 0;
if (server)
{
if (player->griefstrikes > 2)
{
// Send kick
XBOXSTATIC UINT8 buf[2];
buf[0] = n;
buf[1] = KICK_MSG_CON_FAIL;
SendNetXCmd(XD_KICK, &buf, 2);
}
else
{
// Send spectate
changeteam_union NetPacket;
UINT16 usvalue;
NetPacket.value.l = NetPacket.value.b = 0;
NetPacket.packet.newteam = 0;
NetPacket.packet.playernum = n;
NetPacket.packet.verification = true;
usvalue = SHORT(NetPacket.value.l|NetPacket.value.b);
SendNetXCmd(XD_TEAMCHANGE, &usvalue, sizeof(usvalue));
}
}
}
else
{
player->grieftime++;
}
}
}
}
if ((netgame || multiplayer) && player->spectator && cmd->buttons & BT_ATTACK && !player->powers[pw_flashing])
{
player->pflags ^= PF_WANTSTOJOIN;
......