Merge branch 'failed-level-lua' into 'next'

[SUGOI] Make stagefailed more useful, add linedef executor to toggle, and expose to Lua

Closes #361

See merge request STJr/SRB2!1463
This commit is contained in:
SteelT 2021-05-28 21:51:00 -04:00
commit 2cb920a5a6
6 changed files with 112 additions and 42 deletions

View file

@ -496,7 +496,7 @@ extern UINT32 lastcustomtol;
extern tic_t totalplaytime;
extern UINT8 stagefailed;
extern boolean stagefailed;
// Emeralds stored as bits to throw savegame hackers off.
extern UINT16 emeralds;

View file

@ -169,7 +169,7 @@ static boolean exitgame = false;
static boolean retrying = false;
static boolean retryingmodeattack = false;
UINT8 stagefailed; // Used for GEMS BONUS? Also to see if you beat the stage.
boolean stagefailed = false; // Used for GEMS BONUS? Also to see if you beat the stage.
UINT16 emeralds;
INT32 luabanks[NUM_LUABANKS];
@ -3743,7 +3743,7 @@ static void G_UpdateVisited(void)
// Update visitation flags?
if ((!modifiedgame || savemoddata) // Not modified
&& !multiplayer && !demoplayback && (gametype == GT_COOP) // SP/RA/NiGHTS mode
&& !(spec && stagefailed)) // Not failed the special stage
&& !stagefailed) // Did not fail the stage
{
UINT8 earnedEmblems;
@ -3964,7 +3964,7 @@ static void G_DoCompleted(void)
// If the current gametype has no intermission screen set, then don't start it.
Y_DetermineIntermissionType();
if ((skipstats && !modeattacking) || (spec && modeattacking && stagefailed) || (intertype == int_none))
if ((skipstats && !modeattacking) || (modeattacking && stagefailed) || (intertype == int_none))
{
G_UpdateVisited();
G_HandleSaveLevel();
@ -3996,8 +3996,15 @@ void G_AfterIntermission(void)
HU_ClearCEcho();
if ((gametyperules & GTR_CUTSCENES) && mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene.
if ((gametyperules & GTR_CUTSCENES) && mapheaderinfo[gamemap-1]->cutscenenum
&& !modeattacking
&& skipstats <= 1
&& (gamecomplete || !(marathonmode & MA_NOCUTSCENES))
&& stagefailed == false)
{
// Start a custom cutscene.
F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false);
}
else
{
if (nextmap < 1100-1)

View file

@ -380,6 +380,9 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word, "gamestate")) {
lua_pushinteger(L, gamestate);
return 1;
} else if (fastcmp(word, "stagefailed")) {
lua_pushboolean(L, stagefailed);
return 1;
}
return 0;
}
@ -429,6 +432,8 @@ int LUA_CheckGlobals(lua_State *L, const char *word)
}
else if (fastcmp(word, "mapmusflags"))
mapmusflags = (UINT16)luaL_checkinteger(L, 2);
else if (fastcmp(word, "stagefailed"))
stagefailed = luaL_checkboolean(L, 2);
else
return 0;

View file

@ -3443,8 +3443,10 @@ static void P_InitLevelSettings(void)
numstarposts = 0;
ssspheres = timeinmap = 0;
// special stage
stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial
// Assume Special Stages were failed in unless proven otherwise - via P_GiveEmerald or emerald touchspecial
// Normal stages will default to be OK, until a Lua script / linedef executor says otherwise.
stagefailed = G_IsSpecialStage(gamemap);
// Reset temporary record data
memset(&ntemprecords, 0, sizeof(nightsdata_t));

View file

@ -3902,6 +3902,21 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
}
break;
case 466: // Set level failure state
{
if (line->flags & ML_NOCLIMB)
{
stagefailed = false;
CONS_Debug(DBG_GAMELOGIC, "Stage can be completed successfully!\n");
}
else
{
stagefailed = true;
CONS_Debug(DBG_GAMELOGIC, "Stage will end in failure...\n");
}
}
break;
case 480: // Polyobj_DoorSlide
case 481: // Polyobj_DoorSwing
PolyDoor(line);

View file

@ -1330,24 +1330,40 @@ void Y_StartIntermission(void)
usetile = false;
// set up the "got through act" message according to skin name
// too long so just show "YOU GOT THROUGH THE ACT"
if (strlen(skins[players[consoleplayer].skin].realname) > 13)
if (stagefailed)
{
strcpy(data.coop.passed1, "you got");
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act");
strcpy(data.coop.passed1, mapheaderinfo[gamemap-1]->lvlttl);
if (mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)
{
data.spec.passed2[0] = '\0';
}
else
{
strcpy(data.coop.passed2, "Zone");
}
}
// long enough that "X GOT" won't fit so use "X PASSED THE ACT"
else if (strlen(skins[players[consoleplayer].skin].realname) > 8)
{
strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "passed act" : "passed the act");
}
// length is okay for normal use
else
{
snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s got",
skins[players[consoleplayer].skin].realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act");
// too long so just show "YOU GOT THROUGH THE ACT"
if (strlen(skins[players[consoleplayer].skin].realname) > 13)
{
strcpy(data.coop.passed1, "you got");
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act");
}
// long enough that "X GOT" won't fit so use "X PASSED THE ACT"
else if (strlen(skins[players[consoleplayer].skin].realname) > 8)
{
strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "passed act" : "passed the act");
}
// length is okay for normal use
else
{
snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s got",
skins[players[consoleplayer].skin].realname);
strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act");
}
}
// set X positions
@ -1364,6 +1380,13 @@ void Y_StartIntermission(void)
// The above value is not precalculated because it needs only be computed once
// at the start of intermission, and precalculating it would preclude mods
// changing the font to one of a slightly different width.
if ((stagefailed) && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
{
// Bit of a hack, offset so that the "Zone" text is right aligned like title cards.
data.coop.passedx2 = (data.coop.passedx1 + V_LevelNameWidth(data.coop.passed1)) - V_LevelNameWidth(data.coop.passed2);
}
break;
}
@ -1784,21 +1807,30 @@ static void Y_SetTimeBonus(player_t *player, y_bonus_t *bstruct)
strncpy(bstruct->patch, "YB_TIME", sizeof(bstruct->patch));
bstruct->display = true;
// calculate time bonus
secs = player->realtime / TICRATE;
if (secs < 30) /* :30 */ bonus = 50000;
else if (secs < 60) /* 1:00 */ bonus = 10000;
else if (secs < 90) /* 1:30 */ bonus = 5000;
else if (secs < 120) /* 2:00 */ bonus = 4000;
else if (secs < 180) /* 3:00 */ bonus = 3000;
else if (secs < 240) /* 4:00 */ bonus = 2000;
else if (secs < 300) /* 5:00 */ bonus = 1000;
else if (secs < 360) /* 6:00 */ bonus = 500;
else if (secs < 420) /* 7:00 */ bonus = 400;
else if (secs < 480) /* 8:00 */ bonus = 300;
else if (secs < 540) /* 9:00 */ bonus = 200;
else if (secs < 600) /* 10:00 */ bonus = 100;
else /* TIME TAKEN: TOO LONG */ bonus = 0;
if (stagefailed == true)
{
// Time Bonus would be very easy to cheese by failing immediately.
bonus = 0;
}
else
{
// calculate time bonus
secs = player->realtime / TICRATE;
if (secs < 30) /* :30 */ bonus = 50000;
else if (secs < 60) /* 1:00 */ bonus = 10000;
else if (secs < 90) /* 1:30 */ bonus = 5000;
else if (secs < 120) /* 2:00 */ bonus = 4000;
else if (secs < 180) /* 3:00 */ bonus = 3000;
else if (secs < 240) /* 4:00 */ bonus = 2000;
else if (secs < 300) /* 5:00 */ bonus = 1000;
else if (secs < 360) /* 6:00 */ bonus = 500;
else if (secs < 420) /* 7:00 */ bonus = 400;
else if (secs < 480) /* 8:00 */ bonus = 300;
else if (secs < 540) /* 9:00 */ bonus = 200;
else if (secs < 600) /* 10:00 */ bonus = 100;
else /* TIME TAKEN: TOO LONG */ bonus = 0;
}
bstruct->points = bonus;
}
@ -1851,12 +1883,21 @@ static void Y_SetGuardBonus(player_t *player, y_bonus_t *bstruct)
strncpy(bstruct->patch, "YB_GUARD", sizeof(bstruct->patch));
bstruct->display = true;
if (player->timeshit == 0) bonus = 10000;
else if (player->timeshit == 1) bonus = 5000;
else if (player->timeshit == 2) bonus = 1000;
else if (player->timeshit == 3) bonus = 500;
else if (player->timeshit == 4) bonus = 100;
else bonus = 0;
if (stagefailed == true)
{
// "No-hit" runs would be very easy to cheese by failing immediately.
bonus = 0;
}
else
{
if (player->timeshit == 0) bonus = 10000;
else if (player->timeshit == 1) bonus = 5000;
else if (player->timeshit == 2) bonus = 1000;
else if (player->timeshit == 3) bonus = 500;
else if (player->timeshit == 4) bonus = 100;
else bonus = 0;
}
bstruct->points = bonus;
}