mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2025-01-30 21:20:54 +00:00
Merge branch 'exit-move-lj' into 'master'
Post-exit movement See merge request STJr/SRB2Internal!486
This commit is contained in:
commit
233ff8bd27
13 changed files with 106 additions and 9 deletions
|
@ -87,6 +87,7 @@ static void JoinTimeout_OnChange(void);
|
||||||
|
|
||||||
static void CoopStarposts_OnChange(void);
|
static void CoopStarposts_OnChange(void);
|
||||||
static void CoopLives_OnChange(void);
|
static void CoopLives_OnChange(void);
|
||||||
|
static void ExitMove_OnChange(void);
|
||||||
|
|
||||||
static void Ringslinger_OnChange(void);
|
static void Ringslinger_OnChange(void);
|
||||||
static void Gravity_OnChange(void);
|
static void Gravity_OnChange(void);
|
||||||
|
@ -361,9 +362,12 @@ consvar_t cv_cooplives = {"cooplives", "Avoid Game Over", CV_NETVAR|CV_CALL|CV_C
|
||||||
|
|
||||||
static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}};
|
static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}};
|
||||||
consvar_t cv_advancemap = {"advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
consvar_t cv_advancemap = {"advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||||
|
|
||||||
static CV_PossibleValue_t playersforexit_cons_t[] = {{0, "One"}, {1, "1/4"}, {2, "Half"}, {3, "3/4"}, {4, "All"}, {0, NULL}};
|
static CV_PossibleValue_t playersforexit_cons_t[] = {{0, "One"}, {1, "1/4"}, {2, "Half"}, {3, "3/4"}, {4, "All"}, {0, NULL}};
|
||||||
consvar_t cv_playersforexit = {"playersforexit", "All", CV_NETVAR, playersforexit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
consvar_t cv_playersforexit = {"playersforexit", "All", CV_NETVAR, playersforexit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||||
|
|
||||||
|
consvar_t cv_exitmove = {"exitmove", "Off", CV_NETVAR|CV_CALL, CV_OnOff, ExitMove_OnChange, 0, NULL, NULL, 0, 0, NULL};
|
||||||
|
|
||||||
consvar_t cv_runscripts = {"runscripts", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
|
consvar_t cv_runscripts = {"runscripts", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||||
|
|
||||||
consvar_t cv_pause = {"pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
consvar_t cv_pause = {"pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
|
||||||
|
@ -522,6 +526,7 @@ void D_RegisterServerCommands(void)
|
||||||
CV_RegisterVar(&cv_inttime);
|
CV_RegisterVar(&cv_inttime);
|
||||||
CV_RegisterVar(&cv_advancemap);
|
CV_RegisterVar(&cv_advancemap);
|
||||||
CV_RegisterVar(&cv_playersforexit);
|
CV_RegisterVar(&cv_playersforexit);
|
||||||
|
CV_RegisterVar(&cv_exitmove);
|
||||||
CV_RegisterVar(&cv_timelimit);
|
CV_RegisterVar(&cv_timelimit);
|
||||||
CV_RegisterVar(&cv_playbackspeed);
|
CV_RegisterVar(&cv_playbackspeed);
|
||||||
CV_RegisterVar(&cv_forceskin);
|
CV_RegisterVar(&cv_forceskin);
|
||||||
|
@ -3788,6 +3793,17 @@ static void CoopLives_OnChange(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ExitMove_OnChange(void)
|
||||||
|
{
|
||||||
|
if (!(netgame || multiplayer) || gametype != GT_COOP)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cv_exitmove.value)
|
||||||
|
CONS_Printf(M_GetText("Players can now move after completing the level.\n"));
|
||||||
|
else
|
||||||
|
CONS_Printf(M_GetText("Players can no longer move after completing the level.\n"));
|
||||||
|
}
|
||||||
|
|
||||||
UINT32 timelimitintics = 0;
|
UINT32 timelimitintics = 0;
|
||||||
|
|
||||||
/** Deals with a timelimit change by printing the change to the console.
|
/** Deals with a timelimit change by printing the change to the console.
|
||||||
|
|
|
@ -94,7 +94,7 @@ extern consvar_t cv_recycler;
|
||||||
|
|
||||||
extern consvar_t cv_itemfinder;
|
extern consvar_t cv_itemfinder;
|
||||||
|
|
||||||
extern consvar_t cv_inttime, cv_coopstarposts, cv_cooplives, cv_advancemap, cv_playersforexit;
|
extern consvar_t cv_inttime, cv_coopstarposts, cv_cooplives, cv_advancemap, cv_playersforexit, cv_exitmove;
|
||||||
extern consvar_t cv_overtime;
|
extern consvar_t cv_overtime;
|
||||||
extern consvar_t cv_startinglives;
|
extern consvar_t cv_startinglives;
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,7 @@ typedef enum
|
||||||
/*** misc ***/
|
/*** misc ***/
|
||||||
PF_FORCESTRAFE = 1<<28, // Turning inputs are translated into strafing inputs
|
PF_FORCESTRAFE = 1<<28, // Turning inputs are translated into strafing inputs
|
||||||
PF_CANCARRY = 1<<29, // Can carry another player?
|
PF_CANCARRY = 1<<29, // Can carry another player?
|
||||||
|
PF_FINISHED = 1<<30, // The player finished the level. NOT the same as exiting
|
||||||
|
|
||||||
// up to 1<<31 is free
|
// up to 1<<31 is free
|
||||||
} pflags_t;
|
} pflags_t;
|
||||||
|
|
|
@ -8572,6 +8572,7 @@ static const char *const PLAYERFLAG_LIST[] = {
|
||||||
/*** misc ***/
|
/*** misc ***/
|
||||||
"FORCESTRAFE", // Translate turn inputs into strafe inputs
|
"FORCESTRAFE", // Translate turn inputs into strafe inputs
|
||||||
"CANCARRY", // Can carry?
|
"CANCARRY", // Can carry?
|
||||||
|
"FINISHED",
|
||||||
|
|
||||||
NULL // stop loop here.
|
NULL // stop loop here.
|
||||||
};
|
};
|
||||||
|
|
25
src/g_game.c
25
src/g_game.c
|
@ -2833,6 +2833,31 @@ void G_AddPlayer(INT32 playernum)
|
||||||
P_DoPlayerExit(p);
|
P_DoPlayerExit(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean G_EnoughPlayersFinished(void)
|
||||||
|
{
|
||||||
|
UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value);
|
||||||
|
INT32 total = 0;
|
||||||
|
INT32 exiting = 0;
|
||||||
|
INT32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < MAXPLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (!playeringame[i] || players[i].spectator || players[i].bot)
|
||||||
|
continue;
|
||||||
|
if (players[i].lives <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
total++;
|
||||||
|
if (players[i].pflags & PF_FINISHED)
|
||||||
|
exiting++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exiting)
|
||||||
|
return exiting * 4 / total >= numneeded;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void G_ExitLevel(void)
|
void G_ExitLevel(void)
|
||||||
{
|
{
|
||||||
if (gamestate == GS_LEVEL)
|
if (gamestate == GS_LEVEL)
|
||||||
|
|
|
@ -208,6 +208,7 @@ boolean G_GametypeHasSpectators(void);
|
||||||
boolean G_RingSlingerGametype(void);
|
boolean G_RingSlingerGametype(void);
|
||||||
boolean G_PlatformGametype(void);
|
boolean G_PlatformGametype(void);
|
||||||
boolean G_TagGametype(void);
|
boolean G_TagGametype(void);
|
||||||
|
boolean G_EnoughPlayersFinished(void);
|
||||||
void G_ExitLevel(void);
|
void G_ExitLevel(void);
|
||||||
void G_NextLevel(void);
|
void G_NextLevel(void);
|
||||||
void G_Continue(void);
|
void G_Continue(void);
|
||||||
|
|
|
@ -2444,7 +2444,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I
|
||||||
V_DrawSmallScaledPatch(x-32, y-4, 0, tagico);
|
V_DrawSmallScaledPatch(x-32, y-4, 0, tagico);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (players[tab[i].num].exiting)
|
if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED))
|
||||||
V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon);
|
V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon);
|
||||||
|
|
||||||
if (gametype == GT_RACE)
|
if (gametype == GT_RACE)
|
||||||
|
@ -2748,7 +2748,7 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
|
||||||
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
|
else if (G_TagGametype() && players[tab[i].num].pflags & PF_TAGIT)
|
||||||
V_DrawSmallScaledPatch(x-28, y-4, 0, tagico);
|
V_DrawSmallScaledPatch(x-28, y-4, 0, tagico);
|
||||||
|
|
||||||
if (players[tab[i].num].exiting)
|
if (players[tab[i].num].exiting || (players[tab[i].num].pflags & PF_FINISHED))
|
||||||
V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon);
|
V_DrawSmallScaledPatch(x - SHORT(exiticon->width)/2 - 1, y-3, 0, exiticon);
|
||||||
|
|
||||||
// Draw emeralds
|
// Draw emeralds
|
||||||
|
|
|
@ -1165,6 +1165,17 @@ static int lib_pElementalFire(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lib_pDoPlayerFinish(lua_State *L)
|
||||||
|
{
|
||||||
|
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||||
|
NOHUD
|
||||||
|
INLEVEL
|
||||||
|
if (!player)
|
||||||
|
return LUA_ErrInvalid(L, "player_t");
|
||||||
|
P_DoPlayerFinish(player);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int lib_pDoPlayerExit(lua_State *L)
|
static int lib_pDoPlayerExit(lua_State *L)
|
||||||
{
|
{
|
||||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||||
|
@ -2674,6 +2685,13 @@ static int lib_gSetCustomExitVars(lua_State *L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lib_gEnoughPlayersFinished(lua_State *L)
|
||||||
|
{
|
||||||
|
INLEVEL
|
||||||
|
lua_pushboolean(L, G_EnoughPlayersFinished());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int lib_gExitLevel(lua_State *L)
|
static int lib_gExitLevel(lua_State *L)
|
||||||
{
|
{
|
||||||
int n = lua_gettop(L); // Num arguments
|
int n = lua_gettop(L); // Num arguments
|
||||||
|
@ -2869,6 +2887,7 @@ static luaL_Reg lib[] = {
|
||||||
{"P_DoBubbleBounce",lib_pDoBubbleBounce},
|
{"P_DoBubbleBounce",lib_pDoBubbleBounce},
|
||||||
{"P_BlackOw",lib_pBlackOw},
|
{"P_BlackOw",lib_pBlackOw},
|
||||||
{"P_ElementalFire",lib_pElementalFire},
|
{"P_ElementalFire",lib_pElementalFire},
|
||||||
|
{"P_DoPlayerFinish",lib_pDoPlayerFinish},
|
||||||
{"P_DoPlayerExit",lib_pDoPlayerExit},
|
{"P_DoPlayerExit",lib_pDoPlayerExit},
|
||||||
{"P_InstaThrust",lib_pInstaThrust},
|
{"P_InstaThrust",lib_pInstaThrust},
|
||||||
{"P_ReturnThrustX",lib_pReturnThrustX},
|
{"P_ReturnThrustX",lib_pReturnThrustX},
|
||||||
|
@ -2981,6 +3000,7 @@ static luaL_Reg lib[] = {
|
||||||
{"G_BuildMapName",lib_gBuildMapName},
|
{"G_BuildMapName",lib_gBuildMapName},
|
||||||
{"G_DoReborn",lib_gDoReborn},
|
{"G_DoReborn",lib_gDoReborn},
|
||||||
{"G_SetCustomExitVars",lib_gSetCustomExitVars},
|
{"G_SetCustomExitVars",lib_gSetCustomExitVars},
|
||||||
|
{"G_EnoughPlayersFinished",lib_gEnoughPlayersFinished},
|
||||||
{"G_ExitLevel",lib_gExitLevel},
|
{"G_ExitLevel",lib_gExitLevel},
|
||||||
{"G_IsSpecialStage",lib_gIsSpecialStage},
|
{"G_IsSpecialStage",lib_gIsSpecialStage},
|
||||||
{"G_GametypeUsesLives",lib_gGametypeUsesLives},
|
{"G_GametypeUsesLives",lib_gGametypeUsesLives},
|
||||||
|
|
|
@ -172,6 +172,7 @@ void P_ElementalFire(player_t *player, boolean cropcircle);
|
||||||
void P_DoPityCheck(player_t *player);
|
void P_DoPityCheck(player_t *player);
|
||||||
void P_PlayerThink(player_t *player);
|
void P_PlayerThink(player_t *player);
|
||||||
void P_PlayerAfterThink(player_t *player);
|
void P_PlayerAfterThink(player_t *player);
|
||||||
|
void P_DoPlayerFinish(player_t *player);
|
||||||
void P_DoPlayerExit(player_t *player);
|
void P_DoPlayerExit(player_t *player);
|
||||||
void P_NightserizePlayer(player_t *player, INT32 ptime);
|
void P_NightserizePlayer(player_t *player, INT32 ptime);
|
||||||
|
|
||||||
|
|
|
@ -592,6 +592,9 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
|
||||||
if (!(tails->pflags & PF_CANCARRY))
|
if (!(tails->pflags & PF_CANCARRY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (sonic->pflags & PF_FINISHED)
|
||||||
|
return;
|
||||||
|
|
||||||
if (tails->bot == 1)
|
if (tails->bot == 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -4675,7 +4675,7 @@ DoneSection2:
|
||||||
{
|
{
|
||||||
INT32 lineindex;
|
INT32 lineindex;
|
||||||
|
|
||||||
P_DoPlayerExit(player);
|
P_DoPlayerFinish(player);
|
||||||
|
|
||||||
P_SetupSignExit(player);
|
P_SetupSignExit(player);
|
||||||
// important: use sector->tag on next line instead of player->mo->subsector->tag
|
// important: use sector->tag on next line instead of player->mo->subsector->tag
|
||||||
|
|
35
src/p_user.c
35
src/p_user.c
|
@ -2131,6 +2131,30 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type)
|
||||||
P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do
|
P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Called when \p player finishes the level.
|
||||||
|
*
|
||||||
|
* Only use for cases where the player should be able to move
|
||||||
|
* while waiting for others to finish. Otherwise, use P_DoPlayerExit().
|
||||||
|
*
|
||||||
|
* In single player or if ::cv_exitmove is disabled, this will also cause
|
||||||
|
* P_PlayerThink() to call P_DoPlayerExit(), so you do not need to
|
||||||
|
* make a special cases for those.
|
||||||
|
*
|
||||||
|
* \param player The player who finished the level.
|
||||||
|
* \sa P_DoPlayerExit
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void P_DoPlayerFinish(player_t *player)
|
||||||
|
{
|
||||||
|
if (player->pflags & PF_FINISHED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
player->pflags |= PF_FINISHED;
|
||||||
|
|
||||||
|
if (netgame)
|
||||||
|
CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// P_DoPlayerExit
|
// P_DoPlayerExit
|
||||||
//
|
//
|
||||||
|
@ -2168,9 +2192,6 @@ void P_DoPlayerExit(player_t *player)
|
||||||
player->powers[pw_underwater] = 0;
|
player->powers[pw_underwater] = 0;
|
||||||
player->powers[pw_spacetime] = 0;
|
player->powers[pw_spacetime] = 0;
|
||||||
P_RestoreMusic(player);
|
P_RestoreMusic(player);
|
||||||
|
|
||||||
if (playeringame[player-players] && netgame && !circuitmap)
|
|
||||||
CONS_Printf(M_GetText("%s has completed the level.\n"), player_names[player-players]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SPACESPECIAL 12
|
#define SPACESPECIAL 12
|
||||||
|
@ -11417,6 +11438,14 @@ void P_PlayerThink(player_t *player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (player->pflags & PF_FINISHED)
|
||||||
|
{
|
||||||
|
if (cv_exitmove.value && !G_EnoughPlayersFinished())
|
||||||
|
player->exiting = 0;
|
||||||
|
else
|
||||||
|
P_DoPlayerExit(player);
|
||||||
|
}
|
||||||
|
|
||||||
// check water content, set stuff in mobj
|
// check water content, set stuff in mobj
|
||||||
P_MobjCheckWater(player->mo);
|
P_MobjCheckWater(player->mo);
|
||||||
|
|
||||||
|
|
|
@ -2106,7 +2106,7 @@ static void ST_drawTextHUD(void)
|
||||||
textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game"))
|
textHUDdraw(M_GetText("\x82""FIRE:""\x80 Enter game"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gametype == GT_COOP && (!stplyr->spectator || (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))) && stplyr->exiting)
|
if (gametype == GT_COOP && (!stplyr->spectator || (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap))) && (stplyr->exiting || (stplyr->pflags & PF_FINISHED)))
|
||||||
{
|
{
|
||||||
UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value);
|
UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value);
|
||||||
if (numneeded)
|
if (numneeded)
|
||||||
|
@ -2121,7 +2121,7 @@ static void ST_drawTextHUD(void)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
total++;
|
total++;
|
||||||
if (players[i].exiting)
|
if (players[i].exiting || (players[i].pflags & PF_FINISHED))
|
||||||
exiting++;
|
exiting++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue