Implement lives system

Lose a life & restart the current race if you place below the top half. Lose all of your lives, and you get kicked to the title screen.
This commit is contained in:
Sally Coolatta 2020-05-13 02:14:39 -04:00
parent 63797b35f7
commit fa5fccffc5
16 changed files with 303 additions and 219 deletions

View file

@ -580,6 +580,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
// Score is resynched in the rspfirm resync packet
rsp->health = 0; // resynched with mo health
rsp->lives = players[i].lives;
rsp->lostlife = players[i].lostlife;
rsp->continues = players[i].continues;
rsp->scoreadd = players[i].scoreadd;
rsp->xtralife = players[i].xtralife;
@ -710,6 +711,7 @@ static void resynch_read_player(resynch_pak *rsp)
// Score is resynched in the rspfirm resync packet
players[i].health = rsp->health;
players[i].lives = rsp->lives;
players[i].lostlife = rsp->lostlife;
players[i].continues = rsp->continues;
players[i].scoreadd = rsp->scoreadd;
players[i].xtralife = rsp->xtralife;

View file

@ -219,6 +219,7 @@ typedef struct
// Score is resynched in the confirm resync packet
INT32 health;
SINT8 lives;
boolean lostlife;
SINT8 continues;
UINT8 scoreadd;
SINT8 xtralife;

View file

