inv-ring: merge common parts of control modules

This commit is contained in:
Marcin Kurczewski 2025-01-06 20:57:25 +01:00
parent a15b0d61fa
commit d7b6103d66
20 changed files with 356 additions and 504 deletions

View file

@ -414,6 +414,10 @@
"CONTROL_CUSTOM_2": "User Keys 2",
"CONTROL_CUSTOM_3": "User Keys 3",
"CONTROL_DEFAULT_KEYS": "Default Keys",
"HEADING_GAME_OVER": "GAME OVER",
"HEADING_INVENTORY": "INVENTORY",
"HEADING_ITEMS": "ITEMS",
"HEADING_OPTION": "OPTION",
"KEYMAP_ACTION": "Action",
"KEYMAP_BACK": "Back",
"KEYMAP_DRAW_WEAPON": "Draw Weapon",

View file

@ -1,12 +1,45 @@
#include "game/inventory_ring/priv.h"
#include "game/const.h"
#include "game/game_string.h"
#include "game/input.h"
#include "game/inventory.h"
#include "game/inventory_ring/vars.h"
#include "game/math.h"
#include "game/objects/names.h"
#include "game/output.h"
#include "game/overlay.h"
#include "game/text.h"
#include "version.h"
#include <stddef.h>
#include <stdio.h>
#define RING_CAMERA_Y_OFFSET (-96)
typedef enum {
// clang-format off
PASS_MESH_SPINE = 1 << 0,
PASS_MESH_FRONT = 1 << 1,
PASS_MESH_IN_FRONT = 1 << 2,
PASS_MESH_PAGE_2 = 1 << 3,
PASS_MESH_BACK = 1 << 4,
PASS_MESH_IN_BACK = 1 << 5,
PASS_MESH_PAGE_1 = 1 << 6,
PASS_MESH_COMMON = PASS_MESH_SPINE | PASS_MESH_BACK | PASS_MESH_FRONT,
// clang-format on
} PASS_MESH;
typedef enum {
IT_NAME,
IT_QTY,
IT_NUMBER_OF,
} INV_TEXT;
static TEXTSTRING *m_HeadingText = NULL;
static TEXTSTRING *m_VersionText = NULL;
static TEXTSTRING *m_Arrows[4] = {};
static TEXTSTRING *m_ItemText[IT_NUMBER_OF] = {};
static GAME_OBJECT_ID m_RequestedObjectID = NO_OBJECT;
static void M_HandleRequestedObject(INV_RING *ring);
@ -328,3 +361,217 @@ void InvRing_MotionItemDeselect(
motion->item_z_trans_target = 0;
motion->item_z_trans_rate = -(inv_item->z_trans_sel / motion->count);
}
void InvRing_SelectMeshes(INVENTORY_ITEM *const inv_item)
{
switch (inv_item->object_id) {
case O_PASSPORT_OPTION: {
struct {
int32_t frame;
uint32_t meshes;
} frame_map[] = {
#if TR_VERSION == 1
{ 14, PASS_MESH_IN_FRONT | PASS_MESH_PAGE_1 },
{ 18, PASS_MESH_IN_FRONT | PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2 },
{ 19, PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2 },
{ 23, PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2 | PASS_MESH_IN_BACK },
{ 28, PASS_MESH_PAGE_2 | PASS_MESH_IN_BACK },
{ 29, 0 },
{ -1, -1 }, // sentinel
#elif TR_VERSION == 2
{ 3, PASS_MESH_IN_FRONT },
{ 16, PASS_MESH_IN_FRONT | PASS_MESH_PAGE_1 },
{ 18, PASS_MESH_IN_FRONT | PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2 },
{ 19, PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2 },
{ 23, PASS_MESH_IN_BACK | PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2 },
{ 28, PASS_MESH_IN_BACK | PASS_MESH_PAGE_2 },
{ 29, 0 },
{ -1, -1 }, // sentinel
#endif
};
for (int32_t i = 0; frame_map[i].frame != -1; i++) {
if (inv_item->current_frame <= frame_map[i].frame) {
inv_item->meshes_drawn = PASS_MESH_COMMON | frame_map[i].meshes;
break;
}
}
break;
}
case O_COMPASS_OPTION:
if (inv_item->current_frame == 0 || inv_item->current_frame >= 18) {
inv_item->meshes_drawn = inv_item->meshes_sel;
} else {
inv_item->meshes_drawn = -1;
}
break;
default:
inv_item->meshes_drawn = -1;
break;
}
}
void InvRing_ShowItemName(const INVENTORY_ITEM *const inv_item)
{
if (m_ItemText[IT_NAME] != NULL) {
return;
}
if (inv_item->object_id == O_PASSPORT_OPTION) {
return;
}
m_ItemText[IT_NAME] =
Text_Create(0, -16, Object_GetName(inv_item->object_id));
Text_AlignBottom(m_ItemText[IT_NAME], true);
Text_CentreH(m_ItemText[IT_NAME], true);
}
void InvRing_ShowItemQuantity(const char *const fmt, const int32_t qty)
{
if (m_ItemText[IT_QTY] != NULL) {
return;
}
char string[128];
sprintf(string, fmt, qty);
Overlay_MakeAmmoString(string);
m_ItemText[IT_QTY] = Text_Create(64, -56, string);
Text_AlignBottom(m_ItemText[IT_QTY], true);
Text_CentreH(m_ItemText[IT_QTY], true);
}
void InvRing_RemoveItemTexts(void)
{
for (int32_t i = 0; i < IT_NUMBER_OF; i++) {
Text_Remove(m_ItemText[i]);
m_ItemText[i] = NULL;
}
}
void InvRing_ShowHeader(INV_RING *const ring)
{
if (ring->mode == INV_TITLE_MODE) {
return;
}
if (m_HeadingText == NULL) {
switch (ring->type) {
case RT_MAIN:
m_HeadingText = Text_Create(0, 26, GS(HEADING_INVENTORY));
break;
case RT_OPTION:
if (ring->mode == INV_DEATH_MODE) {
m_HeadingText = Text_Create(0, 26, GS(HEADING_GAME_OVER));
} else {
m_HeadingText = Text_Create(0, 26, GS(HEADING_OPTION));
}
break;
case RT_KEYS:
m_HeadingText = Text_Create(0, 26, GS(HEADING_ITEMS));
break;
}
Text_CentreH(m_HeadingText, true);
}
if (ring->mode != INV_GAME_MODE) {
return;
}
if (m_Arrows[INV_RING_ARROW_TL] == NULL
&& (ring->type == RT_OPTION
|| (ring->type == RT_MAIN
&& g_InvRing_Source[RT_KEYS].count > 0))) {
m_Arrows[INV_RING_ARROW_TL] = Text_Create(20, 28, "\\{arrow up}");
m_Arrows[INV_RING_ARROW_TR] = Text_Create(-20, 28, "\\{arrow up}");
Text_AlignRight(m_Arrows[INV_RING_ARROW_TR], true);
}
if (m_Arrows[INV_RING_ARROW_BL] == NULL
&& ((ring->type == RT_MAIN && !InvRing_IsOptionLockedOut())
|| ring->type == RT_KEYS)) {
m_Arrows[INV_RING_ARROW_BL] = Text_Create(20, -15, "\\{arrow down}");
Text_AlignBottom(m_Arrows[INV_RING_ARROW_BL], true);
m_Arrows[INV_RING_ARROW_BR] = Text_Create(-20, -15, "\\{arrow down}");
Text_AlignBottom(m_Arrows[INV_RING_ARROW_BR], true);
Text_AlignRight(m_Arrows[INV_RING_ARROW_BR], true);
}
}
void InvRing_RemoveHeader(void)
{
Text_Remove(m_HeadingText);
m_HeadingText = NULL;
for (int32_t i = 0; i < 4; i++) {
Text_Remove(m_Arrows[i]);
m_Arrows[i] = NULL;
}
}
void InvRing_HideArrow(const INV_RING_ARROW arrow, const bool hide)
{
if (m_Arrows[arrow] != NULL) {
Text_Hide(m_Arrows[arrow], hide);
}
}
void InvRing_ShowVersionText(void)
{
m_VersionText = Text_Create(-20, -18, g_TRXVersion);
Text_AlignRight(m_VersionText, true);
Text_AlignBottom(m_VersionText, true);
Text_SetScale(m_VersionText, TEXT_BASE_SCALE * 0.5, TEXT_BASE_SCALE * 0.5);
}
void InvRing_RemoveVersionText(void)
{
Text_Remove(m_VersionText);
m_VersionText = NULL;
}
void InvRing_UpdateInventoryItem(
const INV_RING *const ring, INVENTORY_ITEM *const inv_item,
const int32_t num_frames)
{
if (inv_item != ring->list[ring->current_object]) {
for (int32_t i = 0; i < num_frames; i++) {
if (inv_item->y_rot < 0) {
inv_item->y_rot += 256;
} else if (inv_item->y_rot > 0) {
inv_item->y_rot -= 256;
}
}
} else if (ring->rotating) {
for (int32_t i = 0; i < num_frames; i++) {
if (inv_item->y_rot > 0) {
inv_item->y_rot -= 512;
} else if (inv_item->y_rot < 0) {
inv_item->y_rot += 512;
}
}
} else if (
ring->motion.status == RNG_SELECTED
|| ring->motion.status == RNG_DESELECTING
|| ring->motion.status == RNG_SELECTING
|| ring->motion.status == RNG_DESELECT
|| ring->motion.status == RNG_CLOSING_ITEM) {
for (int32_t i = 0; i < num_frames; i++) {
const int32_t delta = inv_item->y_rot_sel - inv_item->y_rot;
if (delta != 0) {
if (delta > 0 && delta < DEG_180) {
inv_item->y_rot += 1024;
} else {
inv_item->y_rot -= 1024;
}
inv_item->y_rot &= ~(1024 - 1);
}
}
} else if (
ring->number_of_objects == 1 || (!g_Input.right && !g_Input.left)) {
for (int32_t i = 0; i < num_frames; i++) {
inv_item->y_rot += 256;
}
}
}

