From 1f4ca33ef29ff295a70eb7cdc98318127aed964e Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Tue, 1 Feb 2022 20:27:03 -0500 Subject: [PATCH 01/25] compass: add total number of pickups and killables Resolves #362. --- bin/cfg/Tomb1Main_gameflow.json5 | 4 +-- bin/cfg/Tomb1Main_gameflow_ub.json5 | 4 +-- src/game/game.c | 7 +++-- src/game/gameflow.h | 2 ++ src/game/level.c | 42 +++++++++++++++++++++++++++++ src/game/option_compass.c | 8 ++++-- src/init.c | 4 +-- 7 files changed, 61 insertions(+), 10 deletions(-) diff --git a/bin/cfg/Tomb1Main_gameflow.json5 b/bin/cfg/Tomb1Main_gameflow.json5 index 2abbe746a..cb51dccf0 100644 --- a/bin/cfg/Tomb1Main_gameflow.json5 +++ b/bin/cfg/Tomb1Main_gameflow.json5 @@ -534,8 +534,8 @@ "KEYMAP_CAMERA_RESET": "Reset Camera", "STATS_TIME_TAKEN_FMT": "TIME TAKEN %s", "STATS_SECRETS_FMT": "SECRETS %d OF %d", - "STATS_PICKUPS_FMT": "PICKUPS %d", - "STATS_KILLS_FMT": "KILLS %d", + "STATS_PICKUPS_FMT": "PICKUPS %d OF %d", + "STATS_KILLS_FMT": "KILLS %d OF %d", "PAUSE_PAUSED": "Paused", "PAUSE_EXIT_TO_TITLE": "Exit to title?", "PAUSE_CONTINUE": "Continue", diff --git a/bin/cfg/Tomb1Main_gameflow_ub.json5 b/bin/cfg/Tomb1Main_gameflow_ub.json5 index 22956f4fb..808cd9019 100644 --- a/bin/cfg/Tomb1Main_gameflow_ub.json5 +++ b/bin/cfg/Tomb1Main_gameflow_ub.json5 @@ -165,8 +165,8 @@ "KEYMAP_CAMERA_RESET": "Reset Camera", "STATS_TIME_TAKEN_FMT": "TIME TAKEN %s", "STATS_SECRETS_FMT": "SECRETS %d OF %d", - "STATS_PICKUPS_FMT": "PICKUPS %d", - "STATS_KILLS_FMT": "KILLS %d", + "STATS_PICKUPS_FMT": "PICKUPS %d OF %d", + "STATS_KILLS_FMT": "KILLS %d OF %d", "PAUSE_PAUSED": "Paused", "PAUSE_EXIT_TO_TITLE": "Exit to title?", "PAUSE_CONTINUE": "Continue", diff --git a/src/game/game.c b/src/game/game.c index 5929ee8b1..cb2bda43a 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -157,13 +157,16 @@ void LevelStats(int32_t level_num) // pickups sprintf( - string, g_GameFlow.strings[GS_STATS_PICKUPS_FMT], g_GameInfo.pickups); + string, g_GameFlow.strings[GS_STATS_PICKUPS_FMT], g_GameInfo.pickups, + g_GameFlow.levels[level_num].pickups); txt = Text_Create(0, 10, string); Text_CentreH(txt, 1); Text_CentreV(txt, 1); // kills - sprintf(string, g_GameFlow.strings[GS_STATS_KILLS_FMT], g_GameInfo.kills); + sprintf( + string, g_GameFlow.strings[GS_STATS_KILLS_FMT], g_GameInfo.kills, + g_GameFlow.levels[level_num].kills); txt = Text_Create(0, -20, string); Text_CentreH(txt, 1); Text_CentreV(txt, 1); diff --git a/src/game/gameflow.h b/src/game/gameflow.h index 40c97369d..221614a1b 100644 --- a/src/game/gameflow.h +++ b/src/game/gameflow.h @@ -31,6 +31,8 @@ typedef struct GAMEFLOW_LEVEL { char *puzzle4; int8_t demo; int16_t secrets; + int16_t pickups; + int16_t kills; GAMEFLOW_SEQUENCE *sequence; struct { bool override; diff --git a/src/game/level.c b/src/game/level.c index eefd2ff90..ba3a8888d 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -17,6 +17,9 @@ #include +#define NUM_PICKUP_OBJ 28 +#define NUM_KILLABLE_OBJ 26 + static int32_t m_MeshCount = 0; static int32_t m_MeshPtrCount = 0; static int32_t m_AnimCount = 0; @@ -34,6 +37,27 @@ static int32_t m_AnimTextureRangeCount = 0; static int32_t m_SpriteInfoCount = 0; static int32_t m_SpriteCount = 0; static int32_t m_OverlapCount = 0; +static int32_t m_LevelPickups = 0; +static int32_t m_LevelKillables = 0; + +int16_t m_PickupObjs[NUM_PICKUP_OBJ] = { + O_COG_1, O_COG_2, O_COG_3, O_PICKUP_ITEM1, + O_PICKUP_ITEM2, O_KEY_ITEM1, O_KEY_ITEM2, O_KEY_ITEM3, + O_KEY_ITEM4, O_PUZZLE_ITEM1, O_PUZZLE_ITEM2, O_PUZZLE_ITEM3, + O_PUZZLE_ITEM4, O_GUN_ITEM, O_SHOTGUN_ITEM, O_MAGNUM_ITEM, + O_UZI_ITEM, O_GUN_AMMO_ITEM, O_SG_AMMO_ITEM, O_MAG_AMMO_ITEM, + O_UZI_AMMO_ITEM, O_EXPLOSIVE_ITEM, O_MEDI_ITEM, O_BIGMEDI_ITEM, + O_SCION_ITEM, O_SCION_ITEM2, O_SCION_ITEM4, O_LEADBAR_ITEM, +}; + +int16_t m_KillableObjs[NUM_KILLABLE_OBJ] = { + O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, + O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, + O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, + O_WARRIOR3, O_CENTAUR, O_DINO_WARRIOR, O_LARSON, O_PIERRE, + O_SKATEBOARD, O_MERCENARY1, O_MERCENARY2, O_MERCENARY3, O_NATLA, + O_ABORTION, +}; static bool Level_LoadRooms(MYFILE *fp); static bool Level_LoadObjects(MYFILE *fp); @@ -369,6 +393,8 @@ static bool Level_LoadSprites(MYFILE *fp) static bool Level_LoadItems(MYFILE *fp) { + m_LevelPickups = 0; + m_LevelKillables = 0; int32_t item_count = 0; File_Read(&item_count, sizeof(int32_t), 1, fp); @@ -403,6 +429,20 @@ static bool Level_LoadItems(MYFILE *fp) } InitialiseItem(i); + + // Calculate number of pickups in a level + for (int16_t j = 0; j < NUM_PICKUP_OBJ; j++) { + if (item->object_number == m_PickupObjs[j]) { + m_LevelPickups++; + } + } + + // Calculate number of killable objects in a level + for (int16_t j = 0; j < NUM_KILLABLE_OBJ; j++) { + if (item->object_number == m_KillableObjs[j]) { + m_LevelKillables++; + } + } } } @@ -672,6 +712,8 @@ bool Level_Load(int level_num) } g_GameFlow.levels[level_num].secrets = GetSecretCount(); + g_GameFlow.levels[level_num].pickups = m_LevelPickups; + g_GameFlow.levels[level_num].kills = m_LevelKillables; return ret; } diff --git a/src/game/option_compass.c b/src/game/option_compass.c index af35ef265..808b14554 100644 --- a/src/game/option_compass.c +++ b/src/game/option_compass.c @@ -56,11 +56,15 @@ static void Option_CompassInitText() m_Text[TEXT_SECRETS] = Text_Create(0, y, buf); y += ROW_HEIGHT; - sprintf(buf, g_GameFlow.strings[GS_STATS_PICKUPS_FMT], g_GameInfo.pickups); + sprintf( + buf, g_GameFlow.strings[GS_STATS_PICKUPS_FMT], g_GameInfo.pickups, + g_GameFlow.levels[g_CurrentLevel].pickups); m_Text[TEXT_PICKUPS] = Text_Create(0, y, buf); y += ROW_HEIGHT; - sprintf(buf, g_GameFlow.strings[GS_STATS_KILLS_FMT], g_GameInfo.kills); + sprintf( + buf, g_GameFlow.strings[GS_STATS_KILLS_FMT], g_GameInfo.kills, + g_GameFlow.levels[g_CurrentLevel].kills); m_Text[TEXT_KILLS] = Text_Create(0, y, buf); y += ROW_HEIGHT; diff --git a/src/init.c b/src/init.c index 4d183b7b9..dcb8d9ec8 100644 --- a/src/init.c +++ b/src/init.c @@ -65,8 +65,8 @@ GAMEFLOW_DEFAULT_STRING g_GameFlowDefaultStrings[] = { { GS_KEYMAP_CAMERA_RESET, "Reset Camera" }, { GS_STATS_TIME_TAKEN_FMT, "TIME TAKEN %s" }, { GS_STATS_SECRETS_FMT, "SECRETS %d OF %d" }, - { GS_STATS_PICKUPS_FMT, "PICKUPS %d" }, - { GS_STATS_KILLS_FMT, "KILLS %d" }, + { GS_STATS_PICKUPS_FMT, "PICKUPS %d OF %d" }, + { GS_STATS_KILLS_FMT, "KILLS %d OF %d" }, { GS_PAUSE_PAUSED, "Paused" }, { GS_PAUSE_EXIT_TO_TITLE, "Exit to title?" }, { GS_PAUSE_CONTINUE, "Continue" }, From 5f46e5f68103d477c289a2ea17826f267d94511c Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Thu, 3 Feb 2022 10:38:41 -0500 Subject: [PATCH 02/25] remove inventory cog object from pickup and add scion3 to kills --- src/game/level.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/game/level.c b/src/game/level.c index ba3a8888d..e3a4b4c6c 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -17,8 +17,8 @@ #include -#define NUM_PICKUP_OBJ 28 -#define NUM_KILLABLE_OBJ 26 +#define NUM_PICKUP_OBJ 24 +#define NUM_KILLABLE_OBJ 27 static int32_t m_MeshCount = 0; static int32_t m_MeshPtrCount = 0; @@ -40,23 +40,24 @@ static int32_t m_OverlapCount = 0; static int32_t m_LevelPickups = 0; static int32_t m_LevelKillables = 0; +// TODO: game doesn't add O_SCION_ITEM4 (complete Scion Atlantis) as pickup int16_t m_PickupObjs[NUM_PICKUP_OBJ] = { - O_COG_1, O_COG_2, O_COG_3, O_PICKUP_ITEM1, - O_PICKUP_ITEM2, O_KEY_ITEM1, O_KEY_ITEM2, O_KEY_ITEM3, - O_KEY_ITEM4, O_PUZZLE_ITEM1, O_PUZZLE_ITEM2, O_PUZZLE_ITEM3, - O_PUZZLE_ITEM4, O_GUN_ITEM, O_SHOTGUN_ITEM, O_MAGNUM_ITEM, - O_UZI_ITEM, O_GUN_AMMO_ITEM, O_SG_AMMO_ITEM, O_MAG_AMMO_ITEM, - O_UZI_AMMO_ITEM, O_EXPLOSIVE_ITEM, O_MEDI_ITEM, O_BIGMEDI_ITEM, - O_SCION_ITEM, O_SCION_ITEM2, O_SCION_ITEM4, O_LEADBAR_ITEM, + O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_KEY_ITEM2, + O_KEY_ITEM3, O_KEY_ITEM4, O_PUZZLE_ITEM1, O_PUZZLE_ITEM2, + O_PUZZLE_ITEM3, O_PUZZLE_ITEM4, O_GUN_ITEM, O_SHOTGUN_ITEM, + O_MAGNUM_ITEM, O_UZI_ITEM, O_GUN_AMMO_ITEM, O_SG_AMMO_ITEM, + O_MAG_AMMO_ITEM, O_UZI_AMMO_ITEM, O_EXPLOSIVE_ITEM, O_MEDI_ITEM, + O_BIGMEDI_ITEM, O_SCION_ITEM, O_SCION_ITEM2, O_LEADBAR_ITEM, }; +// TODO: need to check only active mummies int16_t m_KillableObjs[NUM_KILLABLE_OBJ] = { O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, O_WARRIOR3, O_CENTAUR, O_DINO_WARRIOR, O_LARSON, O_PIERRE, O_SKATEBOARD, O_MERCENARY1, O_MERCENARY2, O_MERCENARY3, O_NATLA, - O_ABORTION, + O_ABORTION, O_SCION_ITEM3 }; static bool Level_LoadRooms(MYFILE *fp); From c7df93cb84fae5b9267f1895da6281f57c266892 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Thu, 3 Feb 2022 14:32:10 -0500 Subject: [PATCH 03/25] simplify pickup and killable obj arrays --- src/game/level.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/game/level.c b/src/game/level.c index e3a4b4c6c..0eda3a3d0 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -17,9 +17,6 @@ #include -#define NUM_PICKUP_OBJ 24 -#define NUM_KILLABLE_OBJ 27 - static int32_t m_MeshCount = 0; static int32_t m_MeshPtrCount = 0; static int32_t m_AnimCount = 0; @@ -41,23 +38,24 @@ static int32_t m_LevelPickups = 0; static int32_t m_LevelKillables = 0; // TODO: game doesn't add O_SCION_ITEM4 (complete Scion Atlantis) as pickup -int16_t m_PickupObjs[NUM_PICKUP_OBJ] = { - O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_KEY_ITEM2, - O_KEY_ITEM3, O_KEY_ITEM4, O_PUZZLE_ITEM1, O_PUZZLE_ITEM2, - O_PUZZLE_ITEM3, O_PUZZLE_ITEM4, O_GUN_ITEM, O_SHOTGUN_ITEM, - O_MAGNUM_ITEM, O_UZI_ITEM, O_GUN_AMMO_ITEM, O_SG_AMMO_ITEM, - O_MAG_AMMO_ITEM, O_UZI_AMMO_ITEM, O_EXPLOSIVE_ITEM, O_MEDI_ITEM, - O_BIGMEDI_ITEM, O_SCION_ITEM, O_SCION_ITEM2, O_LEADBAR_ITEM, -}; +int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, + O_KEY_ITEM2, O_KEY_ITEM3, O_KEY_ITEM4, + O_PUZZLE_ITEM1, O_PUZZLE_ITEM2, O_PUZZLE_ITEM3, + O_PUZZLE_ITEM4, O_GUN_ITEM, O_SHOTGUN_ITEM, + O_MAGNUM_ITEM, O_UZI_ITEM, O_GUN_AMMO_ITEM, + O_SG_AMMO_ITEM, O_MAG_AMMO_ITEM, O_UZI_AMMO_ITEM, + O_EXPLOSIVE_ITEM, O_MEDI_ITEM, O_BIGMEDI_ITEM, + O_SCION_ITEM, O_SCION_ITEM2, O_LEADBAR_ITEM, + NO_ITEM }; // TODO: need to check only active mummies -int16_t m_KillableObjs[NUM_KILLABLE_OBJ] = { - O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, - O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, - O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, - O_WARRIOR3, O_CENTAUR, O_DINO_WARRIOR, O_LARSON, O_PIERRE, - O_SKATEBOARD, O_MERCENARY1, O_MERCENARY2, O_MERCENARY3, O_NATLA, - O_ABORTION, O_SCION_ITEM3 +int16_t m_KillableObjs[] = { + O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, + O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, + O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, + O_WARRIOR3, O_CENTAUR, O_DINO_WARRIOR, O_LARSON, O_PIERRE, + O_SKATEBOARD, O_MERCENARY1, O_MERCENARY2, O_MERCENARY3, O_NATLA, + O_ABORTION, O_SCION_ITEM3, NO_ITEM }; static bool Level_LoadRooms(MYFILE *fp); @@ -432,14 +430,14 @@ static bool Level_LoadItems(MYFILE *fp) InitialiseItem(i); // Calculate number of pickups in a level - for (int16_t j = 0; j < NUM_PICKUP_OBJ; j++) { + for (int16_t j = 0; m_PickupObjs[j] != NO_ITEM; j++) { if (item->object_number == m_PickupObjs[j]) { m_LevelPickups++; } } // Calculate number of killable objects in a level - for (int16_t j = 0; j < NUM_KILLABLE_OBJ; j++) { + for (int16_t j = 0; m_KillableObjs[j] != NO_ITEM; j++) { if (item->object_number == m_KillableObjs[j]) { m_LevelKillables++; } From 968ba9ba0114b657d440f766f3cfd5e8b95d2521 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Thu, 3 Feb 2022 19:36:44 -0500 Subject: [PATCH 04/25] wip: fix mummy kills; pierre almost fixed pickup and kills --- src/game/ai/baldy.c | 3 +- src/game/ai/cowboy.c | 2 +- src/game/ai/skate_kid.c | 6 +- src/game/larafire.c | 2 +- src/game/level.c | 206 +++++++++++++++++++++++++++++++++++----- src/game/savegame.c | 6 +- src/game/setup.c | 6 +- src/global/types.h | 6 +- 8 files changed, 196 insertions(+), 41 deletions(-) diff --git a/src/game/ai/baldy.c b/src/game/ai/baldy.c index 75a50ddfd..e59dc0089 100644 --- a/src/game/ai/baldy.c +++ b/src/game/ai/baldy.c @@ -54,8 +54,7 @@ void BaldyControl(int16_t item_num) if (item->hit_points <= 0) { if (item->current_anim_state != BALDY_DEATH) { item->current_anim_state = BALDY_DEATH; - item->anim_number = - g_Objects[O_MERCENARY3].anim_index + BALDY_DIE_ANIM; + item->anim_number = g_Objects[O_BALDY].anim_index + BALDY_DIE_ANIM; item->frame_number = g_Anims[item->anim_number].frame_base; SpawnItem(item, O_SHOTGUN_ITEM); } diff --git a/src/game/ai/cowboy.c b/src/game/ai/cowboy.c index e5ff63ebc..54c57072b 100644 --- a/src/game/ai/cowboy.c +++ b/src/game/ai/cowboy.c @@ -50,7 +50,7 @@ void CowboyControl(int16_t item_num) if (item->current_anim_state != COWBOY_DEATH) { item->current_anim_state = COWBOY_DEATH; item->anim_number = - g_Objects[O_MERCENARY2].anim_index + COWBOY_DIE_ANIM; + g_Objects[O_COWBOY].anim_index + COWBOY_DIE_ANIM; item->frame_number = g_Anims[item->anim_number].frame_base; SpawnItem(item, O_MAGNUM_ITEM); } diff --git a/src/game/ai/skate_kid.c b/src/game/ai/skate_kid.c index 61d160cd0..e7b4020dc 100644 --- a/src/game/ai/skate_kid.c +++ b/src/game/ai/skate_kid.c @@ -51,7 +51,7 @@ void SkateKidControl(int16_t item_num) if (item->current_anim_state != SKATE_KID_DEATH) { item->current_anim_state = SKATE_KID_DEATH; item->anim_number = - g_Objects[O_MERCENARY1].anim_index + SKATE_KID_DIE_ANIM; + g_Objects[O_SKATEKID].anim_index + SKATE_KID_DIE_ANIM; item->frame_number = g_Anims[item->anim_number].frame_base; SpawnItem(item, O_UZI_ITEM); } @@ -144,9 +144,9 @@ void DrawSkateKid(ITEM_INFO *item) int16_t frame = item->frame_number; item->object_number = O_SKATEBOARD; item->anim_number = anim + g_Objects[O_SKATEBOARD].anim_index - - g_Objects[O_MERCENARY1].anim_index; + - g_Objects[O_SKATEKID].anim_index; DrawAnimatingItem(item); item->anim_number = anim; item->frame_number = frame; - item->object_number = O_MERCENARY1; + item->object_number = O_SKATEKID; } diff --git a/src/game/larafire.c b/src/game/larafire.c index a3a140600..ba97e2307 100644 --- a/src/game/larafire.c +++ b/src/game/larafire.c @@ -628,7 +628,7 @@ void HitTarget(ITEM_INFO *item, GAME_VECTOR *hitpos, int32_t damage) Sound_Effect(SFX_RAT_CHIRP, &item->pos, SPM_NORMAL); break; - case O_MERCENARY1: + case O_SKATEKID: Sound_Effect(SFX_SKATEBOARD_HIT, &item->pos, SPM_NORMAL); break; diff --git a/src/game/level.c b/src/game/level.c index 0eda3a3d0..bcd66d3c6 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -16,6 +16,13 @@ #include "memory.h" #include +#include + +#define TT_SIZE 256 +#define PIERRE_ITEMS 3 +#define SKATEKID_ITEMS 1 +#define COWBOY_ITEMS 1 +#define BALDY_ITEMS 1 static int32_t m_MeshCount = 0; static int32_t m_MeshPtrCount = 0; @@ -37,7 +44,13 @@ static int32_t m_OverlapCount = 0; static int32_t m_LevelPickups = 0; static int32_t m_LevelKillables = 0; -// TODO: game doesn't add O_SCION_ITEM4 (complete Scion Atlantis) as pickup +int32_t m_PierreDrops = 0; +int32_t m_PierreKills = 0; +int16_t m_PierreIdxs[TT_SIZE] = { 0 }; + +int32_t m_MummyKills = 0; +int16_t m_MummyIdxs[TT_SIZE] = { 0 }; + int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_KEY_ITEM2, O_KEY_ITEM3, O_KEY_ITEM4, O_PUZZLE_ITEM1, O_PUZZLE_ITEM2, O_PUZZLE_ITEM3, @@ -48,14 +61,13 @@ int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_SCION_ITEM, O_SCION_ITEM2, O_LEADBAR_ITEM, NO_ITEM }; -// TODO: need to check only active mummies int16_t m_KillableObjs[] = { - O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, - O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, - O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, - O_WARRIOR3, O_CENTAUR, O_DINO_WARRIOR, O_LARSON, O_PIERRE, - O_SKATEBOARD, O_MERCENARY1, O_MERCENARY2, O_MERCENARY3, O_NATLA, - O_ABORTION, O_SCION_ITEM3, NO_ITEM + O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, + O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, + O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, + O_WARRIOR3, O_CENTAUR, O_DINO_WARRIOR, O_LARSON, O_SKATEBOARD, + O_SKATEKID, O_COWBOY, O_BALDY, O_NATLA, O_ABORTION, + O_SCION_ITEM3, NO_ITEM }; static bool Level_LoadRooms(MYFILE *fp); @@ -72,6 +84,8 @@ static bool Level_LoadCinematic(MYFILE *fp); static bool Level_LoadDemo(MYFILE *fp); static bool Level_LoadSamples(MYFILE *fp); static bool Level_LoadTexturePages(MYFILE *fp); +static void Level_CalculateStats(); +static void Level_CheckObjTriggers(); static bool Level_LoadFromFile(const char *filename, int32_t level_num); @@ -392,8 +406,6 @@ static bool Level_LoadSprites(MYFILE *fp) static bool Level_LoadItems(MYFILE *fp) { - m_LevelPickups = 0; - m_LevelKillables = 0; int32_t item_count = 0; File_Read(&item_count, sizeof(int32_t), 1, fp); @@ -426,22 +438,7 @@ static bool Level_LoadItems(MYFILE *fp) "Level_LoadItems(): Bad Object number (%d) on Item %d", item->object_number, i); } - InitialiseItem(i); - - // Calculate number of pickups in a level - for (int16_t j = 0; m_PickupObjs[j] != NO_ITEM; j++) { - if (item->object_number == m_PickupObjs[j]) { - m_LevelPickups++; - } - } - - // Calculate number of killable objects in a level - for (int16_t j = 0; m_KillableObjs[j] != NO_ITEM; j++) { - if (item->object_number == m_KillableObjs[j]) { - m_LevelKillables++; - } - } } } @@ -711,8 +708,167 @@ bool Level_Load(int level_num) } g_GameFlow.levels[level_num].secrets = GetSecretCount(); + Level_CalculateStats(); g_GameFlow.levels[level_num].pickups = m_LevelPickups; g_GameFlow.levels[level_num].kills = m_LevelKillables; return ret; } + +static void Level_CalculateStats() +{ + m_LevelPickups = 0; + m_LevelKillables = 0; + memset(m_PierreIdxs, 0, sizeof(m_PierreIdxs)); + memset(m_MummyIdxs, 0, sizeof(m_MummyIdxs)); + + if (g_LevelItemCount) { + if (g_LevelItemCount > MAX_ITEMS) { + Shell_ExitSystem( + "Level_GetPickupCount(): Too Many g_Items being Loaded!!"); + return; + } + + LOG_DEBUG("g_LevelItemCount: %d", g_LevelItemCount); + for (int i = 0; i < g_LevelItemCount; i++) { + ITEM_INFO *item = &g_Items[i]; + LOG_DEBUG( + " i: %d, item->object_number: %d", i, item->object_number); + + if (item->object_number < 0 || item->object_number >= O_NUMBER_OF) { + Shell_ExitSystemFmt( + "Level_GetPickupCount(): Bad Object number (%d) on Item %d", + item->object_number, i); + } + + // Calculate number of pickups in a level + for (int j = 0; m_PickupObjs[j] != NO_ITEM; j++) { + if (item->object_number == m_PickupObjs[j]) { + if (item->object_number == O_SKATEKID) { + m_LevelPickups += SKATEKID_ITEMS; + } else if (item->object_number == O_COWBOY) { + m_LevelPickups += COWBOY_ITEMS; + } else if (item->object_number == O_BALDY) { + m_LevelPickups += BALDY_ITEMS; + } else { + m_LevelPickups++; + } + } + } + + // Calculate number of killable objects in a level + for (int j = 0; m_KillableObjs[j] != NO_ITEM; j++) { + if (item->object_number == m_KillableObjs[j]) { + m_LevelKillables++; + } + } + } + } + + // Check triggers for special pickups / kills + Level_CheckObjTriggers(); +} + +static bool Level_FindElement(int16_t elem, int16_t array[], int16_t size) +{ + for (int16_t i = 0; i < size; i++) { + if (array[i] == elem) { + return true; + } + } + return false; +} + +static void Level_CheckObjTriggers() +{ + int16_t pierre_idx = 0; + int16_t mummy_idx = 0; + + for (int i = 0; i < g_RoomCount; i++) { + ROOM_INFO *r = &g_RoomInfo[i]; + FLOOR_INFO *floor = &r->floor[0]; + for (int j = 0; j < r->y_size * r->x_size; j++, floor++) { + LOG_DEBUG("room i: %d", i); + int k = floor->index; + if (!k) { + continue; + } + + while (1) { + uint16_t floor = g_FloorData[k++]; + + switch (floor & DATA_TYPE) { + case FT_DOOR: + case FT_ROOF: + case FT_TILT: + k++; + break; + + case FT_LAVA: + break; + + case FT_TRIGGER: { + uint16_t trig_type = (floor & 0x3F00) >> 8; + uint16_t trigger_data = g_FloorData[k++]; + + if (trig_type != TT_TRIGGER) { + k++; + } + + while (1) { + int16_t command = g_FloorData[k++]; + int16_t item_idx = command & VALUE_BITS; + if (trig_type == TT_TRIGGER) { + ITEM_INFO *item = &g_Items[item_idx]; + OBJECT_INFO *object = + &g_Objects[item->object_number]; + LOG_DEBUG( + "item->object_number: %d", item->object_number); + LOG_DEBUG(" item_idx: %d", item_idx); + LOG_DEBUG( + " trigger_data: %d", + trigger_data & IF_ONESHOT); + LOG_DEBUG( + " Level_FindElement: %d", + Level_FindElement( + item_idx, m_PierreIdxs, TT_SIZE)); + + // Add Pierre pickup and kills if oneshot trigger + if (item->object_number == O_PIERRE + && trigger_data & IF_ONESHOT + && !Level_FindElement( + item_idx, m_PierreIdxs, TT_SIZE)) { + LOG_DEBUG(" Add Pierre #%d", item_idx); + m_LevelPickups += PIERRE_ITEMS; + m_LevelKillables += 1; + m_PierreIdxs[pierre_idx++] = item_idx; + } + + // Check for activated mummies + if (item->object_number == O_MUMMY + && !Level_FindElement( + item_idx, m_MummyIdxs, TT_SIZE)) { + LOG_DEBUG(" Add Mummy #%d", item_idx); + m_LevelKillables += 1; + m_MummyIdxs[mummy_idx++] = item_idx; + } + + } else { + k++; + } + + if (command & END_BIT) { + break; + } + } + break; + } + } + + if (floor & END_BIT) { + break; + } + } + } + } +} \ No newline at end of file diff --git a/src/game/savegame.c b/src/game/savegame.c index c68e28524..87f260d07 100644 --- a/src/game/savegame.c +++ b/src/game/savegame.c @@ -590,20 +590,20 @@ void SaveGame_ApplySaveBuffer(GAME_INFO *game_info) g_MusicTrackFlags[MX_PIERRE_SPEECH] |= IF_ONESHOT; } - if (item->object_number == O_MERCENARY1 && item->hit_points <= 0) { + if (item->object_number == O_SKATEKID && item->hit_points <= 0) { if (!Inv_RequestItem(O_UZI_ITEM)) { SpawnItem(item, O_UZI_ITEM); } } - if (item->object_number == O_MERCENARY2 && item->hit_points <= 0) { + if (item->object_number == O_COWBOY && item->hit_points <= 0) { if (!Inv_RequestItem(O_MAGNUM_ITEM)) { SpawnItem(item, O_MAGNUM_ITEM); } g_MusicTrackFlags[MX_COWBOY_SPEECH] |= IF_ONESHOT; } - if (item->object_number == O_MERCENARY3 && item->hit_points <= 0) { + if (item->object_number == O_BALDY && item->hit_points <= 0) { if (!Inv_RequestItem(O_SHOTGUN_ITEM)) { SpawnItem(item, O_SHOTGUN_ITEM); } diff --git a/src/game/setup.c b/src/game/setup.c index 80c032b92..f0f68b22b 100644 --- a/src/game/setup.c +++ b/src/game/setup.c @@ -195,9 +195,9 @@ void BaddyObjects() SetupWarrior3(&g_Objects[O_WARRIOR3]); SetupCentaur(&g_Objects[O_CENTAUR]); SetupMummy(&g_Objects[O_MUMMY]); - SetupSkateKid(&g_Objects[O_MERCENARY1]); - SetupCowboy(&g_Objects[O_MERCENARY2]); - SetupBaldy(&g_Objects[O_MERCENARY3]); + SetupSkateKid(&g_Objects[O_SKATEKID]); + SetupCowboy(&g_Objects[O_COWBOY]); + SetupBaldy(&g_Objects[O_BALDY]); SetupAbortion(&g_Objects[O_ABORTION]); SetupNatla(&g_Objects[O_NATLA]); SetupPod(&g_Objects[O_PODS]); diff --git a/src/global/types.h b/src/global/types.h index eb43b0ba1..0830d1b1b 100644 --- a/src/global/types.h +++ b/src/global/types.h @@ -55,9 +55,9 @@ typedef enum GAME_OBJECT_ID { O_LARSON = 27, O_PIERRE = 28, O_SKATEBOARD = 29, - O_MERCENARY1 = 30, - O_MERCENARY2 = 31, - O_MERCENARY3 = 32, + O_SKATEKID = 30, + O_COWBOY = 31, + O_BALDY = 32, O_NATLA = 33, O_ABORTION = 34, // a.k.a. Adam, Torso or Evil Natla O_FALLING_BLOCK = 35, From ae4dba74b79156c670cff109d1e1aee98d2e27f2 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Fri, 4 Feb 2022 00:39:51 -0500 Subject: [PATCH 05/25] fix Pierre stats calc and other mercenaries --- src/game/level.c | 163 ++++++++++++++++++++++------------------------- 1 file changed, 77 insertions(+), 86 deletions(-) diff --git a/src/game/level.c b/src/game/level.c index bcd66d3c6..82b10459b 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -744,17 +744,17 @@ static void Level_CalculateStats() // Calculate number of pickups in a level for (int j = 0; m_PickupObjs[j] != NO_ITEM; j++) { if (item->object_number == m_PickupObjs[j]) { - if (item->object_number == O_SKATEKID) { - m_LevelPickups += SKATEKID_ITEMS; - } else if (item->object_number == O_COWBOY) { - m_LevelPickups += COWBOY_ITEMS; - } else if (item->object_number == O_BALDY) { - m_LevelPickups += BALDY_ITEMS; - } else { - m_LevelPickups++; - } + m_LevelPickups++; } } + // Spawn pickups on death + if (item->object_number == O_SKATEKID) { + m_LevelPickups += SKATEKID_ITEMS; + } else if (item->object_number == O_COWBOY) { + m_LevelPickups += COWBOY_ITEMS; + } else if (item->object_number == O_BALDY) { + m_LevelPickups += BALDY_ITEMS; + } // Calculate number of killable objects in a level for (int j = 0; m_KillableObjs[j] != NO_ITEM; j++) { @@ -786,89 +786,80 @@ static void Level_CheckObjTriggers() for (int i = 0; i < g_RoomCount; i++) { ROOM_INFO *r = &g_RoomInfo[i]; - FLOOR_INFO *floor = &r->floor[0]; - for (int j = 0; j < r->y_size * r->x_size; j++, floor++) { - LOG_DEBUG("room i: %d", i); - int k = floor->index; - if (!k) { - continue; - } - - while (1) { - uint16_t floor = g_FloorData[k++]; - - switch (floor & DATA_TYPE) { - case FT_DOOR: - case FT_ROOF: - case FT_TILT: - k++; - break; + for (int x_floor = 0; x_floor < r->x_size; x_floor++) { + for (int y_floor = 0; y_floor < r->y_size; y_floor++) { - case FT_LAVA: - break; - - case FT_TRIGGER: { - uint16_t trig_type = (floor & 0x3F00) >> 8; - uint16_t trigger_data = g_FloorData[k++]; - - if (trig_type != TT_TRIGGER) { - k++; + if (x_floor == 0 || x_floor == r->x_size - 1) { + if (y_floor == 0 || y_floor == r->y_size - 1) { + continue; } + } - while (1) { - int16_t command = g_FloorData[k++]; - int16_t item_idx = command & VALUE_BITS; - if (trig_type == TT_TRIGGER) { - ITEM_INFO *item = &g_Items[item_idx]; - OBJECT_INFO *object = - &g_Objects[item->object_number]; - LOG_DEBUG( - "item->object_number: %d", item->object_number); - LOG_DEBUG(" item_idx: %d", item_idx); - LOG_DEBUG( - " trigger_data: %d", - trigger_data & IF_ONESHOT); - LOG_DEBUG( - " Level_FindElement: %d", - Level_FindElement( - item_idx, m_PierreIdxs, TT_SIZE)); - - // Add Pierre pickup and kills if oneshot trigger - if (item->object_number == O_PIERRE - && trigger_data & IF_ONESHOT - && !Level_FindElement( - item_idx, m_PierreIdxs, TT_SIZE)) { - LOG_DEBUG(" Add Pierre #%d", item_idx); - m_LevelPickups += PIERRE_ITEMS; - m_LevelKillables += 1; - m_PierreIdxs[pierre_idx++] = item_idx; - } + FLOOR_INFO *floor = &r->floor[x_floor + y_floor * r->x_size]; + if (!floor->index) { + continue; + } - // Check for activated mummies - if (item->object_number == O_MUMMY - && !Level_FindElement( - item_idx, m_MummyIdxs, TT_SIZE)) { - LOG_DEBUG(" Add Mummy #%d", item_idx); - m_LevelKillables += 1; - m_MummyIdxs[mummy_idx++] = item_idx; + int16_t *data = &g_FloorData[floor->index]; + int16_t type; + int16_t trigger; + int16_t trig_flags; + do { + type = *data++; + + switch (type & DATA_TYPE) { + case FT_TILT: + case FT_ROOF: + case FT_DOOR: + data++; + break; + + case FT_LAVA: + break; + + case FT_TRIGGER: + trig_flags = *data; + data++; + do { + trigger = *data++; + if (TRIG_BITS(trigger) != TO_OBJECT) { + if (TRIG_BITS(trigger) == TO_CAMERA) { + trigger = *data++; + } + } else { + int16_t idx = trigger & VALUE_BITS; + ITEM_INFO *item = &g_Items[idx]; + + LOG_DEBUG("idx: %d", idx); + LOG_DEBUG( + " trig_flags: %d", + trig_flags & IF_ONESHOT); + + // Add Pierre pickup and kills if oneshot + if (item->object_number == O_PIERRE + && trig_flags & IF_ONESHOT + && !Level_FindElement( + idx, m_PierreIdxs, TT_SIZE)) { + LOG_DEBUG(" Add pierre: %d", idx); + m_LevelPickups += PIERRE_ITEMS; + m_LevelKillables += 1; + m_PierreIdxs[pierre_idx++] = idx; + } + + // Check for activated mummies + if (item->object_number == O_MUMMY + && !Level_FindElement( + idx, m_MummyIdxs, TT_SIZE)) { + LOG_DEBUG(" Add Mummy: %d", idx); + m_LevelKillables += 1; + m_MummyIdxs[mummy_idx++] = idx; + } } - - } else { - k++; - } - - if (command & END_BIT) { - break; - } + } while (!(trigger & END_BIT)); + break; } - break; - } - } - - if (floor & END_BIT) { - break; - } + } while (!(type & END_BIT)); } } } -} \ No newline at end of file +} From 378a51d7dafe55106ad97e68882a16e2ad4734a5 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Fri, 4 Feb 2022 17:42:29 -0500 Subject: [PATCH 06/25] wip: fix floor trigger parsing, mutants in progress --- src/game/level.c | 102 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 29 deletions(-) diff --git a/src/game/level.c b/src/game/level.c index 82b10459b..f56971875 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -43,13 +43,18 @@ static int32_t m_SpriteCount = 0; static int32_t m_OverlapCount = 0; static int32_t m_LevelPickups = 0; static int32_t m_LevelKillables = 0; +static FLOOR_INFO **m_FloorArray; -int32_t m_PierreDrops = 0; -int32_t m_PierreKills = 0; -int16_t m_PierreIdxs[TT_SIZE] = { 0 }; +typedef struct STAT_INFO { + int32_t drops; + int32_t kills; + int16_t cur_idx; + int16_t idxs[TT_SIZE]; +} STAT_INFO; -int32_t m_MummyKills = 0; -int16_t m_MummyIdxs[TT_SIZE] = { 0 }; +static STAT_INFO m_Pierre = { 0 }; +static STAT_INFO m_Mummy = { 0 }; +static STAT_INFO m_Pod = { 0 }; int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_KEY_ITEM2, O_KEY_ITEM3, O_KEY_ITEM4, @@ -62,14 +67,16 @@ int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, NO_ITEM }; int16_t m_KillableObjs[] = { - O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, - O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, - O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, - O_WARRIOR3, O_CENTAUR, O_DINO_WARRIOR, O_LARSON, O_SKATEBOARD, - O_SKATEKID, O_COWBOY, O_BALDY, O_NATLA, O_ABORTION, - O_SCION_ITEM3, NO_ITEM + O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, + O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, + O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_CENTAUR, + O_DINO_WARRIOR, O_LARSON, O_SKATEBOARD, O_SKATEKID, O_COWBOY, + O_BALDY, O_NATLA, O_ABORTION, O_SCION_ITEM3, NO_ITEM }; +int16_t m_KillableMutants[] = { O_WARRIOR1, O_WARRIOR2, O_WARRIOR3, + O_CENTAUR, O_ABORTION, NO_ITEM }; + static bool Level_LoadRooms(MYFILE *fp); static bool Level_LoadObjects(MYFILE *fp); static bool Level_LoadSprites(MYFILE *fp); @@ -85,7 +92,8 @@ static bool Level_LoadDemo(MYFILE *fp); static bool Level_LoadSamples(MYFILE *fp); static bool Level_LoadTexturePages(MYFILE *fp); static void Level_CalculateStats(); -static void Level_CheckObjTriggers(); +static bool Level_FindElement(int16_t elem, int16_t array[], int16_t size); +static void Level_CalculateTriggers(); static bool Level_LoadFromFile(const char *filename, int32_t level_num); @@ -185,6 +193,10 @@ static bool Level_LoadRooms(MYFILE *fp) File_Read(&g_RoomCount, sizeof(uint16_t), 1, fp); LOG_INFO("%d rooms", g_RoomCount); + // Copy for stats info + m_FloorArray = + GameBuf_Alloc(sizeof(FLOOR_INFO *) * g_RoomCount, GBUF_ROOM_FLOOR); + g_RoomInfo = GameBuf_Alloc(sizeof(ROOM_INFO) * g_RoomCount, GBUF_ROOM_INFOS); int i = 0; @@ -266,6 +278,13 @@ static bool Level_LoadRooms(MYFILE *fp) current_room_info->right = 0; current_room_info->item_number = -1; current_room_info->fx_number = -1; + + // Save copy of floor info for stats calculation + m_FloorArray[i] = + GameBuf_Alloc(sizeof(FLOOR_INFO) * count4, GBUF_ROOM_FLOOR); + memcpy( + m_FloorArray[i], current_room_info->floor, + sizeof(FLOOR_INFO) * count4); } File_Read(&m_FloorDataSize, sizeof(uint32_t), 1, fp); @@ -711,6 +730,7 @@ bool Level_Load(int level_num) Level_CalculateStats(); g_GameFlow.levels[level_num].pickups = m_LevelPickups; g_GameFlow.levels[level_num].kills = m_LevelKillables; + Memory_FreePointer(&m_FloorArray); return ret; } @@ -719,8 +739,9 @@ static void Level_CalculateStats() { m_LevelPickups = 0; m_LevelKillables = 0; - memset(m_PierreIdxs, 0, sizeof(m_PierreIdxs)); - memset(m_MummyIdxs, 0, sizeof(m_MummyIdxs)); + memset(&m_Pierre, 0, sizeof(m_Pierre)); + memset(&m_Mummy, 0, sizeof(m_Mummy)); + memset(&m_Pod, 0, sizeof(m_Pod)); if (g_LevelItemCount) { if (g_LevelItemCount > MAX_ITEMS) { @@ -759,14 +780,25 @@ static void Level_CalculateStats() // Calculate number of killable objects in a level for (int j = 0; m_KillableObjs[j] != NO_ITEM; j++) { if (item->object_number == m_KillableObjs[j]) { + LOG_DEBUG("Killable: %d", i); + m_LevelKillables++; + } + } + + // Mutants + for (int j = 0; m_KillableMutants[j] != NO_ITEM; j++) { + if (item->object_number == m_KillableMutants[j] + && !Level_FindElement(i, m_Pod.idxs, TT_SIZE)) { + LOG_DEBUG("Killable mutant: %d", i); m_LevelKillables++; + m_Pod.idxs[m_Pod.cur_idx++] = i; } } } } // Check triggers for special pickups / kills - Level_CheckObjTriggers(); + Level_CalculateTriggers(); } static bool Level_FindElement(int16_t elem, int16_t array[], int16_t size) @@ -779,11 +811,8 @@ static bool Level_FindElement(int16_t elem, int16_t array[], int16_t size) return false; } -static void Level_CheckObjTriggers() +static void Level_CalculateTriggers() { - int16_t pierre_idx = 0; - int16_t mummy_idx = 0; - for (int i = 0; i < g_RoomCount; i++) { ROOM_INFO *r = &g_RoomInfo[i]; for (int x_floor = 0; x_floor < r->x_size; x_floor++) { @@ -795,7 +824,9 @@ static void Level_CheckObjTriggers() } } - FLOOR_INFO *floor = &r->floor[x_floor + y_floor * r->x_size]; + FLOOR_INFO *floor = + &m_FloorArray[i][x_floor + y_floor * r->x_size]; + if (!floor->index) { continue; } @@ -804,6 +835,7 @@ static void Level_CheckObjTriggers() int16_t type; int16_t trigger; int16_t trig_flags; + int16_t trig_type; do { type = *data++; @@ -820,8 +852,11 @@ static void Level_CheckObjTriggers() case FT_TRIGGER: trig_flags = *data; data++; + trig_type = (type >> 8) & 0x3F; + LOG_DEBUG(" trig_type: %d", trig_type); do { trigger = *data++; + LOG_DEBUG(" idx: %d", trigger & VALUE_BITS); if (TRIG_BITS(trigger) != TO_OBJECT) { if (TRIG_BITS(trigger) == TO_CAMERA) { trigger = *data++; @@ -830,29 +865,38 @@ static void Level_CheckObjTriggers() int16_t idx = trigger & VALUE_BITS; ITEM_INFO *item = &g_Items[idx]; - LOG_DEBUG("idx: %d", idx); LOG_DEBUG( - " trig_flags: %d", + " trig_flags: %d", trig_flags & IF_ONESHOT); // Add Pierre pickup and kills if oneshot if (item->object_number == O_PIERRE && trig_flags & IF_ONESHOT && !Level_FindElement( - idx, m_PierreIdxs, TT_SIZE)) { - LOG_DEBUG(" Add pierre: %d", idx); + idx, m_Pierre.idxs, TT_SIZE)) { + LOG_DEBUG(" Add pierre: %d", idx); m_LevelPickups += PIERRE_ITEMS; m_LevelKillables += 1; - m_PierreIdxs[pierre_idx++] = idx; + m_Pierre.idxs[m_Pierre.cur_idx++] = idx; } - // Check for activated mummies + // Check for mummy triggers if (item->object_number == O_MUMMY && !Level_FindElement( - idx, m_MummyIdxs, TT_SIZE)) { - LOG_DEBUG(" Add Mummy: %d", idx); + idx, m_Mummy.idxs, TT_SIZE)) { + LOG_DEBUG(" Add Mummy: %d", idx); + m_LevelKillables += 1; + m_Mummy.idxs[m_Mummy.cur_idx++] = idx; + } + + // Check for mutant triggers + if ((item->object_number == O_PODS + || item->object_number == O_BIG_POD) + && !Level_FindElement( + idx, m_Pod.idxs, TT_SIZE)) { + LOG_DEBUG(" Add Pod Mutant: %d", idx); m_LevelKillables += 1; - m_MummyIdxs[mummy_idx++] = idx; + m_Pod.idxs[m_Pod.cur_idx++] = idx; } } } while (!(trigger & END_BIT)); From cf7fc97d4c58501d7a92d35703b769f846d4a9ce Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Fri, 4 Feb 2022 20:49:39 -0500 Subject: [PATCH 07/25] fix mutant calcs and add bat/statue trigger checks --- src/game/level.c | 98 ++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/src/game/level.c b/src/game/level.c index f56971875..3ede5639a 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -18,7 +18,7 @@ #include #include -#define TT_SIZE 256 +#define STAT_SIZE 512 #define PIERRE_ITEMS 3 #define SKATEKID_ITEMS 1 #define COWBOY_ITEMS 1 @@ -43,18 +43,21 @@ static int32_t m_SpriteCount = 0; static int32_t m_OverlapCount = 0; static int32_t m_LevelPickups = 0; static int32_t m_LevelKillables = 0; -static FLOOR_INFO **m_FloorArray; +static int32_t m_UninitItemCount = 0; +static FLOOR_INFO **m_FloorArray = NULL; typedef struct STAT_INFO { int32_t drops; int32_t kills; int16_t cur_idx; - int16_t idxs[TT_SIZE]; + int16_t idxs[STAT_SIZE]; } STAT_INFO; -static STAT_INFO m_Pierre = { 0 }; -static STAT_INFO m_Mummy = { 0 }; -static STAT_INFO m_Pod = { 0 }; +static STAT_INFO m_Pierres = { 0 }; +static STAT_INFO m_Mummies = { 0 }; +static STAT_INFO m_Pods = { 0 }; +static STAT_INFO m_Bats = { 0 }; +static STAT_INFO m_Statues = { 0 }; int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_KEY_ITEM2, O_KEY_ITEM3, O_KEY_ITEM4, @@ -66,17 +69,16 @@ int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_SCION_ITEM, O_SCION_ITEM2, O_LEADBAR_ITEM, NO_ITEM }; +// A few enemies removed because they need trigger checks int16_t m_KillableObjs[] = { - O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, - O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, - O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_CENTAUR, - O_DINO_WARRIOR, O_LARSON, O_SKATEBOARD, O_SKATEKID, O_COWBOY, - O_BALDY, O_NATLA, O_ABORTION, O_SCION_ITEM3, NO_ITEM + O_WOLF, O_BEAR, O_CROCODILE, O_ALLIGATOR, O_LION, + O_LIONESS, O_PUMA, O_APE, O_RAT, O_VOLE, + O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, O_WARRIOR3, + O_CENTAUR, O_ABORTION, O_DINO_WARRIOR, O_LARSON, O_SKATEBOARD, + O_SKATEKID, O_COWBOY, O_BALDY, O_NATLA, O_SCION_ITEM3, + NO_ITEM }; -int16_t m_KillableMutants[] = { O_WARRIOR1, O_WARRIOR2, O_WARRIOR3, - O_CENTAUR, O_ABORTION, NO_ITEM }; - static bool Level_LoadRooms(MYFILE *fp); static bool Level_LoadObjects(MYFILE *fp); static bool Level_LoadSprites(MYFILE *fp); @@ -425,6 +427,7 @@ static bool Level_LoadSprites(MYFILE *fp) static bool Level_LoadItems(MYFILE *fp) { + m_UninitItemCount = 0; int32_t item_count = 0; File_Read(&item_count, sizeof(int32_t), 1, fp); @@ -439,6 +442,7 @@ static bool Level_LoadItems(MYFILE *fp) g_Items = GameBuf_Alloc(sizeof(ITEM_INFO) * MAX_ITEMS, GBUF_ITEMS); g_LevelItemCount = item_count; + m_UninitItemCount = item_count; InitialiseItemArray(MAX_ITEMS); for (int i = 0; i < item_count; i++) { @@ -739,22 +743,20 @@ static void Level_CalculateStats() { m_LevelPickups = 0; m_LevelKillables = 0; - memset(&m_Pierre, 0, sizeof(m_Pierre)); - memset(&m_Mummy, 0, sizeof(m_Mummy)); - memset(&m_Pod, 0, sizeof(m_Pod)); + memset(&m_Pierres, 0, sizeof(m_Pierres)); + memset(&m_Mummies, 0, sizeof(m_Mummies)); + memset(&m_Pods, 0, sizeof(m_Pods)); + memset(&m_Bats, 0, sizeof(m_Bats)); - if (g_LevelItemCount) { - if (g_LevelItemCount > MAX_ITEMS) { + if (m_UninitItemCount) { + if (m_UninitItemCount > MAX_ITEMS) { Shell_ExitSystem( "Level_GetPickupCount(): Too Many g_Items being Loaded!!"); return; } - LOG_DEBUG("g_LevelItemCount: %d", g_LevelItemCount); - for (int i = 0; i < g_LevelItemCount; i++) { + for (int i = 0; i < m_UninitItemCount; i++) { ITEM_INFO *item = &g_Items[i]; - LOG_DEBUG( - " i: %d, item->object_number: %d", i, item->object_number); if (item->object_number < 0 || item->object_number >= O_NUMBER_OF) { Shell_ExitSystemFmt( @@ -780,24 +782,13 @@ static void Level_CalculateStats() // Calculate number of killable objects in a level for (int j = 0; m_KillableObjs[j] != NO_ITEM; j++) { if (item->object_number == m_KillableObjs[j]) { - LOG_DEBUG("Killable: %d", i); - m_LevelKillables++; - } - } - - // Mutants - for (int j = 0; m_KillableMutants[j] != NO_ITEM; j++) { - if (item->object_number == m_KillableMutants[j] - && !Level_FindElement(i, m_Pod.idxs, TT_SIZE)) { - LOG_DEBUG("Killable mutant: %d", i); m_LevelKillables++; - m_Pod.idxs[m_Pod.cur_idx++] = i; } } } } - // Check triggers for special pickups / kills + // Check triggers for special pickups / killables Level_CalculateTriggers(); } @@ -853,10 +844,8 @@ static void Level_CalculateTriggers() trig_flags = *data; data++; trig_type = (type >> 8) & 0x3F; - LOG_DEBUG(" trig_type: %d", trig_type); do { trigger = *data++; - LOG_DEBUG(" idx: %d", trigger & VALUE_BITS); if (TRIG_BITS(trigger) != TO_OBJECT) { if (TRIG_BITS(trigger) == TO_CAMERA) { trigger = *data++; @@ -865,38 +854,47 @@ static void Level_CalculateTriggers() int16_t idx = trigger & VALUE_BITS; ITEM_INFO *item = &g_Items[idx]; - LOG_DEBUG( - " trig_flags: %d", - trig_flags & IF_ONESHOT); - // Add Pierre pickup and kills if oneshot if (item->object_number == O_PIERRE && trig_flags & IF_ONESHOT && !Level_FindElement( - idx, m_Pierre.idxs, TT_SIZE)) { - LOG_DEBUG(" Add pierre: %d", idx); + idx, m_Pierres.idxs, STAT_SIZE)) { m_LevelPickups += PIERRE_ITEMS; m_LevelKillables += 1; - m_Pierre.idxs[m_Pierre.cur_idx++] = idx; + m_Pierres.idxs[m_Pierres.cur_idx++] = idx; } // Check for mummy triggers if (item->object_number == O_MUMMY && !Level_FindElement( - idx, m_Mummy.idxs, TT_SIZE)) { - LOG_DEBUG(" Add Mummy: %d", idx); + idx, m_Mummies.idxs, STAT_SIZE)) { m_LevelKillables += 1; - m_Mummy.idxs[m_Mummy.cur_idx++] = idx; + m_Mummies.idxs[m_Mummies.cur_idx++] = idx; } // Check for mutant triggers if ((item->object_number == O_PODS || item->object_number == O_BIG_POD) && !Level_FindElement( - idx, m_Pod.idxs, TT_SIZE)) { - LOG_DEBUG(" Add Pod Mutant: %d", idx); + idx, m_Pods.idxs, STAT_SIZE)) { + m_LevelKillables += 1; + m_Pods.idxs[m_Pods.cur_idx++] = idx; + } + + // Check for bat triggers + if ((item->object_number == O_BAT) + && !Level_FindElement( + idx, m_Bats.idxs, STAT_SIZE)) { + m_LevelKillables += 1; + m_Bats.idxs[m_Bats.cur_idx++] = idx; + } + + // Check for statue triggers + if ((item->object_number == O_STATUE) + && !Level_FindElement( + idx, m_Statues.idxs, STAT_SIZE)) { m_LevelKillables += 1; - m_Pod.idxs[m_Pod.cur_idx++] = idx; + m_Statues.idxs[m_Statues.cur_idx++] = idx; } } } while (!(trigger & END_BIT)); From 129ab7d5dbce6d000cddff491df30f5a9b91a432 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Fri, 4 Feb 2022 20:59:14 -0500 Subject: [PATCH 08/25] move secret count to Level_CalculateTrigger --- src/game/level.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/game/level.c b/src/game/level.c index 3ede5639a..d0ece2158 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -43,6 +43,7 @@ static int32_t m_SpriteCount = 0; static int32_t m_OverlapCount = 0; static int32_t m_LevelPickups = 0; static int32_t m_LevelKillables = 0; +static int32_t m_LevelSecrets = 0; static int32_t m_UninitItemCount = 0; static FLOOR_INFO **m_FloorArray = NULL; @@ -730,8 +731,8 @@ bool Level_Load(int level_num) } } - g_GameFlow.levels[level_num].secrets = GetSecretCount(); Level_CalculateStats(); + g_GameFlow.levels[level_num].secrets = m_LevelSecrets; g_GameFlow.levels[level_num].pickups = m_LevelPickups; g_GameFlow.levels[level_num].kills = m_LevelKillables; Memory_FreePointer(&m_FloorArray); @@ -741,12 +742,15 @@ bool Level_Load(int level_num) static void Level_CalculateStats() { + // Clear old values m_LevelPickups = 0; m_LevelKillables = 0; + m_LevelSecrets = 0; memset(&m_Pierres, 0, sizeof(m_Pierres)); memset(&m_Mummies, 0, sizeof(m_Mummies)); memset(&m_Pods, 0, sizeof(m_Pods)); memset(&m_Bats, 0, sizeof(m_Bats)); + memset(&m_Statues, 0, sizeof(m_Statues)); if (m_UninitItemCount) { if (m_UninitItemCount > MAX_ITEMS) { @@ -804,6 +808,8 @@ static bool Level_FindElement(int16_t elem, int16_t array[], int16_t size) static void Level_CalculateTriggers() { + uint32_t secrets = 0; + for (int i = 0; i < g_RoomCount; i++) { ROOM_INFO *r = &g_RoomInfo[i]; for (int x_floor = 0; x_floor < r->x_size; x_floor++) { @@ -846,6 +852,13 @@ static void Level_CalculateTriggers() trig_type = (type >> 8) & 0x3F; do { trigger = *data++; + if (TRIG_BITS(trigger) == TO_SECRET) { + int16_t number = trigger & VALUE_BITS; + if (!(secrets & (1 << number))) { + secrets |= (1 << number); + m_LevelSecrets++; + } + } if (TRIG_BITS(trigger) != TO_OBJECT) { if (TRIG_BITS(trigger) == TO_CAMERA) { trigger = *data++; From 3cb58df4d38aa838539dbfb302300b03c73752c9 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 10:00:31 -0500 Subject: [PATCH 09/25] stats: create stats file for level stats --- meson.build | 1 + src/game/level.c | 233 +------------------------------------------- src/game/stats.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++ src/game/stats.h | 12 +++ 4 files changed, 266 insertions(+), 228 deletions(-) create mode 100644 src/game/stats.c create mode 100644 src/game/stats.h diff --git a/meson.build b/meson.build index f7c12621f..0c35c2612 100644 --- a/meson.build +++ b/meson.build @@ -189,6 +189,7 @@ sources = [ 'src/game/shell.c', 'src/game/sound.c', 'src/game/sphere.c', + 'src/game/stats.c', 'src/game/text.c', 'src/game/traps/damocles_sword.c', 'src/game/traps/dart.c', diff --git a/src/game/level.c b/src/game/level.c index d0ece2158..01b8345f8 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -10,6 +10,7 @@ #include "game/setup.h" #include "game/shell.h" #include "game/sound.h" +#include "game/stats.h" #include "game/viewport.h" #include "global/vars.h" #include "log.h" @@ -18,12 +19,6 @@ #include #include -#define STAT_SIZE 512 -#define PIERRE_ITEMS 3 -#define SKATEKID_ITEMS 1 -#define COWBOY_ITEMS 1 -#define BALDY_ITEMS 1 - static int32_t m_MeshCount = 0; static int32_t m_MeshPtrCount = 0; static int32_t m_AnimCount = 0; @@ -41,45 +36,9 @@ static int32_t m_AnimTextureRangeCount = 0; static int32_t m_SpriteInfoCount = 0; static int32_t m_SpriteCount = 0; static int32_t m_OverlapCount = 0; -static int32_t m_LevelPickups = 0; -static int32_t m_LevelKillables = 0; -static int32_t m_LevelSecrets = 0; static int32_t m_UninitItemCount = 0; static FLOOR_INFO **m_FloorArray = NULL; -typedef struct STAT_INFO { - int32_t drops; - int32_t kills; - int16_t cur_idx; - int16_t idxs[STAT_SIZE]; -} STAT_INFO; - -static STAT_INFO m_Pierres = { 0 }; -static STAT_INFO m_Mummies = { 0 }; -static STAT_INFO m_Pods = { 0 }; -static STAT_INFO m_Bats = { 0 }; -static STAT_INFO m_Statues = { 0 }; - -int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, - O_KEY_ITEM2, O_KEY_ITEM3, O_KEY_ITEM4, - O_PUZZLE_ITEM1, O_PUZZLE_ITEM2, O_PUZZLE_ITEM3, - O_PUZZLE_ITEM4, O_GUN_ITEM, O_SHOTGUN_ITEM, - O_MAGNUM_ITEM, O_UZI_ITEM, O_GUN_AMMO_ITEM, - O_SG_AMMO_ITEM, O_MAG_AMMO_ITEM, O_UZI_AMMO_ITEM, - O_EXPLOSIVE_ITEM, O_MEDI_ITEM, O_BIGMEDI_ITEM, - O_SCION_ITEM, O_SCION_ITEM2, O_LEADBAR_ITEM, - NO_ITEM }; - -// A few enemies removed because they need trigger checks -int16_t m_KillableObjs[] = { - O_WOLF, O_BEAR, O_CROCODILE, O_ALLIGATOR, O_LION, - O_LIONESS, O_PUMA, O_APE, O_RAT, O_VOLE, - O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, O_WARRIOR3, - O_CENTAUR, O_ABORTION, O_DINO_WARRIOR, O_LARSON, O_SKATEBOARD, - O_SKATEKID, O_COWBOY, O_BALDY, O_NATLA, O_SCION_ITEM3, - NO_ITEM -}; - static bool Level_LoadRooms(MYFILE *fp); static bool Level_LoadObjects(MYFILE *fp); static bool Level_LoadSprites(MYFILE *fp); @@ -94,9 +53,6 @@ static bool Level_LoadCinematic(MYFILE *fp); static bool Level_LoadDemo(MYFILE *fp); static bool Level_LoadSamples(MYFILE *fp); static bool Level_LoadTexturePages(MYFILE *fp); -static void Level_CalculateStats(); -static bool Level_FindElement(int16_t elem, int16_t array[], int16_t size); -static void Level_CalculateTriggers(); static bool Level_LoadFromFile(const char *filename, int32_t level_num); @@ -731,190 +687,11 @@ bool Level_Load(int level_num) } } - Level_CalculateStats(); - g_GameFlow.levels[level_num].secrets = m_LevelSecrets; - g_GameFlow.levels[level_num].pickups = m_LevelPickups; - g_GameFlow.levels[level_num].kills = m_LevelKillables; + Stats_CalculateStats(m_UninitItemCount, m_FloorArray); + g_GameFlow.levels[level_num].pickups = Stats_GetPickups(); + g_GameFlow.levels[level_num].kills = Stats_GetKillables(); + g_GameFlow.levels[level_num].secrets = Stats_GetSecrets(); Memory_FreePointer(&m_FloorArray); return ret; } - -static void Level_CalculateStats() -{ - // Clear old values - m_LevelPickups = 0; - m_LevelKillables = 0; - m_LevelSecrets = 0; - memset(&m_Pierres, 0, sizeof(m_Pierres)); - memset(&m_Mummies, 0, sizeof(m_Mummies)); - memset(&m_Pods, 0, sizeof(m_Pods)); - memset(&m_Bats, 0, sizeof(m_Bats)); - memset(&m_Statues, 0, sizeof(m_Statues)); - - if (m_UninitItemCount) { - if (m_UninitItemCount > MAX_ITEMS) { - Shell_ExitSystem( - "Level_GetPickupCount(): Too Many g_Items being Loaded!!"); - return; - } - - for (int i = 0; i < m_UninitItemCount; i++) { - ITEM_INFO *item = &g_Items[i]; - - if (item->object_number < 0 || item->object_number >= O_NUMBER_OF) { - Shell_ExitSystemFmt( - "Level_GetPickupCount(): Bad Object number (%d) on Item %d", - item->object_number, i); - } - - // Calculate number of pickups in a level - for (int j = 0; m_PickupObjs[j] != NO_ITEM; j++) { - if (item->object_number == m_PickupObjs[j]) { - m_LevelPickups++; - } - } - // Spawn pickups on death - if (item->object_number == O_SKATEKID) { - m_LevelPickups += SKATEKID_ITEMS; - } else if (item->object_number == O_COWBOY) { - m_LevelPickups += COWBOY_ITEMS; - } else if (item->object_number == O_BALDY) { - m_LevelPickups += BALDY_ITEMS; - } - - // Calculate number of killable objects in a level - for (int j = 0; m_KillableObjs[j] != NO_ITEM; j++) { - if (item->object_number == m_KillableObjs[j]) { - m_LevelKillables++; - } - } - } - } - - // Check triggers for special pickups / killables - Level_CalculateTriggers(); -} - -static bool Level_FindElement(int16_t elem, int16_t array[], int16_t size) -{ - for (int16_t i = 0; i < size; i++) { - if (array[i] == elem) { - return true; - } - } - return false; -} - -static void Level_CalculateTriggers() -{ - uint32_t secrets = 0; - - for (int i = 0; i < g_RoomCount; i++) { - ROOM_INFO *r = &g_RoomInfo[i]; - for (int x_floor = 0; x_floor < r->x_size; x_floor++) { - for (int y_floor = 0; y_floor < r->y_size; y_floor++) { - - if (x_floor == 0 || x_floor == r->x_size - 1) { - if (y_floor == 0 || y_floor == r->y_size - 1) { - continue; - } - } - - FLOOR_INFO *floor = - &m_FloorArray[i][x_floor + y_floor * r->x_size]; - - if (!floor->index) { - continue; - } - - int16_t *data = &g_FloorData[floor->index]; - int16_t type; - int16_t trigger; - int16_t trig_flags; - int16_t trig_type; - do { - type = *data++; - - switch (type & DATA_TYPE) { - case FT_TILT: - case FT_ROOF: - case FT_DOOR: - data++; - break; - - case FT_LAVA: - break; - - case FT_TRIGGER: - trig_flags = *data; - data++; - trig_type = (type >> 8) & 0x3F; - do { - trigger = *data++; - if (TRIG_BITS(trigger) == TO_SECRET) { - int16_t number = trigger & VALUE_BITS; - if (!(secrets & (1 << number))) { - secrets |= (1 << number); - m_LevelSecrets++; - } - } - if (TRIG_BITS(trigger) != TO_OBJECT) { - if (TRIG_BITS(trigger) == TO_CAMERA) { - trigger = *data++; - } - } else { - int16_t idx = trigger & VALUE_BITS; - ITEM_INFO *item = &g_Items[idx]; - - // Add Pierre pickup and kills if oneshot - if (item->object_number == O_PIERRE - && trig_flags & IF_ONESHOT - && !Level_FindElement( - idx, m_Pierres.idxs, STAT_SIZE)) { - m_LevelPickups += PIERRE_ITEMS; - m_LevelKillables += 1; - m_Pierres.idxs[m_Pierres.cur_idx++] = idx; - } - - // Check for mummy triggers - if (item->object_number == O_MUMMY - && !Level_FindElement( - idx, m_Mummies.idxs, STAT_SIZE)) { - m_LevelKillables += 1; - m_Mummies.idxs[m_Mummies.cur_idx++] = idx; - } - - // Check for mutant triggers - if ((item->object_number == O_PODS - || item->object_number == O_BIG_POD) - && !Level_FindElement( - idx, m_Pods.idxs, STAT_SIZE)) { - m_LevelKillables += 1; - m_Pods.idxs[m_Pods.cur_idx++] = idx; - } - - // Check for bat triggers - if ((item->object_number == O_BAT) - && !Level_FindElement( - idx, m_Bats.idxs, STAT_SIZE)) { - m_LevelKillables += 1; - m_Bats.idxs[m_Bats.cur_idx++] = idx; - } - - // Check for statue triggers - if ((item->object_number == O_STATUE) - && !Level_FindElement( - idx, m_Statues.idxs, STAT_SIZE)) { - m_LevelKillables += 1; - m_Statues.idxs[m_Statues.cur_idx++] = idx; - } - } - } while (!(trigger & END_BIT)); - break; - } - } while (!(type & END_BIT)); - } - } - } -} diff --git a/src/game/stats.c b/src/game/stats.c new file mode 100644 index 000000000..e8e5df98b --- /dev/null +++ b/src/game/stats.c @@ -0,0 +1,248 @@ +#include "game/stats.h" + +#include "game/shell.h" +#include "global/vars.h" +#include "log.h" + +#include +#include + +#define STAT_SIZE 512 +#define PIERRE_ITEMS 3 +#define SKATEKID_ITEMS 1 +#define COWBOY_ITEMS 1 +#define BALDY_ITEMS 1 + +static int32_t m_LevelPickups = 0; +static int32_t m_LevelKillables = 0; +static int32_t m_LevelSecrets = 0; + +typedef struct STAT_INFO { + int32_t drops; + int32_t kills; + int16_t cur_idx; + int16_t idxs[STAT_SIZE]; +} STAT_INFO; + +static STAT_INFO m_Pierres = { 0 }; +static STAT_INFO m_Mummies = { 0 }; +static STAT_INFO m_Pods = { 0 }; +static STAT_INFO m_Bats = { 0 }; +static STAT_INFO m_Statues = { 0 }; + +int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, + O_KEY_ITEM2, O_KEY_ITEM3, O_KEY_ITEM4, + O_PUZZLE_ITEM1, O_PUZZLE_ITEM2, O_PUZZLE_ITEM3, + O_PUZZLE_ITEM4, O_GUN_ITEM, O_SHOTGUN_ITEM, + O_MAGNUM_ITEM, O_UZI_ITEM, O_GUN_AMMO_ITEM, + O_SG_AMMO_ITEM, O_MAG_AMMO_ITEM, O_UZI_AMMO_ITEM, + O_EXPLOSIVE_ITEM, O_MEDI_ITEM, O_BIGMEDI_ITEM, + O_SCION_ITEM, O_SCION_ITEM2, O_LEADBAR_ITEM, + NO_ITEM }; + +// A few enemies removed because they need trigger checks +int16_t m_KillableObjs[] = { + O_WOLF, O_BEAR, O_CROCODILE, O_ALLIGATOR, O_LION, + O_LIONESS, O_PUMA, O_APE, O_RAT, O_VOLE, + O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, O_WARRIOR3, + O_CENTAUR, O_ABORTION, O_DINO_WARRIOR, O_LARSON, O_SKATEBOARD, + O_SKATEKID, O_COWBOY, O_BALDY, O_NATLA, O_SCION_ITEM3, + NO_ITEM +}; + +static bool Stats_FindElement(int16_t elem, int16_t array[], int16_t size); +static void Stats_CheckTriggers(FLOOR_INFO **floor_array); + +static bool Stats_FindElement(int16_t elem, int16_t array[], int16_t size) +{ + for (int16_t i = 0; i < size; i++) { + if (array[i] == elem) { + return true; + } + } + return false; +} + +static void Stats_CheckTriggers(FLOOR_INFO **floor_array) +{ + uint32_t secrets = 0; + + for (int i = 0; i < g_RoomCount; i++) { + ROOM_INFO *r = &g_RoomInfo[i]; + for (int x_floor = 0; x_floor < r->x_size; x_floor++) { + for (int y_floor = 0; y_floor < r->y_size; y_floor++) { + + if (x_floor == 0 || x_floor == r->x_size - 1) { + if (y_floor == 0 || y_floor == r->y_size - 1) { + continue; + } + } + + FLOOR_INFO *floor = + &floor_array[i][x_floor + y_floor * r->x_size]; + + if (!floor->index) { + continue; + } + + int16_t *data = &g_FloorData[floor->index]; + int16_t type; + int16_t trigger; + int16_t trig_flags; + int16_t trig_type; + do { + type = *data++; + + switch (type & DATA_TYPE) { + case FT_TILT: + case FT_ROOF: + case FT_DOOR: + data++; + break; + + case FT_LAVA: + break; + + case FT_TRIGGER: + trig_flags = *data; + data++; + trig_type = (type >> 8) & 0x3F; + do { + trigger = *data++; + if (TRIG_BITS(trigger) == TO_SECRET) { + int16_t number = trigger & VALUE_BITS; + if (!(secrets & (1 << number))) { + secrets |= (1 << number); + m_LevelSecrets++; + } + } + if (TRIG_BITS(trigger) != TO_OBJECT) { + if (TRIG_BITS(trigger) == TO_CAMERA) { + trigger = *data++; + } + } else { + int16_t idx = trigger & VALUE_BITS; + ITEM_INFO *item = &g_Items[idx]; + + // Add Pierre pickup and kills if oneshot + if (item->object_number == O_PIERRE + && trig_flags & IF_ONESHOT + && !Stats_FindElement( + idx, m_Pierres.idxs, STAT_SIZE)) { + m_LevelPickups += PIERRE_ITEMS; + m_LevelKillables += 1; + m_Pierres.idxs[m_Pierres.cur_idx++] = idx; + } + + // Check for mummy triggers + if (item->object_number == O_MUMMY + && !Stats_FindElement( + idx, m_Mummies.idxs, STAT_SIZE)) { + m_LevelKillables += 1; + m_Mummies.idxs[m_Mummies.cur_idx++] = idx; + } + + // Check for mutant triggers + if ((item->object_number == O_PODS + || item->object_number == O_BIG_POD) + && !Stats_FindElement( + idx, m_Pods.idxs, STAT_SIZE)) { + m_LevelKillables += 1; + m_Pods.idxs[m_Pods.cur_idx++] = idx; + } + + // Check for bat triggers + if ((item->object_number == O_BAT) + && !Stats_FindElement( + idx, m_Bats.idxs, STAT_SIZE)) { + m_LevelKillables += 1; + m_Bats.idxs[m_Bats.cur_idx++] = idx; + } + + // Check for statue triggers + if ((item->object_number == O_STATUE) + && !Stats_FindElement( + idx, m_Statues.idxs, STAT_SIZE)) { + m_LevelKillables += 1; + m_Statues.idxs[m_Statues.cur_idx++] = idx; + } + } + } while (!(trigger & END_BIT)); + break; + } + } while (!(type & END_BIT)); + } + } + } +} + +void Stats_CalculateStats(int32_t uninit_item_count, FLOOR_INFO **floor_array) +{ + // Clear old values + m_LevelPickups = 0; + m_LevelKillables = 0; + m_LevelSecrets = 0; + memset(&m_Pierres, 0, sizeof(m_Pierres)); + memset(&m_Mummies, 0, sizeof(m_Mummies)); + memset(&m_Pods, 0, sizeof(m_Pods)); + memset(&m_Bats, 0, sizeof(m_Bats)); + memset(&m_Statues, 0, sizeof(m_Statues)); + + if (uninit_item_count) { + if (uninit_item_count > MAX_ITEMS) { + Shell_ExitSystem( + "Stats_GetPickupCount(): Too Many g_Items being Loaded!!"); + return; + } + + for (int i = 0; i < uninit_item_count; i++) { + ITEM_INFO *item = &g_Items[i]; + + if (item->object_number < 0 || item->object_number >= O_NUMBER_OF) { + Shell_ExitSystemFmt( + "Stats_GetPickupCount(): Bad Object number (%d) on Item %d", + item->object_number, i); + } + + // Calculate number of pickups in a level + for (int j = 0; m_PickupObjs[j] != NO_ITEM; j++) { + if (item->object_number == m_PickupObjs[j]) { + m_LevelPickups++; + } + } + // Spawn pickups on death + if (item->object_number == O_SKATEKID) { + m_LevelPickups += SKATEKID_ITEMS; + } else if (item->object_number == O_COWBOY) { + m_LevelPickups += COWBOY_ITEMS; + } else if (item->object_number == O_BALDY) { + m_LevelPickups += BALDY_ITEMS; + } + + // Calculate number of killable objects in a level + for (int j = 0; m_KillableObjs[j] != NO_ITEM; j++) { + if (item->object_number == m_KillableObjs[j]) { + m_LevelKillables++; + } + } + } + } + + // Check triggers for special pickups / killables + Stats_CheckTriggers(floor_array); +} + +int32_t Stats_GetPickups() +{ + return m_LevelPickups; +} + +int32_t Stats_GetKillables() +{ + return m_LevelKillables; +} + +int32_t Stats_GetSecrets() +{ + return m_LevelSecrets; +} \ No newline at end of file diff --git a/src/game/stats.h b/src/game/stats.h new file mode 100644 index 000000000..3a1ebd831 --- /dev/null +++ b/src/game/stats.h @@ -0,0 +1,12 @@ +#pragma once + +#include "global/types.h" + +#include +#include +#include + +void Stats_CalculateStats(int32_t uninit_item_count, FLOOR_INFO **floor_array); +int32_t Stats_GetPickups(); +int32_t Stats_GetKillables(); +int32_t Stats_GetSecrets(); From 1aa0136606f2323fd09891b13b742e39969a90bf Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 12:43:15 -0500 Subject: [PATCH 10/25] stats: simplify killable logic and check all objects for triggers --- src/game/shell.c | 2 + src/game/stats.c | 115 ++++++++++++++--------------------------------- src/game/stats.h | 1 + 3 files changed, 36 insertions(+), 82 deletions(-) diff --git a/src/game/shell.c b/src/game/shell.c index 80bac8880..472daf7c5 100644 --- a/src/game/shell.c +++ b/src/game/shell.c @@ -29,6 +29,7 @@ #include "specific/s_input.h" #include "specific/s_misc.h" #include "specific/s_shell.h" +#include "src/game/stats.h" #include #include @@ -75,6 +76,7 @@ void Shell_Main() Music_Init(); Input_Init(); FMV_Init(); + Stats_Init(); if (!GameFlow_LoadFromFile(gameflow_path)) { Shell_ExitSystem("MAIN: unable to load script file"); diff --git a/src/game/stats.c b/src/game/stats.c index e8e5df98b..3ead9b9ea 100644 --- a/src/game/stats.c +++ b/src/game/stats.c @@ -16,19 +16,8 @@ static int32_t m_LevelPickups = 0; static int32_t m_LevelKillables = 0; static int32_t m_LevelSecrets = 0; - -typedef struct STAT_INFO { - int32_t drops; - int32_t kills; - int16_t cur_idx; - int16_t idxs[STAT_SIZE]; -} STAT_INFO; - -static STAT_INFO m_Pierres = { 0 }; -static STAT_INFO m_Mummies = { 0 }; -static STAT_INFO m_Pods = { 0 }; -static STAT_INFO m_Bats = { 0 }; -static STAT_INFO m_Statues = { 0 }; +static bool m_KillableItems[MAX_ITEMS] = { 0 }; +bool m_IfKillable[O_NUMBER_OF] = { 0 }; int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_KEY_ITEM2, O_KEY_ITEM3, O_KEY_ITEM4, @@ -40,29 +29,19 @@ int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_SCION_ITEM, O_SCION_ITEM2, O_LEADBAR_ITEM, NO_ITEM }; -// A few enemies removed because they need trigger checks +// Pierre has special trigger check int16_t m_KillableObjs[] = { - O_WOLF, O_BEAR, O_CROCODILE, O_ALLIGATOR, O_LION, - O_LIONESS, O_PUMA, O_APE, O_RAT, O_VOLE, - O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, O_WARRIOR3, - O_CENTAUR, O_ABORTION, O_DINO_WARRIOR, O_LARSON, O_SKATEBOARD, - O_SKATEKID, O_COWBOY, O_BALDY, O_NATLA, O_SCION_ITEM3, + O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, + O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, + O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, + O_WARRIOR3, O_CENTAUR, O_MUMMY, O_ABORTION, O_DINO_WARRIOR, + O_FISH, O_LARSON, O_SKATEKID, O_COWBOY, O_BALDY, + O_NATLA, O_SCION_ITEM3, O_STATUE, O_PODS, O_BIG_POD, NO_ITEM }; -static bool Stats_FindElement(int16_t elem, int16_t array[], int16_t size); static void Stats_CheckTriggers(FLOOR_INFO **floor_array); -static bool Stats_FindElement(int16_t elem, int16_t array[], int16_t size) -{ - for (int16_t i = 0; i < size; i++) { - if (array[i] == elem) { - return true; - } - } - return false; -} - static void Stats_CheckTriggers(FLOOR_INFO **floor_array) { uint32_t secrets = 0; @@ -127,44 +106,28 @@ static void Stats_CheckTriggers(FLOOR_INFO **floor_array) // Add Pierre pickup and kills if oneshot if (item->object_number == O_PIERRE && trig_flags & IF_ONESHOT - && !Stats_FindElement( - idx, m_Pierres.idxs, STAT_SIZE)) { + && !m_KillableItems[idx]) { + m_KillableItems[idx] = true; m_LevelPickups += PIERRE_ITEMS; m_LevelKillables += 1; - m_Pierres.idxs[m_Pierres.cur_idx++] = idx; - } - - // Check for mummy triggers - if (item->object_number == O_MUMMY - && !Stats_FindElement( - idx, m_Mummies.idxs, STAT_SIZE)) { - m_LevelKillables += 1; - m_Mummies.idxs[m_Mummies.cur_idx++] = idx; } - // Check for mutant triggers - if ((item->object_number == O_PODS - || item->object_number == O_BIG_POD) - && !Stats_FindElement( - idx, m_Pods.idxs, STAT_SIZE)) { + // Add killable if object triggered + if (m_IfKillable[item->object_number] + && !m_KillableItems[idx]) { + m_KillableItems[idx] = true; m_LevelKillables += 1; - m_Pods.idxs[m_Pods.cur_idx++] = idx; - } - // Check for bat triggers - if ((item->object_number == O_BAT) - && !Stats_FindElement( - idx, m_Bats.idxs, STAT_SIZE)) { - m_LevelKillables += 1; - m_Bats.idxs[m_Bats.cur_idx++] = idx; - } - - // Check for statue triggers - if ((item->object_number == O_STATUE) - && !Stats_FindElement( - idx, m_Statues.idxs, STAT_SIZE)) { - m_LevelKillables += 1; - m_Statues.idxs[m_Statues.cur_idx++] = idx; + // Add mercenary pickups + if (item->object_number == O_SKATEKID) { + m_LevelPickups += SKATEKID_ITEMS; + } + if (item->object_number == O_COWBOY) { + m_LevelPickups += COWBOY_ITEMS; + } + if (item->object_number == O_BALDY) { + m_LevelPickups += BALDY_ITEMS; + } } } } while (!(trigger & END_BIT)); @@ -176,17 +139,20 @@ static void Stats_CheckTriggers(FLOOR_INFO **floor_array) } } +void Stats_Init() +{ + for (int i = 0; m_KillableObjs[i] != NO_ITEM; i++) { + m_IfKillable[m_KillableObjs[i]] = true; + } +} + void Stats_CalculateStats(int32_t uninit_item_count, FLOOR_INFO **floor_array) { // Clear old values m_LevelPickups = 0; m_LevelKillables = 0; m_LevelSecrets = 0; - memset(&m_Pierres, 0, sizeof(m_Pierres)); - memset(&m_Mummies, 0, sizeof(m_Mummies)); - memset(&m_Pods, 0, sizeof(m_Pods)); - memset(&m_Bats, 0, sizeof(m_Bats)); - memset(&m_Statues, 0, sizeof(m_Statues)); + memset(&m_KillableItems, 0, sizeof(m_KillableItems)); if (uninit_item_count) { if (uninit_item_count > MAX_ITEMS) { @@ -210,21 +176,6 @@ void Stats_CalculateStats(int32_t uninit_item_count, FLOOR_INFO **floor_array) m_LevelPickups++; } } - // Spawn pickups on death - if (item->object_number == O_SKATEKID) { - m_LevelPickups += SKATEKID_ITEMS; - } else if (item->object_number == O_COWBOY) { - m_LevelPickups += COWBOY_ITEMS; - } else if (item->object_number == O_BALDY) { - m_LevelPickups += BALDY_ITEMS; - } - - // Calculate number of killable objects in a level - for (int j = 0; m_KillableObjs[j] != NO_ITEM; j++) { - if (item->object_number == m_KillableObjs[j]) { - m_LevelKillables++; - } - } } } diff --git a/src/game/stats.h b/src/game/stats.h index 3a1ebd831..01ba90c30 100644 --- a/src/game/stats.h +++ b/src/game/stats.h @@ -6,6 +6,7 @@ #include #include +void Stats_Init(); void Stats_CalculateStats(int32_t uninit_item_count, FLOOR_INFO **floor_array); int32_t Stats_GetPickups(); int32_t Stats_GetKillables(); From 493cb211f6249a9935ba2e8f5278fbf49f1e278d Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 12:44:04 -0500 Subject: [PATCH 11/25] stats: make m_IfKillable static --- src/game/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/stats.c b/src/game/stats.c index 3ead9b9ea..8fbd7d5c2 100644 --- a/src/game/stats.c +++ b/src/game/stats.c @@ -17,7 +17,7 @@ static int32_t m_LevelPickups = 0; static int32_t m_LevelKillables = 0; static int32_t m_LevelSecrets = 0; static bool m_KillableItems[MAX_ITEMS] = { 0 }; -bool m_IfKillable[O_NUMBER_OF] = { 0 }; +static bool m_IfKillable[O_NUMBER_OF] = { 0 }; int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_KEY_ITEM2, O_KEY_ITEM3, O_KEY_ITEM4, From 96c44f928d8ec86f9e5f8f5d0f48164f2df57a39 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 12:45:47 -0500 Subject: [PATCH 12/25] update CHANGELOG and README for stats calculation --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a6f42525c..b33337699 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,7 @@ Not all options are turned on by default. Refer to `Tomb1Main.json5` for details - added ability to skip FMVs with the Action key - added fade effects - added a vsync option +- added total pickups and kills per level to the stats screen - changed internal game memory limit from 3.5 MB to 16 MB - changed moveable limit from 256 to 10240 - changed maximum textures from 2048 to 8192 From 3972df6e68db3c8b7a7b378e9a120644d65cbf5f Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 12:46:59 -0500 Subject: [PATCH 13/25] stats: remove unused define --- src/game/stats.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/game/stats.c b/src/game/stats.c index 8fbd7d5c2..1b0696d60 100644 --- a/src/game/stats.c +++ b/src/game/stats.c @@ -7,7 +7,6 @@ #include #include -#define STAT_SIZE 512 #define PIERRE_ITEMS 3 #define SKATEKID_ITEMS 1 #define COWBOY_ITEMS 1 From f56505dd74ac7acd935921c4da556df3fe5bed45 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 13:05:31 -0500 Subject: [PATCH 14/25] move levelstats to stats.c --- src/game/game.c | 103 ----------------------------------------- src/game/gameflow.c | 3 +- src/game/shell.c | 2 +- src/game/stats.c | 109 +++++++++++++++++++++++++++++++++++++++++++- src/game/stats.h | 1 + 5 files changed, 112 insertions(+), 106 deletions(-) diff --git a/src/game/game.c b/src/game/game.c index cb2bda43a..74e785203 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -9,13 +9,10 @@ #include "game/gameflow.h" #include "game/input.h" #include "game/music.h" -#include "game/output.h" #include "game/savegame.h" -#include "game/screen.h" #include "game/setup.h" #include "game/shell.h" #include "game/sound.h" -#include "game/text.h" #include "global/const.h" #include "global/vars.h" #include "log.h" @@ -106,103 +103,3 @@ int32_t LevelCompleteSequence(int32_t level_num) { return GF_EXIT_TO_TITLE; } - -void LevelStats(int32_t level_num) -{ - char string[100]; - char time_str[100]; - TEXTSTRING *txt; - - Text_RemoveAll(); - - // heading - sprintf(string, "%s", g_GameFlow.levels[level_num].level_title); - txt = Text_Create(0, -50, string); - Text_CentreH(txt, 1); - Text_CentreV(txt, 1); - - // time taken - int32_t seconds = g_GameInfo.timer / 30; - int32_t hours = seconds / 3600; - int32_t minutes = (seconds / 60) % 60; - seconds %= 60; - if (hours) { - sprintf( - time_str, "%d:%d%d:%d%d", hours, minutes / 10, minutes % 10, - seconds / 10, seconds % 10); - } else { - sprintf(time_str, "%d:%d%d", minutes, seconds / 10, seconds % 10); - } - sprintf(string, g_GameFlow.strings[GS_STATS_TIME_TAKEN_FMT], time_str); - txt = Text_Create(0, 70, string); - Text_CentreH(txt, 1); - Text_CentreV(txt, 1); - - // secrets - int32_t secrets_taken = 0; - int32_t secrets_total = MAX_SECRETS; - do { - if (g_GameInfo.secrets & 1) { - secrets_taken++; - } - g_GameInfo.secrets >>= 1; - secrets_total--; - } while (secrets_total); - sprintf( - string, g_GameFlow.strings[GS_STATS_SECRETS_FMT], secrets_taken, - g_GameFlow.levels[level_num].secrets); - txt = Text_Create(0, 40, string); - Text_CentreH(txt, 1); - Text_CentreV(txt, 1); - - // pickups - sprintf( - string, g_GameFlow.strings[GS_STATS_PICKUPS_FMT], g_GameInfo.pickups, - g_GameFlow.levels[level_num].pickups); - txt = Text_Create(0, 10, string); - Text_CentreH(txt, 1); - Text_CentreV(txt, 1); - - // kills - sprintf( - string, g_GameFlow.strings[GS_STATS_KILLS_FMT], g_GameInfo.kills, - g_GameFlow.levels[level_num].kills); - txt = Text_Create(0, -20, string); - Text_CentreH(txt, 1); - Text_CentreV(txt, 1); - - Output_FadeToSemiBlack(true); - // wait till a skip key is pressed - do { - if (g_ResetFlag) { - break; - } - Output_InitialisePolyList(); - Draw_DrawScene(false); - Input_Update(); - Text_Draw(); - Output_DumpScreen(); - } while (!g_InputDB.select && !g_InputDB.deselect); - - Output_FadeToBlack(false); - Text_RemoveAll(); - - // finish fading - while (Output_FadeIsAnimating()) { - Output_InitialisePolyList(); - Draw_DrawScene(false); - Output_DumpScreen(); - } - - Output_FadeReset(); - - if (level_num == g_GameFlow.last_level_num) { - g_GameInfo.bonus_flag = GBF_NGPLUS; - } else { - CreateStartInfo(level_num + 1); - ModifyStartInfo(level_num + 1); - } - - g_GameInfo.start[g_CurrentLevel].flags.available = 0; - Screen_ApplyResolution(); -} diff --git a/src/game/gameflow.c b/src/game/gameflow.c index fd14df3e2..e415d6149 100644 --- a/src/game/gameflow.c +++ b/src/game/gameflow.c @@ -15,6 +15,7 @@ #include "game/screen.h" #include "game/settings.h" #include "game/shell.h" +#include "game/stats.h" #include "global/const.h" #include "global/vars.h" #include "json.h" @@ -1077,7 +1078,7 @@ GameFlow_InterpretSequence(int32_t level_num, GAMEFLOW_LEVEL_TYPE level_type) break; case GFS_LEVEL_STATS: - LevelStats((int32_t)seq->data); + Stats_LevelEnd((int32_t)seq->data); break; case GFS_DISPLAY_PICTURE: diff --git a/src/game/shell.c b/src/game/shell.c index 472daf7c5..98599c319 100644 --- a/src/game/shell.c +++ b/src/game/shell.c @@ -20,6 +20,7 @@ #include "game/setup.h" #include "game/shell.h" #include "game/sound.h" +#include "game/stats.h" #include "game/text.h" #include "global/const.h" #include "global/types.h" @@ -29,7 +30,6 @@ #include "specific/s_input.h" #include "specific/s_misc.h" #include "specific/s_shell.h" -#include "src/game/stats.h" #include #include diff --git a/src/game/stats.c b/src/game/stats.c index 1b0696d60..2ee2003d5 100644 --- a/src/game/stats.c +++ b/src/game/stats.c @@ -1,6 +1,13 @@ #include "game/stats.h" +#include "game/draw.h" +#include "game/gameflow.h" +#include "game/input.h" +#include "game/output.h" +#include "game/savegame.h" +#include "game/screen.h" #include "game/shell.h" +#include "game/text.h" #include "global/vars.h" #include "log.h" @@ -195,4 +202,104 @@ int32_t Stats_GetKillables() int32_t Stats_GetSecrets() { return m_LevelSecrets; -} \ No newline at end of file +} + +void Stats_LevelEnd(int32_t level_num) +{ + char string[100]; + char time_str[100]; + TEXTSTRING *txt; + + Text_RemoveAll(); + + // heading + sprintf(string, "%s", g_GameFlow.levels[level_num].level_title); + txt = Text_Create(0, -50, string); + Text_CentreH(txt, 1); + Text_CentreV(txt, 1); + + // time taken + int32_t seconds = g_GameInfo.timer / 30; + int32_t hours = seconds / 3600; + int32_t minutes = (seconds / 60) % 60; + seconds %= 60; + if (hours) { + sprintf( + time_str, "%d:%d%d:%d%d", hours, minutes / 10, minutes % 10, + seconds / 10, seconds % 10); + } else { + sprintf(time_str, "%d:%d%d", minutes, seconds / 10, seconds % 10); + } + sprintf(string, g_GameFlow.strings[GS_STATS_TIME_TAKEN_FMT], time_str); + txt = Text_Create(0, 70, string); + Text_CentreH(txt, 1); + Text_CentreV(txt, 1); + + // secrets + int32_t secrets_taken = 0; + int32_t secrets_total = MAX_SECRETS; + do { + if (g_GameInfo.secrets & 1) { + secrets_taken++; + } + g_GameInfo.secrets >>= 1; + secrets_total--; + } while (secrets_total); + sprintf( + string, g_GameFlow.strings[GS_STATS_SECRETS_FMT], secrets_taken, + g_GameFlow.levels[level_num].secrets); + txt = Text_Create(0, 40, string); + Text_CentreH(txt, 1); + Text_CentreV(txt, 1); + + // pickups + sprintf( + string, g_GameFlow.strings[GS_STATS_PICKUPS_FMT], g_GameInfo.pickups, + g_GameFlow.levels[level_num].pickups); + txt = Text_Create(0, 10, string); + Text_CentreH(txt, 1); + Text_CentreV(txt, 1); + + // kills + sprintf( + string, g_GameFlow.strings[GS_STATS_KILLS_FMT], g_GameInfo.kills, + g_GameFlow.levels[level_num].kills); + txt = Text_Create(0, -20, string); + Text_CentreH(txt, 1); + Text_CentreV(txt, 1); + + Output_FadeToSemiBlack(true); + // wait till a skip key is pressed + do { + if (g_ResetFlag) { + break; + } + Output_InitialisePolyList(); + Draw_DrawScene(false); + Input_Update(); + Text_Draw(); + Output_DumpScreen(); + } while (!g_InputDB.select && !g_InputDB.deselect); + + Output_FadeToBlack(false); + Text_RemoveAll(); + + // finish fading + while (Output_FadeIsAnimating()) { + Output_InitialisePolyList(); + Draw_DrawScene(false); + Output_DumpScreen(); + } + + Output_FadeReset(); + + if (level_num == g_GameFlow.last_level_num) { + g_GameInfo.bonus_flag = GBF_NGPLUS; + } else { + CreateStartInfo(level_num + 1); + ModifyStartInfo(level_num + 1); + } + + g_GameInfo.start[g_CurrentLevel].flags.available = 0; + Screen_ApplyResolution(); +} diff --git a/src/game/stats.h b/src/game/stats.h index 01ba90c30..036873482 100644 --- a/src/game/stats.h +++ b/src/game/stats.h @@ -11,3 +11,4 @@ void Stats_CalculateStats(int32_t uninit_item_count, FLOOR_INFO **floor_array); int32_t Stats_GetPickups(); int32_t Stats_GetKillables(); int32_t Stats_GetSecrets(); +void Stats_LevelEnd(int32_t level_num); From 8383a65522e5b6c18b144e83500c7b3d33e79b3b Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 13:09:41 -0500 Subject: [PATCH 15/25] remove stats.h unused imports --- src/game/stats.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/game/stats.h b/src/game/stats.h index 036873482..a0d0ead18 100644 --- a/src/game/stats.h +++ b/src/game/stats.h @@ -2,8 +2,6 @@ #include "global/types.h" -#include -#include #include void Stats_Init(); From d1bc94c6271f5eb2e81bbce16031371cd0c59192 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 17:33:13 -0500 Subject: [PATCH 16/25] lower case "of" in stats screens --- bin/cfg/Tomb1Main_gameflow.json5 | 6 +++--- bin/cfg/Tomb1Main_gameflow_ub.json5 | 6 +++--- src/init.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bin/cfg/Tomb1Main_gameflow.json5 b/bin/cfg/Tomb1Main_gameflow.json5 index cb51dccf0..1fcd5f297 100644 --- a/bin/cfg/Tomb1Main_gameflow.json5 +++ b/bin/cfg/Tomb1Main_gameflow.json5 @@ -533,9 +533,9 @@ "KEYMAP_CAMERA_RIGHT": "Camera Right", "KEYMAP_CAMERA_RESET": "Reset Camera", "STATS_TIME_TAKEN_FMT": "TIME TAKEN %s", - "STATS_SECRETS_FMT": "SECRETS %d OF %d", - "STATS_PICKUPS_FMT": "PICKUPS %d OF %d", - "STATS_KILLS_FMT": "KILLS %d OF %d", + "STATS_SECRETS_FMT": "SECRETS %d of %d", + "STATS_PICKUPS_FMT": "PICKUPS %d of %d", + "STATS_KILLS_FMT": "KILLS %d of %d", "PAUSE_PAUSED": "Paused", "PAUSE_EXIT_TO_TITLE": "Exit to title?", "PAUSE_CONTINUE": "Continue", diff --git a/bin/cfg/Tomb1Main_gameflow_ub.json5 b/bin/cfg/Tomb1Main_gameflow_ub.json5 index 808cd9019..97fa87be9 100644 --- a/bin/cfg/Tomb1Main_gameflow_ub.json5 +++ b/bin/cfg/Tomb1Main_gameflow_ub.json5 @@ -164,9 +164,9 @@ "KEYMAP_CAMERA_RIGHT": "Camera Right", "KEYMAP_CAMERA_RESET": "Reset Camera", "STATS_TIME_TAKEN_FMT": "TIME TAKEN %s", - "STATS_SECRETS_FMT": "SECRETS %d OF %d", - "STATS_PICKUPS_FMT": "PICKUPS %d OF %d", - "STATS_KILLS_FMT": "KILLS %d OF %d", + "STATS_SECRETS_FMT": "SECRETS %d of %d", + "STATS_PICKUPS_FMT": "PICKUPS %d of %d", + "STATS_KILLS_FMT": "KILLS %d of %d", "PAUSE_PAUSED": "Paused", "PAUSE_EXIT_TO_TITLE": "Exit to title?", "PAUSE_CONTINUE": "Continue", diff --git a/src/init.c b/src/init.c index dcb8d9ec8..d9c0359b3 100644 --- a/src/init.c +++ b/src/init.c @@ -64,9 +64,9 @@ GAMEFLOW_DEFAULT_STRING g_GameFlowDefaultStrings[] = { { GS_KEYMAP_CAMERA_RIGHT, "Camera Right" }, { GS_KEYMAP_CAMERA_RESET, "Reset Camera" }, { GS_STATS_TIME_TAKEN_FMT, "TIME TAKEN %s" }, - { GS_STATS_SECRETS_FMT, "SECRETS %d OF %d" }, - { GS_STATS_PICKUPS_FMT, "PICKUPS %d OF %d" }, - { GS_STATS_KILLS_FMT, "KILLS %d OF %d" }, + { GS_STATS_SECRETS_FMT, "SECRETS %d of %d" }, + { GS_STATS_PICKUPS_FMT, "PICKUPS %d of %d" }, + { GS_STATS_KILLS_FMT, "KILLS %d of %d" }, { GS_PAUSE_PAUSED, "Paused" }, { GS_PAUSE_EXIT_TO_TITLE, "Exit to title?" }, { GS_PAUSE_CONTINUE, "Continue" }, From 593565aad703dc2c1f536772b318acc655a43a64 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 18:52:04 -0500 Subject: [PATCH 17/25] rework stats, level, and remove old secret counter Implement rr's patch from PR. --- src/game/control.h | 2 -- src/game/control_util.c | 66 ----------------------------------------- src/game/game.c | 8 +++++ src/game/gameflow.c | 2 -- src/game/level.c | 25 ++-------------- src/game/stats.c | 43 ++++++++++++++++++++------- src/game/stats.h | 4 ++- 7 files changed, 47 insertions(+), 103 deletions(-) diff --git a/src/game/control.h b/src/game/control.h index 0553ad15b..cc7c20ff1 100644 --- a/src/game/control.h +++ b/src/game/control.h @@ -24,6 +24,4 @@ void FlipMap(); void RemoveRoomFlipItems(ROOM_INFO *r); void AddRoomFlipItems(ROOM_INFO *r); -int32_t GetSecretCount(); - bool Control_Pause(); diff --git a/src/game/control_util.c b/src/game/control_util.c index 92b5708c8..0134d66fe 100644 --- a/src/game/control_util.c +++ b/src/game/control_util.c @@ -606,69 +606,3 @@ int32_t ClipTarget(GAME_VECTOR *start, GAME_VECTOR *target, FLOOR_INFO *floor) return 1; } - -int GetSecretCount() -{ - int count = 0; - uint32_t secrets = 0; - - for (int i = 0; i < g_RoomCount; i++) { - ROOM_INFO *r = &g_RoomInfo[i]; - FLOOR_INFO *floor = &r->floor[0]; - for (int j = 0; j < r->y_size * r->x_size; j++, floor++) { - int k = floor->index; - if (!k) { - continue; - } - - while (1) { - uint16_t floor = g_FloorData[k++]; - - switch (floor & DATA_TYPE) { - case FT_DOOR: - case FT_ROOF: - case FT_TILT: - k++; - break; - - case FT_LAVA: - break; - - case FT_TRIGGER: { - uint16_t trig_type = (floor & 0x3F00) >> 8; - k++; // skip basic trigger stuff - - if (trig_type == TT_SWITCH || trig_type == TT_KEY - || trig_type == TT_PICKUP) { - k++; - } - - while (1) { - int16_t command = g_FloorData[k++]; - if (TRIG_BITS(command) == TO_CAMERA) { - k++; - } else if (TRIG_BITS(command) == TO_SECRET) { - int16_t number = command & VALUE_BITS; - if (!(secrets & (1 << number))) { - secrets |= (1 << number); - count++; - } - } - - if (command & END_BIT) { - break; - } - } - break; - } - } - - if (floor & END_BIT) { - break; - } - } - } - } - - return count; -} diff --git a/src/game/game.c b/src/game/game.c index 74e785203..f992b5efd 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -8,11 +8,14 @@ #include "game/draw.h" #include "game/gameflow.h" #include "game/input.h" +#include "game/inv.h" #include "game/music.h" #include "game/savegame.h" +#include "game/settings.h" #include "game/setup.h" #include "game/shell.h" #include "game/sound.h" +#include "game/stats.h" #include "global/const.h" #include "global/vars.h" #include "log.h" @@ -65,6 +68,11 @@ int32_t GameLoop(GAMEFLOW_LEVEL_TYPE level_type) g_OverlayFlag = 1; InitialiseCamera(); + Stats_CalculateStats(); + g_GameFlow.levels[g_CurrentLevel].pickups = Stats_GetPickups(); + g_GameFlow.levels[g_CurrentLevel].kills = Stats_GetKillables(); + g_GameFlow.levels[g_CurrentLevel].secrets = Stats_GetSecrets(); + bool ask_for_save = g_GameFlow.enable_save_crystals && level_type == GFL_NORMAL && g_CurrentLevel != g_GameFlow.first_level_num diff --git a/src/game/gameflow.c b/src/game/gameflow.c index e415d6149..8d18f0620 100644 --- a/src/game/gameflow.c +++ b/src/game/gameflow.c @@ -994,8 +994,6 @@ static void FixPyramidSecretTrigger() } global_secrets |= room_secrets; } - - g_GameFlow.levels[g_CurrentLevel].secrets = GetSecretCount(); } GAMEFLOW_OPTION diff --git a/src/game/level.c b/src/game/level.c index 01b8345f8..963c6381f 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -17,7 +17,6 @@ #include "memory.h" #include -#include static int32_t m_MeshCount = 0; static int32_t m_MeshPtrCount = 0; @@ -36,8 +35,6 @@ static int32_t m_AnimTextureRangeCount = 0; static int32_t m_SpriteInfoCount = 0; static int32_t m_SpriteCount = 0; static int32_t m_OverlapCount = 0; -static int32_t m_UninitItemCount = 0; -static FLOOR_INFO **m_FloorArray = NULL; static bool Level_LoadRooms(MYFILE *fp); static bool Level_LoadObjects(MYFILE *fp); @@ -88,6 +85,7 @@ static bool Level_LoadFromFile(const char *filename, int32_t level_num) if (!Level_LoadRooms(fp)) { return false; } + Stats_ObserveRoomsLoad(); if (!Level_LoadObjects(fp)) { return false; @@ -116,6 +114,7 @@ static bool Level_LoadFromFile(const char *filename, int32_t level_num) if (!Level_LoadItems(fp)) { return false; } + Stats_ObserveItemsLoad(); if (!Level_LoadDepthQ(fp)) { return false; @@ -152,10 +151,6 @@ static bool Level_LoadRooms(MYFILE *fp) File_Read(&g_RoomCount, sizeof(uint16_t), 1, fp); LOG_INFO("%d rooms", g_RoomCount); - // Copy for stats info - m_FloorArray = - GameBuf_Alloc(sizeof(FLOOR_INFO *) * g_RoomCount, GBUF_ROOM_FLOOR); - g_RoomInfo = GameBuf_Alloc(sizeof(ROOM_INFO) * g_RoomCount, GBUF_ROOM_INFOS); int i = 0; @@ -237,13 +232,6 @@ static bool Level_LoadRooms(MYFILE *fp) current_room_info->right = 0; current_room_info->item_number = -1; current_room_info->fx_number = -1; - - // Save copy of floor info for stats calculation - m_FloorArray[i] = - GameBuf_Alloc(sizeof(FLOOR_INFO) * count4, GBUF_ROOM_FLOOR); - memcpy( - m_FloorArray[i], current_room_info->floor, - sizeof(FLOOR_INFO) * count4); } File_Read(&m_FloorDataSize, sizeof(uint32_t), 1, fp); @@ -384,7 +372,6 @@ static bool Level_LoadSprites(MYFILE *fp) static bool Level_LoadItems(MYFILE *fp) { - m_UninitItemCount = 0; int32_t item_count = 0; File_Read(&item_count, sizeof(int32_t), 1, fp); @@ -399,7 +386,7 @@ static bool Level_LoadItems(MYFILE *fp) g_Items = GameBuf_Alloc(sizeof(ITEM_INFO) * MAX_ITEMS, GBUF_ITEMS); g_LevelItemCount = item_count; - m_UninitItemCount = item_count; + // m_UninitItemCount = item_count; InitialiseItemArray(MAX_ITEMS); for (int i = 0; i < item_count; i++) { @@ -687,11 +674,5 @@ bool Level_Load(int level_num) } } - Stats_CalculateStats(m_UninitItemCount, m_FloorArray); - g_GameFlow.levels[level_num].pickups = Stats_GetPickups(); - g_GameFlow.levels[level_num].kills = Stats_GetKillables(); - g_GameFlow.levels[level_num].secrets = Stats_GetSecrets(); - Memory_FreePointer(&m_FloorArray); - return ret; } diff --git a/src/game/stats.c b/src/game/stats.c index 2ee2003d5..5cc2ff3a7 100644 --- a/src/game/stats.c +++ b/src/game/stats.c @@ -1,6 +1,7 @@ #include "game/stats.h" #include "game/draw.h" +#include "game/gamebuf.h" #include "game/gameflow.h" #include "game/input.h" #include "game/output.h" @@ -19,6 +20,8 @@ #define COWBOY_ITEMS 1 #define BALDY_ITEMS 1 +static int32_t m_CachedItemCount = 0; +static FLOOR_INFO **m_CachedFloorArray = NULL; static int32_t m_LevelPickups = 0; static int32_t m_LevelKillables = 0; static int32_t m_LevelSecrets = 0; @@ -46,9 +49,9 @@ int16_t m_KillableObjs[] = { NO_ITEM }; -static void Stats_CheckTriggers(FLOOR_INFO **floor_array); +static void Stats_CheckTriggers(); -static void Stats_CheckTriggers(FLOOR_INFO **floor_array) +static void Stats_CheckTriggers() { uint32_t secrets = 0; @@ -64,7 +67,7 @@ static void Stats_CheckTriggers(FLOOR_INFO **floor_array) } FLOOR_INFO *floor = - &floor_array[i][x_floor + y_floor * r->x_size]; + &m_CachedFloorArray[i][x_floor + y_floor * r->x_size]; if (!floor->index) { continue; @@ -145,6 +148,26 @@ static void Stats_CheckTriggers(FLOOR_INFO **floor_array) } } +void Stats_ObserveRoomsLoad() +{ + m_CachedFloorArray = + GameBuf_Alloc(g_RoomCount * sizeof(FLOOR_INFO *), GBUF_ROOM_FLOOR); + for (int i = 0; i < g_RoomCount; i++) { + const ROOM_INFO *current_room_info = &g_RoomInfo[i]; + int count = current_room_info->y_size * current_room_info->x_size; + m_CachedFloorArray[i] = + GameBuf_Alloc(count * sizeof(FLOOR_INFO), GBUF_ROOM_FLOOR); + memcpy( + m_CachedFloorArray[i], current_room_info->floor, + count * sizeof(FLOOR_INFO)); + } +} + +void Stats_ObserveItemsLoad() +{ + m_CachedItemCount = g_LevelItemCount; +} + void Stats_Init() { for (int i = 0; m_KillableObjs[i] != NO_ITEM; i++) { @@ -152,7 +175,7 @@ void Stats_Init() } } -void Stats_CalculateStats(int32_t uninit_item_count, FLOOR_INFO **floor_array) +void Stats_CalculateStats() { // Clear old values m_LevelPickups = 0; @@ -160,19 +183,19 @@ void Stats_CalculateStats(int32_t uninit_item_count, FLOOR_INFO **floor_array) m_LevelSecrets = 0; memset(&m_KillableItems, 0, sizeof(m_KillableItems)); - if (uninit_item_count) { - if (uninit_item_count > MAX_ITEMS) { + if (m_CachedItemCount) { + if (m_CachedItemCount > MAX_ITEMS) { Shell_ExitSystem( - "Stats_GetPickupCount(): Too Many g_Items being Loaded!!"); + "Stats_CalculateStats(): Too Many g_Items being Loaded!!"); return; } - for (int i = 0; i < uninit_item_count; i++) { + for (int i = 0; i < m_CachedItemCount; i++) { ITEM_INFO *item = &g_Items[i]; if (item->object_number < 0 || item->object_number >= O_NUMBER_OF) { Shell_ExitSystemFmt( - "Stats_GetPickupCount(): Bad Object number (%d) on Item %d", + "Stats_CalculateStats(): Bad Object number (%d) on Item %d", item->object_number, i); } @@ -186,7 +209,7 @@ void Stats_CalculateStats(int32_t uninit_item_count, FLOOR_INFO **floor_array) } // Check triggers for special pickups / killables - Stats_CheckTriggers(floor_array); + Stats_CheckTriggers(); } int32_t Stats_GetPickups() diff --git a/src/game/stats.h b/src/game/stats.h index a0d0ead18..4c5ecb1de 100644 --- a/src/game/stats.h +++ b/src/game/stats.h @@ -4,8 +4,10 @@ #include +void Stats_ObserveRoomsLoad(); +void Stats_ObserveItemsLoad(); void Stats_Init(); -void Stats_CalculateStats(int32_t uninit_item_count, FLOOR_INFO **floor_array); +void Stats_CalculateStats(); int32_t Stats_GetPickups(); int32_t Stats_GetKillables(); int32_t Stats_GetSecrets(); From 8fcbe97da9560908b2f59eba7710793ff21be97c Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 19:09:37 -0500 Subject: [PATCH 18/25] remove Stats_Init --- src/game/shell.c | 2 -- src/game/stats.c | 20 ++++++++++++-------- src/game/stats.h | 1 - 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/game/shell.c b/src/game/shell.c index 98599c319..80bac8880 100644 --- a/src/game/shell.c +++ b/src/game/shell.c @@ -20,7 +20,6 @@ #include "game/setup.h" #include "game/shell.h" #include "game/sound.h" -#include "game/stats.h" #include "game/text.h" #include "global/const.h" #include "global/types.h" @@ -76,7 +75,6 @@ void Shell_Main() Music_Init(); Input_Init(); FMV_Init(); - Stats_Init(); if (!GameFlow_LoadFromFile(gameflow_path)) { Shell_ExitSystem("MAIN: unable to load script file"); diff --git a/src/game/stats.c b/src/game/stats.c index 5cc2ff3a7..d7395cea7 100644 --- a/src/game/stats.c +++ b/src/game/stats.c @@ -50,6 +50,7 @@ int16_t m_KillableObjs[] = { }; static void Stats_CheckTriggers(); +static bool Stats_IsObjectKillable(int32_t obj_num); static void Stats_CheckTriggers() { @@ -122,7 +123,7 @@ static void Stats_CheckTriggers() } // Add killable if object triggered - if (m_IfKillable[item->object_number] + if (Stats_IsObjectKillable(item->object_number) && !m_KillableItems[idx]) { m_KillableItems[idx] = true; m_LevelKillables += 1; @@ -148,6 +149,16 @@ static void Stats_CheckTriggers() } } +static bool Stats_IsObjectKillable(int32_t obj_num) +{ + for (int i = 0; m_KillableObjs[i] != NO_ITEM; i++) { + if (m_KillableObjs[i] == obj_num) { + return true; + } + } + return false; +} + void Stats_ObserveRoomsLoad() { m_CachedFloorArray = @@ -168,13 +179,6 @@ void Stats_ObserveItemsLoad() m_CachedItemCount = g_LevelItemCount; } -void Stats_Init() -{ - for (int i = 0; m_KillableObjs[i] != NO_ITEM; i++) { - m_IfKillable[m_KillableObjs[i]] = true; - } -} - void Stats_CalculateStats() { // Clear old values diff --git a/src/game/stats.h b/src/game/stats.h index 4c5ecb1de..87ad46830 100644 --- a/src/game/stats.h +++ b/src/game/stats.h @@ -6,7 +6,6 @@ void Stats_ObserveRoomsLoad(); void Stats_ObserveItemsLoad(); -void Stats_Init(); void Stats_CalculateStats(); int32_t Stats_GetPickups(); int32_t Stats_GetKillables(); From a0cd255f4b5ac1d0d4a5e8fab6f542a2672a1fbe Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 19:20:42 -0500 Subject: [PATCH 19/25] address more PR comments Remove unused includes. Rename end of level stat function. Remove unused variable and comments. Change stats shell errors to log errors. --- CHANGELOG.md | 1 + src/game/game.c | 2 -- src/game/gameflow.c | 2 +- src/game/level.c | 2 +- src/game/stats.c | 13 +++++-------- src/game/stats.h | 2 +- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3496e2e6..ae3329cae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ## [Unreleased](https://github.com/rr-/Tomb1Main/compare/2.5...master) +- added total pickups and kills per level to the compass and end level stats screens (#362) - changed fade animations to block the main menu inventory ring like in PS1 (#379) - changed fade animations to be FPS-independent - changed fade animations to run faster in the main menu diff --git a/src/game/game.c b/src/game/game.c index f992b5efd..13684343b 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -8,10 +8,8 @@ #include "game/draw.h" #include "game/gameflow.h" #include "game/input.h" -#include "game/inv.h" #include "game/music.h" #include "game/savegame.h" -#include "game/settings.h" #include "game/setup.h" #include "game/shell.h" #include "game/sound.h" diff --git a/src/game/gameflow.c b/src/game/gameflow.c index 8d18f0620..7667467ea 100644 --- a/src/game/gameflow.c +++ b/src/game/gameflow.c @@ -1076,7 +1076,7 @@ GameFlow_InterpretSequence(int32_t level_num, GAMEFLOW_LEVEL_TYPE level_type) break; case GFS_LEVEL_STATS: - Stats_LevelEnd((int32_t)seq->data); + Stats_Show((int32_t)seq->data); break; case GFS_DISPLAY_PICTURE: diff --git a/src/game/level.c b/src/game/level.c index 963c6381f..d8dbced72 100644 --- a/src/game/level.c +++ b/src/game/level.c @@ -386,7 +386,6 @@ static bool Level_LoadItems(MYFILE *fp) g_Items = GameBuf_Alloc(sizeof(ITEM_INFO) * MAX_ITEMS, GBUF_ITEMS); g_LevelItemCount = item_count; - // m_UninitItemCount = item_count; InitialiseItemArray(MAX_ITEMS); for (int i = 0; i < item_count; i++) { @@ -405,6 +404,7 @@ static bool Level_LoadItems(MYFILE *fp) "Level_LoadItems(): Bad Object number (%d) on Item %d", item->object_number, i); } + InitialiseItem(i); } } diff --git a/src/game/stats.c b/src/game/stats.c index d7395cea7..f7bb5953a 100644 --- a/src/game/stats.c +++ b/src/game/stats.c @@ -181,7 +181,6 @@ void Stats_ObserveItemsLoad() void Stats_CalculateStats() { - // Clear old values m_LevelPickups = 0; m_LevelKillables = 0; m_LevelSecrets = 0; @@ -189,8 +188,7 @@ void Stats_CalculateStats() if (m_CachedItemCount) { if (m_CachedItemCount > MAX_ITEMS) { - Shell_ExitSystem( - "Stats_CalculateStats(): Too Many g_Items being Loaded!!"); + LOG_ERROR("Too Many g_Items being Loaded!!"); return; } @@ -198,12 +196,11 @@ void Stats_CalculateStats() ITEM_INFO *item = &g_Items[i]; if (item->object_number < 0 || item->object_number >= O_NUMBER_OF) { - Shell_ExitSystemFmt( - "Stats_CalculateStats(): Bad Object number (%d) on Item %d", - item->object_number, i); + LOG_ERROR( + "Bad Object number (%d) on Item %d", item->object_number, + i); } - // Calculate number of pickups in a level for (int j = 0; m_PickupObjs[j] != NO_ITEM; j++) { if (item->object_number == m_PickupObjs[j]) { m_LevelPickups++; @@ -231,7 +228,7 @@ int32_t Stats_GetSecrets() return m_LevelSecrets; } -void Stats_LevelEnd(int32_t level_num) +void Stats_Show(int32_t level_num) { char string[100]; char time_str[100]; diff --git a/src/game/stats.h b/src/game/stats.h index 87ad46830..b83356fcf 100644 --- a/src/game/stats.h +++ b/src/game/stats.h @@ -10,4 +10,4 @@ void Stats_CalculateStats(); int32_t Stats_GetPickups(); int32_t Stats_GetKillables(); int32_t Stats_GetSecrets(); -void Stats_LevelEnd(int32_t level_num); +void Stats_Show(int32_t level_num); From aa06ec78c5250ab88dc6fad9a064804057ff9845 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 19:47:37 -0500 Subject: [PATCH 20/25] add continue if bad object number --- src/game/stats.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/game/stats.c b/src/game/stats.c index f7bb5953a..5bf506850 100644 --- a/src/game/stats.c +++ b/src/game/stats.c @@ -199,6 +199,7 @@ void Stats_CalculateStats() LOG_ERROR( "Bad Object number (%d) on Item %d", item->object_number, i); + continue; } for (int j = 0; m_PickupObjs[j] != NO_ITEM; j++) { From 3c0b18e7371e88dfbdac713ced712f865328140f Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 5 Feb 2022 21:14:07 -0500 Subject: [PATCH 21/25] check for only valid pods --- src/game/stats.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/game/stats.c b/src/game/stats.c index 5bf506850..bf5125f5d 100644 --- a/src/game/stats.c +++ b/src/game/stats.c @@ -38,15 +38,14 @@ int16_t m_PickupObjs[] = { O_PICKUP_ITEM1, O_PICKUP_ITEM2, O_KEY_ITEM1, O_SCION_ITEM, O_SCION_ITEM2, O_LEADBAR_ITEM, NO_ITEM }; -// Pierre has special trigger check +// Pierre and pods have special trigger check int16_t m_KillableObjs[] = { O_WOLF, O_BEAR, O_BAT, O_CROCODILE, O_ALLIGATOR, O_LION, O_LIONESS, O_PUMA, O_APE, O_RAT, O_VOLE, O_DINOSAUR, O_RAPTOR, O_WARRIOR1, O_WARRIOR2, O_WARRIOR3, O_CENTAUR, O_MUMMY, O_ABORTION, O_DINO_WARRIOR, O_FISH, O_LARSON, O_SKATEKID, O_COWBOY, O_BALDY, - O_NATLA, O_SCION_ITEM3, O_STATUE, O_PODS, O_BIG_POD, - NO_ITEM + O_NATLA, O_SCION_ITEM3, O_STATUE, NO_ITEM }; static void Stats_CheckTriggers(); @@ -111,20 +110,39 @@ static void Stats_CheckTriggers() } } else { int16_t idx = trigger & VALUE_BITS; + + if (m_KillableItems[idx]) { + continue; + } + ITEM_INFO *item = &g_Items[idx]; // Add Pierre pickup and kills if oneshot if (item->object_number == O_PIERRE - && trig_flags & IF_ONESHOT - && !m_KillableItems[idx]) { + && trig_flags & IF_ONESHOT) { m_KillableItems[idx] = true; m_LevelPickups += PIERRE_ITEMS; m_LevelKillables += 1; } + // Check for only valid pods + if ((item->object_number == O_PODS + || item->object_number == O_BIG_POD) + && item->data != NULL) { + int16_t bug_item_num = + *(int16_t *)item->data; + const ITEM_INFO *bug_item = + &g_Items[bug_item_num]; + if (g_Objects[bug_item->object_number] + .loaded) { + m_KillableItems[idx] = true; + m_LevelKillables += 1; + } + } + // Add killable if object triggered - if (Stats_IsObjectKillable(item->object_number) - && !m_KillableItems[idx]) { + if (Stats_IsObjectKillable( + item->object_number)) { m_KillableItems[idx] = true; m_LevelKillables += 1; From 7c194bfd4e7648013010acc0c7accb8dfe511c0e Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sun, 6 Feb 2022 12:34:50 -0500 Subject: [PATCH 22/25] note unreachable items and kills in the README --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index b33337699..985da4327 100644 --- a/README.md +++ b/README.md @@ -343,6 +343,25 @@ Not all options are turned on by default. Refer to `Tomb1Main.json5` for details and music) and there is planned work towards reducing the amount of Windows-only code. +## Level kills and pickup notes +The game can show the total number of pickups and kills in a level by checking +the compass in the inventory or at the end of level stats screen. Due to some +of the levels' designs, some of these kills and pickups are not obtainable. +See the table below for the discrepancies. + +Tomb Raider 1: +| Level | Kills | Pickups | +| ----------- | ----------- | ----------- | +| Palace Midas | | 23 (+1 unreachable medis) | +| Atlantis | | 53 (+2 unreachable medis, +1 unreachable uzi ammo) | + +Unfinished Business: +| Level | Kills | Pickups | +| ----------- | ----------- | ----------- | +| Return to Egypt | 42 (+1 unreachable enemy) | | +| Temple of the Cat | | 64 (+1 unreachable magnum ammo) | +| Atlanetean Stronghold | 32 (+1 unreachable Centaur) | | + ## Current road map Note: this section may be subject to change. From 2da97c905340edbad5142aa1d24a303afb9e6440 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sun, 6 Feb 2022 12:36:50 -0500 Subject: [PATCH 23/25] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 985da4327..0f75e62ec 100644 --- a/README.md +++ b/README.md @@ -346,7 +346,7 @@ Not all options are turned on by default. Refer to `Tomb1Main.json5` for details ## Level kills and pickup notes The game can show the total number of pickups and kills in a level by checking the compass in the inventory or at the end of level stats screen. Due to some -of the levels' designs, some of these kills and pickups are not obtainable. +of the levels' design, some of these kills and pickups are not obtainable. See the table below for the discrepancies. Tomb Raider 1: From 55348c627f7a442c384716c4adfdc59a9f919975 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sun, 6 Feb 2022 14:59:57 -0500 Subject: [PATCH 24/25] split up trigger checking function --- src/game/stats.c | 207 ++++++++++++++++++++++++----------------------- 1 file changed, 106 insertions(+), 101 deletions(-) diff --git a/src/game/stats.c b/src/game/stats.c index bf5125f5d..103f58219 100644 --- a/src/game/stats.c +++ b/src/game/stats.c @@ -25,6 +25,7 @@ static FLOOR_INFO **m_CachedFloorArray = NULL; static int32_t m_LevelPickups = 0; static int32_t m_LevelKillables = 0; static int32_t m_LevelSecrets = 0; +static uint32_t m_SecretRoom = 0; static bool m_KillableItems[MAX_ITEMS] = { 0 }; static bool m_IfKillable[O_NUMBER_OF] = { 0 }; @@ -48,10 +49,12 @@ int16_t m_KillableObjs[] = { O_NATLA, O_SCION_ITEM3, O_STATUE, NO_ITEM }; -static void Stats_CheckTriggers(); +static void Stats_TraverseFloor(); +static void Stats_CheckTriggers( + ROOM_INFO *r, int room_num, int x_floor, int y_floor); static bool Stats_IsObjectKillable(int32_t obj_num); -static void Stats_CheckTriggers() +static void Stats_TraverseFloor() { uint32_t secrets = 0; @@ -59,112 +62,113 @@ static void Stats_CheckTriggers() ROOM_INFO *r = &g_RoomInfo[i]; for (int x_floor = 0; x_floor < r->x_size; x_floor++) { for (int y_floor = 0; y_floor < r->y_size; y_floor++) { + Stats_CheckTriggers(r, i, x_floor, y_floor); + } + } + } +} - if (x_floor == 0 || x_floor == r->x_size - 1) { - if (y_floor == 0 || y_floor == r->y_size - 1) { - continue; +static void Stats_CheckTriggers( + ROOM_INFO *r, int room_num, int x_floor, int y_floor) +{ + if (x_floor == 0 || x_floor == r->x_size - 1) { + if (y_floor == 0 || y_floor == r->y_size - 1) { + return; + } + } + + FLOOR_INFO *floor = + &m_CachedFloorArray[room_num][x_floor + y_floor * r->x_size]; + + if (!floor->index) { + return; + } + + int16_t *data = &g_FloorData[floor->index]; + int16_t type; + int16_t trigger; + int16_t trig_flags; + int16_t trig_type; + do { + type = *data++; + + switch (type & DATA_TYPE) { + case FT_TILT: + case FT_ROOF: + case FT_DOOR: + data++; + break; + + case FT_LAVA: + break; + + case FT_TRIGGER: + trig_flags = *data; + data++; + trig_type = (type >> 8) & 0x3F; + do { + trigger = *data++; + if (TRIG_BITS(trigger) == TO_SECRET) { + int16_t number = trigger & VALUE_BITS; + if (!(m_SecretRoom & (1 << number))) { + m_SecretRoom |= (1 << number); + m_LevelSecrets++; } } + if (TRIG_BITS(trigger) != TO_OBJECT) { + if (TRIG_BITS(trigger) == TO_CAMERA) { + trigger = *data++; + } + } else { + int16_t idx = trigger & VALUE_BITS; - FLOOR_INFO *floor = - &m_CachedFloorArray[i][x_floor + y_floor * r->x_size]; + if (m_KillableItems[idx]) { + continue; + } - if (!floor->index) { - continue; - } + ITEM_INFO *item = &g_Items[idx]; - int16_t *data = &g_FloorData[floor->index]; - int16_t type; - int16_t trigger; - int16_t trig_flags; - int16_t trig_type; - do { - type = *data++; - - switch (type & DATA_TYPE) { - case FT_TILT: - case FT_ROOF: - case FT_DOOR: - data++; - break; - - case FT_LAVA: - break; - - case FT_TRIGGER: - trig_flags = *data; - data++; - trig_type = (type >> 8) & 0x3F; - do { - trigger = *data++; - if (TRIG_BITS(trigger) == TO_SECRET) { - int16_t number = trigger & VALUE_BITS; - if (!(secrets & (1 << number))) { - secrets |= (1 << number); - m_LevelSecrets++; - } - } - if (TRIG_BITS(trigger) != TO_OBJECT) { - if (TRIG_BITS(trigger) == TO_CAMERA) { - trigger = *data++; - } - } else { - int16_t idx = trigger & VALUE_BITS; - - if (m_KillableItems[idx]) { - continue; - } - - ITEM_INFO *item = &g_Items[idx]; - - // Add Pierre pickup and kills if oneshot - if (item->object_number == O_PIERRE - && trig_flags & IF_ONESHOT) { - m_KillableItems[idx] = true; - m_LevelPickups += PIERRE_ITEMS; - m_LevelKillables += 1; - } - - // Check for only valid pods - if ((item->object_number == O_PODS - || item->object_number == O_BIG_POD) - && item->data != NULL) { - int16_t bug_item_num = - *(int16_t *)item->data; - const ITEM_INFO *bug_item = - &g_Items[bug_item_num]; - if (g_Objects[bug_item->object_number] - .loaded) { - m_KillableItems[idx] = true; - m_LevelKillables += 1; - } - } - - // Add killable if object triggered - if (Stats_IsObjectKillable( - item->object_number)) { - m_KillableItems[idx] = true; - m_LevelKillables += 1; - - // Add mercenary pickups - if (item->object_number == O_SKATEKID) { - m_LevelPickups += SKATEKID_ITEMS; - } - if (item->object_number == O_COWBOY) { - m_LevelPickups += COWBOY_ITEMS; - } - if (item->object_number == O_BALDY) { - m_LevelPickups += BALDY_ITEMS; - } - } - } - } while (!(trigger & END_BIT)); - break; + // Add Pierre pickup and kills if oneshot + if (item->object_number == O_PIERRE + && trig_flags & IF_ONESHOT) { + m_KillableItems[idx] = true; + m_LevelPickups += PIERRE_ITEMS; + m_LevelKillables += 1; } - } while (!(type & END_BIT)); - } + + // Check for only valid pods + if ((item->object_number == O_PODS + || item->object_number == O_BIG_POD) + && item->data != NULL) { + int16_t bug_item_num = *(int16_t *)item->data; + const ITEM_INFO *bug_item = &g_Items[bug_item_num]; + if (g_Objects[bug_item->object_number].loaded) { + m_KillableItems[idx] = true; + m_LevelKillables += 1; + } + } + + // Add killable if object triggered + if (Stats_IsObjectKillable(item->object_number)) { + m_KillableItems[idx] = true; + m_LevelKillables += 1; + + // Add mercenary pickups + if (item->object_number == O_SKATEKID) { + m_LevelPickups += SKATEKID_ITEMS; + } + if (item->object_number == O_COWBOY) { + m_LevelPickups += COWBOY_ITEMS; + } + if (item->object_number == O_BALDY) { + m_LevelPickups += BALDY_ITEMS; + } + } + } + } while (!(trigger & END_BIT)); + break; } - } + } while (!(type & END_BIT)); } static bool Stats_IsObjectKillable(int32_t obj_num) @@ -202,6 +206,7 @@ void Stats_CalculateStats() m_LevelPickups = 0; m_LevelKillables = 0; m_LevelSecrets = 0; + m_SecretRoom = 0; memset(&m_KillableItems, 0, sizeof(m_KillableItems)); if (m_CachedItemCount) { @@ -229,7 +234,7 @@ void Stats_CalculateStats() } // Check triggers for special pickups / killables - Stats_CheckTriggers(); + Stats_TraverseFloor(); } int32_t Stats_GetPickups() From 08c929aa387c63f0475c35b75cf551055f7af90c Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sun, 6 Feb 2022 15:08:23 -0500 Subject: [PATCH 25/25] update README with full pickups and kills --- README.md | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0f75e62ec..ad5e89e05 100644 --- a/README.md +++ b/README.md @@ -347,20 +347,34 @@ Not all options are turned on by default. Refer to `Tomb1Main.json5` for details The game can show the total number of pickups and kills in a level by checking the compass in the inventory or at the end of level stats screen. Due to some of the levels' design, some of these kills and pickups are not obtainable. -See the table below for the discrepancies. +See the table below for the discrepancies. Unreachable items are in parentheses. Tomb Raider 1: -| Level | Kills | Pickups | -| ----------- | ----------- | ----------- | -| Palace Midas | | 23 (+1 unreachable medis) | -| Atlantis | | 53 (+2 unreachable medis, +1 unreachable uzi ammo) | +Level | Kills | Pickups | Secrets | +| ----------- | ----------- | ----------- | ----------- | +| Caves | 14 | 7 | 3 | +| City of Vilcabamba | 29 | 13 | 3 | +| Lost Valley | 13 | 16 | 5 | +| Tomb of Qualopec | 8 | 8 | 3 | +| St. Francis' Folly | 23 | 19 | 4 | +| Colosseum | 26 | 14 | 3 | +| Palace Midas | 43 | 23 (+1 medipack) | 3 | +| Cistern | 34 | 28 | 3 | +| Tomb of Tihocan | 17 | 26 | 2 | +| City of Khamoon | 14 | 24 | 3 | +| Obelisk of Khamoon | 16 | 38 | 3 | +| Sanctuary of the Scion | 15 | 29 | 1 | +| Natla's Mines | 3 | 30 | 3 | +| Atlantis | 32 | 53 (+2 medipacks, +1 uzi ammo) | 3 | +| The Great Pyramid | 6 | 31 | 3 | Unfinished Business: -| Level | Kills | Pickups | -| ----------- | ----------- | ----------- | -| Return to Egypt | 42 (+1 unreachable enemy) | | -| Temple of the Cat | | 64 (+1 unreachable magnum ammo) | -| Atlanetean Stronghold | 32 (+1 unreachable Centaur) | | +| Level | Kills | Pickups | Secrets | +| ----------- | ----------- | ----------- | ----------- | +| Return to Egypt | 42 (+1 panther) | 53 | 3 | +| Temple of the Cat | 44 | 64 (+1 magnum ammo) | 4 | +| Atlanetean Stronghold | 32 (+1 Centaur) | 63 | 2 | +| The Hive | 41 | 60 | 1 | ## Current road map