@ -5710,14 +5710,14 @@ void Command_ExitGame_f(void)
void Command_Retry_f(void)
{
if (!(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING))
if (!(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION))
{
CONS_Printf(M_GetText("You must be in a level to use this.\n"));
else if (netgame || multiplayer)
CONS_Printf(M_GetText("This only works in single player.\n"));
/*else if (!&players[consoleplayer] || players[consoleplayer].lives <= 1)
CONS_Printf(M_GetText("You can't retry without any lives remaining!\n"));
else if (G_IsSpecialStage(gamemap))
CONS_Printf(M_GetText("You can't retry special stages!\n"));*/
}
else if (netgame || grandprixinfo.roundnum == 0)
{
CONS_Printf(M_GetText("This only works in Grand Prix.\n"));
}
else
{
M_ClearMenus(true);

View file

@ -506,6 +506,7 @@ typedef struct player_s
UINT32 charflags; // Extra abilities/settings for skins (combinable stuff)
// See SF_ flags
SINT8 lives;
boolean lostlife;
SINT8 continues; // continues that player has acquired
SINT8 xtralife; // Ring Extra Life counter

View file

@ -2354,15 +2354,17 @@ void G_Ticker(boolean run)
if (gamestate == GS_LEVEL)
{
// Or, alternatively, retry.
if (!(netgame || multiplayer) && G_GetRetryFlag())
if (G_GetRetryFlag())
{
G_ClearRetryFlag();
// Costs a life to retry ... unless the player in question is dead already.
/*if (G_GametypeUsesLives() && players[consoleplayer].playerstate == PST_LIVE)
players[consoleplayer].lives -= 1;
G_DoReborn(consoleplayer);*/
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
{
K_PlayerLoseLife(&players[i]);
}
}
D_MapChange(gamemap, gametype, (cv_kartencore.value == 1), true, 1, false, false);
}
@ -2569,6 +2571,7 @@ void G_PlayerReborn(INT32 player)
player_t *p;
INT32 score, marescore;
INT32 lives;
boolean lostlife;
INT32 continues;
// SRB2kart
UINT8 kartspeed;
@ -2613,6 +2616,7 @@ void G_PlayerReborn(INT32 player)
score = players[player].score;
marescore = players[player].marescore;
lives = players[player].lives;
lostlife = players[player].lostlife;
continues = players[player].continues;
ctfteam = players[player].ctfteam;
exiting = players[player].exiting;
@ -2697,6 +2701,7 @@ void G_PlayerReborn(INT32 player)
p->score = score;
p->marescore = marescore;
p->lives = lives;
p->lostlife = lostlife;
p->continues = continues;
p->pflags = pflags;
p->ctfteam = ctfteam;
@ -3217,6 +3222,47 @@ void G_ExitLevel(void)
{
if (gamestate == GS_LEVEL)
{
if (grandprixinfo.roundnum > 0 && grandprixinfo.wonround != true)
{
UINT8 i;
// You didn't win...
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator && !players[i].bot)
{
if (players[i].lives > 0)
{
break;
}
}
}
if (i == MAXPLAYERS)
{
// GAME OVER, try again from the start!
if (netgame)
{
; // restart cup here if we do online GP
}
else
{
D_QuitNetGame();
CL_Reset();
D_StartTitle();
}
}
else
{
// Go redo this course.
G_SetRetryFlag();
}
return;
}
gameaction = ga_completed;
lastdraw = true;
@ -3292,18 +3338,15 @@ boolean G_IsSpecialStage(INT32 mapnum)
//
boolean G_GametypeUsesLives(void)
{
// SRB2kart NEEDS no lives
#if 0
// Coop, Competitive
if ((gametype == GT_COOP || gametype == GT_COMPETITION)
&& !modeattacking // No lives in Time Attack
//&& !G_IsSpecialStage(gamemap)
&& !(maptol & TOL_NIGHTS)) // No lives in NiGHTS
if ((grandprixinfo.roundnum > 0) // In Grand Prix
&& (gametype == GT_RACE) // NOT in bonus round
&& !(modeattacking) // NOT in Record Attack
&& !G_IsSpecialStage(gamemap)) // NOT in special stage
{
return true;
}
return false;
#else
return false;
#endif
}
//
@ -4570,43 +4613,42 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool
if (!demo.playback && !netgame) // Netgame sets random seed elsewhere, demo playback sets seed just before us!
P_SetRandSeed(M_RandomizedSeed()); // Use a more "Random" random seed
//SRB2Kart - Score is literally the only thing you SHOULDN'T reset at all times
//if (resetplayer)
// Clear a bunch of variables
tokenlist = token = sstimer = redscore = bluescore = lastmap = 0;
racecountdown = exitcountdown = mapreset = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
// Clear a bunch of variables
tokenlist = token = sstimer = redscore = bluescore = lastmap = 0;
racecountdown = exitcountdown = mapreset = 0;
players[i].playerstate = PST_REBORN;
players[i].starpostangle = players[i].starpostnum = players[i].starposttime = 0;
players[i].starpostx = players[i].starposty = players[i].starpostz = 0;
for (i = 0; i < MAXPLAYERS; i++)
// The latter two should clear by themselves, but just in case
players[i].pflags &= ~(PF_TAGIT|PF_TAGGED|PF_FULLSTASIS);
// Clear cheatcodes too, just in case.
players[i].pflags &= ~(PF_GODMODE|PF_NOCLIP|PF_INVIS);
players[i].marescore = 0;
if (resetplayer && !(multiplayer && demo.playback)) // SRB2Kart
{
players[i].playerstate = PST_REBORN;
players[i].starpostangle = players[i].starpostnum = players[i].starposttime = 0;
players[i].starpostx = players[i].starposty = players[i].starpostz = 0;
players[i].score = 0;
players[i].lives = 3; // SRB2Kart
// The latter two should clear by themselves, but just in case
players[i].pflags &= ~(PF_TAGIT|PF_TAGGED|PF_FULLSTASIS);
// Clear cheatcodes too, just in case.
players[i].pflags &= ~(PF_GODMODE|PF_NOCLIP|PF_INVIS);
players[i].marescore = 0;
if (resetplayer && !(multiplayer && demo.playback)) // SRB2Kart
if (grandprixinfo.roundnum == 0 || grandprixinfo.initalize == true)
{
players[i].score = 0;
players[i].lives = 3;
}
}
// Reset unlockable triggers
unlocktriggers = 0;
// clear itemfinder, just in case
if (!dedicated) // except in dedicated servers, where it is not registered and can actually I_Error debug builds
CV_StealthSetValue(&cv_itemfinder, 0);
}
// Reset unlockable triggers
unlocktriggers = 0;
// clear itemfinder, just in case
if (!dedicated) // except in dedicated servers, where it is not registered and can actually I_Error debug builds
CV_StealthSetValue(&cv_itemfinder, 0);
// internal game map
// well this check is useless because it is done before (d_netcmd.c::command_map_f)
// but in case of for demos....

View file

@ -1,15 +1,3 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2007-2016 by John "JTE" Muniz.
// Copyright (C) 2011-2018 by Sonic Team Junior.
//
// 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 k_bot.c
/// \brief Basic bot handling
#include "doomdef.h"
#include "d_player.h"
#include "g_game.h"

View file

@ -1,14 +1,5 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2007-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2018 by Sonic Team Junior.
//
// 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 k_bot.h
/// \brief Basic bot handling
#ifndef __K_BOT__
#define __K_BOT__
#include "k_waypoint.h"
#include "d_player.h"
@ -28,3 +19,5 @@ boolean K_PlayerUsesBotMovement(player_t *player);
boolean K_BotCanTakeCut(player_t *player);
fixed_t K_BotRubberband(player_t *player);
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd);
#endif