View file

@ -1,3 +1,7 @@
GS_DEFINE(HEADING_INVENTORY, "INVENTORY")
GS_DEFINE(HEADING_GAME_OVER, "GAME OVER")
GS_DEFINE(HEADING_OPTION, "OPTION")
GS_DEFINE(HEADING_ITEMS, "ITEMS")
GS_DEFINE(OSD_POS_GET, "Level: %d (%s) Room: %d\nPosition: %.3f, %.3f, %.3f\nRotation: %.3f,%.3f,%.3f")
GS_DEFINE(OSD_CURRENT_HEALTH_GET, "Current Lara's health: %d")
GS_DEFINE(OSD_CURRENT_HEALTH_SET, "Lara's health set to %d")

View file

@ -10,6 +10,13 @@
#define INV_RING_CAMERA_START_HEIGHT (-0x600) // = -1536
#define INV_RING_RADIUS 688
typedef enum {
INV_RING_ARROW_TL,
INV_RING_ARROW_TR,
INV_RING_ARROW_BL,
INV_RING_ARROW_BR,
} INV_RING_ARROW;
void InvRing_InitRing(
INV_RING *ring, RING_TYPE type, INVENTORY_ITEM **list, int16_t qty,
int16_t current);
@ -34,3 +41,18 @@ void InvRing_MotionCameraPos(INV_RING *ring, int16_t target);
void InvRing_MotionCameraPitch(INV_RING *ring, int16_t target);
void InvRing_MotionItemSelect(INV_RING *ring, const INVENTORY_ITEM *inv_item);
void InvRing_MotionItemDeselect(INV_RING *ring, const INVENTORY_ITEM *inv_item);
void InvRing_ShowItemName(const INVENTORY_ITEM *inv_item);
void InvRing_ShowItemQuantity(const char *fmt, int32_t qty);
void InvRing_RemoveItemTexts(void);
void InvRing_SelectMeshes(INVENTORY_ITEM *inv_item);
void InvRing_ShowHeader(INV_RING *ring);
void InvRing_RemoveHeader(void);
void InvRing_HideArrow(INV_RING_ARROW arrow, bool hide);
void InvRing_ShowVersionText(void);
void InvRing_RemoveVersionText(void);
void InvRing_UpdateInventoryItem(
const INV_RING *ring, INVENTORY_ITEM *inv_item, int32_t num_frames);
extern bool InvRing_IsOptionLockedOut(void);

View file

@ -0,0 +1,3 @@
#pragma once
extern void Overlay_MakeAmmoString(char *string);

3
src/libtrx/version.h Normal file
View file

@ -0,0 +1,3 @@
#pragma once
extern const char *g_TRXVersion;

View file

@ -1,7 +1,3 @@
GS_DEFINE(HEADING_INVENTORY, "INVENTORY")
GS_DEFINE(HEADING_GAME_OVER, "GAME OVER")
GS_DEFINE(HEADING_OPTION, "OPTION")
GS_DEFINE(HEADING_ITEMS, "ITEMS")
GS_DEFINE(PASSPORT_SELECT_LEVEL, "Select Level")
GS_DEFINE(PASSPORT_RESTART_LEVEL, "Restart Level")
GS_DEFINE(PASSPORT_STORY_SO_FAR, "Story so far...")

View file

@ -27,34 +27,10 @@
#include <libtrx/game/objects/names.h>
#include <libtrx/memory.h>
typedef enum {
IT_NAME = 0,
IT_QTY = 1,
IT_NUMBER_OF = 2,
} INV_TEXT;
#define INV_FRAMES 2
typedef enum {
// clang-format off
PASS_MESH_SPINE = 1 << 0,
PASS_MESH_FRONT = 1 << 1,
PASS_MESH_IN_FRONT = 1 << 2,
PASS_MESH_PAGE_2 = 1 << 3,
PASS_MESH_BACK = 1 << 4,
PASS_MESH_IN_BACK = 1 << 5,
PASS_MESH_PAGE_1 = 1 << 6,
PASS_MESH_COMMON = PASS_MESH_SPINE | PASS_MESH_BACK | PASS_MESH_FRONT,
// clang-format on
} PASS_MESH;
static TEXTSTRING *m_UpArrow1 = NULL;
static TEXTSTRING *m_UpArrow2 = NULL;
static TEXTSTRING *m_DownArrow1 = NULL;
static TEXTSTRING *m_DownArrow2 = NULL;
static TEXTSTRING *m_ExamineItemText = NULL;
static TEXTSTRING *m_UseItemText = NULL;
static TEXTSTRING *m_VersionText = NULL;
static TEXTSTRING *m_HeadingText = NULL;
static TEXTSTRING *m_ItemText[IT_NUMBER_OF] = {};
static CLOCK_TIMER m_DemoTimer = { 0 };
static int32_t m_StartLevel;
static GAME_OBJECT_ID m_InvChosen;
@ -63,11 +39,6 @@ static TEXTSTRING *M_InitExamineText(
int32_t x_pos, const char *role_str, const char *input_str);
static void M_InitExamineOverlay(INV_RING *ring);
static void M_RemoveExamineOverlay(void);
static void M_RemoveItemsText(void);
static void M_RemoveVersionText(void);
static void M_InitHeader(INV_RING *ring);
static void M_RemoveHeader(void);
static void M_ShowItemQuantity(const char *fmt, int32_t qty);
static void M_ShowAmmoQuantity(const char *fmt, int32_t qty);
static void M_RingIsOpen(INV_RING *ring);
@ -89,7 +60,6 @@ static TEXTSTRING *M_InitExamineText(
Text_AlignBottom(text, true);
Text_CentreH(text, true);
Text_Hide(text, true);
return text;
}
@ -119,125 +89,28 @@ static void M_RemoveExamineOverlay(void)
m_UseItemText = NULL;
}
static void M_RemoveItemsText(void)
{
for (int32_t i = 0; i < IT_NUMBER_OF; i++) {
Text_Remove(m_ItemText[i]);
m_ItemText[i] = NULL;
}
}
static void M_RemoveVersionText(void)
{
Text_Remove(m_VersionText);
m_VersionText = NULL;
}
static void M_InitHeader(INV_RING *const ring)
{
if (ring->mode == INV_TITLE_MODE) {
return;
}
if (m_HeadingText == NULL) {
switch (ring->type) {
case RT_MAIN:
m_HeadingText = Text_Create(0, 26, GS(HEADING_INVENTORY));
break;
case RT_OPTION:
if (ring->mode == INV_DEATH_MODE) {
m_HeadingText = Text_Create(0, 26, GS(HEADING_GAME_OVER));
} else {
m_HeadingText = Text_Create(0, 26, GS(HEADING_OPTION));
}
break;
case RT_KEYS:
m_HeadingText = Text_Create(0, 26, GS(HEADING_ITEMS));
break;
}
Text_CentreH(m_HeadingText, true);
}
if (ring->mode != INV_GAME_MODE) {
return;
}
if (m_UpArrow1 == NULL
&& (ring->type == RT_OPTION
|| (ring->type == RT_MAIN
&& g_InvRing_Source[RT_KEYS].count > 0))) {
m_UpArrow1 = Text_Create(20, 28, "\\{arrow up}");
m_UpArrow2 = Text_Create(-20, 28, "\\{arrow up}");
Text_AlignRight(m_UpArrow2, true);
}
if (m_DownArrow1 == NULL
&& (ring->type == RT_MAIN || ring->type == RT_KEYS)) {
m_DownArrow1 = Text_Create(20, -15, "\\{arrow down}");
Text_AlignBottom(m_DownArrow1, true);
m_DownArrow2 = Text_Create(-20, -15, "\\{arrow down}");
Text_AlignBottom(m_DownArrow2, true);
Text_AlignRight(m_DownArrow2, true);
}
}
static void M_RemoveHeader(void)
{
Text_Remove(m_HeadingText);
m_HeadingText = NULL;
Text_Remove(m_UpArrow1);
m_UpArrow1 = NULL;
Text_Remove(m_UpArrow2);
m_UpArrow2 = NULL;
Text_Remove(m_DownArrow1);
m_DownArrow1 = NULL;
Text_Remove(m_DownArrow2);
m_DownArrow2 = NULL;
}
static void M_ShowItemQuantity(const char *const fmt, const int32_t qty)
{
if (m_ItemText[IT_QTY] == NULL) {
char string[64];
sprintf(string, fmt, qty);
Overlay_MakeAmmoString(string);
m_ItemText[IT_QTY] = Text_Create(64, -56, string);
Text_AlignBottom(m_ItemText[IT_QTY], true);
Text_CentreH(m_ItemText[IT_QTY], true);
}
}
static void M_ShowAmmoQuantity(const char *const fmt, const int32_t qty)
{
if (!(g_GameInfo.bonus_flag & GBF_NGPLUS)) {
M_ShowItemQuantity(fmt, qty);
InvRing_ShowItemQuantity(fmt, qty);
}
}
static void M_RingIsOpen(INV_RING *const ring)
{
M_InitHeader(ring);
InvRing_ShowHeader(ring);
M_InitExamineOverlay(ring);
}
static void M_RingIsNotOpen(INV_RING *const ring)
{
M_RemoveHeader();
InvRing_RemoveHeader();
M_RemoveExamineOverlay();
}
static void M_RingNotActive(const INVENTORY_ITEM *const inv_item)
{
if (m_ItemText[IT_NAME] == NULL
&& inv_item->object_id != O_PASSPORT_OPTION) {
m_ItemText[IT_NAME] =
Text_Create(0, -16, Object_GetName(inv_item->object_id));
Text_AlignBottom(m_ItemText[IT_NAME], 1);
Text_CentreH(m_ItemText[IT_NAME], 1);
}
InvRing_ShowItemName(inv_item);
const int32_t qty = Inv_RequestItem(inv_item->object_id);
bool show_examine_option = false;
@ -256,19 +129,19 @@ static void M_RingNotActive(const INVENTORY_ITEM *const inv_item)
break;
case O_SG_AMMO_OPTION:
M_ShowItemQuantity("%d", qty * NUM_SG_SHELLS);
InvRing_ShowItemQuantity("%d", qty * NUM_SG_SHELLS);
break;
case O_MAG_AMMO_OPTION:
case O_UZI_AMMO_OPTION:
M_ShowItemQuantity("%d", qty * 2);
InvRing_ShowItemQuantity("%d", qty * 2);
break;
case O_MEDI_OPTION:
case O_BIGMEDI_OPTION:
Overlay_BarSetHealthTimer(40);
if (qty > 1) {
M_ShowItemQuantity("%d", qty);
InvRing_ShowItemQuantity("%d", qty);
}
break;
@ -285,7 +158,7 @@ static void M_RingNotActive(const INVENTORY_ITEM *const inv_item)
case O_PUZZLE_OPTION_4:
case O_SCION_OPTION:
if (qty > 1) {
M_ShowItemQuantity("%d", qty);
InvRing_ShowItemQuantity("%d", qty);
}
show_examine_option = !Option_Examine_IsActive()
@ -299,20 +172,20 @@ static void M_RingNotActive(const INVENTORY_ITEM *const inv_item)
if (inv_item->object_id == O_MEDI_OPTION
|| inv_item->object_id == O_BIGMEDI_OPTION) {
if (g_Config.ui.healthbar_location == BL_TOP_LEFT) {
Text_Hide(m_UpArrow1, true);
InvRing_HideArrow(INV_RING_ARROW_TL, true);
} else if (g_Config.ui.healthbar_location == BL_TOP_RIGHT) {
Text_Hide(m_UpArrow2, true);
InvRing_HideArrow(INV_RING_ARROW_TR, true);
} else if (g_Config.ui.healthbar_location == BL_BOTTOM_LEFT) {
Text_Hide(m_DownArrow1, true);
InvRing_HideArrow(INV_RING_ARROW_BL, true);
} else if (g_Config.ui.healthbar_location == BL_BOTTOM_RIGHT) {
Text_Hide(m_DownArrow2, true);
InvRing_HideArrow(INV_RING_ARROW_BR, true);
}
g_GameInfo.inv_showing_medpack = true;
} else {
Text_Hide(m_UpArrow1, false);
Text_Hide(m_UpArrow2, false);
Text_Hide(m_DownArrow1, false);
Text_Hide(m_DownArrow2, false);
InvRing_HideArrow(INV_RING_ARROW_TL, false);
InvRing_HideArrow(INV_RING_ARROW_TR, false);
InvRing_HideArrow(INV_RING_ARROW_BL, false);
InvRing_HideArrow(INV_RING_ARROW_BR, false);
g_GameInfo.inv_showing_medpack = false;
}
@ -327,45 +200,10 @@ static void M_RingActive(INV_RING *const ring)
InvRing_RemoveAllText();
}
static void M_SelectMeshes(INVENTORY_ITEM *const inv_item)
{
switch (inv_item->object_id) {
case O_PASSPORT_OPTION:
inv_item->meshes_drawn = PASS_MESH_COMMON;
if (inv_item->current_frame <= 14) {
inv_item->meshes_drawn |= PASS_MESH_IN_FRONT | PASS_MESH_PAGE_1;
} else if (inv_item->current_frame < 19) {
inv_item->meshes_drawn |=
PASS_MESH_IN_FRONT | PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2;
} else if (inv_item->current_frame == 19) {
inv_item->meshes_drawn |= PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2;
} else if (inv_item->current_frame < 24) {
inv_item->meshes_drawn |=
PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2 | PASS_MESH_IN_BACK;
} else if (inv_item->current_frame < 29) {
inv_item->meshes_drawn |= PASS_MESH_PAGE_2 | PASS_MESH_IN_BACK;
} else if (inv_item->current_frame == 29) {
}
break;
case O_COMPASS_OPTION:
if (inv_item->current_frame == 0 || inv_item->current_frame >= 18) {
inv_item->meshes_drawn = inv_item->meshes_sel;
} else {
inv_item->meshes_drawn = -1;
}
break;
default:
inv_item->meshes_drawn = -1;
break;
}
}
static bool M_AnimateInventoryItem(INVENTORY_ITEM *inv_item)
{
if (inv_item->current_frame == inv_item->goal_frame) {
M_SelectMeshes(inv_item);
InvRing_SelectMeshes(inv_item);
return false;
}
@ -376,7 +214,7 @@ static bool M_AnimateInventoryItem(INVENTORY_ITEM *inv_item)
inv_item->current_frame = inv_item->frames_total - 1;
}
M_SelectMeshes(inv_item);
InvRing_SelectMeshes(inv_item);
return true;
}
@ -850,8 +688,8 @@ bool InvRing_CanExamine(void)
void InvRing_RemoveAllText(void)
{
M_RemoveHeader();
M_RemoveItemsText();
InvRing_RemoveHeader();
InvRing_RemoveItemTexts();
M_RemoveExamineOverlay();
}
@ -868,14 +706,10 @@ INV_RING *InvRing_Open(const INVENTORY_MODE mode)
if (mode == INV_TITLE_MODE) {
g_InvRing_Source[RT_OPTION].count = TITLE_RING_OBJECTS;
m_VersionText = Text_Create(-20, -18, g_TR1XVersion);
Text_AlignRight(m_VersionText, 1);
Text_AlignBottom(m_VersionText, 1);
Text_SetScale(
m_VersionText, TEXT_BASE_SCALE * 0.5, TEXT_BASE_SCALE * 0.5);
InvRing_ShowVersionText();
} else {
g_InvRing_Source[RT_OPTION].count = OPTION_RING_OBJECTS;
M_RemoveVersionText();
InvRing_RemoveVersionText();
}
g_InvRing_Source[RT_MAIN].current = 0;
@ -954,7 +788,7 @@ PHASE_CONTROL InvRing_Close(INV_RING *const ring)
PHASE_CONTROL result = { .action = PHASE_ACTION_NO_WAIT };
InvRing_RemoveAllText();
M_RemoveVersionText();
InvRing_RemoveVersionText();
if (ring->list != NULL) {
INVENTORY_ITEM *const inv_item = ring->list[ring->current_object];
@ -1145,3 +979,8 @@ PHASE_CONTROL InvRing_Control(INV_RING *const ring, const int32_t num_frames)
return (PHASE_CONTROL) { .action = PHASE_ACTION_CONTINUE };
}
bool InvRing_IsOptionLockedOut(void)
{
return false;
}

