cmd/demo: add demo_num argument

This commit is contained in:
Marcin Kurczewski 2024-12-28 16:33:12 +01:00
parent f8bda9ed08
commit 26d1e0b01c
22 changed files with 95 additions and 33 deletions

View file

@ -732,6 +732,7 @@
"OSD_GIVE_ITEM_CHEAT": "Lara's backpack just got way heavier!",
"OSD_HEAL_ALREADY_FULL_HP": "Lara's already at full health",
"OSD_HEAL_SUCCESS": "Healed Lara back to full health",
"OSD_INVALID_DEMO": "Invalid demo",
"OSD_INVALID_ITEM": "Unknown item: %s",
"OSD_INVALID_LEVEL": "Invalid level",
"OSD_INVALID_OBJECT": "Invalid object",

View file

@ -220,6 +220,7 @@
"OSD_GIVE_ITEM_CHEAT": "Lara's backpack just got way heavier!",
"OSD_HEAL_ALREADY_FULL_HP": "Lara's already at full health",
"OSD_HEAL_SUCCESS": "Healed Lara back to full health",
"OSD_INVALID_DEMO": "Invalid demo",
"OSD_INVALID_ITEM": "Unknown item: %s",
"OSD_INVALID_LEVEL": "Invalid level",
"OSD_INVALID_OBJECT": "Invalid object",

View file

@ -299,6 +299,7 @@
"OSD_GIVE_ITEM_CHEAT": "Lara's backpack just got way heavier!",
"OSD_HEAL_ALREADY_FULL_HP": "Lara's already at full health",
"OSD_HEAL_SUCCESS": "Healed Lara back to full health",
"OSD_INVALID_DEMO": "Invalid demo",
"OSD_INVALID_ITEM": "Unknown item: %s",
"OSD_INVALID_LEVEL": "Invalid level",
"OSD_INVALID_OBJECT": "Invalid object",

View file

@ -460,6 +460,7 @@
"OSD_GIVE_ITEM_CHEAT": "Lara's backpack just got way heavier!",
"OSD_HEAL_ALREADY_FULL_HP": "Lara's already at full health",
"OSD_HEAL_SUCCESS": "Healed Lara back to full health",
"OSD_INVALID_DEMO": "Invalid demo",
"OSD_INVALID_ITEM": "Unknown item: %s",
"OSD_INVALID_LEVEL": "Invalid level",
"OSD_INVALID_OBJECT": "Invalid object",

View file

