Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compass: add total number of pickups and killables #387

Merged
merged 25 commits into from Feb 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1f4ca33
compass: add total number of pickups and killables
walkawayy Feb 2, 2022
5f46e5f
remove inventory cog object from pickup and add scion3 to kills
walkawayy Feb 3, 2022
c7df93c
simplify pickup and killable obj arrays
walkawayy Feb 3, 2022
968ba9b
wip: fix mummy kills; pierre almost fixed pickup and kills
walkawayy Feb 4, 2022
ae4dba7
fix Pierre stats calc and other mercenaries
walkawayy Feb 4, 2022
378a51d
wip: fix floor trigger parsing, mutants in progress
walkawayy Feb 4, 2022
cf7fc97
fix mutant calcs and add bat/statue trigger checks
walkawayy Feb 5, 2022
129ab7d
move secret count to Level_CalculateTrigger
walkawayy Feb 5, 2022
3cb58df
stats: create stats file for level stats
walkawayy Feb 5, 2022
1aa0136
stats: simplify killable logic and check all objects for triggers
walkawayy Feb 5, 2022
493cb21
stats: make m_IfKillable static
walkawayy Feb 5, 2022
96c44f9
update CHANGELOG and README for stats calculation
walkawayy Feb 5, 2022
3972df6
stats: remove unused define
walkawayy Feb 5, 2022
f56505d
move levelstats to stats.c
walkawayy Feb 5, 2022
8383a65
remove stats.h unused imports
walkawayy Feb 5, 2022
d1bc94c
lower case "of" in stats screens
walkawayy Feb 5, 2022
593565a
rework stats, level, and remove old secret counter
walkawayy Feb 5, 2022
8fcbe97
remove Stats_Init
walkawayy Feb 6, 2022
a0cd255
address more PR comments
walkawayy Feb 6, 2022
aa06ec7
add continue if bad object number
walkawayy Feb 6, 2022
3c0b18e
check for only valid pods
walkawayy Feb 6, 2022
7c194bf
note unreachable items and kills in the README
walkawayy Feb 6, 2022
2da97c9
fix typo
walkawayy Feb 6, 2022
55348c6
split up trigger checking function
walkawayy Feb 6, 2022
08c929a
update README with full pickups and kills
walkawayy Feb 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions 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
Expand Down
34 changes: 34 additions & 0 deletions README.md
Expand Up @@ -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
Expand Down Expand Up @@ -342,6 +343,39 @@ 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' design, some of these kills and pickups are not obtainable.
See the table below for the discrepancies. Unreachable items are in parentheses.

Tomb Raider 1:
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 | 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

Note: this section may be subject to change.
Expand Down
6 changes: 3 additions & 3 deletions bin/cfg/Tomb1Main_gameflow.json5
Expand Up @@ -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",
"STATS_KILLS_FMT": "KILLS %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",
Expand Down
6 changes: 3 additions & 3 deletions bin/cfg/Tomb1Main_gameflow_ub.json5
Expand Up @@ -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",
"STATS_KILLS_FMT": "KILLS %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",
Expand Down
1 change: 1 addition & 0 deletions meson.build
Expand Up @@ -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',
Expand Down
3 changes: 1 addition & 2 deletions src/game/ai/baldy.c
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/game/ai/cowboy.c
Expand Up @@ -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);
}
Expand Down
6 changes: 3 additions & 3 deletions src/game/ai/skate_kid.c
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}
2 changes: 0 additions & 2 deletions src/game/control.h
Expand Up @@ -24,6 +24,4 @@ void FlipMap();
void RemoveRoomFlipItems(ROOM_INFO *r);
void AddRoomFlipItems(ROOM_INFO *r);

int32_t GetSecretCount();

bool Control_Pause();
66 changes: 0 additions & 66 deletions src/game/control_util.c
Expand Up @@ -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;
}
106 changes: 6 additions & 100 deletions src/game/game.c
Expand Up @@ -9,13 +9,11 @@
#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 "game/stats.h"
#include "global/const.h"
#include "global/vars.h"
#include "log.h"
Expand Down Expand Up @@ -68,6 +66,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
Expand Down Expand Up @@ -106,100 +109,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);
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);
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();
}
5 changes: 2 additions & 3 deletions src/game/gameflow.c
Expand Up @@ -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"
Expand Down Expand Up @@ -993,8 +994,6 @@ static void FixPyramidSecretTrigger()
}
global_secrets |= room_secrets;
}

g_GameFlow.levels[g_CurrentLevel].secrets = GetSecretCount();
}

GAMEFLOW_OPTION
Expand Down Expand Up @@ -1077,7 +1076,7 @@ GameFlow_InterpretSequence(int32_t level_num, GAMEFLOW_LEVEL_TYPE level_type)
break;

case GFS_LEVEL_STATS:
LevelStats((int32_t)seq->data);
Stats_Show((int32_t)seq->data);
break;

case GFS_DISPLAY_PICTURE:
Expand Down
2 changes: 2 additions & 0 deletions src/game/gameflow.h
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/game/larafire.c
Expand Up @@ -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;

Expand Down