From fa5fccffc58acb6556f392a5f0f0749db9cef59a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 13 May 2020 02:14:39 -0400 Subject: [PATCH] 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. --- src/d_clisrv.c | 2 + src/d_clisrv.h | 1 + src/d_netcmd.c | 14 ++--- src/d_player.h | 1 + src/g_game.c | 130 +++++++++++++++++++++++++++--------------- src/k_bot.c | 12 ---- src/k_bot.h | 15 ++--- src/k_grandprix.c | 27 +++++++++ src/k_grandprix.h | 5 +- src/k_kart.c | 9 +-- src/lua_playerlib.c | 4 ++ src/m_menu.c | 4 +- src/p_inter.c | 135 ++++++++++++++++++++++++++++++-------------- src/p_saveg.c | 2 + src/p_setup.c | 37 ++++++------ src/p_user.c | 124 +++++++++++++++------------------------- 16 files changed, 303 insertions(+), 219 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 358ab15f3..5d7c0da83 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -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; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index abf43e5f9..027ad42dd 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -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; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 500520e12..244e6df59 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -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); diff --git a/src/d_player.h b/src/d_player.h index 40e5a4bc0..d3af08ede 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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 diff --git a/src/g_game.c b/src/g_game.c index 99230316b..a5e31994b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -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.... diff --git a/src/k_bot.c b/src/k_bot.c index a6a7b0a29..b7f79efd9 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -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" diff --git a/src/k_bot.h b/src/k_bot.h index ef7409f97..afdbf5ee9 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -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 diff --git a/src/k_grandprix.c b/src/k_grandprix.c index c3a4185cc..f54055598 100644 --- a/src/k_grandprix.c +++ b/src/k_grandprix.c @@ -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 +} diff --git a/src/k_grandprix.h b/src/k_grandprix.h index d0734bc42..2127a5eb6 100644 --- a/src/k_grandprix.h +++ b/src/k_grandprix.h @@ -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 - diff --git a/src/k_kart.c b/src/k_kart.c index 5a6c0db34..cf984252c 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -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); diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 5088045f7..0a51c1e09 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -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")) diff --git a/src/m_menu.c b/src/m_menu.c index 34e0696c8..7dd5cf7c9 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -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, diff --git a/src/p_inter.c b/src/p_inter.c index d6dc7a9e6..0aad1bc33 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -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]) diff --git a/src/p_saveg.c b/src/p_saveg.c index 007ce919c..6f8b5cb79 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -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 diff --git a/src/p_setup.c b/src/p_setup.c index 73cbc615a..5228f7ed8 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -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; } diff --git a/src/p_user.c b/src/p_user.c index 5b638152a..34fa8642f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -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)