@ -1,5 +1,6 @@
## [Unreleased](https://github.com/LostArtefacts/TRX/compare/tr1-4.7.1...develop) - ××××-××-××
- added an option for pickup aids, which will show an intermittent twinkle when Lara is nearby pickup items (#2076)
- added an optional demo number argument to the `/demo` command
- changed demo to be interrupted only by esc or action keys
- fixed being unable to load some old custom levels that contain certain (invalid) floor data (#2114, regression from 4.3)
- fixed a desync in the Lost Valley demo if responsive swim cancellation was enabled (#2113, regression from 4.6)

View file

@ -66,7 +66,8 @@ Currently supported commands:
Saves the game to the specified savegame slot.
- `/demo`
Starts the demo.
`/demo {num}`
Starts the specified demo. If no number is chosen, the demos will cycle.
- `/title`
Exits the game to main screen.

View file

@ -8,6 +8,7 @@
- added an optional fix for drawing a free flare during the underwater pickup animation (#2123)
- added an optional fix for Lara drifting into walls when collecting underwater items (#2096)
- added an option to control how music is played while underwater (#1937)
- added an optional demo number argument to the `/demo` command
- changed demo to be interrupted only by esc or action keys
- fixed Lara prioritising throwing a spent flare while mid-air, so to avoid missing ledge grabs (#1989)
- fixed Lara at times not being able to jump immediately after going from her walking to running animation (#1587)

View file

@ -52,7 +52,8 @@ Currently supported commands:
Saves the game to the specified savegame slot.
- `/demo`
Starts the demo.
`/demo {num}`
Starts the specified demo. If no number is chosen, the demos will cycle.
- `/title`
Exits the game to main screen.

View file

@ -1,5 +1,6 @@
#include "game/console/cmd/play_demo.h"
#include "game/game_string.h"
#include "game/gameflow/common.h"
#include "strings.h"
@ -7,12 +8,26 @@ static COMMAND_RESULT M_Entrypoint(const COMMAND_CONTEXT *ctx);
static COMMAND_RESULT M_Entrypoint(const COMMAND_CONTEXT *const ctx)
{
if (!String_IsEmpty(ctx->args)) {
int32_t demo_to_load = -1;
if (String_ParseInteger(ctx->args, &demo_to_load)) {
demo_to_load--;
if (demo_to_load >= 0 && demo_to_load < Gameflow_GetDemoCount()) {
Gameflow_OverrideCommand((GAMEFLOW_COMMAND) {
.action = GF_START_DEMO,
.param = demo_to_load,
});
return CR_SUCCESS;
} else {
Console_Log(GS(OSD_INVALID_DEMO));
return CR_FAILURE;
}
} else if (String_IsEmpty(ctx->args)) {
Gameflow_OverrideCommand(
(GAMEFLOW_COMMAND) { .action = GF_START_DEMO, .param = -1 });
return CR_SUCCESS;
} else {
return CR_BAD_INVOCATION;
}
Gameflow_OverrideCommand((GAMEFLOW_COMMAND) { .action = GF_START_DEMO });
return CR_SUCCESS;
}
CONSOLE_COMMAND g_Console_Cmd_PlayDemo = {

View file

@ -33,6 +33,7 @@ GS_DEFINE(OSD_POS_SET_ITEM, "Teleported to object: %s")
GS_DEFINE(OSD_POS_SET_ITEM_FAIL, "Failed to teleport to object: %s")
GS_DEFINE(OSD_INVALID_LEVEL, "Invalid level")
GS_DEFINE(OSD_PLAY_LEVEL, "Loading %s")
GS_DEFINE(OSD_INVALID_DEMO, "Invalid demo")
GS_DEFINE(OSD_LOAD_GAME, "Loaded game from save slot %d")
GS_DEFINE(OSD_LOAD_GAME_FAIL_UNAVAILABLE_SLOT, "Save slot %d is not available")
GS_DEFINE(OSD_LOAD_GAME_FAIL_INVALID_SLOT, "Invalid save slot %d")

View file

@ -3,6 +3,7 @@
#include "./types.h"
extern int32_t Gameflow_GetLevelCount(void);
extern int32_t Gameflow_GetDemoCount(void);
extern const char *Gameflow_GetLevelFileName(int32_t level_num);
extern const char *Gameflow_GetLevelTitle(int32_t level_num);
extern int32_t Gameflow_GetGymLevelNumber(void);

View file

@ -1374,6 +1374,18 @@ int32_t Gameflow_GetLevelCount(void)
return g_GameFlow.level_count;
}
int32_t Gameflow_GetDemoCount(void)
{
int32_t demo_count = 0;
for (int32_t i = g_GameFlow.first_level_num; i <= g_GameFlow.last_level_num;
i++) {
if (g_GameFlow.levels[i].demo) {
demo_count++;
}
}
return demo_count;
}
const char *Gameflow_GetLevelFileName(int32_t level_num)
{
return g_GameFlow.levels[level_num].level_file;

View file

@ -58,7 +58,7 @@ static int32_t m_DemoLevel = -1;
static uint32_t *m_DemoPtr = NULL;
static bool M_ProcessInput(void);
static int32_t M_ChooseLevel(void);
static int32_t M_ChooseLevel(int32_t demo_num);
static void M_PrepareConfig(void);
static void M_RestoreConfig(void);
static void M_PrepareResumeInfo(void);
@ -131,10 +131,10 @@ static bool M_ProcessInput(void)
return true;
}
static int32_t M_ChooseLevel(void)
static int32_t M_ChooseLevel(const int32_t demo_num)
{
bool any_demos = false;
for (int i = g_GameFlow.first_level_num; i < g_GameFlow.last_level_num;
for (int32_t i = g_GameFlow.first_level_num; i <= g_GameFlow.last_level_num;
i++) {
if (g_GameFlow.levels[i].demo) {
any_demos = true;
@ -144,6 +144,21 @@ static int32_t M_ChooseLevel(void)
return -1;
}
if (demo_num >= 0) {
int32_t j = 0;
for (int32_t i = g_GameFlow.first_level_num;
i <= g_GameFlow.last_level_num; i++) {
if (g_GameFlow.levels[i].demo) {
if (j == demo_num) {
return i;
}
j++;
}
}
return -1;
}
// pick the next demo
int16_t level_num = m_DemoLevel;
do {
level_num++;
@ -218,7 +233,7 @@ static void M_Start(const PHASE_DEMO_ARGS *const args)
return;
}
m_DemoLevel = M_ChooseLevel();
m_DemoLevel = M_ChooseLevel(args != NULL ? args->demo_num : -1);
if (m_DemoLevel == -1) {
m_State = STATE_INVALID;
return;

View file

@ -3,6 +3,7 @@
#include "game/phase/phase.h"
typedef struct {
int32_t demo_num;
bool resume_existing;
} PHASE_DEMO_ARGS;

View file

@ -239,7 +239,7 @@ static PHASE_CONTROL Inv_Close(GAME_OBJECT_ID inv_chosen)
if (m_StartDemo) {
return (PHASE_CONTROL) {
.end = true,
.command = { .action = GF_START_DEMO },
.command = { .action = GF_START_DEMO, .param = -1 },
};
}

View file

@ -13,6 +13,7 @@
#include "game/option.h"
#include "game/output.h"
#include "game/phase/phase.h"
#include "game/phase/phase_demo.h"
#include "game/savegame.h"
#include "game/screen.h"
#include "game/sound.h"
@ -172,10 +173,13 @@ void Shell_Main(void)
command = GameFlow_InterpretSequence(command.param, GFL_CUTSCENE);
break;
case GF_START_DEMO:
Phase_Set(PHASE_DEMO, NULL);
case GF_START_DEMO: {
PHASE_DEMO_ARGS *const args = Memory_Alloc(sizeof(PHASE_DEMO_ARGS));
args->demo_num = command.param;
Phase_Set(PHASE_DEMO, args);
command = Phase_Run();
break;
}
case GF_LEVEL_COMPLETE:
command = (GAMEFLOW_COMMAND) { .action = GF_EXIT_TO_TITLE };

View file

@ -84,7 +84,7 @@ int16_t TitleSequence(void)
}
if (dir == GFD_START_DEMO) {
return GFD_START_DEMO;
return GFD_START_DEMO | 0xFF;
}
if (g_Inv_Chosen == O_PHOTO_OPTION) {

View file

@ -3,9 +3,7 @@
#include "game/input.h"
#include "global/vars.h"
#include <libtrx/log.h>
static int32_t m_DemoLevel = 0;
static int32_t m_DemoIdx = 0;
static INPUT_STATE m_OldDemoInputDB = { 0 };
static int32_t M_GetNextLevel(void);
@ -15,20 +13,23 @@ static int32_t M_GetNextLevel(void)
if (g_GameFlow.num_demos <= 0) {
return -1;
}
if (m_DemoLevel >= g_GameFlow.num_demos) {
m_DemoLevel = 0;
}
const int32_t level_num = g_GF_ValidDemos[m_DemoLevel];
m_DemoLevel++;
const int32_t level_num = g_GF_ValidDemos[m_DemoIdx];
m_DemoIdx++;
m_DemoIdx %= g_GameFlow.num_demos;
return level_num;
}
int32_t Demo_ChooseLevel(int32_t level_num)
int32_t Demo_ChooseLevel(int32_t demo_num)
{
if (level_num < 0) {
level_num = M_GetNextLevel();
if (demo_num < 0) {
return M_GetNextLevel();
} else if (g_GameFlow.num_demos <= 0) {
return -1;
} else if (demo_num < 0 || demo_num >= g_GameFlow.num_demos) {
return -1;
} else {
return g_GF_ValidDemos[demo_num];
}
return level_num;
}
bool Demo_GetInput(void)

View file

@ -8,8 +8,6 @@ GS_DEFINE(OSD_FLIPMAP_OFF, "Flipmap set to OFF")
GS_DEFINE(OSD_FLIPMAP_FAIL_ALREADY_ON, "Flipmap is already ON")
GS_DEFINE(OSD_FLIPMAP_FAIL_ALREADY_OFF, "Flipmap is already OFF")
GS_DEFINE(OSD_COMPLETE_LEVEL, "Level complete!")
GS_DEFINE(OSD_PLAY_LEVEL, "Loading %s")
GS_DEFINE(OSD_INVALID_LEVEL, "Invalid level")
GS_DEFINE(OSD_INVALID_SAVE_SLOT, "Invalid save slot %d")
GS_DEFINE(OSD_DOOR_OPEN, "Open Sesame!")
GS_DEFINE(OSD_DOOR_CLOSE, "Close Sesame!")

View file

@ -651,10 +651,9 @@ void GF_ModifyInventory(const int32_t level, const int32_t type)
}
}
GAME_FLOW_DIR GF_StartDemo(int32_t level_num)
GAME_FLOW_DIR GF_StartDemo(const int32_t level_num)
{
level_num = Demo_ChooseLevel(level_num);
if (level_num == -1) {
if (level_num < 0) {
return GFD_EXIT_TO_TITLE;
}
PHASE *const demo_phase = Phase_Demo_Create(level_num);

View file

@ -221,6 +221,11 @@ int32_t Gameflow_GetLevelCount(void)
return g_GameflowNew.level_count;
}
int32_t Gameflow_GetDemoCount(void)
{
return g_GameFlow.num_demos;
}
const char *Gameflow_GetLevelFileName(int32_t level_num)
{
return g_GF_LevelFileNames[level_num];
@ -253,7 +258,7 @@ void Gameflow_OverrideCommand(const GAMEFLOW_COMMAND command)
g_GF_OverrideDir = GFD_START_FMV;
break;
case GF_START_DEMO:
g_GF_OverrideDir = GFD_START_DEMO;
g_GF_OverrideDir = GFD_START_DEMO | (command.param & 0xFF);
break;
case GF_EXIT_TO_TITLE:
g_GF_OverrideDir = GFD_EXIT_TO_TITLE;

View file

@ -409,7 +409,9 @@ void Shell_Main(void)
break;
case GFD_START_DEMO:
gf_option = GF_DoLevelSequence(Demo_ChooseLevel(-1), GFL_DEMO);
const int32_t level_num = Demo_ChooseLevel((int8_t)gf_param);
gf_option = level_num >= 0 ? GF_DoLevelSequence(level_num, GFL_DEMO)
: GFD_EXIT_TO_TITLE;
break;
case GFD_LEVEL_COMPLETE: