diff --git a/data/tr1/ship/cfg/TR1X_gameflow.json5 b/data/tr1/ship/cfg/TR1X_gameflow.json5 index 566134982..f853cae49 100644 --- a/data/tr1/ship/cfg/TR1X_gameflow.json5 +++ b/data/tr1/ship/cfg/TR1X_gameflow.json5 @@ -338,7 +338,7 @@ {"type": "play_fmv", "fmv_id": 8}, {"type": "loading_screen", "path": "data/images/atlantis.webp"}, {"type": "load_level"}, - {"type": "give_item", "object_id": 84, "quantity": 1}, + {"type": "give_item", "object_id": "pistols", "quantity": 1}, {"type": "setup_bacon_lara", "anchor_room": 10}, {"type": "play_level"}, {"type": "play_fmv", "fmv_id": 9}, @@ -378,7 +378,7 @@ "path": "data/cut1.phd", "type": "cutscene", "music_track": 0, - "lara_type": 77, + "lara_type": "player_1", "inherit_injections": false, "injections": [ "data/injections/backpack_cut.bin", @@ -401,7 +401,7 @@ "path": "data/cut2.phd", "type": "cutscene", "music_track": 0, - "lara_type": 77, + "lara_type": "player_1", "inherit_injections": false, "injections": [ "data/injections/backpack_cut.bin", @@ -413,8 +413,8 @@ {"type": "load_level"}, {"type": "set_cutscene_angle", "value": 16380}, {"type": "play_synced_audio", "audio_id": 25}, - {"type": "mesh_swap", "object1_id": 77, "object2_id": 1, "mesh_id": 1}, - {"type": "mesh_swap", "object1_id": 77, "object2_id": 1, "mesh_id": 4}, + {"type": "mesh_swap", "object1_id": "player_1", "object2_id": "pistol_anim", "mesh_id": 1}, + {"type": "mesh_swap", "object1_id": "player_1", "object2_id": "pistol_anim", "mesh_id": 4}, {"type": "play_level"}, {"type": "level_stats", "level_id": 9}, {"type": "exit_to_level", "level_id": 10}, @@ -449,7 +449,7 @@ "music_track": 0, "draw_distance_fade": 12.0, "draw_distance_max": 18.0, - "lara_type": 77, + "lara_type": "player_1", "inherit_injections": false, "injections": [ "data/injections/backpack_cut.bin", @@ -462,8 +462,8 @@ {"type": "load_level"}, {"type": "set_cutscene_angle", "value": 16384}, {"type": "play_synced_audio", "audio_id": 22}, - {"type": "mesh_swap", "object1_id": 77, "object2_id": 1, "mesh_id": 1}, - {"type": "mesh_swap", "object1_id": 77, "object2_id": 1, "mesh_id": 4}, + {"type": "mesh_swap", "object1_id": "player_1", "object2_id": "pistol_anim", "mesh_id": 1}, + {"type": "mesh_swap", "object1_id": "player_1", "object2_id": "pistol_anim", "mesh_id": 4}, {"type": "play_level"}, {"type": "level_stats", "level_id": 14}, {"type": "exit_to_level", "level_id": 15}, diff --git a/data/tr2/ship/cfg/TR2X_gameflow.json5 b/data/tr2/ship/cfg/TR2X_gameflow.json5 index afce2c21f..e2db05a2b 100644 --- a/data/tr2/ship/cfg/TR2X_gameflow.json5 +++ b/data/tr2/ship/cfg/TR2X_gameflow.json5 @@ -49,9 +49,9 @@ "music_track": 33, "sequence": [ {"type": "play_fmv", "fmv_id": 2}, - {"type": "add_secret_reward", "item": "grenade_launcher"}, - {"type": "add_secret_reward", "item": "grenade_launcher_ammo", "qty": 2}, - {"type": "add_secret_reward", "item": "small_medipack"}, + {"type": "add_secret_reward", "object_id": "grenade_launcher"}, + {"type": "add_secret_reward", "object_id": "grenade_launcher_ammo", "quantity": 2}, + {"type": "add_secret_reward", "object_id": "small_medipack"}, {"type": "play_level"}, {"type": "play_cutscene", "cutscene_id": 0}, {"type": "level_complete"}, @@ -66,7 +66,7 @@ "path": "data/boat.tr2", "music_track": -1, "sequence": [ - {"type": "add_secret_reward", "item": "magnums_ammo", "qty": 4}, + {"type": "add_secret_reward", "object_id": "magnums_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -78,7 +78,7 @@ "music_track": -1, "sequence": [ {"type": "enable_sunset"}, - {"type": "add_secret_reward", "item": "shotgun_ammo", "qty": 4}, + {"type": "add_secret_reward", "object_id": "shotgun_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -89,8 +89,8 @@ "path": "data/opera.tr2", "music_track": 31, "sequence": [ - {"type": "add_secret_reward", "item": "uzis"}, - {"type": "add_secret_reward", "item": "uzis_ammo", "qty": 4}, + {"type": "add_secret_reward", "object_id": "uzis"}, + {"type": "add_secret_reward", "object_id": "uzis_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "play_cutscene", "cutscene_id": 1}, {"type": "level_complete"}, @@ -109,8 +109,8 @@ {"type": "play_fmv", "fmv_id": 3}, {"type": "set_lara_start_anim", "anim": 8}, {"type": "remove_weapons"}, - {"type": "add_secret_reward", "item": "uzis"}, - {"type": "add_secret_reward", "item": "uzis_ammo", "qty": 2}, + {"type": "add_secret_reward", "object_id": "uzis"}, + {"type": "add_secret_reward", "object_id": "uzis_ammo", "quantity": 2}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -124,7 +124,7 @@ "path": "data/platform.tr2", "music_track": 58, "sequence": [ - {"type": "add_secret_reward", "item": "uzis_ammo", "qty": 4}, + {"type": "add_secret_reward", "object_id": "uzis_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "play_cutscene", "cutscene_id": 2}, {"type": "level_complete"}, @@ -140,7 +140,7 @@ "music_track": 34, "sequence": [ {"type": "play_fmv", "fmv_id": 4}, - {"type": "add_secret_reward", "item": "harpoon_gun_ammo", "qty": 4}, + {"type": "add_secret_reward", "object_id": "harpoon_gun_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -151,8 +151,8 @@ "path": "data/keel.tr2", "music_track": 31, "sequence": [ - {"type": "add_secret_reward", "item": "grenade_launcher"}, - {"type": "add_secret_reward", "item": "grenade_launcher_ammo", "qty": 2}, + {"type": "add_secret_reward", "object_id": "grenade_launcher"}, + {"type": "add_secret_reward", "object_id": "grenade_launcher_ammo", "quantity": 2}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -167,7 +167,7 @@ "path": "data/living.tr2", "music_track": 34, "sequence": [ - {"type": "add_secret_reward", "item": "m16_ammo", "qty": 4}, + {"type": "add_secret_reward", "object_id": "m16_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -178,7 +178,7 @@ "path": "data/deck.tr2", "music_track": 31, "sequence": [ - {"type": "add_secret_reward", "item": "grenade_launcher_ammo", "qty": 4}, + {"type": "add_secret_reward", "object_id": "grenade_launcher_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -193,8 +193,8 @@ "music_track": 33, "sequence": [ {"type": "play_fmv", "fmv_id": 5}, - {"type": "give_item", "item": "puzzle_4"}, - {"type": "add_secret_reward", "item": "uzis_ammo", "qty": 4}, + {"type": "give_item", "object_id": "puzzle_4"}, + {"type": "add_secret_reward", "object_id": "uzis_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -209,8 +209,8 @@ "path": "data/monastry.tr2", "music_track": -1, "sequence": [ - {"type": "give_item", "item": "puzzle_4"}, - {"type": "add_secret_reward", "item": "m16_ammo", "qty": 4}, + {"type": "give_item", "object_id": "puzzle_4"}, + {"type": "add_secret_reward", "object_id": "m16_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -224,8 +224,8 @@ "path": "data/catacomb.tr2", "music_track": 31, "sequence": [ - {"type": "add_secret_reward", "item": "grenade_launcher_ammo", "qty": 2}, - {"type": "add_secret_reward", "item": "m16_ammo", "qty": 2}, + {"type": "add_secret_reward", "object_id": "grenade_launcher_ammo", "quantity": 2}, + {"type": "add_secret_reward", "object_id": "m16_ammo", "quantity": 2}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -240,7 +240,7 @@ "path": "data/icecave.tr2", "music_track": 31, "sequence": [ - {"type": "add_secret_reward", "item": "grenade_launcher_ammo", "qty": 4}, + {"type": "add_secret_reward", "object_id": "grenade_launcher_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -256,7 +256,7 @@ "music_track": 59, "sequence": [ {"type": "play_fmv", "fmv_id": 6}, - {"type": "add_secret_reward", "item": "uzis_ammo", "qty": 8}, + {"type": "add_secret_reward", "object_id": "uzis_ammo", "quantity": 8}, {"type": "play_level"}, {"type": "play_cutscene", "cutscene_id": 3}, {"type": "level_complete"}, @@ -273,7 +273,7 @@ "music_track": 59, "sequence": [ {"type": "disable_floor", "height": 9728}, - {"type": "add_secret_reward", "item": "grenade_launcher_ammo", "qty": 8}, + {"type": "add_secret_reward", "object_id": "grenade_launcher_ammo", "quantity": 8}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -301,7 +301,7 @@ "music_track": -1, "sequence": [ {"type": "set_secret_count", "count": 0}, - {"type": "give_item", "item": "key_1"}, + {"type": "give_item", "object_id": "key_1"}, {"type": "set_lara_start_anim", "anim": 9}, {"type": "remove_weapons"}, {"type": "remove_ammo"}, @@ -320,7 +320,7 @@ "path": "data/boat.tr2", "music_track": -1, "sequence": [ - {"type": "add_secret_reward", "item": "magnums_ammo", "qty": 4}, + {"type": "add_secret_reward", "object_id": "magnums_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -331,8 +331,8 @@ "path": "data/keel.tr2", "music_track": 31, "sequence": [ - {"type": "add_secret_reward", "item": "grenade_launcher"}, - {"type": "add_secret_reward", "item": "grenade_launcher_ammo", "qty": 2}, + {"type": "add_secret_reward", "object_id": "grenade_launcher"}, + {"type": "add_secret_reward", "object_id": "grenade_launcher_ammo", "quantity": 2}, {"type": "play_level"}, {"type": "level_complete"}, ], @@ -347,8 +347,8 @@ "path": "data/skidoo.tr2", "music_track": 33, "sequence": [ - {"type": "give_item", "item": "puzzle_4"}, - {"type": "add_secret_reward", "item": "uzis_ammo", "qty": 4}, + {"type": "give_item", "object_id": "puzzle_4"}, + {"type": "add_secret_reward", "object_id": "uzis_ammo", "quantity": 4}, {"type": "play_level"}, {"type": "level_complete"}, ], diff --git a/docs/tr1/GAMEFLOW.md b/docs/tr1/GAMEFLOW.md index 15567fc57..34f619fb3 100644 --- a/docs/tr1/GAMEFLOW.md +++ b/docs/tr1/GAMEFLOW.md @@ -336,7 +336,7 @@ Following are each of the properties available within a level. lara_type - Integer + Integer / string No Used only in cutscene levels to link the braid (if enabled) to the @@ -562,7 +562,7 @@ default gameflow for examples. object_id - Integer + Integer / String Adds the specified item and quantity to Lara's inventory. If used, this must appear after the load_level sequence. @@ -929,7 +929,7 @@ This translates as follows. object_ids - Integer array + Integer / string array A list of item types to drop. These items will spawn dynamically and do not need to be added to the level file. Duplicate IDs are permitted diff --git a/src/tr1/game/game_flow/reader.c b/src/tr1/game/game_flow/reader.c index 107884d03..1b6f99985 100644 --- a/src/tr1/game/game_flow/reader.c +++ b/src/tr1/game/game_flow/reader.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -31,9 +32,10 @@ typedef void (*M_LOAD_ARRAY_FUNC)( static void M_LoadArray( JSON_OBJECT *obj, const char *key, size_t element_size, - M_LOAD_ARRAY_FUNC load_func, GAME_FLOW *const gf, int32_t *const count, - void **const elements, void *user_arg); + M_LOAD_ARRAY_FUNC load_func, GAME_FLOW *gf, int32_t *count, void **elements, + void *user_arg); +static GAME_OBJECT_ID M_GetObjectFromJSONValue(const JSON_VALUE *value); static bool M_IsLegacySequence(const char *type_str); static int32_t M_HandleIntEvent( JSON_OBJECT *event_obj, GAME_FLOW_SEQUENCE_EVENT *event, void *extra_data, @@ -102,6 +104,24 @@ static M_SEQUENCE_EVENT_HANDLER m_SequenceEventHandlers[] = { // clang-format on }; +static GAME_OBJECT_ID M_GetObjectFromJSONValue(const JSON_VALUE *const value) +{ + int32_t object_id = JSON_ValueGetInt(value, JSON_INVALID_NUMBER); + if (object_id == JSON_INVALID_NUMBER) { + const char *const object_key = + JSON_ValueGetString(value, JSON_INVALID_STRING); + if (object_key == JSON_INVALID_STRING) { + return NO_OBJECT; + } + object_id = Object_IdFromKey(object_key); + LOG_DEBUG("Chuj %s: %d", object_key, object_id); + } + if (object_id < 0 || object_id >= O_NUMBER_OF) { + return NO_OBJECT; + } + return object_id; +} + static void M_LoadArray( JSON_OBJECT *const obj, const char *const key, const size_t element_size, M_LOAD_ARRAY_FUNC load_func, GAME_FLOW *const gf, int32_t *const count, @@ -135,8 +155,8 @@ static bool M_IsLegacySequence(const char *const type_str) } static int32_t M_HandleIntEvent( - JSON_OBJECT *event_obj, GAME_FLOW_SEQUENCE_EVENT *event, void *extra_data, - void *user_arg) + JSON_OBJECT *const event_obj, GAME_FLOW_SEQUENCE_EVENT *const event, + void *const extra_data, void *const user_arg) { if (event != NULL) { event->data = @@ -146,12 +166,12 @@ static int32_t M_HandleIntEvent( } static int32_t M_HandlePictureEvent( - JSON_OBJECT *event_obj, GAME_FLOW_SEQUENCE_EVENT *event, void *extra_data, - void *user_arg) + JSON_OBJECT *const event_obj, GAME_FLOW_SEQUENCE_EVENT *const event, + void *const extra_data, void *const user_arg) { const char *const path = JSON_ObjectGetString(event_obj, "path", NULL); if (path == NULL) { - LOG_ERROR("Missing picture path"); + Shell_ExitSystem("Missing picture path"); return -1; } if (event != NULL) { @@ -167,13 +187,13 @@ static int32_t M_HandlePictureEvent( } static int32_t M_HandleTotalStatsEvent( - JSON_OBJECT *event_obj, GAME_FLOW_SEQUENCE_EVENT *event, void *extra_data, - void *user_arg) + JSON_OBJECT *const event_obj, GAME_FLOW_SEQUENCE_EVENT *const event, + void *const extra_data, void *const user_arg) { const char *const path = JSON_ObjectGetString(event_obj, "background_path", NULL); if (path == NULL) { - LOG_ERROR("Missing picture path"); + Shell_ExitSystem("Missing picture path"); return -1; } if (event != NULL) { @@ -185,13 +205,13 @@ static int32_t M_HandleTotalStatsEvent( } static int32_t M_HandleAddItemEvent( - JSON_OBJECT *event_obj, GAME_FLOW_SEQUENCE_EVENT *event, void *extra_data, - void *user_arg) + JSON_OBJECT *const event_obj, GAME_FLOW_SEQUENCE_EVENT *const event, + void *const extra_data, void *const user_arg) { const GAME_OBJECT_ID object_id = - JSON_ObjectGetInt(event_obj, "object_id", JSON_INVALID_NUMBER); - if (object_id == JSON_INVALID_NUMBER) { - LOG_ERROR("Invalid item: %s", object_id); + M_GetObjectFromJSONValue(JSON_ObjectGetValue(event_obj, "object_id")); + if (object_id == NO_OBJECT) { + Shell_ExitSystem("Invalid item"); return -1; } if (event != NULL) { @@ -204,19 +224,19 @@ static int32_t M_HandleAddItemEvent( } static int32_t M_HandleMeshSwapEvent( - JSON_OBJECT *event_obj, GAME_FLOW_SEQUENCE_EVENT *event, void *extra_data, - void *user_arg) + JSON_OBJECT *const event_obj, GAME_FLOW_SEQUENCE_EVENT *const event, + void *const extra_data, void *const user_arg) { const GAME_OBJECT_ID object1_id = - JSON_ObjectGetInt(event_obj, "object1_id", JSON_INVALID_NUMBER); - if (object1_id == JSON_INVALID_NUMBER) { - Shell_ExitSystem("'object1_id' must be a number"); + M_GetObjectFromJSONValue(JSON_ObjectGetValue(event_obj, "object1_id")); + if (object1_id == NO_OBJECT) { + Shell_ExitSystem("'object1_id' is invalid"); } const GAME_OBJECT_ID object2_id = - JSON_ObjectGetInt(event_obj, "object2_id", JSON_INVALID_NUMBER); - if (object2_id == JSON_INVALID_NUMBER) { - Shell_ExitSystem("'object2_id' must be a number"); + M_GetObjectFromJSONValue(JSON_ObjectGetValue(event_obj, "object2_id")); + if (object2_id == NO_OBJECT) { + Shell_ExitSystem("'object2_id' is invalid"); } const int32_t mesh_num = @@ -286,8 +306,8 @@ static size_t M_LoadSequenceEvent( handler++; } if (handler->event_type != type) { - LOG_ERROR("Unknown game flow sequence event type: '%s'", type); - return -1; + Shell_ExitSystemFmt( + "Unknown game flow sequence event type: '%s'", type); } int32_t extra_data_size = 0; @@ -371,7 +391,7 @@ static void M_LoadLevels(JSON_OBJECT *const obj, GAME_FLOW *const gf) g_GameInfo.current = Memory_Alloc(sizeof(RESUME_INFO) * level_count); JSON_ARRAY_ELEMENT *jlvl_elem = jlvl_arr->start; - int level_num = 0; + int32_t level_num = 0; gf->has_demo = 0; gf->gym_level_num = -1; @@ -477,9 +497,9 @@ static void M_LoadLevels(JSON_OBJECT *const obj, GAME_FLOW *const gf) level->injections.data_paths = Memory_Alloc(sizeof(char *) * level->injections.count); - int inj_base_index = 0; + int32_t inj_base_index = 0; if (tmp_i) { - for (int i = 0; i < gf->injections.count; i++) { + for (int32_t i = 0; i < gf->injections.count; i++) { level->injections.data_paths[i] = Memory_DupStr(gf->injections.data_paths[i]); } @@ -495,7 +515,7 @@ static void M_LoadLevels(JSON_OBJECT *const obj, GAME_FLOW *const gf) level->injections.count = gf->injections.count; level->injections.data_paths = Memory_Alloc(sizeof(char *) * level->injections.count); - for (int i = 0; i < gf->injections.count; i++) { + for (int32_t i = 0; i < gf->injections.count; i++) { level->injections.data_paths[i] = Memory_DupStr(gf->injections.data_paths[i]); } @@ -503,13 +523,20 @@ static void M_LoadLevels(JSON_OBJECT *const obj, GAME_FLOW *const gf) level->injections.count = 0; } - tmp_i = JSON_ObjectGetInt(jlvl_obj, "lara_type", (int32_t)O_LARA); - if (tmp_i < 0 || tmp_i >= O_NUMBER_OF) { - Shell_ExitSystemFmt( - "level %d: 'lara_type' must be a valid game object id", - level_num); + { + JSON_VALUE *const tmp_v = + JSON_ObjectGetValue(jlvl_obj, "lara_type"); + if (tmp_v == NULL) { + level->lara_type = O_LARA; + } else { + level->lara_type = M_GetObjectFromJSONValue(tmp_v); + } + if (level->lara_type == NO_OBJECT) { + Shell_ExitSystemFmt( + "level %d: 'lara_type' must be a valid game object id", + level_num); + } } - level->lara_type = (GAME_OBJECT_ID)tmp_i; tmp_arr = JSON_ObjectGetArray(jlvl_obj, "item_drops"); level->item_drops.count = 0; @@ -523,7 +550,7 @@ static void M_LoadLevels(JSON_OBJECT *const obj, GAME_FLOW *const gf) level->item_drops.data = Memory_Alloc( sizeof(GAME_FLOW_DROP_ITEM_DATA) * (signed)tmp_arr->length); - for (int i = 0; i < level->item_drops.count; i++) { + for (int32_t i = 0; i < level->item_drops.count; i++) { GAME_FLOW_DROP_ITEM_DATA *data = &level->item_drops.data[i]; JSON_OBJECT *jlvl_data = JSON_ArrayGetObject(tmp_arr, i); @@ -545,9 +572,10 @@ static void M_LoadLevels(JSON_OBJECT *const obj, GAME_FLOW *const gf) data->count = (signed)object_arr->length; data->object_ids = Memory_Alloc(sizeof(int16_t) * data->count); - for (int j = 0; j < data->count; j++) { - int id = JSON_ArrayGetInt(object_arr, j, -1); - if (id < 0 || id >= O_NUMBER_OF) { + for (int32_t j = 0; j < data->count; j++) { + const GAME_OBJECT_ID id = M_GetObjectFromJSONValue( + JSON_ArrayGetValue(object_arr, j)); + if (id == NO_OBJECT) { Shell_ExitSystemFmt( "level %d, item drop %d, index %d: 'object_id' " "must be a valid object id", @@ -594,7 +622,7 @@ static void M_LoadFMVs(JSON_OBJECT *const obj, GAME_FLOW *const gf) static void M_LoadRoot(JSON_OBJECT *const obj, GAME_FLOW *const gf) { const char *tmp_s; - int tmp_i; + int32_t tmp_i; double tmp_d; JSON_ARRAY *tmp_arr; diff --git a/src/tr2/game/game_flow/reader.c b/src/tr2/game/game_flow/reader.c index f80a5b6b4..120898383 100644 --- a/src/tr2/game/game_flow/reader.c +++ b/src/tr2/game/game_flow/reader.c @@ -28,9 +28,15 @@ typedef void (*M_LOAD_ARRAY_FUNC)( JSON_OBJECT *source_elem, GAME_FLOW *gf, void *target_elem, size_t target_elem_idx, void *user_arg); +static GAME_OBJECT_ID M_GetObjectFromJSONValue(const JSON_VALUE *value); static GAME_FLOW_COMMAND M_LoadCommand( JSON_OBJECT *jcmd, GAME_FLOW_COMMAND fallback); +static void M_LoadArray( + JSON_OBJECT *obj, const char *key, size_t element_size, + M_LOAD_ARRAY_FUNC load_func, GAME_FLOW *gf, int32_t *count, void **elements, + void *user_arg); + static int32_t M_HandleIntEvent( JSON_OBJECT *event_obj, GAME_FLOW_SEQUENCE_EVENT *event, void *extra_data, void *user_arg); @@ -47,11 +53,6 @@ static void M_LoadSequence(JSON_ARRAY *jarr, GAME_FLOW_SEQUENCE *sequence); static void M_LoadGlobalInjections(JSON_OBJECT *obj, GAME_FLOW *gf); static void M_LoadRoot(JSON_OBJECT *obj, GAME_FLOW *gf); -static void M_LoadArray( - JSON_OBJECT *obj, const char *key, size_t element_size, - M_LOAD_ARRAY_FUNC load_func, GAME_FLOW *const gf, int32_t *const count, - void **const elements, void *user_arg); - static void M_LoadLevel( JSON_OBJECT *obj, const GAME_FLOW *gf, GAME_FLOW_LEVEL *level, size_t idx, void *user_arg); @@ -95,6 +96,23 @@ static M_SEQUENCE_EVENT_HANDLER m_SequenceEventHandlers[] = { // clang-format on }; +static GAME_OBJECT_ID M_GetObjectFromJSONValue(const JSON_VALUE *const value) +{ + int32_t object_id = JSON_ValueGetInt(value, JSON_INVALID_NUMBER); + if (object_id == JSON_INVALID_NUMBER) { + const char *const object_key = + JSON_ValueGetString(value, JSON_INVALID_STRING); + if (object_key == JSON_INVALID_STRING) { + return NO_OBJECT; + } + object_id = Object_IdFromKey(object_key); + } + if (object_id < 0 || object_id >= O_NUMBER_OF) { + return NO_OBJECT; + } + return object_id; +} + static GAME_FLOW_COMMAND M_LoadCommand( JSON_OBJECT *const jcmd, const GAME_FLOW_COMMAND fallback) { @@ -106,14 +124,14 @@ static GAME_FLOW_COMMAND M_LoadCommand( JSON_ObjectGetString(jcmd, "action", JSON_INVALID_STRING); const int32_t param = JSON_ObjectGetInt(jcmd, "param", -1); if (action_str == JSON_INVALID_STRING) { - LOG_ERROR("Unknown game flow action: %s", action_str); + Shell_ExitSystemFmt("Unknown game flow action: %s", action_str); return fallback; } const GAME_FLOW_ACTION action = ENUM_MAP_GET(GAME_FLOW_ACTION, action_str, (GAME_FLOW_ACTION)-1234); if (action == (GAME_FLOW_ACTION)-1234) { - LOG_ERROR("Unknown game flow action: %s", action_str); + Shell_ExitSystemFmt("Unknown game flow action: %s", action_str); return fallback; } @@ -121,8 +139,8 @@ static GAME_FLOW_COMMAND M_LoadCommand( } static int32_t M_HandleIntEvent( - JSON_OBJECT *event_obj, GAME_FLOW_SEQUENCE_EVENT *event, void *extra_data, - void *user_arg) + JSON_OBJECT *const event_obj, GAME_FLOW_SEQUENCE_EVENT *const event, + void *const extra_data, void *const user_arg) { if (event != NULL) { event->data = @@ -132,12 +150,12 @@ static int32_t M_HandleIntEvent( } static int32_t M_HandlePictureEvent( - JSON_OBJECT *event_obj, GAME_FLOW_SEQUENCE_EVENT *event, void *extra_data, - void *user_arg) + JSON_OBJECT *const event_obj, GAME_FLOW_SEQUENCE_EVENT *const event, + void *const extra_data, void *const user_arg) { const char *const path = JSON_ObjectGetString(event_obj, "path", NULL); if (path == NULL) { - LOG_ERROR("Missing picture path"); + Shell_ExitSystem("Missing picture path"); return -1; } if (event != NULL) { @@ -153,21 +171,21 @@ static int32_t M_HandlePictureEvent( } static int32_t M_HandleAddItemEvent( - JSON_OBJECT *event_obj, GAME_FLOW_SEQUENCE_EVENT *event, void *extra_data, - void *user_arg) + JSON_OBJECT *const event_obj, GAME_FLOW_SEQUENCE_EVENT *const event, + void *const extra_data, void *const user_arg) { + const GAME_OBJECT_ID object_id = + M_GetObjectFromJSONValue(JSON_ObjectGetValue(event_obj, "object_id")); + if (object_id == NO_OBJECT) { + Shell_ExitSystem("Invalid item"); + return -1; + } if (event != NULL) { - const char *const object_key = - JSON_ObjectGetString(event_obj, "item", JSON_INVALID_STRING); - const GAME_OBJECT_ID object_id = Object_IdFromKey(object_key); - if (object_id == NO_OBJECT) { - LOG_ERROR("Invalid item: %s", object_key); - } GAME_FLOW_ADD_ITEM_DATA *const event_data = extra_data; event_data->object_id = object_id; + event_data->qty = JSON_ObjectGetInt(event_obj, "quantity", 1); event_data->inv_type = event->type == GFS_ADD_ITEM ? GF_INV_REGULAR : GF_INV_SECRET; - event_data->qty = JSON_ObjectGetInt(event_obj, "qty", 1); event->data = event_data; } return sizeof(GAME_FLOW_ADD_ITEM_DATA); @@ -188,7 +206,8 @@ static size_t M_LoadSequenceEvent( } if (handler->event_type != type) { - LOG_ERROR("Unknown game flow sequence event type: '%s'", type); + Shell_ExitSystemFmt( + "Unknown game flow sequence event type: '%s'", type); return -1; }