mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2025-03-22 10:52:23 +00:00
Lots of death stuff.
* Genesis-style love and attention to the death event. * Only visibly decrement lives/rings when you're respawning (or game over, see below). * Faster no-button-press respawn. * Game Over specific love. * Animation of Level Title font coming in from the sides. * https://cdn.discordapp.com/attachments/428262628893261828/617692325438554132/srb20067.gif * Change gameovertics to 10 seconds instead of 15. * Make the minimum time before you can force going to the Continue screen longer. * Accomodate death in MP special stages as a form of exit. * Don't have your rings or spheres reset when you die in a special stage, so that the stage isn't softlocked with the new harder limits. * Fix a bug with CoopLives_OnChange where changing to infinite lives didn't force a game-overed player to respawn. Also, two not-quite death things which nonetheless were relevant to change: * Fix quitting a special stage having some of the shared spheres/rings disappear into the aether. * Fix a warning during compilation for the Ring Penalty print.
This commit is contained in:
parent
602154fe8b
commit
f07309707d
7 changed files with 77 additions and 60 deletions
|
@ -2415,7 +2415,7 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
|
|||
// the remaining players.
|
||||
if (G_IsSpecialStage(gamemap))
|
||||
{
|
||||
INT32 i, count, increment, spheres;
|
||||
INT32 i, count, sincrement, spheres, rincrement, rings;
|
||||
|
||||
for (i = 0, count = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
@ -2425,18 +2425,35 @@ static void CL_RemovePlayer(INT32 playernum, INT32 reason)
|
|||
|
||||
count--;
|
||||
spheres = players[playernum].spheres;
|
||||
increment = spheres/count;
|
||||
rings = players[playernum].rings;
|
||||
sincrement = spheres/count;
|
||||
rincrement = rings/count;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && i != playernum)
|
||||
{
|
||||
if (spheres < increment)
|
||||
if (spheres < 2*sincrement)
|
||||
{
|
||||
P_GivePlayerSpheres(&players[i], spheres);
|
||||
spheres = 0;
|
||||
}
|
||||
else
|
||||
P_GivePlayerSpheres(&players[i], increment);
|
||||
{
|
||||
P_GivePlayerSpheres(&players[i], sincrement);
|
||||
spheres -= sincrement;
|
||||
}
|
||||
|
||||
spheres -= increment;
|
||||
if (rings < 2*rincrement)
|
||||
{
|
||||
P_GivePlayerRings(&players[i], rings);
|
||||
rings = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_GivePlayerRings(&players[i], rincrement);
|
||||
rings -= rincrement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2706,14 +2706,6 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum)
|
|||
}
|
||||
}
|
||||
|
||||
// Clear player score and rings if a spectator.
|
||||
if (players[playernum].spectator)
|
||||
{
|
||||
players[playernum].score = players[playernum].rings = 0;
|
||||
if (players[playernum].mo)
|
||||
players[playernum].mo->health = 1;
|
||||
}
|
||||
|
||||
// In tag, check to see if you still have a game.
|
||||
if (G_TagGametype())
|
||||
P_CheckSurvivors();
|
||||
|
@ -3600,7 +3592,7 @@ static void CoopLives_OnChange(void)
|
|||
{
|
||||
case 0:
|
||||
CONS_Printf(M_GetText("Players can now respawn indefinitely.\n"));
|
||||
return;
|
||||
break;
|
||||
case 1:
|
||||
CONS_Printf(M_GetText("Lives are now per-player.\n"));
|
||||
return;
|
||||
|
|
20
src/g_game.c
20
src/g_game.c
|
@ -215,7 +215,7 @@ UINT16 spacetimetics = 11*TICRATE + (TICRATE/2);
|
|||
UINT16 extralifetics = 4*TICRATE;
|
||||
UINT16 nightslinktics = 2*TICRATE;
|
||||
|
||||
INT32 gameovertics = 15*TICRATE;
|
||||
INT32 gameovertics = 10*TICRATE;
|
||||
|
||||
UINT8 ammoremovaltics = 2*TICRATE;
|
||||
|
||||
|
@ -2145,6 +2145,8 @@ void G_PlayerReborn(INT32 player)
|
|||
boolean outofcoop;
|
||||
INT16 bot;
|
||||
SINT8 pity;
|
||||
INT16 rings;
|
||||
INT16 spheres;
|
||||
|
||||
score = players[player].score;
|
||||
lives = players[player].lives;
|
||||
|
@ -2199,6 +2201,17 @@ void G_PlayerReborn(INT32 player)
|
|||
bot = players[player].bot;
|
||||
pity = players[player].pity;
|
||||
|
||||
if (!G_IsSpecialStage(gamemap))
|
||||
{
|
||||
rings = (ultimatemode ? 0 : mapheaderinfo[gamemap-1]->startrings);
|
||||
spheres = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rings = players[player].rings;
|
||||
spheres = players[player].spheres;
|
||||
}
|
||||
|
||||
p = &players[player];
|
||||
memset(p, 0, sizeof (*p));
|
||||
|
||||
|
@ -2252,6 +2265,8 @@ void G_PlayerReborn(INT32 player)
|
|||
if (bot)
|
||||
p->bot = 1; // reset to AI-controlled
|
||||
p->pity = pity;
|
||||
p->rings = rings;
|
||||
p->spheres = spheres;
|
||||
|
||||
// Don't do anything immediately
|
||||
p->pflags |= PF_USEDOWN;
|
||||
|
@ -2259,7 +2274,6 @@ void G_PlayerReborn(INT32 player)
|
|||
p->pflags |= PF_JUMPDOWN;
|
||||
|
||||
p->playerstate = PST_LIVE;
|
||||
p->rings = p->spheres = 0; // 0 rings
|
||||
p->panim = PA_IDLE; // standing animation
|
||||
|
||||
//if ((netgame || multiplayer) && !p->spectator) -- moved into P_SpawnPlayer to account for forced changes there
|
||||
|
@ -2370,8 +2384,6 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost)
|
|||
|
||||
P_SpawnPlayer(playernum);
|
||||
|
||||
players[playernum].rings = mapheaderinfo[gamemap-1]->startrings;
|
||||
|
||||
if (starpost) //Don't even bother with looking for a place to spawn.
|
||||
{
|
||||
P_MovePlayerToStarpost(playernum);
|
||||
|
|
|
@ -3500,7 +3500,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
return true;
|
||||
}
|
||||
|
||||
if (G_IsSpecialStage(gamemap))
|
||||
if (G_IsSpecialStage(gamemap) && !(damagetype & DMG_DEATHMASK))
|
||||
{
|
||||
P_SpecialStageDamage(player, inflictor, source);
|
||||
return true;
|
||||
|
@ -3524,10 +3524,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
|
||||
// Instant-Death
|
||||
if (damagetype & DMG_DEATHMASK)
|
||||
{
|
||||
P_KillPlayer(player, source, damage);
|
||||
player->rings = player->spheres = 0;
|
||||
}
|
||||
else if (metalrecording)
|
||||
{
|
||||
if (!inflictor)
|
||||
|
|
|
@ -10397,7 +10397,7 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
&& ((leveltime > 0
|
||||
&& ((G_IsSpecialStage(gamemap) && (maptol & TOL_NIGHTS)) // late join special stage
|
||||
|| (cv_coopstarposts.value == 2 && (p->jointime < 1 || p->outofcoop)))) // late join or die in new coop
|
||||
|| (((cv_cooplives.value == 1) || !P_GetLives(p)) && p->lives <= 0))); // game over and can't redistribute lives
|
||||
|| (!P_GetLives(p) && p->lives <= 0))); // game over and can't redistribute lives
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -10464,7 +10464,6 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
P_SetupStateAnimation(mobj, mobj->state);
|
||||
|
||||
mobj->health = 1;
|
||||
p->rings = p->spheres = 0;
|
||||
p->playerstate = PST_LIVE;
|
||||
|
||||
p->bonustime = false;
|
||||
|
|
30
src/p_user.c
30
src/p_user.c
|
@ -9027,19 +9027,22 @@ boolean P_GetLives(player_t *player)
|
|||
INT32 i, maxlivesplayer = -1, livescheck = 1;
|
||||
if (!(netgame || multiplayer)
|
||||
|| (gametype != GT_COOP)
|
||||
|| (cv_cooplives.value == 1)
|
||||
|| (player->lives == INFLIVES))
|
||||
return true;
|
||||
|
||||
if ((cv_cooplives.value == 2 || cv_cooplives.value == 0) && player->lives > 0)
|
||||
return true;
|
||||
|
||||
if (cv_cooplives.value == 0) // infinite lives
|
||||
{
|
||||
player->lives++;
|
||||
if (player->lives < 1)
|
||||
player->lives = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((cv_cooplives.value == 2 || cv_cooplives.value == 1) && player->lives > 0)
|
||||
return true;
|
||||
|
||||
if (cv_cooplives.value == 1)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
|
@ -9146,7 +9149,7 @@ static void P_DeathThink(player_t *player)
|
|||
// continue logic
|
||||
if (!(netgame || multiplayer) && player->lives <= 0)
|
||||
{
|
||||
if (player->deadtimer > TICRATE && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && player->continues > 0)
|
||||
if (player->deadtimer > (3*TICRATE) && (cmd->buttons & BT_USE || cmd->buttons & BT_JUMP) && player->continues > 0)
|
||||
G_UseContinue();
|
||||
else if (player->deadtimer >= gameovertics)
|
||||
G_UseContinue(); // Even if we don't have one this handles ending the game
|
||||
|
@ -9170,12 +9173,12 @@ static void P_DeathThink(player_t *player)
|
|||
// Force respawn if idle for more than 30 seconds in shooter modes.
|
||||
if (player->deadtimer > 30*TICRATE && !G_PlatformGametype())
|
||||
player->playerstate = PST_REBORN;
|
||||
else if ((player->lives > 0 || j != MAXPLAYERS) && !G_IsSpecialStage(gamemap)) // Don't allow "click to respawn" in special stages!
|
||||
else if ((player->lives > 0 || j != MAXPLAYERS) && !(G_IsSpecialStage(gamemap))) // Don't allow "click to respawn" in special stages!
|
||||
{
|
||||
if (gametype == GT_COOP && (netgame || multiplayer) && cv_coopstarposts.value == 2)
|
||||
{
|
||||
P_ConsiderAllGone();
|
||||
if ((player->deadtimer > 5*TICRATE) || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE)))
|
||||
if ((player->deadtimer > TICRATE<<1) || ((cmd->buttons & BT_JUMP) && (player->deadtimer > TICRATE)))
|
||||
{
|
||||
//player->spectator = true;
|
||||
player->outofcoop = true;
|
||||
|
@ -9191,16 +9194,11 @@ static void P_DeathThink(player_t *player)
|
|||
player->playerstate = PST_REBORN;
|
||||
else switch(gametype) {
|
||||
case GT_COOP:
|
||||
if (player->deadtimer > TICRATE)
|
||||
player->playerstate = PST_REBORN;
|
||||
break;
|
||||
case GT_COMPETITION:
|
||||
case GT_RACE:
|
||||
if (player->deadtimer > TICRATE)
|
||||
player->playerstate = PST_REBORN;
|
||||
break;
|
||||
case GT_RACE:
|
||||
player->playerstate = PST_REBORN;
|
||||
break;
|
||||
default:
|
||||
if (player->deadtimer > cv_respawntime.value*TICRATE)
|
||||
player->playerstate = PST_REBORN;
|
||||
|
@ -9209,7 +9207,7 @@ static void P_DeathThink(player_t *player)
|
|||
}
|
||||
|
||||
// Single player auto respawn
|
||||
if (!(netgame || multiplayer) && player->deadtimer > 5*TICRATE)
|
||||
if (!(netgame || multiplayer) && player->deadtimer > TICRATE<<1)
|
||||
player->playerstate = PST_REBORN;
|
||||
}
|
||||
}
|
||||
|
@ -11011,8 +11009,6 @@ void P_PlayerThink(player_t *player)
|
|||
{
|
||||
if (gametype != GT_COOP)
|
||||
player->score = 0;
|
||||
player->mo->health = 1;
|
||||
player->rings = player->spheres = 0;
|
||||
}
|
||||
else if ((netgame || multiplayer) && player->lives <= 0 && gametype != GT_COOP)
|
||||
{
|
||||
|
|
|
@ -66,8 +66,6 @@ patch_t *sboperiod; // Period for time centiseconds
|
|||
patch_t *livesback; // Lives icon background
|
||||
static patch_t *nrec_timer; // Timer for NiGHTS records
|
||||
static patch_t *sborings;
|
||||
static patch_t *sboover;
|
||||
static patch_t *timeover;
|
||||
static patch_t *stlivex;
|
||||
static patch_t *sboredrings;
|
||||
static patch_t *sboredtime;
|
||||
|
@ -253,8 +251,6 @@ void ST_LoadGraphics(void)
|
|||
sbocolon = W_CachePatchName("STTCOLON", PU_HUDGFX); // Colon for time
|
||||
sboperiod = W_CachePatchName("STTPERIO", PU_HUDGFX); // Period for time centiseconds
|
||||
|
||||
sboover = W_CachePatchName("SBOOVER", PU_HUDGFX);
|
||||
timeover = W_CachePatchName("TIMEOVER", PU_HUDGFX);
|
||||
stlivex = W_CachePatchName("STLIVEX", PU_HUDGFX);
|
||||
livesback = W_CachePatchName("STLIVEBK", PU_HUDGFX);
|
||||
nrec_timer = W_CachePatchName("NGRTIMER", PU_HUDGFX); // Timer for NiGHTS
|
||||
|
@ -768,7 +764,12 @@ static inline void ST_drawRings(void)
|
|||
|
||||
ST_DrawPatchFromHud(HUD_RINGS, ((!stplyr->spectator && stplyr->rings <= 0 && leveltime/5 & 1) ? sboredrings : sborings), ((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS));
|
||||
|
||||
ringnum = ((objectplacing) ? op_currentdoomednum : max(stplyr->rings, 0));
|
||||
if (objectplacing)
|
||||
ringnum = op_currentdoomednum;
|
||||
else if (stplyr->rings < 0 || stplyr->spectator || stplyr->playerstate == PST_REBORN)
|
||||
ringnum = 0;
|
||||
else
|
||||
ringnum = stplyr->rings;
|
||||
|
||||
if (cv_timetic.value == 2) // Yes, even in modeattacking
|
||||
ST_DrawNumFromHud(HUD_RINGSNUMTICS, ringnum, V_PERPLAYER|((stplyr->spectator) ? V_HUDTRANSHALF : V_HUDTRANS));
|
||||
|
@ -877,6 +878,8 @@ static void ST_drawLivesArea(void)
|
|||
'\x16' | 0x80 | hudinfo[HUD_LIVES].f|V_PERPLAYER|V_HUDTRANS, false);
|
||||
else
|
||||
{
|
||||
if (stplyr->playerstate == PST_DEAD && !(stplyr->spectator) && (livescount || stplyr->deadtimer < (TICRATE<<1)))
|
||||
livescount++;
|
||||
if (livescount > 99)
|
||||
livescount = 99;
|
||||
V_DrawRightAlignedString(hudinfo[HUD_LIVES].x+58, hudinfo[HUD_LIVES].y+8,
|
||||
|
@ -1960,7 +1963,7 @@ static void ST_drawWeaponRing(powertype_t weapon, INT32 rwflag, INT32 wepflag, I
|
|||
|
||||
static void ST_drawMatchHUD(void)
|
||||
{
|
||||
char penaltystr[5];
|
||||
char penaltystr[7];
|
||||
const INT32 y = 176; // HUD_LIVES
|
||||
INT32 offset = (BASEVIDWIDTH / 2) - (NUM_WEAPONS * 10) - 6;
|
||||
|
||||
|
@ -2409,25 +2412,20 @@ static void ST_overlayDrawer(void)
|
|||
}
|
||||
}
|
||||
|
||||
// GAME OVER pic
|
||||
// GAME OVER hud
|
||||
if ((gametype == GT_COOP)
|
||||
&& (netgame || multiplayer)
|
||||
&& (cv_cooplives.value == 0))
|
||||
;
|
||||
else if (G_GametypeUsesLives() && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer)))
|
||||
{
|
||||
patch_t *p;
|
||||
|
||||
if (countdown == 1)
|
||||
p = timeover;
|
||||
else
|
||||
p = sboover;
|
||||
INT32 i = MAXPLAYERS;
|
||||
INT32 deadtimer = stplyr->spectator ? TICRATE : (stplyr->deadtimer-(TICRATE<<1));
|
||||
|
||||
if ((gametype == GT_COOP)
|
||||
&& (netgame || multiplayer)
|
||||
&& (cv_cooplives.value != 1))
|
||||
{
|
||||
INT32 i;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
|
@ -2437,15 +2435,21 @@ static void ST_overlayDrawer(void)
|
|||
continue;
|
||||
|
||||
if (players[i].lives > 0)
|
||||
{
|
||||
p = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p)
|
||||
V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, BASEVIDHEIGHT/2 - (SHORT(p->height)/2), V_PERPLAYER|(stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS), p);
|
||||
if (i == MAXPLAYERS && deadtimer >= 0)
|
||||
{
|
||||
const char *first = (countdown == 1) ? "TIME" : "GAME";
|
||||
const char *second = "OVER";
|
||||
INT32 w1 = V_LevelNameWidth(first), w2 = (w1 + 16 + V_LevelNameWidth(second))>>1;
|
||||
INT32 lvlttlx1 = min(6*deadtimer, BASEVIDWIDTH/2), lvlttlx2 = BASEVIDWIDTH - lvlttlx1;
|
||||
UINT32 flags = V_PERPLAYER|(stplyr->spectator ? V_HUDTRANSHALF : V_HUDTRANS);
|
||||
|
||||
V_DrawLevelTitle(lvlttlx1 - w2, (BASEVIDHEIGHT-16)>>1, flags, first);
|
||||
V_DrawLevelTitle(lvlttlx2 + w1 + 16 - w2, (BASEVIDHEIGHT-16)>>1, flags, "OVER");
|
||||
}
|
||||
}
|
||||
|
||||
if (G_GametypeHasTeams())
|
||||
|
|
Loading…
Reference in a new issue