level: support PC demo levels

This commit is contained in:
Carlo Bramini 2024-05-31 21:49:12 +02:00 committed by GitHub
parent 06fbfab586
commit 3f4b452700
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 454 additions and 150 deletions

View file

@ -0,0 +1,280 @@
{
// NOTE: bad changes to this file may result in crashes.
// Lines starting with double slashes are comments and are ignored.
// path to the main menu background image
"main_menu_picture": "data/images/title.webp",
// path to the savegame file
"savegame_fmt_legacy": "save_demo_pc.%d",
"savegame_fmt_bson": "save_demo_pc_%02d.dat",
"force_game_modes": null,
"force_save_crystals": null,
"demo_delay": 16,
"water_color": [0.45, 1.0, 1.0],
"draw_distance_fade": 22.0,
"draw_distance_max": 30.0,
"injections": [
"data/injections/backpack.bin",
"data/injections/braid.bin",
"data/injections/lara_animations.bin",
"data/injections/lara_jumping.bin",
"data/injections/uzi_sfx.bin",
],
"convert_dropped_guns": false,
"levels": [
// Level 2
{
"title": "City of Vilcabamba",
"file": "data_demo_pc/level2.phd",
"type": "level_demo_pc",
"music": 0,
"injections": [
"data/injections/vilcabamba_itemrots.bin",
"data/injections/vilcabamba_textures.bin",
],
"sequence": [
{"type": "loading_screen", "picture_path": "data/images/peru.webp", "display_time": 5},
{"type": "start_game"},
{"type": "loop_game"},
{"type": "stop_game"},
{"type": "level_stats", "level_id": 0},
{"type": "exit_to_level", "level_id": 1},
],
"strings": {
"key1": "Silver Key",
"puzzle1": "Gold Idol"
},
"demo": true,
},
// Level 3
{
"title": "Title",
"file": "data_demo_pc/title.phd",
"type": "title_demo_pc",
"music": 0,
"inherit_injections": false,
"injections": [
"data/injections/pda_model.bin",
],
"sequence": [
{"type": "exit_to_title"},
],
"strings": {},
},
// Level 4
{
"title": "Current Position",
"file": "data/current.phd",
"type": "current",
"music": 0,
"inherit_injections": false,
"sequence": [
{"type": "exit_to_title"},
],
"strings": {},
},
],
"strings": {
"HEADING_INVENTORY": "INVENTORY",
"HEADING_GAME_OVER": "GAME OVER",
"HEADING_OPTION": "OPTION",
"HEADING_ITEMS": "ITEMS",
"PASSPORT_SELECT_LEVEL": "Select Level",
"PASSPORT_RESTART_LEVEL": "Restart Level",
"PASSPORT_STORY_SO_FAR": "Story so far...",
"PASSPORT_LEGACY_SELECT_LEVEL_1": "Legacy saves do not",
"PASSPORT_LEGACY_SELECT_LEVEL_2": "support this feature.",
"PASSPORT_SELECT_MODE": "Select Mode",
"PASSPORT_MODE_NEW_GAME": "New Game",
"PASSPORT_MODE_NEW_GAME_PLUS": "New Game+",
"PASSPORT_MODE_NEW_GAME_JP": "Japanese NG",
"PASSPORT_MODE_NEW_GAME_JP_PLUS": "Japanese NG+",
"PASSPORT_NEW_GAME": "New Game",
"PASSPORT_LOAD_GAME": "Load Game",
"PASSPORT_SAVE_GAME": "Save Game",
"PASSPORT_EXIT_GAME": "Exit Game",
"PASSPORT_EXIT_TO_TITLE": "Exit to Title",
"DETAIL_SELECT_DETAIL": "Select Detail",
"DETAIL_LEVEL_HIGH": "High",
"DETAIL_LEVEL_MEDIUM": "Medium",
"DETAIL_LEVEL_LOW": "Low",
"DETAIL_FPS": "FPS",
"DETAIL_PERSPECTIVE": "Perspective",
"DETAIL_BILINEAR": "Bilinear",
"DETAIL_TEXTURE_FILTER": "Texture filter",
"DETAIL_FBO_FILTER": "FBO filter",
"DETAIL_VSYNC": "VSync",
"DETAIL_BRIGHTNESS": "Brightness",
"DETAIL_UI_TEXT_SCALE": "UI text scale",
"DETAIL_UI_BAR_SCALE": "UI bar scale",
"DETAIL_RENDER_MODE": "Render mode",
"DETAIL_RENDER_MODE_LEGACY": "Window size",
"DETAIL_RENDER_MODE_FBO": "Framebuffer",
"DETAIL_RESOLUTION": "Resolution",
"DETAIL_DECIMAL_FMT": "%d",
"DETAIL_STRING_FMT": "%s",
"DETAIL_FLOAT_FMT": "%.1f",
"DETAIL_RESOLUTION_FMT": "%dx%d",
"SOUND_SET_VOLUMES": "Set Volumes",
"CONTROL_CUSTOMIZE": "Customize Controls",
"CONTROL_KEYBOARD": "Keyboard",
"CONTROL_CONTROLLER": "Controller",
"CONTROL_DEFAULT_KEYS": "Default Keys",
"CONTROL_CUSTOM_1": "Custom Scheme 1",
"CONTROL_CUSTOM_2": "Custom Scheme 2",
"CONTROL_CUSTOM_3": "Custom Scheme 3",
"CONTROL_RESET_DEFAULTS_KEY": "Reset All: Hold R",
"CONTROL_UNBIND_KEY": "Unbind: Hold Backspace",
"CONTROL_RESET_DEFAULTS_BTN": "Reset All: Hold %s",
"CONTROL_UNBIND_BTN": "Unbind: Hold %s",
"KEYMAP_RUN": "Run",
"KEYMAP_BACK": "Back",
"KEYMAP_LEFT": "Left",
"KEYMAP_RIGHT": "Right",
"KEYMAP_STEP_LEFT": "Step Left",
"KEYMAP_STEP_RIGHT": "Step Right",
"KEYMAP_WALK": "Walk",
"KEYMAP_JUMP": "Jump",
"KEYMAP_ACTION": "Action",
"KEYMAP_DRAW_WEAPON": "Draw Weapon",
"KEYMAP_LOOK": "Look",
"KEYMAP_ROLL": "Roll",
"KEYMAP_INVENTORY": "Inventory",
"KEYMAP_PAUSE": "Pause",
"KEYMAP_FLY_CHEAT": "Fly Cheat",
"KEYMAP_ITEM_CHEAT": "Item Cheat",
"KEYMAP_LEVEL_SKIP_CHEAT": "Level Skip",
"KEYMAP_TURBO_CHEAT": "Turbo Speed",
"KEYMAP_ENTER_CONSOLE": "Enter Console",
"KEYMAP_CAMERA_UP": "Camera Up",
"KEYMAP_CAMERA_DOWN": "Camera Down",
"KEYMAP_CAMERA_LEFT": "Camera Left",
"KEYMAP_CAMERA_RIGHT": "Camera Right",
"KEYMAP_CAMERA_RESET": "Reset Camera",
"KEYMAP_EQUIP_PISTOLS": "Equip Pistols",
"KEYMAP_EQUIP_SHOTGUN": "Equip Shotgun",
"KEYMAP_EQUIP_MAGNUMS": "Equip Magnums",
"KEYMAP_EQUIP_UZIS": "Equip Uzis",
"KEYMAP_USE_SMALL_MEDI": "Small Medi",
"KEYMAP_USE_BIG_MEDI": "Large Medi",
"KEYMAP_SAVE": "Quick Save",
"KEYMAP_LOAD": "Quick Load",
"KEYMAP_FPS": "Show FPS",
"KEYMAP_BILINEAR": "Toggle Texture Filter",
"STATS_KILLS_DETAIL_FMT": "KILLS %d of %d",
"STATS_KILLS_BASIC_FMT": "KILLS %d",
"STATS_PICKUPS_DETAIL_FMT": "PICKUPS %d of %d",
"STATS_PICKUPS_BASIC_FMT": "PICKUPS %d",
"STATS_SECRETS_FMT": "SECRETS %d of %d",
"STATS_DEATHS_FMT": "DEATHS %d",
"STATS_TIME_TAKEN_FMT": "TIME TAKEN %s",
"STATS_FINAL_STATISTICS": "Final Statistics",
"STATS_BONUS_STATISTICS": "Bonus Statistics",
"PAUSE_PAUSED": "Paused",
"PAUSE_EXIT_TO_TITLE": "Exit to title?",
"PAUSE_CONTINUE": "Continue",
"PAUSE_QUIT": "Quit",
"PAUSE_ARE_YOU_SURE": "Are you sure?",
"PAUSE_YES": "Yes",
"PAUSE_NO": "No",
"MISC_ON": "On",
"MISC_OFF": "Off",
"MISC_EMPTY_SLOT_FMT": "- EMPTY SLOT %d -",
"MISC_DEMO_MODE": "Demo Mode",
"INV_ITEM_MEDI": "Small Medi Pack",
"INV_ITEM_BIG_MEDI": "Large Medi Pack",
"INV_ITEM_PUZZLE1": "Puzzle",
"INV_ITEM_PUZZLE2": "Puzzle",
"INV_ITEM_PUZZLE3": "Puzzle",
"INV_ITEM_PUZZLE4": "Puzzle",
"INV_ITEM_KEY1": "Key",
"INV_ITEM_KEY2": "Key",
"INV_ITEM_KEY3": "Key",
"INV_ITEM_KEY4": "Key",
"INV_ITEM_PICKUP1": "Pickup",
"INV_ITEM_PICKUP2": "Pickup",
"INV_ITEM_LEADBAR": "Lead Bar",
"INV_ITEM_SCION": "Scion",
"INV_ITEM_PISTOLS": "Pistols",
"INV_ITEM_SHOTGUN": "Shotgun",
"INV_ITEM_MAGNUM": "Magnums",
"INV_ITEM_UZI": "Uzis",
"INV_ITEM_GRENADE": "Grenade",
"INV_ITEM_PISTOL_AMMO": "Pistol Clips",
"INV_ITEM_SHOTGUN_AMMO": "Shotgun Shells",
"INV_ITEM_MAGNUM_AMMO": "Magnum Clips",
"INV_ITEM_UZI_AMMO": "Uzi Clips",
"INV_ITEM_COMPASS": "Compass",
"INV_ITEM_GAME": "Game",
"INV_ITEM_DETAILS": "Detail Levels",
"INV_ITEM_SOUND": "Sound",
"INV_ITEM_CONTROLS": "Controls",
"INV_ITEM_LARAS_HOME": "Lara's Home",
"OSD_FLY_MODE_ON": "Fly mode enabled",
"OSD_FLY_MODE_OFF": "Fly mode disabled",
"OSD_FPS_GET": "FPS currently set to %d",
"OSD_FPS_SET": "FPS set to %d",
"OSD_POS_GET": "Room: %d\nPosition: %.3f, %.3f, %.3f\nRotation: %.3f,%.3f,%.3f",
"OSD_POS_SET_POS": "Teleported to position: %.3f %.3f %.3f",
"OSD_POS_SET_POS_FAIL": "Failed to teleport to position: %.3f %.3f %.3f",
"OSD_POS_SET_ROOM": "Teleported to room: %d",
"OSD_POS_SET_ROOM_FAIL": "Failed to teleport to room: %d",
"OSD_POS_SET_ITEM": "Teleported to object: %s",
"OSD_POS_SET_ITEM_FAIL": "Failed to teleport to object: %s",
"OSD_SPEED_GET": "Current speed: %d",
"OSD_SPEED_SET": "Speed set to %d",
"OSD_BRAID_ON": "Braid enabled",
"OSD_BRAID_OFF": "Braid disabled",
"OSD_VSYNC_ON": "VSync enabled",
"OSD_VSYNC_OFF": "VSync disabled",
"OSD_CHEATS_ON": "Cheats enabled",
"OSD_CHEATS_OFF": "Cheats disabled",
"OSD_GIVE_ITEM": "Added %s to Lara's inventory",
"OSD_GIVE_ITEM_ALL_KEYS": "Surprise! Every key item Lara needs is now in her backpack.",
"OSD_GIVE_ITEM_ALL_GUNS": "Lock'n'load - Lara's armed to the teeth!",
"OSD_GIVE_ITEM_CHEAT": "Lara's backpack just got way heavier!",
"OSD_FLIPMAP_ON": "Flipmap set to ON",
"OSD_FLIPMAP_OFF": "Flipmap set to OFF",
"OSD_FLIPMAP_FAIL_ALREADY_ON": "Flipmap is already ON",
"OSD_FLIPMAP_FAIL_ALREADY_OFF": "Flipmap is already OFF",
"OSD_KILL_ALL": "Poof! %d enemies gone!",
"OSD_KILL_ALL_FAIL": "Uh-oh, there are no enemies left to kill...",
"OSD_KILL": "Bye-bye!",
"OSD_KILL_FAIL": "No enemy nearby...",
"OSD_COMPLETE_LEVEL": "Level complete!",
"OSD_PLAY_LEVEL": "Loading %s",
"OSD_TEXTURE_FILTER_SET": "Texture filter set to %s",
"OSD_TEXTURE_FILTER_NN": "nearest-neighbor",
"OSD_TEXTURE_FILTER_BILINEAR": "bilinear",
"OSD_PERSPECTIVE_FILTER_ON": "Perspective filter enabled",
"OSD_PERSPECTIVE_FILTER_OFF": "Perspective filter disabled",
"OSD_FPS_COUNTER_ON": "FPS counter enabled",
"OSD_FPS_COUNTER_OFF": "FPS counter disabled",
"OSD_UNAVAILABLE_ITEM": "%s is not currently available",
"OSD_INVALID_ITEM": "Unknown item: %s",
"OSD_INVALID_ROOM": "Invalid room: %d. Valid rooms are 0-%d",
"OSD_INVALID_LEVEL": "Invalid level",
"OSD_UNKNOWN_COMMAND": "Unknown command: %s",
"OSD_COMMAND_BAD_INVOCATION": "Invalid invocation: %s",
"OSD_COMMAND_UNAVAILABLE": "This command is not currently available",
"OSD_DOOR_OPEN": "Open Sesame!",
"OSD_DOOR_CLOSE": "Close Sesame!",
"OSD_DOOR_OPEN_FAIL": "No doors in Lara's proximity",
"OSD_LOAD_GAME": "Loaded game from save slot %d",
"OSD_LOAD_GAME_FAIL_UNAVAILABLE_SLOT": "Save slot %d is not available",
"OSD_LOAD_GAME_FAIL_INVALID_SLOT": "Invalid save slot %d",
"OSD_SAVE_GAME": "Save game to save slot %d",
"OSD_SAVE_GAME_FAIL": "Cannot save the game in the current state",
"OSD_SAVE_GAME_FAIL_INVALID_SLOT": "Invalid save slot %d",
"OSD_CURRENT_HEALTH_GET": "Current Lara's health: %d",
"OSD_CURRENT_HEALTH_SET": "Lara's health set to %d",
"OSD_HEAL_ALREADY_FULL_HP": "Lara's already at full health",
"OSD_HEAL_SUCCESS": "Healed Lara back to full health",
},
}

View file

@ -23,6 +23,11 @@
#include <string.h>
typedef struct STRING_TO_ENUM_TYPE {
const char *str;
const int32_t val;
} STRING_TO_ENUM_TYPE;
typedef struct GAMEFLOW_DISPLAY_PICTURE_DATA {
char *path;
double display_time;
@ -41,6 +46,8 @@ typedef struct GAMEFLOW_GIVE_ITEM_DATA {
GAMEFLOW g_GameFlow = { 0 };
static int32_t GameFlow_StringToEnumType(
const char *const str, const STRING_TO_ENUM_TYPE *map);
static TRISTATE_BOOL GameFlow_ReadTristateBool(
struct json_object_s *obj, const char *key);
static bool GameFlow_LoadScriptMeta(struct json_object_s *obj);
@ -51,6 +58,60 @@ static bool GameFlow_LoadLevelSequence(
static bool GameFlow_LoadScriptLevels(struct json_object_s *obj);
static bool GameFlow_LoadFromFileImpl(const char *file_name);
static const STRING_TO_ENUM_TYPE m_GameflowLevelTypeEnumMap[] = {
{ "title", GFL_TITLE },
{ "normal", GFL_NORMAL },
{ "cutscene", GFL_CUTSCENE },
{ "gym", GFL_GYM },
{ "current", GFL_CURRENT },
{ "bonus", GFL_BONUS },
{ "title_demo_pc", GFL_TITLE_DEMO_PC },
{ "level_demo_pc", GFL_LEVEL_DEMO_PC },
{ NULL, -1 },
};
static const STRING_TO_ENUM_TYPE m_GameflowSeqTypeEnumMap[] = {
{ "start_game", GFS_START_GAME },
{ "stop_game", GFS_STOP_GAME },
{ "loop_game", GFS_LOOP_GAME },
{ "start_cine", GFS_START_CINE },
{ "loop_cine", GFS_LOOP_CINE },
{ "play_fmv", GFS_PLAY_FMV },
{ "loading_screen", GFS_LOADING_SCREEN },
{ "display_picture", GFS_DISPLAY_PICTURE },
{ "level_stats", GFS_LEVEL_STATS },
{ "total_stats", GFS_TOTAL_STATS },
{ "exit_to_title", GFS_EXIT_TO_TITLE },
{ "exit_to_level", GFS_EXIT_TO_LEVEL },
{ "exit_to_cine", GFS_EXIT_TO_CINE },
{ "set_cam_x", GFS_SET_CAM_X },
{ "set_cam_y", GFS_SET_CAM_Y },
{ "set_cam_z", GFS_SET_CAM_Z },
{ "set_cam_angle", GFS_SET_CAM_ANGLE },
{ "flip_map", GFS_FLIP_MAP },
{ "remove_guns", GFS_REMOVE_GUNS },
{ "remove_scions", GFS_REMOVE_SCIONS },
{ "remove_ammo", GFS_REMOVE_AMMO },
{ "remove_medipacks", GFS_REMOVE_MEDIPACKS },
{ "give_item", GFS_GIVE_ITEM },
{ "play_synced_audio", GFS_PLAY_SYNCED_AUDIO },
{ "mesh_swap", GFS_MESH_SWAP },
{ "setup_bacon_lara", GFS_SETUP_BACON_LARA },
{ NULL, -1 },
};
static int32_t GameFlow_StringToEnumType(
const char *const str, const STRING_TO_ENUM_TYPE *map)
{
while (map->str) {
if (!strcmp(str, map->str)) {
break;
}
map++;
}
return map->val;
}
static TRISTATE_BOOL GameFlow_ReadTristateBool(
struct json_object_s *obj, const char *key)
{
@ -232,28 +293,19 @@ static bool GameFlow_LoadLevelSequence(
return false;
}
if (!strcmp(type_str, "start_game")) {
seq->type = GFS_START_GAME;
seq->data = (void *)(intptr_t)level_num;
seq->type =
GameFlow_StringToEnumType(type_str, m_GameflowSeqTypeEnumMap);
} else if (!strcmp(type_str, "stop_game")) {
seq->type = GFS_STOP_GAME;
switch (seq->type) {
case GFS_START_GAME:
case GFS_STOP_GAME:
case GFS_LOOP_GAME:
case GFS_START_CINE:
case GFS_LOOP_CINE:
seq->data = (void *)(intptr_t)level_num;
break;
} else if (!strcmp(type_str, "loop_game")) {
seq->type = GFS_LOOP_GAME;
seq->data = (void *)(intptr_t)level_num;
} else if (!strcmp(type_str, "start_cine")) {
seq->type = GFS_START_CINE;
seq->data = (void *)(intptr_t)level_num;
} else if (!strcmp(type_str, "loop_cine")) {
seq->type = GFS_LOOP_CINE;
seq->data = (void *)(intptr_t)level_num;
} else if (!strcmp(type_str, "play_fmv")) {
seq->type = GFS_PLAY_FMV;
case GFS_PLAY_FMV: {
const char *tmp_s = json_object_get_string(
jseq_obj, "fmv_path", JSON_INVALID_STRING);
if (tmp_s == JSON_INVALID_STRING) {
@ -263,16 +315,10 @@ static bool GameFlow_LoadLevelSequence(
return false;
}
seq->data = Memory_DupStr(tmp_s);
} else if (
!strcmp(type_str, "display_picture")
|| !strcmp(type_str, "loading_screen")) {
if (!strcmp(type_str, "loading_screen")) {
seq->type = GFS_LOADING_SCREEN;
} else {
seq->type = GFS_DISPLAY_PICTURE;
}
break;
}
case GFS_LOADING_SCREEN:
case GFS_DISPLAY_PICTURE: {
GAMEFLOW_DISPLAY_PICTURE_DATA *data =
Memory_Alloc(sizeof(GAMEFLOW_DISPLAY_PICTURE_DATA));
@ -297,9 +343,9 @@ static bool GameFlow_LoadLevelSequence(
}
data->display_time = tmp_d;
seq->data = data;
} else if (!strcmp(type_str, "level_stats")) {
seq->type = GFS_LEVEL_STATS;
break;
}
case GFS_LEVEL_STATS: {
int tmp =
json_object_get_int(jseq_obj, "level_id", JSON_INVALID_NUMBER);
if (tmp == JSON_INVALID_NUMBER) {
@ -309,10 +355,9 @@ static bool GameFlow_LoadLevelSequence(
return false;
}
seq->data = (void *)(intptr_t)tmp;
} else if (!strcmp(type_str, "total_stats")) {
seq->type = GFS_TOTAL_STATS;
break;
}
case GFS_TOTAL_STATS: {
GAMEFLOW_DISPLAY_PICTURE_DATA *data =
Memory_Alloc(sizeof(GAMEFLOW_DISPLAY_PICTURE_DATA));
@ -327,12 +372,13 @@ static bool GameFlow_LoadLevelSequence(
data->path = Memory_DupStr(tmp_s);
data->display_time = 0;
seq->data = data;
break;
}
case GFS_EXIT_TO_TITLE:
break;
} else if (!strcmp(type_str, "exit_to_title")) {
seq->type = GFS_EXIT_TO_TITLE;
} else if (!strcmp(type_str, "exit_to_level")) {
seq->type = GFS_EXIT_TO_LEVEL;
case GFS_EXIT_TO_LEVEL:
case GFS_EXIT_TO_CINE: {
int tmp =
json_object_get_int(jseq_obj, "level_id", JSON_INVALID_NUMBER);
if (tmp == JSON_INVALID_NUMBER) {
@ -342,21 +388,12 @@ static bool GameFlow_LoadLevelSequence(
return false;
}
seq->data = (void *)(intptr_t)tmp;
} else if (!strcmp(type_str, "exit_to_cine")) {
seq->type = GFS_EXIT_TO_CINE;
int tmp =
json_object_get_int(jseq_obj, "level_id", JSON_INVALID_NUMBER);
if (tmp == JSON_INVALID_NUMBER) {
LOG_ERROR(
"level %d, sequence %s: 'level_id' must be a number",
level_num, type_str);
return false;
}
seq->data = (void *)(intptr_t)tmp;
} else if (!strcmp(type_str, "set_cam_x")) {
seq->type = GFS_SET_CAM_X;
break;
}
case GFS_SET_CAM_X:
case GFS_SET_CAM_Y:
case GFS_SET_CAM_Z:
case GFS_SET_CAM_ANGLE: {
int tmp =
json_object_get_int(jseq_obj, "value", JSON_INVALID_NUMBER);
if (tmp == JSON_INVALID_NUMBER) {
@ -366,61 +403,16 @@ static bool GameFlow_LoadLevelSequence(
return false;
}
seq->data = (void *)(intptr_t)tmp;
break;
}
case GFS_FLIP_MAP:
case GFS_REMOVE_GUNS:
case GFS_REMOVE_SCIONS:
case GFS_REMOVE_AMMO:
case GFS_REMOVE_MEDIPACKS:
break;
} else if (!strcmp(type_str, "set_cam_y")) {
seq->type = GFS_SET_CAM_Y;
int tmp =
json_object_get_int(jseq_obj, "value", JSON_INVALID_NUMBER);
if (tmp == JSON_INVALID_NUMBER) {
LOG_ERROR(
"level %d, sequence %s: 'value' must be a number",
level_num, type_str);
return false;
}
seq->data = (void *)(intptr_t)tmp;
} else if (!strcmp(type_str, "set_cam_z")) {
seq->type = GFS_SET_CAM_Z;
int tmp =
json_object_get_int(jseq_obj, "value", JSON_INVALID_NUMBER);
if (tmp == JSON_INVALID_NUMBER) {
LOG_ERROR(
"level %d, sequence %s: 'value' must be a number",
level_num, type_str);
return false;
}
seq->data = (void *)(intptr_t)tmp;
} else if (!strcmp(type_str, "set_cam_angle")) {
seq->type = GFS_SET_CAM_ANGLE;
int tmp =
json_object_get_int(jseq_obj, "value", JSON_INVALID_NUMBER);
if (tmp == JSON_INVALID_NUMBER) {
LOG_ERROR(
"level %d, sequence %s: 'value' must be a number",
level_num, type_str);
return false;
}
seq->data = (void *)(intptr_t)tmp;
} else if (!strcmp(type_str, "flip_map")) {
seq->type = GFS_FLIP_MAP;
} else if (!strcmp(type_str, "remove_guns")) {
seq->type = GFS_REMOVE_GUNS;
} else if (!strcmp(type_str, "remove_scions")) {
seq->type = GFS_REMOVE_SCIONS;
} else if (!strcmp(type_str, "remove_ammo")) {
seq->type = GFS_REMOVE_AMMO;
} else if (!strcmp(type_str, "remove_medipacks")) {
seq->type = GFS_REMOVE_MEDIPACKS;
} else if (!strcmp(type_str, "give_item")) {
seq->type = GFS_GIVE_ITEM;
case GFS_GIVE_ITEM: {
GAMEFLOW_GIVE_ITEM_DATA *give_item_data =
Memory_Alloc(sizeof(GAMEFLOW_GIVE_ITEM_DATA));
@ -437,9 +429,9 @@ static bool GameFlow_LoadLevelSequence(
json_object_get_int(jseq_obj, "quantity", 1);
seq->data = give_item_data;
} else if (!strcmp(type_str, "play_synced_audio")) {
seq->type = GFS_PLAY_SYNCED_AUDIO;
break;
}
case GFS_PLAY_SYNCED_AUDIO: {
int tmp =
json_object_get_int(jseq_obj, "audio_id", JSON_INVALID_NUMBER);
if (tmp == JSON_INVALID_NUMBER) {
@ -449,10 +441,9 @@ static bool GameFlow_LoadLevelSequence(
return false;
}
seq->data = (void *)(intptr_t)tmp;
} else if (!strcmp(type_str, "mesh_swap")) {
seq->type = GFS_MESH_SWAP;
break;
}
case GFS_MESH_SWAP: {
GAMEFLOW_MESH_SWAP_DATA *swap_data =
Memory_Alloc(sizeof(GAMEFLOW_MESH_SWAP_DATA));
@ -484,9 +475,9 @@ static bool GameFlow_LoadLevelSequence(
}
seq->data = swap_data;
} else if (!strcmp(type_str, "setup_bacon_lara")) {
seq->type = GFS_SETUP_BACON_LARA;
break;
}
case GFS_SETUP_BACON_LARA: {
int tmp = json_object_get_int(
jseq_obj, "anchor_room", JSON_INVALID_NUMBER);
if (tmp == JSON_INVALID_NUMBER) {
@ -502,16 +493,20 @@ static bool GameFlow_LoadLevelSequence(
return false;
}
seq->data = (void *)(intptr_t)tmp;
break;
}
default:
if (GameFlow_IsLegacySequence(type_str)) {
seq->type = GFS_LEGACY;
LOG_WARNING(
"level %d, sequence %s: legacy type ignored", level_num,
type_str);
} else if (GameFlow_IsLegacySequence(type_str)) {
seq->type = GFS_LEGACY;
LOG_WARNING(
"level %d, sequence %s: legacy type ignored", level_num,
type_str);
} else {
LOG_ERROR("unknown sequence type %s", type_str);
return false;
} else {
LOG_ERROR("unknown sequence type %s", type_str);
return false;
}
break;
}
jseq_elem = jseq_elem->next;
@ -586,35 +581,44 @@ static bool GameFlow_LoadScriptLevels(struct json_object_s *obj)
LOG_ERROR("level %d: 'type' must be a string", level_num);
return false;
}
if (!strcmp(tmp_s, "title")) {
cur->level_type = GFL_TITLE;
cur->level_type =
GameFlow_StringToEnumType(tmp_s, m_GameflowLevelTypeEnumMap);
switch (cur->level_type) {
case GFL_TITLE:
case GFL_TITLE_DEMO_PC:
if (g_GameFlow.title_level_num != -1) {
LOG_ERROR(
"level %d: there can be only one title level", level_num);
return false;
}
g_GameFlow.title_level_num = level_num;
} else if (!strcmp(tmp_s, "gym")) {
cur->level_type = GFL_GYM;
break;
case GFL_GYM:
if (g_GameFlow.gym_level_num != -1) {
LOG_ERROR(
"level %d: there can be only one gym level", level_num);
return false;
}
g_GameFlow.gym_level_num = level_num;
} else if (!strcmp(tmp_s, "normal")) {
cur->level_type = GFL_NORMAL;
break;
case GFL_LEVEL_DEMO_PC:
case GFL_NORMAL:
if (g_GameFlow.first_level_num == -1) {
g_GameFlow.first_level_num = level_num;
}
g_GameFlow.last_level_num = level_num;
} else if (!strcmp(tmp_s, "bonus")) {
cur->level_type = GFL_BONUS;
} else if (!strcmp(tmp_s, "cutscene")) {
cur->level_type = GFL_CUTSCENE;
} else if (!strcmp(tmp_s, "current")) {
cur->level_type = GFL_CURRENT;
} else {
break;
case GFL_BONUS:
case GFL_CUTSCENE:
case GFL_CURRENT:
break;
default:
LOG_ERROR("level %d: unknown level type %s", level_num, tmp_s);
return false;
}

View file

@ -51,10 +51,12 @@ static bool Level_LoadDemo(MYFILE *fp);
static bool Level_LoadSamples(MYFILE *fp);
static bool Level_LoadTexturePages(MYFILE *fp);
static bool Level_LoadFromFile(const char *filename, int32_t level_num);
static bool Level_LoadFromFile(
const char *filename, int32_t level_num, bool is_demo);
static void Level_CompleteSetup(int32_t level_num);
static bool Level_LoadFromFile(const char *filename, int32_t level_num)
static bool Level_LoadFromFile(
const char *filename, int32_t level_num, bool is_demo)
{
int32_t version;
int32_t file_level_num;
@ -96,6 +98,12 @@ static bool Level_LoadFromFile(const char *filename, int32_t level_num)
return false;
}
if (is_demo) {
if (!Level_LoadPalette(fp)) {
return false;
}
}
if (!Level_LoadCameras(fp)) {
return false;
}
@ -121,8 +129,10 @@ static bool Level_LoadFromFile(const char *filename, int32_t level_num)
return false;
}
if (!Level_LoadPalette(fp)) {
return false;
if (!is_demo) {
if (!Level_LoadPalette(fp)) {
return false;
}
}
if (!Level_LoadCinematic(fp)) {
@ -930,8 +940,12 @@ bool Level_Load(int level_num)
g_GameFlow.levels[level_num].injections.length,
g_GameFlow.levels[level_num].injections.data_paths, m_InjectionInfo);
bool ret =
Level_LoadFromFile(g_GameFlow.levels[level_num].level_file, level_num);
bool is_demo =
(g_GameFlow.levels[level_num].level_type == GFL_TITLE_DEMO_PC)
| (g_GameFlow.levels[level_num].level_type == GFL_LEVEL_DEMO_PC);
bool ret = Level_LoadFromFile(
g_GameFlow.levels[level_num].level_file, level_num, is_demo);
if (ret) {
Level_CompleteSetup(level_num);

View file

@ -36,8 +36,9 @@
#define LEVEL_TITLE_SIZE 25
#define TIMESTAMP_SIZE 20
static const char *m_TR1XGameflowPath = "cfg/TR1X_gameflow.json5";
static const char *m_TR1XGameflowGoldPath = "cfg/TR1X_gameflow_ub.json5";
static const char m_TR1XGameflowPath[] = "cfg/TR1X_gameflow.json5";
static const char m_TR1XGameflowGoldPath[] = "cfg/TR1X_gameflow_ub.json5";
static const char m_TR1XGameflowDemoPath[] = "cfg/TR1X_gameflow_demo_pc.json5";
static char *Shell_GetScreenshotName(void);
@ -169,6 +170,9 @@ void Shell_Main(void)
if (!strcmp(args[i], "-gold")) {
gameflow_path = m_TR1XGameflowGoldPath;
}
if (!strcmp(args[i], "-demo_pc")) {
gameflow_path = m_TR1XGameflowDemoPath;
}
}
for (int i = 0; i < arg_count; i++) {
Memory_FreePointer(&args[i]);

View file

@ -958,6 +958,8 @@ typedef enum GAMEFLOW_LEVEL_TYPE {
GFL_RESTART = 7,
GFL_SELECT = 8,
GFL_BONUS = 9,
GFL_TITLE_DEMO_PC = 10,
GFL_LEVEL_DEMO_PC = 11,
} GAMEFLOW_LEVEL_TYPE;
typedef enum GAMEFLOW_OPTION {