View file

@ -230,3 +230,30 @@ void K_FakeBotResults(player_t *bot)
bot->realtime = bot->realtime + (bot->distancetofinish / distfactor);
bot->distancetofinish = 0;
}
void K_PlayerLoseLife(player_t *player)
{
if (!G_GametypeUsesLives())
{
return;
}
if (player->spectator || player->exiting || player->bot || player->lostlife)
{
return;
}
player->lives--;
player->lostlife = true;
#if 0
if (player->lives <= 0)
{
if (P_IsLocalPlayer(player))
{
S_StopMusic();
S_ChangeMusicInternal("gmover", false);
}
}
#endif
}

View file

@ -11,11 +11,12 @@ extern struct grandprixinfo
UINT8 gamespeed; ///< Copy of gamespeed, just to make sure you can't cheat it with cvars
boolean encore; ///< Ditto, but for encore mode
boolean masterbots; ///< If true, all bots should be max difficulty (Master Mode)
boolean initbots; ///< If true, we need to initialize the bots that are competing.
boolean initalize; ///< If true, we need to initialize a new cup.
boolean wonround; ///< If false, then we retry the map instead of going to the next.
} grandprixinfo;
void K_InitGrandPrixBots(void);
void K_FakeBotResults(player_t *bot);
void K_PlayerLoseLife(player_t *player);
#endif

View file

@ -9891,6 +9891,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
static void K_drawKartLapsAndRings(void)
{
const boolean uselives = G_GametypeUsesLives();
SINT8 ringanim_realframe = stplyr->karthud[khud_ringframe];
INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT);
UINT8 rn[2];
@ -9975,7 +9976,7 @@ static void K_drawKartLapsAndRings(void)
}
// Rings
if (netgame)
if (!uselives)
{
V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[1]->width) - 3) : 0), fy-10, V_HUDTRANS|splitflags|flipflag, kp_ringstickersplit[1]);
if (flipflag)
@ -9997,7 +9998,7 @@ static void K_drawKartLapsAndRings(void)
V_DrawScaledPatch(fr-12, fy-23, V_HUDTRANS|splitflags, kp_ringspblocksmall[stplyr->karthud[khud_ringspblock]]);
// Lives
if (!netgame)
if (uselives)
{
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE);
V_DrawMappedPatch(fr+21, fy-13, V_HUDTRANS|splitflags, facemmapprefix[stplyr->skin], colormap);
@ -10015,7 +10016,7 @@ static void K_drawKartLapsAndRings(void)
V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->laps, cv_numlaps.value));
// Rings
if (netgame)
if (!uselives)
V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[1]);
else
V_DrawScaledPatch(LAPS_X, LAPS_Y-11, V_HUDTRANS|splitflags, kp_ringsticker[0]);
@ -10039,7 +10040,7 @@ static void K_drawKartLapsAndRings(void)
V_DrawScaledPatch(LAPS_X-5, LAPS_Y-28, V_HUDTRANS|splitflags, kp_ringspblock[stplyr->karthud[khud_ringspblock]]);
// Lives
if (!netgame)
if (uselives)
{
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE);
V_DrawMappedPatch(LAPS_X+46, LAPS_Y-16, V_HUDTRANS|splitflags, facerankprefix[stplyr->skin], colormap);

View file

@ -241,6 +241,8 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->charflags);
else if (fastcmp(field,"lives"))
lua_pushinteger(L, plr->lives);
else if (fastcmp(field,"lostlife"))
lua_pushboolean(L, plr->lostlife);
else if (fastcmp(field,"continues"))
lua_pushinteger(L, plr->continues);
else if (fastcmp(field,"xtralife"))
@ -489,6 +491,8 @@ static int player_set(lua_State *L)
plr->charflags = (UINT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"lives"))
plr->lives = (SINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"lostlife"))
plr->lostlife = luaL_checkboolean(L, 3);
else if (fastcmp(field,"continues"))
plr->continues = (SINT8)luaL_checkinteger(L, 3);
else if (fastcmp(field,"xtralife"))

View file

@ -7649,7 +7649,9 @@ static void M_StartGrandPrix(INT32 choice)
grandprixinfo.cup = gpcup;
grandprixinfo.roundnum = 1;
grandprixinfo.initbots = true;
grandprixinfo.wonround = false;
grandprixinfo.initalize = true;
G_DeferedInitNew(
false,

View file

@ -29,6 +29,7 @@
#include "k_kart.h" // SRB2kart
#include "k_battle.h"
#include "k_pwrlv.h"
#include "k_grandprix.h"
// CTF player names
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
@ -1972,71 +1973,133 @@ void P_CheckPointLimit(void)
// Checks whether or not to end a race netgame.
boolean P_CheckRacers(void)
{
INT32 i, j, numplayersingame = 0, numexiting = 0;
UINT8 i;
UINT8 numplayersingame = 0;
UINT8 numexiting = 0;
boolean eliminatelast = cv_karteliminatelast.value;
boolean canexit = true;
boolean griefed = false;
// Check if all the players in the race have finished. If so, end the level.
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].exiting || players[i].bot || !players[i].lives)
continue;
if (nospectategrief[i] != -1) // prevent spectate griefing
{
griefed = true;
}
break;
if (!playeringame[i] || players[i].spectator || players[i].lives <= 0) // Not playing
{
// Y'all aren't even playing
continue;
}
numplayersingame++;
if (players[i].exiting || (players[i].pflags & PF_TIMEOVER))
{
numexiting++;
}
else
{
if (players[i].bot)
{
// Isn't a human, thus doesn't matter. (Sorry, robots.)
continue;
}
canexit = false;
}
}
if (i == MAXPLAYERS) // finished
if (canexit)
{
// Everyone's finished, we're done here!
racecountdown = exitcountdown = 0;
return true;
}
for (j = 0; j < MAXPLAYERS; j++)
if (numplayersingame <= 1)
{
if (nospectategrief[j] != -1) // prevent spectate griefing
griefed = true;
if (!playeringame[j] || players[j].spectator)
continue;
numplayersingame++;
if (players[j].exiting)
numexiting++;
// Never do this without enough players.
eliminatelast = false;
}
else
{
if (grandprixinfo.roundnum > 0)
{
// Always do this in GP
eliminatelast = true;
}
else if (griefed)
{
// Don't do this if someone spectated
eliminatelast = false;
}
}
if (cv_karteliminatelast.value && numplayersingame > 1 && !griefed)
if (eliminatelast == true && (numplayersingame <= numexiting-1))
{
// check if we just got unlucky and there was only one guy who was a problem
for (j = i+1; j < MAXPLAYERS; j++)
// Everyone's done playing but one guy apparently.
// Just kill everyone who is still playing.
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[j] || players[j].spectator || players[j].exiting || !players[j].lives)
if (!playeringame[i] || players[i].spectator || players[i].lives <= 0) // Not playing
{
// Y'all aren't even playing
continue;
break;
}
if (players[i].exiting || (players[i].pflags & PF_TIMEOVER))
{
// You're done, you're free to go.
continue;
}
P_DoTimeOver(&players[i]);
}
if (j == MAXPLAYERS) // finish anyways, force a time over
{
P_DoTimeOver(&players[i]);
racecountdown = exitcountdown = 0;
return true;
}
// Everyone should be done playing at this point now.
racecountdown = exitcountdown = 0;
return true;
}
if (!racecountdown) // Check to see if the winners have finished, to set countdown.
// SO, we're not done playing.
// Let's see if it's time to start the death counter!
if (!racecountdown)
{
// If the winners are all done, then start the death timer.
UINT8 winningpos = 1;
winningpos = max(1, numplayersingame/2);
if (numplayersingame % 2) // any remainder?
{
winningpos++;
}
if (numexiting >= winningpos)
racecountdown = (((netgame || multiplayer) ? cv_countdowntime.value : 30)*TICRATE) + 1; // 30 seconds to finish, get going!
{
tic_t countdown = 30*TICRATE; // 30 seconds left to finish, get going!
if (netgame)
{
// Custom timer
countdown = cv_countdowntime.value * TICRATE;
}
racecountdown = countdown + 1;
}
}
if (numplayersingame < 2) // reset nospectategrief in free play
// We're still playing, but no one else is, so we need to reset spectator griefing.
if (numplayersingame <= 1)
{
for (j = 0; j < MAXPLAYERS; j++)
nospectategrief[j] = -1;
memset(nospectategrief, -1, sizeof (nospectategrief));
}
// Turns out we're still having a good time & playing the game, we didn't have to do anything :)
return false;
}
@ -2250,20 +2313,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
target->flags |= MF_NOBLOCKMAP|MF_NOCLIPHEIGHT;
P_SetThingPosition(target);
if (!target->player->bot && !G_IsSpecialStage(gamemap) && G_GametypeUsesLives())
{
target->player->lives -= 1; // Lose a life Tails 03-11-2000
if (target->player->lives <= 0) // Tails 03-14-2000
{
if (P_IsLocalPlayer(target->player)/* && target->player == &players[consoleplayer] */)
{
S_StopMusic(); // Stop the Music! Tails 03-14-2000
S_ChangeMusicInternal("gmover", false); // Yousa dead now, Okieday? Tails 03-14-2000
}
}
}
target->player->playerstate = PST_DEAD;
if (target->player == &players[consoleplayer])

View file

@ -142,6 +142,7 @@ static void P_NetArchivePlayers(void)
WRITEFIXED(save_p, players[i].dashspeed);
WRITEINT32(save_p, players[i].dashtime);
WRITESINT8(save_p, players[i].lives);
WRITEUINT8(save_p, players[i].lostlife);
WRITESINT8(save_p, players[i].continues);
WRITESINT8(save_p, players[i].xtralife);
WRITEUINT8(save_p, players[i].gotcontinue);
@ -327,6 +328,7 @@ static void P_NetUnArchivePlayers(void)
players[i].dashspeed = READFIXED(save_p); // dashing speed
players[i].dashtime = READINT32(save_p); // dashing speed
players[i].lives = READSINT8(save_p);
players[i].lostlife = (boolean)READUINT8(save_p);
players[i].continues = READSINT8(save_p); // continues that player has acquired
players[i].xtralife = READSINT8(save_p); // Ring Extra Life counter
players[i].gotcontinue = READUINT8(save_p); // got continue from stage

View file

@ -2350,6 +2350,8 @@ static void P_LevelInitStuff(void)
memset(localaiming, 0, sizeof(localaiming));
grandprixinfo.wonround = false;
// special stage tokens, emeralds, and ring total
tokenbits = 0;
runemeraldmanager = false;
@ -2399,6 +2401,7 @@ static void P_LevelInitStuff(void)
players[i].realtime = racecountdown = exitcountdown = 0;
curlap = bestlap = 0; // SRB2Kart
players[i].lostlife = false;
players[i].gotcontinue = false;
players[i].xtralife = players[i].deadtimer = players[i].numboxes = players[i].totalring = players[i].laps = 0;
@ -3362,6 +3365,23 @@ boolean P_SetupLevel(boolean skipprecip)
}
#endif
// NOW you can try to spawn in the Battle capsules, if there's not enough players for a match
K_SpawnBattleCapsules();
if (grandprixinfo.roundnum != 0)
{
if (grandprixinfo.initalize == true)
{
K_InitGrandPrixBots();
grandprixinfo.initalize = false;
}
}
else if (!modeattacking)
{
// We're in a Match Race, use simplistic randomized bots.
K_UpdateMatchRaceBots();
}
P_MapEnd();
// Remove the loading shit from the screen
@ -3413,23 +3433,6 @@ boolean P_SetupLevel(boolean skipprecip)
#endif
}
// NOW you can try to spawn in the Battle capsules, if there's not enough players for a match
K_SpawnBattleCapsules();
if (grandprixinfo.roundnum != 0)
{
if (grandprixinfo.initbots == true)
{
K_InitGrandPrixBots();
grandprixinfo.initbots = false;
}
}
else if (!modeattacking)
{
// We're in a Match Race, use simplistic randomized bots.
K_UpdateMatchRaceBots();
}
return true;
}