View file

@ -72,54 +72,16 @@ static void M_DrawItem(
{
if (ring->motion.status == RNG_DONE) {
Output_SetLightAdder(LOW_LIGHT);
} else if (inv_item == ring->list[ring->current_object]) {
if (ring->rotating) {
Output_SetLightAdder(LOW_LIGHT);
for (int j = 0; j < num_frames; j++) {
if (inv_item->y_rot < 0) {
inv_item->y_rot += 512;
} else if (inv_item->y_rot > 0) {
inv_item->y_rot -= 512;
}
}
} else if (
ring->motion.status == RNG_SELECTED
|| ring->motion.status == RNG_DESELECTING
|| ring->motion.status == RNG_SELECTING
|| ring->motion.status == RNG_DESELECT
|| ring->motion.status == RNG_CLOSING_ITEM) {
Output_SetLightAdder(HIGH_LIGHT);
for (int j = 0; j < num_frames; j++) {
if (inv_item->y_rot != inv_item->y_rot_sel) {
if (inv_item->y_rot_sel - inv_item->y_rot > 0
&& inv_item->y_rot_sel - inv_item->y_rot < 0x8000) {
inv_item->y_rot += 1024;
} else {
inv_item->y_rot -= 1024;
}
inv_item->y_rot &= 0xFC00u;
}
}
} else if (
ring->number_of_objects == 1
|| (!g_Input.menu_left && !g_Input.menu_right)
|| !g_Input.menu_left) {
Output_SetLightAdder(HIGH_LIGHT);
for (int j = 0; j < num_frames; j++) {
inv_item->y_rot += 256;
}
}
} else {
} else if (inv_item != ring->list[ring->current_object]) {
Output_SetLightAdder(LOW_LIGHT);
for (int j = 0; j < num_frames; j++) {
if (inv_item->y_rot < 0) {
inv_item->y_rot += 256;
} else if (inv_item->y_rot > 0) {
inv_item->y_rot -= 256;
}
}
} else if (ring->rotating) {
Output_SetLightAdder(LOW_LIGHT);
} else {
Output_SetLightAdder(HIGH_LIGHT);
}
InvRing_UpdateInventoryItem(ring, inv_item, num_frames);
Matrix_TranslateRel(0, inv_item->y_trans, inv_item->z_trans);
Matrix_RotYXZ(inv_item->y_rot, inv_item->x_rot, 0);

View file

@ -4,6 +4,7 @@
#include "global/types.h"
#include <libtrx/config/types.h>
#include <libtrx/game/overlay.h>
#include <stdbool.h>
#include <stdint.h>
@ -36,5 +37,3 @@ void Overlay_DrawGameInfo(void);
void Overlay_DrawFPSInfo(void);
void Overlay_AddPickup(GAME_OBJECT_ID object_id);
void Overlay_MakeAmmoString(char *string);

View file

@ -70,5 +70,5 @@ int16_t g_RoomsToDrawCount = 0;
INVENTORY_MODE g_InvMode;
#ifndef MESON_BUILD
const char *g_TR1XVersion = "TR1X (non-Docker build)";
const char *g_TRXVersion = "TR1X (non-Docker build)";
#endif

View file

@ -9,8 +9,6 @@
#include <stddef.h>
#include <stdint.h>
extern const char *g_TR1XVersion;
extern int32_t g_PhdPersp;
extern int32_t g_PhdLeft;
extern int32_t g_PhdBottom;

View file

@ -33,33 +33,8 @@
#define OPTION_RING_OBJECTS 3
#define INV_FRAMES 2
typedef enum {
// clang-format off
PASS_MESH_SPINE = 1 << 0,
PASS_MESH_FRONT = 1 << 1,
PASS_MESH_IN_FRONT = 1 << 2,
PASS_MESH_PAGE_2 = 1 << 3,
PASS_MESH_BACK = 1 << 4,
PASS_MESH_IN_BACK = 1 << 5,
PASS_MESH_PAGE_1 = 1 << 6,
PASS_MESH_COMMON = PASS_MESH_SPINE | PASS_MESH_BACK | PASS_MESH_FRONT,
// clang-format on
} PASS_MESH;
static TEXTSTRING *m_UpArrow1 = NULL;
static TEXTSTRING *m_UpArrow2 = NULL;
static TEXTSTRING *m_DownArrow1 = NULL;
static TEXTSTRING *m_DownArrow2 = NULL;
static TEXTSTRING *m_VersionText = NULL;
static TEXTSTRING *m_HeadingText = NULL;
static TEXTSTRING *m_ItemText[IT_NUMBER_OF] = {};
static int32_t m_NoInputCounter = 0;
static void M_RemoveItemsText(void);
static void M_RemoveVersionText(void);
static void M_InitHeader(INV_RING *ring);
static void M_RemoveHeader(void);
static void M_ShowItemQuantity(const char *fmt, int32_t qty);
static void M_ShowAmmoQuantity(const char *fmt, int32_t qty);
static void M_RingIsOpen(INV_RING *ring);
@ -67,140 +42,30 @@ static void M_RingIsNotOpen(INV_RING *ring);
static void M_RingNotActive(const INVENTORY_ITEM *inv_item);
static void M_RingActive(void);
static void M_SelectMeshes(INVENTORY_ITEM *inv_item);
static void M_UpdateInventoryItem(
const INV_RING *ring, INVENTORY_ITEM *inv_item, int32_t num_frames);
static bool M_AnimateInventoryItem(INVENTORY_ITEM *inv_item);
static GAME_FLOW_COMMAND M_Control(INV_RING *ring);
static void M_RemoveItemsText(void)
{
for (int32_t i = 0; i < IT_NUMBER_OF; i++) {
Text_Remove(m_ItemText[i]);
m_ItemText[i] = NULL;
}
}
static void M_RemoveVersionText(void)
{
Text_Remove(m_VersionText);
m_VersionText = NULL;
}
static void M_InitHeader(INV_RING *const ring)
{
if (ring->mode == INV_TITLE_MODE) {
return;
}
if (m_HeadingText == NULL) {
switch (ring->type) {
case RT_MAIN:
m_HeadingText = Text_Create(
0, 26, g_GF_GameStrings[GF_S_GAME_HEADING_INVENTORY]);
break;
case RT_OPTION:
if (ring->mode == INV_DEATH_MODE) {
m_HeadingText = Text_Create(
0, 26, g_GF_GameStrings[GF_S_GAME_HEADING_GAME_OVER]);
} else {
m_HeadingText = Text_Create(
0, 26, g_GF_GameStrings[GF_S_GAME_HEADING_OPTION]);
}
break;
case RT_KEYS:
m_HeadingText =
Text_Create(0, 26, g_GF_GameStrings[GF_S_GAME_HEADING_ITEMS]);
break;
}
Text_CentreH(m_HeadingText, true);
}
if (ring->mode != INV_GAME_MODE) {
return;
}
if (m_UpArrow1 == NULL
&& (ring->type == RT_OPTION
|| (ring->type == RT_MAIN
&& g_InvRing_Source[RT_KEYS].count > 0))) {
m_UpArrow1 = Text_Create(20, 28, "\\{arrow up}");
m_UpArrow2 = Text_Create(-20, 28, "\\{arrow up}");
Text_AlignRight(m_UpArrow2, true);
}
if (m_DownArrow1 == NULL
&& ((
(ring->type == RT_MAIN && !g_GameFlow.lockout_option_ring)
|| ring->type == RT_KEYS))) {
m_DownArrow1 = Text_Create(20, -15, "\\{arrow down}");
Text_AlignBottom(m_DownArrow1, true);
m_DownArrow2 = Text_Create(-20, -15, "\\{arrow down}");
Text_AlignBottom(m_DownArrow2, true);
Text_AlignRight(m_DownArrow2, true);
}
}
static void M_RemoveHeader(void)
{
Text_Remove(m_HeadingText);
m_HeadingText = NULL;
Text_Remove(m_UpArrow1);
m_UpArrow1 = NULL;
Text_Remove(m_UpArrow2);
m_UpArrow2 = NULL;
Text_Remove(m_DownArrow1);
m_DownArrow1 = NULL;
Text_Remove(m_DownArrow2);
m_DownArrow2 = NULL;
}
static void M_ShowItemQuantity(const char *const fmt, const int32_t qty)
{
if (m_ItemText[IT_QTY] == NULL) {
char string[64];
sprintf(string, fmt, qty);
Overlay_MakeAmmoString(string);
m_ItemText[IT_QTY] = Text_Create(64, -56, string);
Text_AlignBottom(m_ItemText[IT_QTY], true);
Text_CentreH(m_ItemText[IT_QTY], true);
}
}
static void M_ShowAmmoQuantity(const char *const fmt, const int32_t qty)
{
if (!g_SaveGame.bonus_flag) {
M_ShowItemQuantity(fmt, qty);
InvRing_ShowItemQuantity(fmt, qty);
}
}
static void M_RingIsOpen(INV_RING *const ring)
{
M_InitHeader(ring);
InvRing_ShowHeader(ring);
}
static void M_RingIsNotOpen(INV_RING *const ring)
{
M_RemoveHeader();
InvRing_RemoveHeader();
}
static void M_RingNotActive(const INVENTORY_ITEM *const inv_item)
{
if (m_ItemText[IT_NAME] == NULL) {
if (inv_item->object_id != O_PASSPORT_OPTION) {
m_ItemText[IT_NAME] =
Text_Create(0, -16, Object_GetName(inv_item->object_id));
}
if (m_ItemText[IT_NAME]) {
Text_AlignBottom(m_ItemText[IT_NAME], true);
Text_CentreH(m_ItemText[IT_NAME], true);
}
}
InvRing_ShowItemName(inv_item);
const int32_t qty = Inv_RequestItem(inv_item->object_id);
switch (inv_item->object_id) {
@ -230,19 +95,19 @@ static void M_RingNotActive(const INVENTORY_ITEM *const inv_item)
case O_UZI_AMMO_OPTION:
case O_HARPOON_AMMO_OPTION:
case O_M16_AMMO_OPTION:
M_ShowItemQuantity("%d", 2 * qty);
InvRing_ShowItemQuantity("%d", 2 * qty);
break;
case O_GRENADE_AMMO_OPTION:
case O_FLARES_OPTION:
M_ShowItemQuantity("%d", qty);
InvRing_ShowItemQuantity("%d", qty);
break;
case O_SMALL_MEDIPACK_OPTION:
case O_LARGE_MEDIPACK_OPTION:
g_HealthBarTimer = 40;
Overlay_DrawHealthBar();
M_ShowItemQuantity("%d", qty);
InvRing_ShowItemQuantity("%d", qty);
break;
case O_PUZZLE_OPTION_1:
@ -256,7 +121,7 @@ static void M_RingNotActive(const INVENTORY_ITEM *const inv_item)
case O_PICKUP_OPTION_1:
case O_PICKUP_OPTION_2:
if (qty > 1) {
M_ShowItemQuantity("%d", qty);
InvRing_ShowItemQuantity("%d", qty);
}
break;
@ -264,106 +129,21 @@ static void M_RingNotActive(const INVENTORY_ITEM *const inv_item)
break;
}
if (inv_item->object_id == O_SMALL_MEDIPACK_OPTION
|| inv_item->object_id == O_LARGE_MEDIPACK_OPTION) {
Text_Hide(m_UpArrow1, true);
} else {
Text_Hide(m_UpArrow1, false);
}
InvRing_HideArrow(
INV_RING_ARROW_TL,
inv_item->object_id == O_SMALL_MEDIPACK_OPTION
|| inv_item->object_id == O_LARGE_MEDIPACK_OPTION);
}
static void M_RingActive(void)
{
M_RemoveItemsText();
}
static void M_SelectMeshes(INVENTORY_ITEM *const inv_item)
{
switch (inv_item->object_id) {
case O_PASSPORT_OPTION:
inv_item->meshes_drawn = PASS_MESH_COMMON;
if (inv_item->current_frame < 4) {
inv_item->meshes_drawn |= PASS_MESH_IN_FRONT;
} else if (inv_item->current_frame <= 16) {
inv_item->meshes_drawn |= PASS_MESH_IN_FRONT | PASS_MESH_PAGE_1;
} else if (inv_item->current_frame < 19) {
inv_item->meshes_drawn |=
PASS_MESH_IN_FRONT | PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2;
} else if (inv_item->current_frame == 19) {
inv_item->meshes_drawn |= PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2;
} else if (inv_item->current_frame < 24) {
inv_item->meshes_drawn |=
PASS_MESH_IN_BACK | PASS_MESH_PAGE_1 | PASS_MESH_PAGE_2;
} else if (inv_item->current_frame < 29) {
inv_item->meshes_drawn |= PASS_MESH_IN_BACK | PASS_MESH_PAGE_2;
} else if (inv_item->current_frame == 29) {
}
break;
case O_COMPASS_OPTION:
if (inv_item->current_frame == 0 || inv_item->current_frame >= 18) {
inv_item->meshes_drawn = inv_item->meshes_sel;
} else {
inv_item->meshes_drawn = -1;
}
break;
default:
inv_item->meshes_drawn = -1;
break;
}
}
static void M_UpdateInventoryItem(
const INV_RING *const ring, INVENTORY_ITEM *const inv_item,
const int32_t num_frames)
{
if (ring->motion.status == RNG_DONE
|| inv_item != ring->list[ring->current_object]) {
for (int32_t i = 0; i < num_frames; i++) {
if (inv_item->y_rot < 0) {
inv_item->y_rot += 256;
} else if (inv_item->y_rot > 0) {
inv_item->y_rot -= 256;
}
}
} else if (ring->rotating) {
for (int32_t i = 0; i < num_frames; i++) {
if (inv_item->y_rot > 0) {
inv_item->y_rot -= 512;
} else if (inv_item->y_rot < 0) {
inv_item->y_rot += 512;
}
}
} else if (
ring->motion.status == RNG_SELECTED
|| ring->motion.status == RNG_DESELECTING
|| ring->motion.status == RNG_SELECTING
|| ring->motion.status == RNG_DESELECT
|| ring->motion.status == RNG_CLOSING_ITEM) {
for (int32_t i = 0; i < num_frames; i++) {
const int32_t delta = inv_item->y_rot_sel - inv_item->y_rot;
if (delta != 0) {
if (delta > 0 && delta < PHD_180) {
inv_item->y_rot += 1024;
} else {
inv_item->y_rot -= 1024;
}
inv_item->y_rot &= ~(1024 - 1);
}
}
} else if (
ring->number_of_objects == 1 || (!g_Input.right && !g_Input.left)) {
for (int32_t i = 0; i < num_frames; i++) {
inv_item->y_rot += 256;
}
}
InvRing_RemoveItemTexts();
}
static bool M_AnimateInventoryItem(INVENTORY_ITEM *const inv_item)
{
if (inv_item->current_frame == inv_item->goal_frame) {
M_SelectMeshes(inv_item);
InvRing_SelectMeshes(inv_item);
return false;
}
@ -379,7 +159,7 @@ static bool M_AnimateInventoryItem(INVENTORY_ITEM *const inv_item)
}
}
M_SelectMeshes(inv_item);
InvRing_SelectMeshes(inv_item);
return true;
}
@ -795,7 +575,7 @@ static GAME_FLOW_COMMAND M_Control(INV_RING *const ring)
}
for (int32_t i = 0; i < ring->number_of_objects; i++) {
M_UpdateInventoryItem(ring, ring->list[i], 2);
InvRing_UpdateInventoryItem(ring, ring->list[i], INV_FRAMES);
}
Sound_EndScene();
@ -804,8 +584,8 @@ static GAME_FLOW_COMMAND M_Control(INV_RING *const ring)
void InvRing_RemoveAllText(void)
{
M_RemoveHeader();
M_RemoveItemsText();
InvRing_RemoveHeader();
InvRing_RemoveItemTexts();
}
INV_RING *InvRing_Open(const INVENTORY_MODE mode)
@ -828,14 +608,10 @@ INV_RING *InvRing_Open(const INVENTORY_MODE mode)
if (g_GameFlow.gym_enabled) {
g_InvRing_Source[RT_OPTION].count++;
}
m_VersionText = Text_Create(-20, -18, g_TR2XVersion);
Text_AlignRight(m_VersionText, 1);
Text_AlignBottom(m_VersionText, 1);
Text_SetScale(
m_VersionText, TEXT_BASE_SCALE * 0.5, TEXT_BASE_SCALE * 0.5);
InvRing_ShowVersionText();
} else {
g_InvRing_Source[RT_OPTION].count = OPTION_RING_OBJECTS;
M_RemoveVersionText();
InvRing_RemoveVersionText();
}
for (int32_t i = 0; i < 8; i++) {
@ -927,7 +703,7 @@ GAME_FLOW_COMMAND InvRing_Close(INV_RING *const ring)
GAME_FLOW_COMMAND gf_cmd = { .action = GF_NOOP };
InvRing_RemoveAllText();
M_RemoveVersionText();
InvRing_RemoveVersionText();
if (ring->list != NULL) {
INVENTORY_ITEM *const inv_item = ring->list[ring->current_object];
@ -1079,3 +855,8 @@ GAME_FLOW_COMMAND InvRing_Control(
Output_AnimateTextures(g_Camera.num_frames);
return gf_cmd;
}
bool InvRing_IsOptionLockedOut(void)
{
return g_GameFlow.lockout_option_ring;
}

View file

@ -18,13 +18,13 @@ static void M_DrawItem(
const INV_RING *const ring, const INVENTORY_ITEM *const inv_item)
{
if (ring->motion.status == RNG_DONE) {
g_LsAdder = LOW_LIGHT;
Output_SetLightAdder(LOW_LIGHT);
} else if (inv_item != ring->list[ring->current_object]) {
g_LsAdder = LOW_LIGHT;
Output_SetLightAdder(LOW_LIGHT);
} else if (ring->rotating) {
g_LsAdder = LOW_LIGHT;
Output_SetLightAdder(LOW_LIGHT);
} else {
g_LsAdder = HIGH_LIGHT;
Output_SetLightAdder(HIGH_LIGHT);
}
int32_t minutes;

View file

@ -4,12 +4,6 @@
#include <libtrx/game/inventory_ring/vars.h>
typedef enum {
IT_NAME = 0,
IT_QTY = 1,
IT_NUMBER_OF = 2,
} INV_TEXT;
extern INVENTORY_MODE g_Inv_Mode;
extern int16_t g_Inv_Chosen;
extern int32_t g_Inv_ExtraData[8];

View file

@ -2,12 +2,13 @@
#include "global/types.h"
#include <libtrx/game/overlay.h>
void Overlay_DrawAssaultTimer(void);
void Overlay_DrawGameInfo(bool pickup_state);
void Overlay_DrawHealthBar(void);
void Overlay_DrawAirBar(void);
void Overlay_HideGameInfo(void);
void Overlay_MakeAmmoString(char *string);
void Overlay_DrawAmmoInfo(void);
void Overlay_InitialisePickUpDisplay(void);
void Overlay_DrawPickups(bool pickup_state);

View file

@ -5,7 +5,7 @@
#include <libtrx/game/sound/ids.h>
#ifndef MESON_BUILD
const char *g_TR2XVersion = "TR2X (non-Docker build)";
const char *g_TRXVersion = "TR2X (non-Docker build)";
#endif
GAME_FLOW_COMMAND g_GF_OverrideCommand = { .action = GF_NOOP };

View file

@ -6,7 +6,6 @@
#include <SDL2/SDL.h>
extern const char *g_TR2XVersion;
extern GAME_FLOW_COMMAND g_GF_OverrideCommand;
extern int16_t g_RoomsToDraw[MAX_ROOMS_TO_DRAW];

View file

@ -5,7 +5,7 @@ from pathlib import Path
from shared.versioning import generate_version
TEMPLATE = """
const char *g_TR1XVersion = "TR1X {version}";
const char *g_TRXVersion = "TR1X {version}";
""".lstrip()

View file

@ -5,7 +5,7 @@ from pathlib import Path
from shared.versioning import generate_version
TEMPLATE = """
const char *g_TR2XVersion = "TR2X {version}";
const char *g_TRXVersion = "TR2X {version}";
""".lstrip()