View file

@ -40,13 +40,14 @@
#include "st_stuff.h"
#include "lua_script.h"
#include "lua_hook.h"
#include "k_bot.h"
// Objectplace
#include "m_cheat.h"
// SRB2kart
#include "m_cond.h" // M_UpdateUnlockablesAndExtraEmblems
#include "k_kart.h"
#include "console.h" // CON_LogMessage
#include "k_bot.h"
#include "k_grandprix.h"
#ifdef HW3SOUND
#include "hardware/hw3sound.h"
@ -1681,12 +1682,20 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
// Player exits the map via sector trigger
void P_DoPlayerExit(player_t *player)
{
const boolean losing = K_IsPlayerLosing(player);
if (player->exiting || mapreset)
return;
if (P_IsLocalPlayer(player) && (!player->spectator && !demo.playback))
legitimateexit = true;
if (G_GametypeUsesLives() && losing)
{
// Remove a life from the losing player
K_PlayerLoseLife(player);
}
if (G_RaceGametype()) // If in Race Mode, allow
{
player->exiting = raceexittime+2;
@ -1697,7 +1706,7 @@ void P_DoPlayerExit(player_t *player)
if (P_IsDisplayPlayer(player))
{
sfxenum_t sfx_id;
if (K_IsPlayerLosing(player))
if (losing)
sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_klose].skinsound];
else
sfx_id = ((skin_t *)player->mo->skin)->soundsid[S_sfx[sfx_kwin].skinsound];
@ -1705,7 +1714,7 @@ void P_DoPlayerExit(player_t *player)
}
else
{
if (K_IsPlayerLosing(player))
if (losing)
S_StartSound(player->mo, sfx_klose);
else
S_StartSound(player->mo, sfx_kwin);
@ -1715,10 +1724,6 @@ void P_DoPlayerExit(player_t *player)
if (cv_inttime.value > 0)
P_EndingMusic(player);
// SRB2kart 120217
//if (!exitcountdown)
//exitcountdown = racecountdown + 8*TICRATE;
if (P_CheckRacers())
player->exiting = raceexittime+1;
}
@ -1730,24 +1735,18 @@ void P_DoPlayerExit(player_t *player)
else
player->exiting = raceexittime+2; // Accidental death safeguard???
//player->pflags &= ~PF_GLIDING;
/* // SRB2kart - don't need
if (player->climbing)
if (grandprixinfo.roundnum > 0 && !losing && !player->bot)
{
player->climbing = 0;
player->pflags |= PF_JUMPED;
P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
// YOU WIN
grandprixinfo.wonround = true;
}
*/
player->powers[pw_underwater] = 0;
player->powers[pw_spacetime] = 0;
player->karthud[khud_cardanimation] = 0; // srb2kart: reset battle animation
if (player == &players[consoleplayer])
demo.savebutton = leveltime;
/*if (playeringame[player-players] && netgame && !circuitmap)
CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]);*/
}
#define SPACESPECIAL 12
@ -6995,14 +6994,9 @@ static void P_DeathThink(player_t *player)
K_KartPlayerHUDUpdate(player);
// Force respawn if idle for more than 30 seconds in shooter modes.
if (player->lives > 0 /*&& leveltime >= starttime*/) // *could* you respawn?
if (player->lives > 0 && !(player->pflags & PF_TIMEOVER) && player->deadtimer > TICRATE)
{
// SRB2kart - spawn automatically after 1 second
if (player->deadtimer > ((netgame || multiplayer)
? cv_respawntime.value*TICRATE
: TICRATE)) // don't let them change it in record attack
player->playerstate = PST_REBORN;
player->playerstate = PST_REBORN;
}
// Keep time rolling
@ -8256,13 +8250,28 @@ static void P_CalcPostImg(player_t *player)
void P_DoTimeOver(player_t *player)
{
if (netgame && player->health > 0)
if (player->pflags & PF_TIMEOVER)
{
// NO! Don't do this!
return;
}
if (P_IsLocalPlayer(player) && !demo.playback)
{
legitimateexit = true; // SRB2kart: losing a race is still seeing it through to the end :p
}
if (netgame && !player->bot)
{
CON_LogMessage(va(M_GetText("%s ran out of time.\n"), player_names[player-players]));
}
player->pflags |= PF_TIMEOVER;
if (P_IsLocalPlayer(player) && !demo.playback)
legitimateexit = true; // SRB2kart: losing a race is still seeing it through to the end :p
if (G_GametypeUsesLives())
{
K_PlayerLoseLife(player);
}
if (player->mo)
{
@ -8384,7 +8393,7 @@ void P_PlayerThink(player_t *player)
{
if (playeringame[i] && !players[i].spectator)
{
if (!players[i].exiting && players[i].lives > 0)
if (!players[i].exiting && !(players[i].pflags & PF_TIMEOVER) && players[i].lives > 0)
break;
}
}
@ -8392,24 +8401,26 @@ void P_PlayerThink(player_t *player)
if (i == MAXPLAYERS && player->exiting == raceexittime+2) // finished
player->exiting = raceexittime+1;
#if 0
// If 10 seconds are left on the timer,
// begin the drown music for countdown!
// SRB2Kart: despite how perfect this is, it's disabled FOR A REASON
/*if (racecountdown == 11*TICRATE - 1)
if (racecountdown == 11*TICRATE - 1)
{
if (P_IsLocalPlayer(player))
S_ChangeMusicInternal("drown", false);
}*/
}
#endif
// If you've hit the countdown and you haven't made
// it to the exit, you're a goner!
else if (racecountdown == 1 && !player->exiting && !player->spectator && player->lives > 0)
if (racecountdown == 1 && !player->spectator && !player->exiting && !(player->pflags & PF_TIMEOVER) && player->lives > 0)
{
P_DoTimeOver(player);
if (player->playerstate == PST_DEAD)
{
return;
}
}
}
@ -8423,33 +8434,9 @@ void P_PlayerThink(player_t *player)
if (player->exiting == 2 || exitcountdown == 2)
{
if (cv_playersforexit.value) // Count to be sure everyone's exited
if (server)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].bot)
continue;
if (players[i].lives <= 0)
continue;
if (!players[i].exiting || players[i].exiting > 3)
break;
}
if (i == MAXPLAYERS)
{
if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
}
else
player->exiting = 3;
}
else
{
if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
}
}
}
@ -8487,28 +8474,9 @@ void P_PlayerThink(player_t *player)
player->health = 1;
}
#if 0
if ((netgame || multiplayer) && player->lives <= 0)
{
// In Co-Op, replenish a user's lives if they are depleted.
// of course, this is just a cheap hack, meh...
player->lives = cv_startinglives.value;
}
#else
player->lives = 1; // SRB2Kart
#endif
// SRB2kart 010217
if (leveltime < starttime)
player->powers[pw_nocontrol] = 2;
/*
if ((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE)
{
cmd->buttons &= BT_BRAKE; // Remove all buttons except BT_BRAKE
cmd->forwardmove = 0;
cmd->sidemove = 0;
}
*/
// Synchronizes the "real" amount of time spent in the level.
if (!player->exiting)