mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 20:58:07 +03:00
Compare commits
25 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5e3fb42a25 | ||
![]() |
6d5bdd89a3 | ||
![]() |
a859d668f9 | ||
![]() |
e03c65ca0f | ||
![]() |
ff86b5e712 | ||
![]() |
cdfb5942c1 | ||
![]() |
8b78a7f001 | ||
![]() |
2cd998673f | ||
![]() |
a7269bbe8a | ||
![]() |
f27d0435a9 | ||
![]() |
88f41c5a75 | ||
![]() |
0ba717edd5 | ||
![]() |
3696e84925 | ||
![]() |
e439371c66 | ||
![]() |
92ff6e12c7 | ||
![]() |
73da4c2945 | ||
![]() |
dc41197cd6 | ||
![]() |
890c7f76bb | ||
![]() |
83ac9514cb | ||
![]() |
96b86b1605 | ||
![]() |
607ac811f0 | ||
![]() |
15b758c57d | ||
![]() |
eec8f16d5f | ||
![]() |
2536ff55c1 | ||
![]() |
10b9bcc780 |
65 changed files with 817 additions and 865 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -38,4 +38,11 @@ src/tr2/subprojects/dwarfstack.wrap
|
|||
|
||||
data/tr1/ship/data/images/
|
||||
data/tr2/ship/data/images/
|
||||
data/tr2/ship/data/level1.tr2
|
||||
data/tr2/ship/data/level2.tr2
|
||||
data/tr2/ship/data/level3.tr2
|
||||
data/tr2/ship/data/level4.tr2
|
||||
data/tr2/ship/data/level5.tr2
|
||||
data/tr2/ship/data/main_gm.sfx
|
||||
data/tr2/ship/data/title_gm.tr2
|
||||
data/tr2/ship/music/
|
||||
|
|
|
@ -531,7 +531,9 @@
|
|||
"PHOTO_MODE_ROTATE_PROMPT": "Rotate camera",
|
||||
"PHOTO_MODE_SNAP_PROMPT": "Take picture",
|
||||
"PHOTO_MODE_TITLE": "Photo Mode",
|
||||
"SOUND_SET_VOLUMES": "Set Volumes",
|
||||
"SOUND_DIALOG_MUSIC": "\\{icon sound} Sound",
|
||||
"SOUND_DIALOG_SOUND": "\\{icon music} Music",
|
||||
"SOUND_DIALOG_TITLE": "Set Volumes",
|
||||
"STATS_AMMO": "AMMO HITS/USED",
|
||||
"STATS_BASIC_FMT": "%d",
|
||||
"STATS_BONUS_STATISTICS": "Bonus Statistics",
|
||||
|
|
|
@ -217,6 +217,7 @@
|
|||
],
|
||||
"injections": [
|
||||
"data/injections/living_deck_goon_sfx.bin",
|
||||
"data/injections/living_fd.bin",
|
||||
"data/injections/living_pickup_meshes.bin",
|
||||
"data/injections/seaweed_collision.bin",
|
||||
],
|
||||
|
|
|
@ -655,7 +655,9 @@
|
|||
"PHOTO_MODE_ROTATE_PROMPT": "Rotate camera",
|
||||
"PHOTO_MODE_SNAP_PROMPT": "Take picture",
|
||||
"PHOTO_MODE_TITLE": "Photo Mode",
|
||||
"SOUND_SET_VOLUMES": "Set Volumes",
|
||||
"SOUND_DIALOG_MUSIC": "\\{icon sound} Sound",
|
||||
"SOUND_DIALOG_SOUND": "\\{icon music} Music",
|
||||
"SOUND_DIALOG_TITLE": "Set Volumes",
|
||||
"STATS_AMMO_HITS": "Hits",
|
||||
"STATS_AMMO_USED": "Ammo Used",
|
||||
"STATS_ASSAULT_FINISH": "Finish",
|
||||
|
|
BIN
data/tr2/ship/data/injections/living_fd.bin
Normal file
BIN
data/tr2/ship/data/injections/living_fd.bin
Normal file
Binary file not shown.
20
docs/COMMAND_LINE.md
Normal file
20
docs/COMMAND_LINE.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Command line options
|
||||
|
||||
Currently the following command line interface options are available:
|
||||
|
||||
`-g/--gold` (legacy: `-gold`):
|
||||
Runs the Unfinished Business or the Golden Mask expansion pack, depending
|
||||
on the game.
|
||||
|
||||
`--demo-pc` (TR1X only, legacy: `-demo_pc`):
|
||||
Runs the PC demo level.
|
||||
|
||||
`-l/--level <path>`:
|
||||
Runs the game immediately launching it into the specified level.
|
||||
The path should be absolute. Internally, this option uses
|
||||
`TR*X_gameflow_level.json5` as a template instructing it how to run the
|
||||
game.
|
||||
|
||||
`-s/--save <num>`:
|
||||
Runs the game immediately loading a specific save slot. The first save
|
||||
starts at `num=1`. This option can be combined with `-l/--level`.
|
|
@ -266,30 +266,63 @@ request number, but it's important to carefully review the body field, as it
|
|||
often includes unwanted content.
|
||||
|
||||
|
||||
### Branching model
|
||||
|
||||
We have two branches: `develop` and `stable`. `develop` is where all changes
|
||||
about to be published in the next release land. `stable` is the latest release.
|
||||
We avoid creating merge commits between these two – they should always point to
|
||||
the same HEAD when applicable. This means that any hotfixes that need to be
|
||||
released ahead of unpublished work in `develop` are merged directly to
|
||||
`stable`, and `develop` needs to be then rebased on top of the now-patched
|
||||
`stable`.
|
||||
|
||||
|
||||
### Tooling
|
||||
|
||||
Internal tools are typically coded in a reasonably recent version of Python,
|
||||
while avoiding the use of bash, shell, and similar languages.
|
||||
|
||||
|
||||
### Branching model
|
||||
|
||||
We have two branches: `develop` and `stable`. `develop` is where all changes
|
||||
about to be published in the next release land. `stable` is the latest release.
|
||||
|
||||
|
||||
### Releasing a new version
|
||||
|
||||
New version releases happen automatically whenever a new tag is pushed to the
|
||||
`stable` branch with the help of GitHub actions. In general this is accompanied
|
||||
with a special commit `docs: release X.Y.Z` that also adjusts the changelog.
|
||||
See git history for details.
|
||||
New version releases are published automatically whenever a new tag is pushed
|
||||
to the `stable` branch with the help of GitHub actions.
|
||||
The general workflow is this:
|
||||
|
||||
```console
|
||||
TR_VERSION=...
|
||||
RELEASE_VERSION=...
|
||||
|
||||
# Switch to the stable branch.
|
||||
git checkout stable
|
||||
|
||||
# Merge `develop` into it.
|
||||
git merge develop
|
||||
|
||||
# Create a special commit `docs: release X.Y.Z` marking the release in the
|
||||
# relevant changelog file. Then tag it with `tr1-X.Y.Z` or `tr2-X.Y.Z`.
|
||||
# You can do that by hand, or run the command below:
|
||||
tools/release commit ${TR_VERSION} ${RELEASE_VERSION}
|
||||
|
||||
# Review the changelog content.
|
||||
|
||||
# Switch back to develop.
|
||||
git checkout develop
|
||||
|
||||
# Merge stable using fast-forward.
|
||||
git merge --ff stable
|
||||
|
||||
# Review both branches and changes. If everything is okay, push to GitHub.
|
||||
# You can do this by hand: git push origin develop stable tr1-X.Y.Z, or:
|
||||
# tools/release push ${TR_VERSION} ${RELEASE_VERSION}
|
||||
```
|
||||
|
||||
### Hotfixes
|
||||
|
||||
Hotfix releases are a bit different as we try to not include non-bugfix changes
|
||||
in them. Here instead of merging `develop` to `stable` we cherry-pick relevant
|
||||
changes, resolving conflicts along the way.
|
||||
|
||||
### Versioning
|
||||
|
||||
We increase the major version for significant releases based on judgment,
|
||||
typically defaulting to increasing the minor version. Hotfixes increase the
|
||||
patch version.
|
||||
|
||||
|
||||
## Glossary
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
- added support for antitriggers, like TR2+ (#2580)
|
||||
- added support for aspect ratio-specific images (#1840)
|
||||
- added an option to wraparound when scrolling UI dialogs, such as save/load (#2834)
|
||||
- added aliases to CLI options (`-gold` becomes `-g/--gold`, `-demo_pc` becomes `--demo-pc`)
|
||||
- added a `--help` CLI option (may not output anything on Windows machines – OS bug)
|
||||
- changed the `draw_distance_fade` and `draw_distance_max` to `fog_start` and `fog_end`
|
||||
- changed `Select Detail` dialog title to `Graphic Options`
|
||||
- changed the number of static mesh slots from 50 to 256 (#2734)
|
||||
- changed the "enable EIDOS logo" option to disable the Core Design and Bink Video Codec FMVs as well; renamed to "enable legal" (#2741)
|
||||
- changed sprite pickups to respect the water tint if placed underwater (#2673)
|
||||
- changed save to take priority over load when both inputs are held on the same frame, in line with OG (#2833)
|
||||
- changed the sound dialog appearance (repositioned and added text labels)
|
||||
- changed The Unfinished Business strings to default to the OG strings file for the main tables (#2847)
|
||||
- fixed the bilinear filter to not readjust the UVs (#2258)
|
||||
- fixed disabling the cutscenes causing the game to exit (#2743, regression from 4.8)
|
||||
|
@ -22,6 +25,7 @@
|
|||
- fixed the scale of the four keys in St. Francis' Folly (#2652)
|
||||
- fixed the panther at times not making a sound when it dies, and restored Skate Kid's death SFX (#2647)
|
||||
- fixed pushblocks being rotated when Lara grabs them, most noticeable if asymmetric textures have been used (#2776)
|
||||
- fixed Lara becoming clamped if she picks up an item under a steeply sloped ceiling (#2879)
|
||||
- fixed a crash when 3D pickups are disabled and Lara crosses a trigger to look at a pickup item (#2711, regression from 4.8)
|
||||
- fixed trapezoid filter warping on faces close to the camera (#2629, regression from 4.9)
|
||||
- fixed Mac builds crashing upon start (regression from 4.9)
|
||||
|
@ -37,6 +41,7 @@
|
|||
- fixed Lara at times ending up in incorrect rooms when using the teleport cheat (#2486, regression from 3.0)
|
||||
- fixed the `/pos` console command reporting the base room number when Lara is actually in a flipped room (#2487, regression from 3.0)
|
||||
- fixed clicks in audio sounds (#2846, regression from 2.0)
|
||||
- fixed Lara being killed if she enters the void in a level that uses the `disable_floor` sequence in the game flow (#2874, regression from 4.9)
|
||||
- improved bubble appearance (#2672)
|
||||
- improved rendering performance
|
||||
- improved pause exit dialog - it can now be canceled with escape
|
||||
|
|
|
@ -485,6 +485,7 @@ Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for det
|
|||
- fixed being able to shoot the scion multiple times if save/load is used while it blows up
|
||||
- fixed the game crashing if a cinematic is triggered but the level contains no cinematic frames
|
||||
- fixed pushblocks being rotated when Lara grabs them, most noticeable if asymmetric textures have been used
|
||||
- fixed Lara becoming clamped if she picks up an item under a steeply sloped ceiling
|
||||
|
||||
#### Cheats
|
||||
- added a fly cheat
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
## [Unreleased](https://github.com/LostArtefacts/TRX/compare/tr2-1.0.2...develop) - ××××-××-××
|
||||
## [Unreleased](https://github.com/LostArtefacts/TRX/compare/tr2-1.0.1...develop) - ××××-××-××
|
||||
- added aliases to CLI options (`-gold` becomes `-g/--gold`)
|
||||
- added a `--help` CLI option (may not output anything on Windows machines – OS bug)
|
||||
- changed the sound dialog appearance (repositioned, added text labels and arrows)
|
||||
- fixed Lara being killed if she enters the void in a level that uses the `disable_floor` sequence in the game flow (#2874, regression from 0.10)
|
||||
- fixed flame emitter 23 in room 6 not being deactivated when the lever in room 1 is used (#2851)
|
||||
|
||||
## [1.0.2](https://github.com/LostArtefacts/TRX/compare/tr2-1.0.1...tr2-1.0.2) - 2025-04-26
|
||||
- changed The Golden Mask strings to default to the OG strings file for the main tables (#2847)
|
||||
|
|
|
@ -221,6 +221,7 @@ However, you can easily download them manually from these urls:
|
|||
- fixed the following floor data issues:
|
||||
- **Opera House**: fixed the trigger under item 203 to trigger it rather than item 204
|
||||
- **Wreck of the Maria Doria**: fixed room 98 not having water
|
||||
- **Living Quarters** - fixed flame emitter 23 in room 6 not being deactivated when the lever in room 1 is used
|
||||
- **The Deck**: fixed invalid portals between rooms 17 and 104, which could result in Lara seeing enemies in disconnected rooms
|
||||
- **Tibetan Foothills**: added missing triggers for the drawbridge in room 96 (after the flipmap)
|
||||
- **Catacombs of the Talion**: changed some music triggers to pads near the first yeti, and added missing triggers and ladder in room 116 (after the flipmap)
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
#include "game/const.h"
|
||||
#include "game/item_actions.h"
|
||||
#include "game/rooms/const.h"
|
||||
#include "game/lara/const.h"
|
||||
#include "game/matrix.h"
|
||||
#include "game/rooms.h"
|
||||
|
||||
void Lara_Animate(ITEM *const item)
|
||||
{
|
||||
|
@ -156,3 +158,88 @@ bool Lara_TestBoundsCollide(const ITEM *const item, const int32_t radius)
|
|||
{
|
||||
return Item_TestBoundsCollide(item, Lara_GetItem(), radius);
|
||||
}
|
||||
|
||||
bool Lara_TestPosition(
|
||||
const ITEM *const item, const OBJECT_BOUNDS *const bounds)
|
||||
{
|
||||
const ITEM *const lara = Lara_GetItem();
|
||||
const XYZ_16 rot = {
|
||||
.x = lara->rot.x - item->rot.x,
|
||||
.y = lara->rot.y - item->rot.y,
|
||||
.z = lara->rot.z - item->rot.z,
|
||||
};
|
||||
const XYZ_32 dist = {
|
||||
.x = lara->pos.x - item->pos.x,
|
||||
.y = lara->pos.y - item->pos.y,
|
||||
.z = lara->pos.z - item->pos.z,
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
if (rot.x < bounds->rot.min.x ||
|
||||
rot.x > bounds->rot.max.x ||
|
||||
rot.y < bounds->rot.min.y ||
|
||||
rot.y > bounds->rot.max.y ||
|
||||
rot.z < bounds->rot.min.z ||
|
||||
rot.z > bounds->rot.max.z
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
Matrix_PushUnit();
|
||||
Matrix_Rot16(item->rot);
|
||||
const MATRIX *const m = g_MatrixPtr;
|
||||
const XYZ_32 shift = {
|
||||
.x = (dist.x * m->_00 + dist.y * m->_10 + dist.z * m->_20) >> W2V_SHIFT,
|
||||
.y = (dist.x * m->_01 + dist.y * m->_11 + dist.z * m->_21) >> W2V_SHIFT,
|
||||
.z = (dist.x * m->_02 + dist.y * m->_12 + dist.z * m->_22) >> W2V_SHIFT,
|
||||
};
|
||||
Matrix_Pop();
|
||||
|
||||
// clang-format off
|
||||
return (
|
||||
shift.x >= bounds->shift.min.x &&
|
||||
shift.x <= bounds->shift.max.x &&
|
||||
shift.y >= bounds->shift.min.y &&
|
||||
shift.y <= bounds->shift.max.y &&
|
||||
shift.z >= bounds->shift.min.z &&
|
||||
shift.z <= bounds->shift.max.z
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void Lara_AlignPosition(const ITEM *const item, const XYZ_32 *const vec)
|
||||
{
|
||||
ITEM *const lara = Lara_GetItem();
|
||||
lara->rot = item->rot;
|
||||
Matrix_PushUnit();
|
||||
Matrix_Rot16(item->rot);
|
||||
const MATRIX *const m = g_MatrixPtr;
|
||||
const XYZ_32 shift = {
|
||||
.x = (vec->x * m->_00 + vec->y * m->_01 + vec->z * m->_02) >> W2V_SHIFT,
|
||||
.y = (vec->x * m->_10 + vec->y * m->_11 + vec->z * m->_12) >> W2V_SHIFT,
|
||||
.z = (vec->x * m->_20 + vec->y * m->_21 + vec->z * m->_22) >> W2V_SHIFT,
|
||||
};
|
||||
Matrix_Pop();
|
||||
|
||||
const XYZ_32 new_pos = {
|
||||
.x = item->pos.x + shift.x,
|
||||
.y = item->pos.y + shift.y,
|
||||
.z = item->pos.z + shift.z,
|
||||
};
|
||||
|
||||
int16_t room_num = lara->room_num;
|
||||
const SECTOR *const sector =
|
||||
Room_GetSector(new_pos.x, new_pos.y, new_pos.z, &room_num);
|
||||
const int32_t height =
|
||||
Room_GetHeight(sector, new_pos.x, new_pos.y, new_pos.z);
|
||||
const int32_t ceiling =
|
||||
Room_GetCeiling(sector, new_pos.x, new_pos.y, new_pos.z);
|
||||
|
||||
if (ABS(height - lara->pos.y) > STEP_L
|
||||
|| ABS(ceiling - lara->pos.y) < LARA_HEIGHT) {
|
||||
return;
|
||||
}
|
||||
|
||||
lara->pos = new_pos;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,16 @@
|
|||
|
||||
static uint16_t m_MusicTrackFlags[MAX_MUSIC_TRACKS] = {};
|
||||
|
||||
int32_t Music_GetMinVolume(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t Music_GetMaxVolume(void)
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
void Music_ResetTrackFlags(void)
|
||||
{
|
||||
for (int32_t i = 0; i < MAX_MUSIC_TRACKS; i++) {
|
||||
|
|
|
@ -550,7 +550,7 @@ void Room_SetAbyssHeight(const int16_t height)
|
|||
CLAMPG(m_AbyssMaxHeight, MAX_HEIGHT - STEP_L);
|
||||
}
|
||||
|
||||
bool Room_IsAbyssHeight(const int16_t height)
|
||||
bool Room_IsAbyssHeight(const int32_t height)
|
||||
{
|
||||
return m_AbyssMinHeight != 0 && height >= m_AbyssMinHeight;
|
||||
}
|
||||
|
|
|
@ -6,28 +6,18 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
static int m_ArgCount = 0;
|
||||
static const char **m_ArgStrings = nullptr;
|
||||
|
||||
void Shell_GetCommandLine(int *arg_count, const char ***args)
|
||||
{
|
||||
*arg_count = m_ArgCount;
|
||||
*args = m_ArgStrings;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (!Shell_ParseArgs(argc, (const char **)argv)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *log_path = File_GetFullPath(PROJECT_NAME ".log");
|
||||
Log_Init(log_path);
|
||||
Memory_FreePointer(&log_path);
|
||||
|
||||
LOG_INFO("Game directory: %s", File_GetGameDirectory());
|
||||
|
||||
m_ArgCount = argc;
|
||||
m_ArgStrings = (const char **)argv;
|
||||
|
||||
Shell_Setup();
|
||||
Shell_Main();
|
||||
Shell_Terminate(0);
|
||||
return 0;
|
||||
int32_t exit_code = Shell_Main();
|
||||
Shell_Terminate(exit_code);
|
||||
return exit_code;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
#include "debug.h"
|
||||
#include "game/console/common.h"
|
||||
#include "game/game_string.h"
|
||||
#include "game/scaler.h"
|
||||
#include "game/ui/elements/anchor.h"
|
||||
#include "game/ui/events.h"
|
||||
#include "game/viewport.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
@ -201,3 +203,23 @@ void UI_HandleTextEdit(const char *const text)
|
|||
UI_FireEvent((EVENT) {
|
||||
.name = "text_edit", .sender = nullptr, .data = (void *)text });
|
||||
}
|
||||
|
||||
int32_t UI_GetCanvasWidth(void)
|
||||
{
|
||||
return Scaler_CalcInverse(Viewport_GetWidth(), SCALER_TARGET_GENERIC);
|
||||
}
|
||||
|
||||
int32_t UI_GetCanvasHeight(void)
|
||||
{
|
||||
return Scaler_CalcInverse(Viewport_GetHeight(), SCALER_TARGET_GENERIC);
|
||||
}
|
||||
|
||||
float UI_ScaleX(const float x)
|
||||
{
|
||||
return Scaler_Calc(x, SCALER_TARGET_GENERIC);
|
||||
}
|
||||
|
||||
float UI_ScaleY(const float y)
|
||||
{
|
||||
return Scaler_Calc(y, SCALER_TARGET_GENERIC);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ void UI_PhotoMode(void)
|
|||
char tmp[50];
|
||||
|
||||
UI_BeginModal(0.0f, 0.0f);
|
||||
UI_BeginPad(8.0f, 10.0f);
|
||||
UI_BeginPad(8.0f, 8.0f);
|
||||
UI_BeginFrame(UI_FRAME_DIALOG_BACKGROUND);
|
||||
UI_BeginPad(8.0, 6.0);
|
||||
|
||||
|
|
176
src/libtrx/game/ui/dialogs/sound_settings.c
Normal file
176
src/libtrx/game/ui/dialogs/sound_settings.c
Normal file
|
@ -0,0 +1,176 @@
|
|||
#include "game/ui/dialogs/sound_settings.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "game/game_string.h"
|
||||
#include "game/input.h"
|
||||
#include "game/music.h"
|
||||
#include "game/sound.h"
|
||||
#include "game/ui/elements/anchor.h"
|
||||
#include "game/ui/elements/hide.h"
|
||||
#include "game/ui/elements/label.h"
|
||||
#include "game/ui/elements/modal.h"
|
||||
#include "game/ui/elements/requester.h"
|
||||
#include "game/ui/elements/resize.h"
|
||||
#include "game/ui/elements/spacer.h"
|
||||
#include "game/ui/elements/stack.h"
|
||||
#include "memory.h"
|
||||
#include "strings.h"
|
||||
#include "utils.h"
|
||||
|
||||
typedef struct UI_SOUND_SETTINGS_STATE {
|
||||
UI_REQUESTER_STATE req;
|
||||
} UI_SOUND_SETTINGS_STATE;
|
||||
|
||||
typedef enum {
|
||||
M_ROW_MUSIC = 0,
|
||||
M_ROW_SOUND = 1,
|
||||
M_ROW_COUNT = 2,
|
||||
} M_ROW;
|
||||
|
||||
static const GAME_STRING_ID m_Labels[M_ROW_COUNT] = {
|
||||
GS_ID(SOUND_DIALOG_SOUND),
|
||||
GS_ID(SOUND_DIALOG_MUSIC),
|
||||
};
|
||||
|
||||
static char *M_FormatRowValue(int32_t row);
|
||||
static bool M_CanChange(int32_t row, int32_t dir);
|
||||
static bool M_RequestChange(int32_t row, int32_t dir);
|
||||
|
||||
static char *M_FormatRowValue(const int32_t row)
|
||||
{
|
||||
switch (row) {
|
||||
case M_ROW_MUSIC:
|
||||
return String_Format("%2d", g_Config.audio.music_volume);
|
||||
case M_ROW_SOUND:
|
||||
return String_Format("%2d", g_Config.audio.sound_volume);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool M_CanChange(const int32_t row, const int32_t dir)
|
||||
{
|
||||
switch (row) {
|
||||
case M_ROW_MUSIC:
|
||||
if (dir < 0) {
|
||||
return g_Config.audio.music_volume > Music_GetMinVolume();
|
||||
} else if (dir > 0) {
|
||||
return g_Config.audio.music_volume < Music_GetMaxVolume();
|
||||
}
|
||||
break;
|
||||
case M_ROW_SOUND:
|
||||
if (dir < 0) {
|
||||
return g_Config.audio.sound_volume > Sound_GetMinVolume();
|
||||
} else if (dir > 0) {
|
||||
return g_Config.audio.sound_volume < Sound_GetMaxVolume();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool M_RequestChange(const int32_t row, const int32_t dir)
|
||||
{
|
||||
if (!M_CanChange(row, dir)) {
|
||||
return false;
|
||||
}
|
||||
switch (row) {
|
||||
case M_ROW_MUSIC:
|
||||
g_Config.audio.music_volume += dir;
|
||||
Music_SetVolume(g_Config.audio.music_volume);
|
||||
break;
|
||||
case M_ROW_SOUND:
|
||||
g_Config.audio.sound_volume += dir;
|
||||
Sound_SetMasterVolume(g_Config.audio.sound_volume);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
Config_Write();
|
||||
Sound_Effect(SFX_MENU_PASSPORT, nullptr, SPM_ALWAYS);
|
||||
return true;
|
||||
}
|
||||
|
||||
UI_SOUND_SETTINGS_STATE *UI_SoundSettings_Init(void)
|
||||
{
|
||||
UI_SOUND_SETTINGS_STATE *s = Memory_Alloc(sizeof(UI_SOUND_SETTINGS_STATE));
|
||||
UI_Requester_Init(&s->req, M_ROW_COUNT, M_ROW_COUNT, true);
|
||||
s->req.row_pad = 2.0f;
|
||||
return s;
|
||||
}
|
||||
|
||||
void UI_SoundSettings_Free(UI_SOUND_SETTINGS_STATE *const s)
|
||||
{
|
||||
UI_Requester_Free(&s->req);
|
||||
Memory_Free(s);
|
||||
}
|
||||
|
||||
bool UI_SoundSettings_Control(UI_SOUND_SETTINGS_STATE *const s)
|
||||
{
|
||||
const int32_t choice = UI_Requester_Control(&s->req);
|
||||
if (choice == UI_REQUESTER_CANCEL) {
|
||||
return true;
|
||||
}
|
||||
const int32_t sel = UI_Requester_GetCurrentRow(&s->req);
|
||||
if (g_InputDB.menu_left && sel >= 0) {
|
||||
M_RequestChange(sel, -1);
|
||||
} else if (g_InputDB.menu_right && sel >= 0) {
|
||||
M_RequestChange(sel, +1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UI_SoundSettings(UI_SOUND_SETTINGS_STATE *const s)
|
||||
{
|
||||
const int32_t sel = UI_Requester_GetCurrentRow(&s->req);
|
||||
UI_BeginModal(0.5f, 0.6f);
|
||||
UI_BeginRequester(&s->req, GS(SOUND_DIALOG_TITLE));
|
||||
|
||||
// Measure the maximum width of the value label to prevent the entire
|
||||
// dialog from changing its size as the player changes the sound levels.
|
||||
float value_w = -1.0f;
|
||||
UI_Label_Measure("10", &value_w, nullptr);
|
||||
|
||||
for (int32_t i = 0; i < s->req.max_rows; ++i) {
|
||||
if (!UI_Requester_IsRowVisible(&s->req, i)) {
|
||||
UI_BeginResize(-1.0f, 0.0f);
|
||||
} else {
|
||||
UI_BeginResize(-1.0f, -1.0f);
|
||||
}
|
||||
UI_BeginRequesterRow(&s->req, i);
|
||||
|
||||
UI_BeginStackEx((UI_STACK_SETTINGS) {
|
||||
.orientation = UI_STACK_HORIZONTAL,
|
||||
.align = { .h = UI_STACK_H_ALIGN_DISTRIBUTE },
|
||||
});
|
||||
UI_Label(GameString_Get(m_Labels[i]));
|
||||
UI_Spacer(20.0f, 0.0f);
|
||||
|
||||
UI_BeginStackEx((UI_STACK_SETTINGS) {
|
||||
.orientation = UI_STACK_HORIZONTAL,
|
||||
.align = { .h = UI_STACK_H_ALIGN_DISTRIBUTE },
|
||||
.spacing = { .h = 5.0f },
|
||||
});
|
||||
UI_BeginHide(i != sel || !M_CanChange(i, -1));
|
||||
UI_Label("\\{button left}");
|
||||
UI_EndHide();
|
||||
|
||||
UI_BeginResize(value_w, -1.0f);
|
||||
UI_BeginAnchor(0.5f, 0.5f);
|
||||
UI_Label(M_FormatRowValue(i));
|
||||
UI_EndAnchor();
|
||||
UI_EndResize();
|
||||
|
||||
UI_BeginHide(i != sel || !M_CanChange(i, +1));
|
||||
UI_Label("\\{button right}");
|
||||
UI_EndHide();
|
||||
UI_EndStack();
|
||||
UI_EndStack();
|
||||
|
||||
UI_EndRequesterRow(&s->req, i);
|
||||
UI_EndResize();
|
||||
}
|
||||
|
||||
UI_EndRequester(&s->req);
|
||||
UI_EndModal();
|
||||
}
|
|
@ -15,7 +15,7 @@ static const UI_WIDGET_OPS m_Ops = {
|
|||
static void M_Measure(UI_NODE *const node)
|
||||
{
|
||||
node->measure_w = UI_GetCanvasWidth();
|
||||
node->measure_h = UI_GetCanvasHeight() - TEXT_HEIGHT_FIXED;
|
||||
node->measure_h = UI_GetCanvasHeight();
|
||||
}
|
||||
|
||||
void UI_BeginModal(const float x, const float y)
|
||||
|
|
|
@ -114,7 +114,7 @@ static void M_Layout(
|
|||
int32_t child_count = 0;
|
||||
float total_child_main_size = 0.0f;
|
||||
UI_NODE *child = node->first_child;
|
||||
while (child != NULL) {
|
||||
while (child != nullptr) {
|
||||
switch (data->settings.orientation) {
|
||||
case UI_STACK_HORIZONTAL:
|
||||
total_child_main_size += child->measure_w;
|
||||
|
|
|
@ -132,7 +132,9 @@ GS_DEFINE(PASSPORT_MODE_NEW_GAME_JP_PLUS, "Japanese NG+")
|
|||
GS_DEFINE(PASSPORT_STORY_SO_FAR, "Story so far...")
|
||||
GS_DEFINE(PASSPORT_LEGACY_SELECT_LEVEL_1, "Legacy saves do not")
|
||||
GS_DEFINE(PASSPORT_LEGACY_SELECT_LEVEL_2, "support this feature.")
|
||||
GS_DEFINE(SOUND_SET_VOLUMES, "Set Volumes")
|
||||
GS_DEFINE(SOUND_DIALOG_TITLE, "Set Volumes")
|
||||
GS_DEFINE(SOUND_DIALOG_SOUND, "\\{icon music} Music")
|
||||
GS_DEFINE(SOUND_DIALOG_MUSIC, "\\{icon sound} Sound")
|
||||
GS_DEFINE(OSD_TRAPEZOID_FILTER_ON, "Trapezoid filter enabled")
|
||||
GS_DEFINE(OSD_TRAPEZOID_FILTER_OFF, "Trapezoid filter disabled")
|
||||
GS_DEFINE(DETAIL_INTEGER_FMT, "%d")
|
||||
|
|
|
@ -15,3 +15,5 @@ void Lara_TakeDamage(int16_t damage, bool hit_status);
|
|||
|
||||
bool Lara_TestBoundsCollide(const ITEM *item, int32_t radius);
|
||||
void Lara_Push(const ITEM *item, COLL_INFO *coll, bool hit_on, bool big_push);
|
||||
bool Lara_TestPosition(const ITEM *item, const OBJECT_BOUNDS *bounds);
|
||||
void Lara_AlignPosition(const ITEM *item, const XYZ_32 *vec);
|
||||
|
|
|
@ -31,3 +31,15 @@ extern void Music_Unpause(void);
|
|||
void Music_ResetTrackFlags(void);
|
||||
uint16_t Music_GetTrackFlags(int32_t track_idx);
|
||||
void Music_SetTrackFlags(int32_t track, uint16_t flags);
|
||||
|
||||
// Gets the minimum possible game volume.
|
||||
extern int32_t Music_GetMinVolume(void);
|
||||
|
||||
// Gets the maximum possible game volume.
|
||||
extern int32_t Music_GetMaxVolume(void);
|
||||
|
||||
// Gets the game volume.
|
||||
extern int32_t Music_GetVolume(void);
|
||||
|
||||
// Sets the game volume.
|
||||
extern void Music_SetVolume(int32_t volume);
|
||||
|
|
|
@ -38,14 +38,12 @@ typedef struct {
|
|||
bool disable_lighting;
|
||||
} OBJECT_MESH;
|
||||
|
||||
#if TR_VERSION == 1
|
||||
typedef struct {
|
||||
struct {
|
||||
XYZ_16 min;
|
||||
XYZ_16 max;
|
||||
} shift, rot;
|
||||
} OBJECT_BOUNDS;
|
||||
#endif
|
||||
|
||||
typedef struct OBJECT {
|
||||
int16_t mesh_count;
|
||||
|
@ -66,8 +64,8 @@ typedef struct OBJECT {
|
|||
void (*activate_func)(ITEM *item);
|
||||
void (*handle_flip_func)(ITEM *item, ROOM_FLIP_STATUS flip_status);
|
||||
void (*handle_save_func)(ITEM *item, SAVEGAME_STAGE stage);
|
||||
#if TR_VERSION == 1
|
||||
const OBJECT_BOUNDS *(*bounds_func)(void);
|
||||
#if TR_VERSION == 1
|
||||
bool (*is_usable_func)(int16_t item_num);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ SECTOR *Room_GetPitSector(const SECTOR *sector, int32_t x, int32_t z);
|
|||
SECTOR *Room_GetSkySector(const SECTOR *sector, int32_t x, int32_t z);
|
||||
|
||||
void Room_SetAbyssHeight(int16_t height);
|
||||
bool Room_IsAbyssHeight(int16_t height);
|
||||
bool Room_IsAbyssHeight(int32_t height);
|
||||
HEIGHT_TYPE Room_GetHeightType(void);
|
||||
int16_t Room_GetHeight(const SECTOR *sector, int32_t x, int32_t y, int32_t z);
|
||||
int16_t Room_GetHeightEx(
|
||||
|
|
|
@ -11,13 +11,13 @@ typedef struct {
|
|||
extern void Shell_Shutdown(void);
|
||||
extern SDL_Window *Shell_GetWindow(void);
|
||||
|
||||
extern bool Shell_ParseArgs(int32_t arg_count, const char **args);
|
||||
void Shell_Setup(void);
|
||||
extern void Shell_Main(void);
|
||||
extern int32_t Shell_Main(void);
|
||||
void Shell_Terminate(int32_t exit_code);
|
||||
void Shell_ExitSystem(const char *message);
|
||||
void Shell_ExitSystemFmt(const char *fmt, ...);
|
||||
|
||||
void Shell_GetCommandLine(int *arg_count, const char ***args);
|
||||
void Shell_ScheduleExit(void);
|
||||
bool Shell_IsExiting(void);
|
||||
|
||||
|
|
|
@ -14,6 +14,11 @@ int16_t *Sound_GetSampleLUT(void);
|
|||
SAMPLE_INFO *Sound_GetSampleInfo(SOUND_EFFECT_ID sfx_num);
|
||||
SAMPLE_INFO *Sound_GetSampleInfoByIdx(int32_t info_idx);
|
||||
|
||||
extern int32_t Sound_GetMinVolume(void);
|
||||
extern int32_t Sound_GetMaxVolume(void);
|
||||
extern int32_t Sound_GetMasterVolume(void);
|
||||
extern void Sound_SetMasterVolume(int32_t volume);
|
||||
|
||||
void Sound_ResetSources(void);
|
||||
void Sound_PauseAll(void);
|
||||
void Sound_UnpauseAll(void);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "./ui/dialogs/play_any_level.h"
|
||||
#include "./ui/dialogs/save_slot.h"
|
||||
#include "./ui/dialogs/select_level.h"
|
||||
#include "./ui/dialogs/sound_settings.h"
|
||||
#include "./ui/dialogs/stats.h"
|
||||
#include "./ui/elements/anchor.h"
|
||||
#include "./ui/elements/fade.h"
|
||||
|
|
|
@ -50,10 +50,10 @@ typedef struct UI_NODE {
|
|||
|
||||
// Dimensions in virtual pixels of the screen area
|
||||
// (640x480 for any 4:3 resolution on 1.00 text scaling)
|
||||
extern int32_t UI_GetCanvasWidth(void);
|
||||
extern int32_t UI_GetCanvasHeight(void);
|
||||
extern float UI_ScaleX(float x);
|
||||
extern float UI_ScaleY(float y);
|
||||
int32_t UI_GetCanvasWidth(void);
|
||||
int32_t UI_GetCanvasHeight(void);
|
||||
float UI_ScaleX(float x);
|
||||
float UI_ScaleY(float y);
|
||||
|
||||
// Public API for scene management
|
||||
void UI_BeginScene(void);
|
||||
|
|
21
src/libtrx/include/libtrx/game/ui/dialogs/sound_settings.h
Normal file
21
src/libtrx/include/libtrx/game/ui/dialogs/sound_settings.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
// UI dialog for adjusting music and sound volumes
|
||||
#pragma once
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
typedef struct UI_SOUND_SETTINGS_STATE UI_SOUND_SETTINGS_STATE;
|
||||
|
||||
// state functions
|
||||
// Initialize the sound settings dialog state
|
||||
UI_SOUND_SETTINGS_STATE *UI_SoundSettings_Init(void);
|
||||
|
||||
// Free resources used by the sound settings dialog
|
||||
void UI_SoundSettings_Free(UI_SOUND_SETTINGS_STATE *s);
|
||||
|
||||
// Handle input/control for the sound settings dialog
|
||||
// Returns true if the dialog should be closed
|
||||
bool UI_SoundSettings_Control(UI_SOUND_SETTINGS_STATE *s);
|
||||
|
||||
// draw functions
|
||||
// Render the sound settings dialog
|
||||
void UI_SoundSettings(UI_SOUND_SETTINGS_STATE *s);
|
|
@ -217,6 +217,7 @@ sources = [
|
|||
'game/ui/dialogs/play_any_level.c',
|
||||
'game/ui/dialogs/save_slot.c',
|
||||
'game/ui/dialogs/select_level.c',
|
||||
'game/ui/dialogs/sound_settings.c',
|
||||
'game/ui/dialogs/stats.c',
|
||||
'game/ui/elements/anchor.c',
|
||||
'game/ui/elements/fade.c',
|
||||
|
|
|
@ -196,70 +196,6 @@ bool Item_Test3DRange(int32_t x, int32_t y, int32_t z, int32_t range)
|
|||
&& (SQUARE(x) + SQUARE(y) + SQUARE(z) < SQUARE(range));
|
||||
}
|
||||
|
||||
bool Item_TestPosition(
|
||||
const ITEM *const src_item, const ITEM *const dst_item,
|
||||
const OBJECT_BOUNDS *const bounds)
|
||||
{
|
||||
const XYZ_16 rot = {
|
||||
.x = src_item->rot.x - dst_item->rot.x,
|
||||
.y = src_item->rot.y - dst_item->rot.y,
|
||||
.z = src_item->rot.z - dst_item->rot.z,
|
||||
};
|
||||
if (rot.x < bounds->rot.min.x || rot.x > bounds->rot.max.x
|
||||
|| rot.y < bounds->rot.min.y || rot.y > bounds->rot.max.y
|
||||
|| rot.z < bounds->rot.min.z || rot.z > bounds->rot.max.z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const XYZ_32 dist = {
|
||||
.x = src_item->pos.x - dst_item->pos.x,
|
||||
.y = src_item->pos.y - dst_item->pos.y,
|
||||
.z = src_item->pos.z - dst_item->pos.z,
|
||||
};
|
||||
|
||||
Matrix_PushUnit();
|
||||
Matrix_Rot16(dst_item->rot);
|
||||
MATRIX *mptr = g_MatrixPtr;
|
||||
const XYZ_32 shift = {
|
||||
.x = (mptr->_00 * dist.x + mptr->_10 * dist.y + mptr->_20 * dist.z)
|
||||
>> W2V_SHIFT,
|
||||
.y = (mptr->_01 * dist.x + mptr->_11 * dist.y + mptr->_21 * dist.z)
|
||||
>> W2V_SHIFT,
|
||||
.z = (mptr->_02 * dist.x + mptr->_12 * dist.y + mptr->_22 * dist.z)
|
||||
>> W2V_SHIFT,
|
||||
};
|
||||
Matrix_Pop();
|
||||
|
||||
if (shift.x < bounds->shift.min.x || shift.x > bounds->shift.max.x
|
||||
|| shift.y < bounds->shift.min.y || shift.y > bounds->shift.max.y
|
||||
|| shift.z < bounds->shift.min.z || shift.z > bounds->shift.max.z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Item_AlignPosition(ITEM *src_item, ITEM *dst_item, XYZ_32 *vec)
|
||||
{
|
||||
src_item->rot.x = dst_item->rot.x;
|
||||
src_item->rot.y = dst_item->rot.y;
|
||||
src_item->rot.z = dst_item->rot.z;
|
||||
|
||||
Matrix_PushUnit();
|
||||
Matrix_Rot16(dst_item->rot);
|
||||
MATRIX *mptr = g_MatrixPtr;
|
||||
src_item->pos.x = dst_item->pos.x
|
||||
+ ((mptr->_00 * vec->x + mptr->_01 * vec->y + mptr->_02 * vec->z)
|
||||
>> W2V_SHIFT);
|
||||
src_item->pos.y = dst_item->pos.y
|
||||
+ ((mptr->_10 * vec->x + mptr->_11 * vec->y + mptr->_12 * vec->z)
|
||||
>> W2V_SHIFT);
|
||||
src_item->pos.z = dst_item->pos.z
|
||||
+ ((mptr->_20 * vec->x + mptr->_21 * vec->y + mptr->_22 * vec->z)
|
||||
>> W2V_SHIFT);
|
||||
Matrix_Pop();
|
||||
}
|
||||
|
||||
bool Item_MovePosition(
|
||||
ITEM *item, const ITEM *ref_item, const XYZ_32 *vec, int32_t velocity)
|
||||
{
|
||||
|
|
|
@ -11,9 +11,6 @@ int16_t Item_Spawn(const ITEM *item, GAME_OBJECT_ID obj_id);
|
|||
|
||||
bool Item_IsNearItem(const ITEM *item, const XYZ_32 *pos, int32_t distance);
|
||||
bool Item_Test3DRange(int32_t x, int32_t y, int32_t z, int32_t range);
|
||||
bool Item_TestPosition(
|
||||
const ITEM *src_item, const ITEM *dst_item, const OBJECT_BOUNDS *bounds);
|
||||
void Item_AlignPosition(ITEM *src_item, ITEM *dst_item, XYZ_32 *vec);
|
||||
bool Item_MovePosition(
|
||||
ITEM *src_item, const ITEM *dst_item, const XYZ_32 *vec, int32_t velocity);
|
||||
void Item_ShiftCol(ITEM *item, COLL_INFO *coll);
|
||||
|
|
|
@ -701,16 +701,6 @@ bool Lara_IsNearItem(const XYZ_32 *pos, int32_t distance)
|
|||
return Item_IsNearItem(g_LaraItem, pos, distance);
|
||||
}
|
||||
|
||||
bool Lara_TestPosition(const ITEM *item, const OBJECT_BOUNDS *const bounds)
|
||||
{
|
||||
return Item_TestPosition(g_LaraItem, item, bounds);
|
||||
}
|
||||
|
||||
void Lara_AlignPosition(ITEM *item, XYZ_32 *vec)
|
||||
{
|
||||
Item_AlignPosition(g_LaraItem, item, vec);
|
||||
}
|
||||
|
||||
bool Lara_MovePosition(ITEM *item, XYZ_32 *vec)
|
||||
{
|
||||
int32_t velocity = g_Config.gameplay.enable_walk_to_items
|
||||
|
|
|
@ -26,8 +26,6 @@ void Lara_SwapMeshExtra(void);
|
|||
bool Lara_IsNearItem(const XYZ_32 *pos, int32_t distance);
|
||||
void Lara_UseItem(GAME_OBJECT_ID obj_id);
|
||||
|
||||
bool Lara_TestPosition(const ITEM *item, const OBJECT_BOUNDS *bounds);
|
||||
void Lara_AlignPosition(ITEM *item, XYZ_32 *vec);
|
||||
bool Lara_MovePosition(ITEM *item, XYZ_32 *vec);
|
||||
|
||||
void Lara_RevertToPistolsIfNeeded(void);
|
||||
|
|
|
@ -182,12 +182,12 @@ void Music_Unmute(void)
|
|||
M_SyncVolume(m_AudioStreamID);
|
||||
}
|
||||
|
||||
int16_t Music_GetVolume(void)
|
||||
int32_t Music_GetVolume(void)
|
||||
{
|
||||
return m_Volume;
|
||||
}
|
||||
|
||||
void Music_SetVolume(int16_t volume)
|
||||
void Music_SetVolume(int32_t volume)
|
||||
{
|
||||
if (volume != m_Volume) {
|
||||
m_Volume = volume;
|
||||
|
@ -195,16 +195,6 @@ void Music_SetVolume(int16_t volume)
|
|||
}
|
||||
}
|
||||
|
||||
int16_t Music_GetMinVolume(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t Music_GetMaxVolume(void)
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
void Music_Pause(void)
|
||||
{
|
||||
if (m_AudioStreamID < 0) {
|
||||
|
|
|
@ -19,18 +19,6 @@ void Music_Mute(void);
|
|||
// Unmutes the game music. Doesn't change the music volume.
|
||||
void Music_Unmute(void);
|
||||
|
||||
// Gets the game volume.
|
||||
int16_t Music_GetVolume(void);
|
||||
|
||||
// Sets the game volume. Value can be 0-10.
|
||||
void Music_SetVolume(int16_t volume);
|
||||
|
||||
// Gets the minimum possible game volume.
|
||||
int16_t Music_GetMinVolume(void);
|
||||
|
||||
// Gets the maximum possible game volume.
|
||||
int16_t Music_GetMaxVolume(void);
|
||||
|
||||
// Returns the currently playing track. Includes looped music.
|
||||
MUSIC_TRACK_ID Music_GetCurrentPlayingTrack(void);
|
||||
|
||||
|
|
|
@ -168,6 +168,9 @@ void Option_Draw(INVENTORY_ITEM *const inv_item)
|
|||
case O_COMPASS_OPTION:
|
||||
Option_Compass_Draw();
|
||||
break;
|
||||
case O_SOUND_OPTION:
|
||||
Option_Sound_Draw(inv_item);
|
||||
break;
|
||||
|
||||
case O_PICKUP_OPTION_1:
|
||||
case O_PICKUP_OPTION_2:
|
||||
|
|
|
@ -1,170 +1,48 @@
|
|||
#include "game/option/option_sound.h"
|
||||
|
||||
#include "game/game_string.h"
|
||||
#include "game/input.h"
|
||||
#include "game/music.h"
|
||||
#include "game/sound.h"
|
||||
#include "game/text.h"
|
||||
#include "global/vars.h"
|
||||
|
||||
#include <libtrx/config.h>
|
||||
#include <libtrx/game/ui.h>
|
||||
|
||||
#include <stdio.h>
|
||||
typedef struct {
|
||||
UI_SOUND_SETTINGS_STATE *ui;
|
||||
} M_PRIV;
|
||||
|
||||
typedef enum {
|
||||
TEXT_MUSIC_VOLUME = 0,
|
||||
TEXT_SOUND_VOLUME = 1,
|
||||
TEXT_TITLE = 2,
|
||||
TEXT_TITLE_BORDER = 3,
|
||||
TEXT_LEFT_ARROW = 4,
|
||||
TEXT_RIGHT_ARROW = 5,
|
||||
TEXT_NUMBER_OF = 6,
|
||||
TEXT_OPTION_MIN = TEXT_MUSIC_VOLUME,
|
||||
TEXT_OPTION_MAX = TEXT_SOUND_VOLUME,
|
||||
} SOUND_TEXT;
|
||||
static M_PRIV m_Priv = {};
|
||||
|
||||
static TEXTSTRING *m_Text[TEXT_NUMBER_OF] = {};
|
||||
|
||||
static void M_InitText(void);
|
||||
|
||||
static void M_InitText(void)
|
||||
static void M_Init(M_PRIV *const p)
|
||||
{
|
||||
char buf[20];
|
||||
p->ui = UI_SoundSettings_Init();
|
||||
}
|
||||
|
||||
m_Text[TEXT_LEFT_ARROW] = Text_Create(-45, 0, "\\{button left}");
|
||||
m_Text[TEXT_RIGHT_ARROW] = Text_Create(40, 0, "\\{button right}");
|
||||
|
||||
m_Text[TEXT_TITLE_BORDER] = Text_Create(0, -32, " ");
|
||||
m_Text[TEXT_TITLE] = Text_Create(0, -30, GS(SOUND_SET_VOLUMES));
|
||||
|
||||
if (g_Config.audio.music_volume > 10) {
|
||||
g_Config.audio.music_volume = 10;
|
||||
}
|
||||
sprintf(buf, "\\{icon music} %2d", g_Config.audio.music_volume);
|
||||
m_Text[TEXT_MUSIC_VOLUME] = Text_Create(0, 0, buf);
|
||||
|
||||
if (g_Config.audio.sound_volume > 10) {
|
||||
g_Config.audio.sound_volume = 10;
|
||||
}
|
||||
sprintf(buf, "\\{icon sound} %2d", g_Config.audio.sound_volume);
|
||||
m_Text[TEXT_SOUND_VOLUME] = Text_Create(0, 25, buf);
|
||||
|
||||
Text_AddBackground(m_Text[g_OptionSelected], 128, 0, 0, 0, TS_REQUESTED);
|
||||
Text_AddOutline(m_Text[g_OptionSelected], TS_REQUESTED);
|
||||
Text_AddBackground(m_Text[TEXT_TITLE], 136, 0, 0, 0, TS_HEADING);
|
||||
Text_AddOutline(m_Text[TEXT_TITLE], TS_HEADING);
|
||||
Text_AddBackground(m_Text[TEXT_TITLE_BORDER], 140, 85, 0, 0, TS_BACKGROUND);
|
||||
Text_AddOutline(m_Text[TEXT_TITLE_BORDER], TS_BACKGROUND);
|
||||
|
||||
for (int i = 0; i < TEXT_NUMBER_OF; i++) {
|
||||
Text_CentreH(m_Text[i], 1);
|
||||
Text_CentreV(m_Text[i], 1);
|
||||
static void M_Shutdown(M_PRIV *const p)
|
||||
{
|
||||
if (p->ui != nullptr) {
|
||||
UI_SoundSettings_Free(p->ui);
|
||||
p->ui = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Option_Sound_Control(INVENTORY_ITEM *inv_item, const bool is_busy)
|
||||
void Option_Sound_Control(INVENTORY_ITEM *const inv_item, const bool is_busy)
|
||||
{
|
||||
M_PRIV *const p = &m_Priv;
|
||||
if (is_busy) {
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[20];
|
||||
|
||||
if (!m_Text[TEXT_MUSIC_VOLUME]) {
|
||||
M_InitText();
|
||||
if (p->ui == nullptr) {
|
||||
M_Init(p);
|
||||
}
|
||||
UI_SoundSettings_Control(p->ui);
|
||||
}
|
||||
|
||||
if (g_InputDB.menu_up && g_OptionSelected > TEXT_OPTION_MIN) {
|
||||
Text_RemoveOutline(m_Text[g_OptionSelected]);
|
||||
Text_RemoveBackground(m_Text[g_OptionSelected]);
|
||||
--g_OptionSelected;
|
||||
Text_AddBackground(
|
||||
m_Text[g_OptionSelected], 128, 0, 0, 0, TS_REQUESTED);
|
||||
Text_AddOutline(m_Text[g_OptionSelected], TS_REQUESTED);
|
||||
Text_SetPos(m_Text[TEXT_LEFT_ARROW], -45, 0);
|
||||
Text_SetPos(m_Text[TEXT_RIGHT_ARROW], 40, 0);
|
||||
}
|
||||
|
||||
if (g_InputDB.menu_down && g_OptionSelected < TEXT_OPTION_MAX) {
|
||||
Text_RemoveOutline(m_Text[g_OptionSelected]);
|
||||
Text_RemoveBackground(m_Text[g_OptionSelected]);
|
||||
++g_OptionSelected;
|
||||
Text_AddBackground(
|
||||
m_Text[g_OptionSelected], 128, 0, 0, 0, TS_REQUESTED);
|
||||
Text_AddOutline(m_Text[g_OptionSelected], TS_REQUESTED);
|
||||
Text_SetPos(m_Text[TEXT_LEFT_ARROW], -45, 25);
|
||||
Text_SetPos(m_Text[TEXT_RIGHT_ARROW], 40, 25);
|
||||
}
|
||||
|
||||
switch (g_OptionSelected) {
|
||||
case TEXT_MUSIC_VOLUME:
|
||||
if (g_InputDB.menu_left
|
||||
&& g_Config.audio.music_volume > Music_GetMinVolume()) {
|
||||
g_Config.audio.music_volume--;
|
||||
Config_Write();
|
||||
Music_SetVolume(g_Config.audio.music_volume);
|
||||
Sound_Effect(SFX_MENU_PASSPORT, nullptr, SPM_ALWAYS);
|
||||
sprintf(buf, "\\{icon music} %2d", g_Config.audio.music_volume);
|
||||
Text_ChangeText(m_Text[TEXT_MUSIC_VOLUME], buf);
|
||||
} else if (
|
||||
g_InputDB.menu_right
|
||||
&& g_Config.audio.music_volume < Music_GetMaxVolume()) {
|
||||
g_Config.audio.music_volume++;
|
||||
Config_Write();
|
||||
Music_SetVolume(g_Config.audio.music_volume);
|
||||
Sound_Effect(SFX_MENU_PASSPORT, nullptr, SPM_ALWAYS);
|
||||
sprintf(buf, "\\{icon music} %2d", g_Config.audio.music_volume);
|
||||
Text_ChangeText(m_Text[TEXT_MUSIC_VOLUME], buf);
|
||||
}
|
||||
|
||||
Text_Hide(
|
||||
m_Text[TEXT_LEFT_ARROW],
|
||||
g_Config.audio.music_volume == Music_GetMinVolume());
|
||||
Text_Hide(
|
||||
m_Text[TEXT_RIGHT_ARROW],
|
||||
g_Config.audio.music_volume == Music_GetMaxVolume());
|
||||
|
||||
break;
|
||||
|
||||
case TEXT_SOUND_VOLUME:
|
||||
if (g_InputDB.menu_left
|
||||
&& g_Config.audio.sound_volume > Sound_GetMinVolume()) {
|
||||
g_Config.audio.sound_volume--;
|
||||
Config_Write();
|
||||
Sound_SetMasterVolume(g_Config.audio.sound_volume);
|
||||
Sound_Effect(SFX_MENU_PASSPORT, nullptr, SPM_ALWAYS);
|
||||
sprintf(buf, "\\{icon sound} %2d", g_Config.audio.sound_volume);
|
||||
Text_ChangeText(m_Text[TEXT_SOUND_VOLUME], buf);
|
||||
} else if (
|
||||
g_InputDB.menu_right
|
||||
&& g_Config.audio.sound_volume < Sound_GetMaxVolume()) {
|
||||
g_Config.audio.sound_volume++;
|
||||
Config_Write();
|
||||
Sound_SetMasterVolume(g_Config.audio.sound_volume);
|
||||
Sound_Effect(SFX_MENU_PASSPORT, nullptr, SPM_ALWAYS);
|
||||
sprintf(buf, "\\{icon sound} %2d", g_Config.audio.sound_volume);
|
||||
Text_ChangeText(m_Text[TEXT_SOUND_VOLUME], buf);
|
||||
}
|
||||
|
||||
Text_Hide(
|
||||
m_Text[TEXT_LEFT_ARROW],
|
||||
g_Config.audio.sound_volume == Sound_GetMinVolume());
|
||||
Text_Hide(
|
||||
m_Text[TEXT_RIGHT_ARROW],
|
||||
g_Config.audio.sound_volume == Sound_GetMaxVolume());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_InputDB.menu_confirm || g_InputDB.menu_back) {
|
||||
Option_Sound_Shutdown();
|
||||
void Option_Sound_Draw(INVENTORY_ITEM *const inv_item)
|
||||
{
|
||||
M_PRIV *const p = &m_Priv;
|
||||
if (p->ui != nullptr) {
|
||||
UI_SoundSettings(p->ui);
|
||||
}
|
||||
}
|
||||
|
||||
void Option_Sound_Shutdown(void)
|
||||
{
|
||||
for (int i = 0; i < TEXT_NUMBER_OF; i++) {
|
||||
Text_Remove(m_Text[i]);
|
||||
m_Text[i] = nullptr;
|
||||
}
|
||||
M_Shutdown(&m_Priv);
|
||||
}
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
#include <libtrx/game/inventory_ring/types.h>
|
||||
|
||||
void Option_Sound_Control(INVENTORY_ITEM *inv_item, bool is_busy);
|
||||
void Option_Sound_Draw(INVENTORY_ITEM *inv_item);
|
||||
void Option_Sound_Shutdown(void);
|
||||
|
|
|
@ -49,6 +49,7 @@ typedef struct {
|
|||
int32_t thickness;
|
||||
} LIGHTNING;
|
||||
|
||||
static bool m_Initialized = false;
|
||||
static int32_t m_LightningCount = 0;
|
||||
static LIGHTNING m_LightningTable[MAX_LIGHTNINGS];
|
||||
static int32_t m_TextureMap[GFX_MAX_TEXTURES] = { GFX_NO_TEXTURE };
|
||||
|
@ -385,6 +386,11 @@ static void M_DrawSprite(
|
|||
|
||||
bool Output_Init(void)
|
||||
{
|
||||
if (m_Initialized) {
|
||||
return true;
|
||||
}
|
||||
m_Initialized = true;
|
||||
|
||||
for (int32_t i = 0; i < GFX_MAX_TEXTURES; i++) {
|
||||
m_TextureMap[i] = GFX_NO_TEXTURE;
|
||||
m_TextureSurfaces[i] = nullptr;
|
||||
|
@ -406,6 +412,11 @@ bool Output_Init(void)
|
|||
|
||||
void Output_Shutdown(void)
|
||||
{
|
||||
if (!m_Initialized) {
|
||||
return;
|
||||
}
|
||||
m_Initialized = false;
|
||||
|
||||
Output_Meshes_Shutdown();
|
||||
Output_Sprites_Shutdown();
|
||||
Output_Textures_Shutdown();
|
||||
|
|
|
@ -81,37 +81,18 @@ static SHELL_ARGS m_Args = {
|
|||
|
||||
static const char *m_CurrentGameFlowPath;
|
||||
|
||||
static void M_ParseArgs(SHELL_ARGS *out_args);
|
||||
static void M_ShowHelp(void);
|
||||
static void M_LoadConfig(void);
|
||||
static void M_HandleConfigChange(const EVENT *event, void *data);
|
||||
|
||||
static void M_ParseArgs(SHELL_ARGS *const out_args)
|
||||
static void M_ShowHelp(void)
|
||||
{
|
||||
const char **args = nullptr;
|
||||
int32_t arg_count = 0;
|
||||
Shell_GetCommandLine(&arg_count, &args);
|
||||
|
||||
out_args->mod = M_MOD_OG;
|
||||
|
||||
for (int32_t i = 0; i < arg_count; i++) {
|
||||
if (!strcmp(args[i], "-gold")) {
|
||||
out_args->mod = M_MOD_UB;
|
||||
}
|
||||
if (!strcmp(args[i], "-demo_pc")) {
|
||||
out_args->mod = M_MOD_DEMO_PC;
|
||||
}
|
||||
if ((!strcmp(args[i], "-l") || !strcmp(args[i], "--level"))
|
||||
&& i + 1 < arg_count) {
|
||||
out_args->level_to_play = args[i + 1];
|
||||
out_args->mod = M_MOD_CUSTOM_LEVEL;
|
||||
}
|
||||
if ((!strcmp(args[i], "-s") || !strcmp(args[i], "--save"))
|
||||
&& i + 1 < arg_count) {
|
||||
if (String_ParseInteger(args[i + 1], &out_args->save_to_load)) {
|
||||
out_args->save_to_load--;
|
||||
}
|
||||
}
|
||||
}
|
||||
puts("Currently available options:");
|
||||
puts("");
|
||||
puts("-g/--gold: launch The Unfinished Business expansion pack.");
|
||||
puts(" --demo-pc: launch the PC demo level file.");
|
||||
puts("-l/--level <PATH>: launch a specific level file.");
|
||||
puts("-s/--save <NUM>: launch from a specific save slot (starts at 1).");
|
||||
}
|
||||
|
||||
static void M_HandleConfigChange(const EVENT *const event, void *const data)
|
||||
|
@ -176,10 +157,40 @@ const char *Shell_GetGameFlowPath(void)
|
|||
return m_ModPaths[m_Args.mod].game_flow_path;
|
||||
}
|
||||
|
||||
void Shell_Main(void)
|
||||
bool Shell_ParseArgs(const int32_t arg_count, const char **args)
|
||||
{
|
||||
M_ParseArgs(&m_Args);
|
||||
SHELL_ARGS *const out_args = &m_Args;
|
||||
out_args->mod = M_MOD_OG;
|
||||
|
||||
for (int32_t i = 0; i < arg_count; i++) {
|
||||
if (!strcmp(args[i], "-h") || !strcmp(args[i], "--help")) {
|
||||
M_ShowHelp();
|
||||
return false;
|
||||
}
|
||||
if (!strcmp(args[i], "-g") || !strcmp(args[i], "--gold")
|
||||
|| !strcmp(args[i], "-gold")) {
|
||||
out_args->mod = M_MOD_UB;
|
||||
}
|
||||
if (!strcmp(args[i], "--demo-pc") || !strcmp(args[i], "-demo_pc")) {
|
||||
out_args->mod = M_MOD_DEMO_PC;
|
||||
}
|
||||
if ((!strcmp(args[i], "-l") || !strcmp(args[i], "--level"))
|
||||
&& i + 1 < arg_count) {
|
||||
out_args->level_to_play = args[i + 1];
|
||||
out_args->mod = M_MOD_CUSTOM_LEVEL;
|
||||
}
|
||||
if ((!strcmp(args[i], "-s") || !strcmp(args[i], "--save"))
|
||||
&& i + 1 < arg_count) {
|
||||
if (String_ParseInteger(args[i + 1], &out_args->save_to_load)) {
|
||||
out_args->save_to_load--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t Shell_Main(void)
|
||||
{
|
||||
GameString_Init();
|
||||
EnumMap_Init();
|
||||
Config_Init();
|
||||
|
@ -202,7 +213,7 @@ void Shell_Main(void)
|
|||
|
||||
if (!Output_Init()) {
|
||||
Shell_ExitSystem("Could not initialise video system");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
Screen_Init();
|
||||
|
||||
|
@ -318,6 +329,7 @@ void Shell_Main(void)
|
|||
if (m_Args.level_to_play != nullptr) {
|
||||
Memory_FreePointer(&g_GameFlow.level_tables[GFLT_MAIN].levels[0].path);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Shell_ProcessInput(void)
|
||||
|
|
|
@ -528,18 +528,6 @@ void Sound_StopAll(void)
|
|||
Audio_Sample_CloseAll();
|
||||
}
|
||||
|
||||
void Sound_SetMasterVolume(int8_t volume)
|
||||
{
|
||||
int8_t raw_volume = volume ? 6 * volume + 3 : 0;
|
||||
m_MasterVolumeDefault = raw_volume & 0x3F;
|
||||
m_MasterVolume = raw_volume & 0x3F;
|
||||
}
|
||||
|
||||
int8_t Sound_GetMasterVolume(void)
|
||||
{
|
||||
return (m_MasterVolume - 3) / 6;
|
||||
}
|
||||
|
||||
int32_t Sound_GetMinVolume(void)
|
||||
{
|
||||
return 0;
|
||||
|
@ -550,6 +538,18 @@ int32_t Sound_GetMaxVolume(void)
|
|||
return 10;
|
||||
}
|
||||
|
||||
void Sound_SetMasterVolume(int32_t volume)
|
||||
{
|
||||
int8_t raw_volume = volume ? 6 * volume + 3 : 0;
|
||||
m_MasterVolumeDefault = raw_volume & 0x3F;
|
||||
m_MasterVolume = raw_volume & 0x3F;
|
||||
}
|
||||
|
||||
int32_t Sound_GetMasterVolume(void)
|
||||
{
|
||||
return (m_MasterVolume - 3) / 6;
|
||||
}
|
||||
|
||||
void Sound_ResetAmbient(void)
|
||||
{
|
||||
M_ResetAmbientLoudness();
|
||||
|
|
|
@ -13,10 +13,6 @@ bool Sound_StopEffect(SOUND_EFFECT_ID sfx_num, const XYZ_32 *pos);
|
|||
void Sound_UpdateEffects(void);
|
||||
void Sound_ResetEffects(void);
|
||||
void Sound_StopAmbientSounds(void);
|
||||
int8_t Sound_GetMasterVolume(void);
|
||||
void Sound_SetMasterVolume(int8_t volume);
|
||||
int32_t Sound_GetMinVolume(void);
|
||||
int32_t Sound_GetMaxVolume(void);
|
||||
void Sound_LoadSamples(
|
||||
size_t num_samples, const char **sample_pointers, size_t *sizes);
|
||||
int32_t Sound_GetMaxSamples(void);
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
#include "game/screen.h"
|
||||
|
||||
#include <libtrx/config.h>
|
||||
#include <libtrx/game/ui/common.h>
|
||||
|
||||
int32_t UI_GetCanvasWidth(void)
|
||||
{
|
||||
return Screen_GetResHeightDownscaled(RSR_GENERIC) * 16 / 9;
|
||||
}
|
||||
|
||||
int32_t UI_GetCanvasHeight(void)
|
||||
{
|
||||
return Screen_GetResHeightDownscaled(RSR_GENERIC);
|
||||
}
|
||||
|
||||
float UI_ScaleX(const float x)
|
||||
{
|
||||
return Screen_GetRenderScale(x * 0x10000, RSR_GENERIC) / (float)0x10000;
|
||||
}
|
||||
|
||||
float UI_ScaleY(const float y)
|
||||
{
|
||||
return Screen_GetRenderScale(y * 0x10000, RSR_GENERIC) / (float)0x10000;
|
||||
}
|
|
@ -260,7 +260,6 @@ sources = [
|
|||
'game/spawn.c',
|
||||
'game/stats/common.c',
|
||||
'game/text.c',
|
||||
'game/ui/common.c',
|
||||
'game/ui/dialogs/stats.c',
|
||||
'game/viewport.c',
|
||||
'global/enum_map.c',
|
||||
|
|
|
@ -20,40 +20,6 @@
|
|||
static BOUNDS_16 m_NullBounds = {};
|
||||
static BOUNDS_16 m_InterpolatedBounds = {};
|
||||
|
||||
static OBJECT_BOUNDS M_ConvertBounds(const int16_t *bounds_in);
|
||||
|
||||
static OBJECT_BOUNDS M_ConvertBounds(const int16_t *const bounds_in)
|
||||
{
|
||||
// TODO: remove this conversion utility once we gain control over its
|
||||
// incoming arguments
|
||||
return (OBJECT_BOUNDS) {
|
||||
.shift = {
|
||||
.min = {
|
||||
.x = bounds_in[0],
|
||||
.y = bounds_in[2],
|
||||
.z = bounds_in[4],
|
||||
},
|
||||
.max = {
|
||||
.x = bounds_in[1],
|
||||
.y = bounds_in[3],
|
||||
.z = bounds_in[5],
|
||||
},
|
||||
},
|
||||
.rot = {
|
||||
.min = {
|
||||
.x = bounds_in[6],
|
||||
.y = bounds_in[8],
|
||||
.z = bounds_in[10],
|
||||
},
|
||||
.max = {
|
||||
.x = bounds_in[7],
|
||||
.y = bounds_in[9],
|
||||
.z = bounds_in[11],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
void Item_Control(void)
|
||||
{
|
||||
int16_t item_num = Item_GetNextActive();
|
||||
|
@ -188,95 +154,6 @@ int16_t Item_GetHeight(const ITEM *const item)
|
|||
return height;
|
||||
}
|
||||
|
||||
int32_t Item_TestPosition(
|
||||
const int16_t *const bounds_in, const ITEM *const src_item,
|
||||
const ITEM *const dst_item)
|
||||
{
|
||||
const OBJECT_BOUNDS bounds = M_ConvertBounds(bounds_in);
|
||||
|
||||
const XYZ_16 rot = {
|
||||
.x = dst_item->rot.x - src_item->rot.x,
|
||||
.y = dst_item->rot.y - src_item->rot.y,
|
||||
.z = dst_item->rot.z - src_item->rot.z,
|
||||
};
|
||||
const XYZ_32 dist = {
|
||||
.x = dst_item->pos.x - src_item->pos.x,
|
||||
.y = dst_item->pos.y - src_item->pos.y,
|
||||
.z = dst_item->pos.z - src_item->pos.z,
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
if (rot.x < bounds.rot.min.x ||
|
||||
rot.x > bounds.rot.max.x ||
|
||||
rot.y < bounds.rot.min.y ||
|
||||
rot.y > bounds.rot.max.y ||
|
||||
rot.z < bounds.rot.min.z ||
|
||||
rot.z > bounds.rot.max.z
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
Matrix_PushUnit();
|
||||
Matrix_Rot16(src_item->rot);
|
||||
const MATRIX *const m = g_MatrixPtr;
|
||||
const XYZ_32 shift = {
|
||||
.x = (dist.x * m->_00 + dist.y * m->_10 + dist.z * m->_20) >> W2V_SHIFT,
|
||||
.y = (dist.x * m->_01 + dist.y * m->_11 + dist.z * m->_21) >> W2V_SHIFT,
|
||||
.z = (dist.x * m->_02 + dist.y * m->_12 + dist.z * m->_22) >> W2V_SHIFT,
|
||||
};
|
||||
Matrix_Pop();
|
||||
|
||||
// clang-format off
|
||||
return (
|
||||
shift.x >= bounds.shift.min.x &&
|
||||
shift.x <= bounds.shift.max.x &&
|
||||
shift.y >= bounds.shift.min.y &&
|
||||
shift.y <= bounds.shift.max.y &&
|
||||
shift.z >= bounds.shift.min.z &&
|
||||
shift.z <= bounds.shift.max.z
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void Item_AlignPosition(
|
||||
const XYZ_32 *const vec, const ITEM *const src_item, ITEM *const dst_item)
|
||||
{
|
||||
dst_item->rot = src_item->rot;
|
||||
Matrix_PushUnit();
|
||||
Matrix_Rot16(src_item->rot);
|
||||
const MATRIX *const m = g_MatrixPtr;
|
||||
const XYZ_32 shift = {
|
||||
.x = (vec->x * m->_00 + vec->y * m->_01 + vec->z * m->_02) >> W2V_SHIFT,
|
||||
.y = (vec->x * m->_10 + vec->y * m->_11 + vec->z * m->_12) >> W2V_SHIFT,
|
||||
.z = (vec->x * m->_20 + vec->y * m->_21 + vec->z * m->_22) >> W2V_SHIFT,
|
||||
};
|
||||
Matrix_Pop();
|
||||
|
||||
const XYZ_32 new_pos = {
|
||||
.x = src_item->pos.x + shift.x,
|
||||
.y = src_item->pos.y + shift.y,
|
||||
.z = src_item->pos.z + shift.z,
|
||||
};
|
||||
|
||||
int16_t room_num = dst_item->room_num;
|
||||
const SECTOR *const sector =
|
||||
Room_GetSector(new_pos.x, new_pos.y, new_pos.z, &room_num);
|
||||
const int32_t height =
|
||||
Room_GetHeight(sector, new_pos.x, new_pos.y, new_pos.z);
|
||||
const int32_t ceiling =
|
||||
Room_GetCeiling(sector, new_pos.x, new_pos.y, new_pos.z);
|
||||
|
||||
if (ABS(height - dst_item->pos.y) > STEP_L
|
||||
|| ABS(ceiling - dst_item->pos.y) < LARA_HEIGHT) {
|
||||
return;
|
||||
}
|
||||
|
||||
dst_item->pos.x = new_pos.x;
|
||||
dst_item->pos.y = new_pos.y;
|
||||
dst_item->pos.z = new_pos.z;
|
||||
}
|
||||
|
||||
int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frames[], int32_t *rate)
|
||||
{
|
||||
const ANIM *const anim = Item_GetAnim(item);
|
||||
|
|
|
@ -8,10 +8,6 @@ void Item_Control(void);
|
|||
void Item_ClearKilled(void);
|
||||
void Item_ShiftCol(ITEM *item, COLL_INFO *coll);
|
||||
void Item_UpdateRoom(ITEM *item, int32_t height);
|
||||
int32_t Item_TestPosition(
|
||||
const int16_t *bounds, const ITEM *src_item, const ITEM *dst_item);
|
||||
void Item_AlignPosition(
|
||||
const XYZ_32 *vec, const ITEM *src_item, ITEM *dst_item);
|
||||
int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frmptr[], int32_t *rate);
|
||||
bool Item_IsNearItem(const ITEM *item, const XYZ_32 *pos, int32_t distance);
|
||||
|
||||
|
|
|
@ -10,33 +10,37 @@
|
|||
#include "game/sound.h"
|
||||
#include "global/vars.h"
|
||||
|
||||
#include <libtrx/game/lara.h>
|
||||
|
||||
#define EXPLOSION_START_FRAME 76
|
||||
#define EXPLOSION_END_FRAME 99
|
||||
#define EXPLOSION_ACTION_FRAME 80
|
||||
|
||||
static XYZ_32 m_DetonatorPosition = { .x = 0, .y = 0, .z = 0 };
|
||||
|
||||
static int16_t m_GongBounds[12] = {
|
||||
-WALL_L / 2,
|
||||
+WALL_L,
|
||||
-100,
|
||||
+100,
|
||||
-WALL_L / 2 - 300,
|
||||
-WALL_L / 2 + 100,
|
||||
-30 * DEG_1,
|
||||
+30 * DEG_1,
|
||||
+0,
|
||||
+0,
|
||||
+0,
|
||||
+0,
|
||||
static const OBJECT_BOUNDS m_GongBounds = {
|
||||
.shift = {
|
||||
.min = { .x = -WALL_L / 2, .y = -100, .z = -WALL_L / 2 - 300, },
|
||||
.max = { .x = +WALL_L, .y = +100, .z = -WALL_L / 2 + 100, },
|
||||
},
|
||||
.rot = {
|
||||
.min = { .x = -30 * DEG_1, .y = 0, .z = 0, },
|
||||
.max = { .x = +30 * DEG_1, .y = 0, .z = 0, },
|
||||
},
|
||||
};
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void);
|
||||
static void M_CreateGongBonger(ITEM *lara_item);
|
||||
static void M_Setup1(OBJECT *obj);
|
||||
static void M_Setup2(OBJECT *obj);
|
||||
static void M_Control(int16_t item_num);
|
||||
static void M_Collision(int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void)
|
||||
{
|
||||
return &m_GongBounds;
|
||||
}
|
||||
|
||||
static void M_CreateGongBonger(ITEM *const lara_item)
|
||||
{
|
||||
const int16_t item_gong_bonger_num = Item_Create();
|
||||
|
@ -64,12 +68,14 @@ static void M_CreateGongBonger(ITEM *const lara_item)
|
|||
static void M_Setup1(OBJECT *const obj)
|
||||
{
|
||||
obj->collision_func = M_Collision;
|
||||
obj->bounds_func = M_Bounds;
|
||||
}
|
||||
|
||||
static void M_Setup2(OBJECT *const obj)
|
||||
{
|
||||
obj->collision_func = M_Collision;
|
||||
obj->control_func = M_Control;
|
||||
obj->bounds_func = Pickup_Bounds;
|
||||
obj->save_flags = 1;
|
||||
obj->save_anim = 1;
|
||||
}
|
||||
|
@ -102,6 +108,7 @@ static void M_Collision(
|
|||
}
|
||||
|
||||
ITEM *const item = Item_Get(item_num);
|
||||
const OBJECT *const obj = Object_Get(item->object_id);
|
||||
const XYZ_16 old_rot = item->rot;
|
||||
const int16_t x = item->rot.x;
|
||||
const int16_t y = item->rot.y;
|
||||
|
@ -117,16 +124,11 @@ static void M_Collision(
|
|||
goto normal_collision;
|
||||
}
|
||||
|
||||
if (item->object_id == O_DETONATOR_2) {
|
||||
if (!Item_TestPosition(g_PickupBounds, item, lara_item)) {
|
||||
goto normal_collision;
|
||||
}
|
||||
} else {
|
||||
if (!Item_TestPosition(m_GongBounds, item, lara_item)) {
|
||||
goto normal_collision;
|
||||
} else {
|
||||
item->rot = old_rot;
|
||||
}
|
||||
if (!Lara_TestPosition(item, obj->bounds_func())) {
|
||||
goto normal_collision;
|
||||
}
|
||||
if (item->object_id == O_DETONATOR_1) {
|
||||
item->rot = old_rot;
|
||||
}
|
||||
|
||||
if (g_Inv_Chosen == NO_OBJECT) {
|
||||
|
@ -138,7 +140,7 @@ static void M_Collision(
|
|||
}
|
||||
|
||||
Inv_RemoveItem(O_KEY_OPTION_2);
|
||||
Item_AlignPosition(&m_DetonatorPosition, item, lara_item);
|
||||
Lara_AlignPosition(item, &m_DetonatorPosition);
|
||||
Item_SwitchToObjAnim(lara_item, LA_EXTRA_BREATH, 0, O_LARA_EXTRA);
|
||||
lara_item->current_anim_state = LA_EXTRA_BREATH;
|
||||
if (item->object_id == O_DETONATOR_2) {
|
||||
|
|
|
@ -6,6 +6,7 @@ static void M_Setup(OBJECT *obj);
|
|||
static void M_Setup(OBJECT *const obj)
|
||||
{
|
||||
obj->collision_func = Pickup_Collision;
|
||||
obj->bounds_func = Pickup_Bounds;
|
||||
obj->control_func = Flare_Control;
|
||||
obj->draw_func = Flare_DrawInAir;
|
||||
obj->save_position = 1;
|
||||
|
|
|
@ -17,29 +17,29 @@ static XYZ_32 m_KeyholePosition = {
|
|||
.z = WALL_L / 2 - LARA_RADIUS - 50,
|
||||
};
|
||||
|
||||
static int16_t m_KeyholeBounds[12] = {
|
||||
// clang-format off
|
||||
-200,
|
||||
+200,
|
||||
+0,
|
||||
+0,
|
||||
+WALL_L / 2 - 200,
|
||||
+WALL_L / 2,
|
||||
-10 * DEG_1,
|
||||
+10 * DEG_1,
|
||||
-30 * DEG_1,
|
||||
+30 * DEG_1,
|
||||
-10 * DEG_1,
|
||||
+10 * DEG_1,
|
||||
// clang-format on
|
||||
static const OBJECT_BOUNDS m_KeyHoleBounds = {
|
||||
.shift = {
|
||||
.min = { .x = -200, .y = +0, .z = +WALL_L / 2 - 200, },
|
||||
.max = { .x = +200, .y = +0, .z = +WALL_L / 2, },
|
||||
},
|
||||
.rot = {
|
||||
.min = { .x = -10 * DEG_1, .y = -30 * DEG_1, .z = -10 * DEG_1, },
|
||||
.max = { .x = +10 * DEG_1, .y = +30 * DEG_1, .z = +10 * DEG_1, },
|
||||
},
|
||||
};
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void);
|
||||
static void M_Consume(
|
||||
ITEM *lara_item, ITEM *keyhole_item, GAME_OBJECT_ID key_obj_id);
|
||||
static void M_Refuse(const ITEM *lara_item);
|
||||
static void M_Setup(OBJECT *obj);
|
||||
static void M_Collision(int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void)
|
||||
{
|
||||
return &m_KeyHoleBounds;
|
||||
}
|
||||
|
||||
static void M_Refuse(const ITEM *const lara_item)
|
||||
{
|
||||
if (lara_item->pos.x == g_InteractPosition.x
|
||||
|
@ -57,7 +57,7 @@ static void M_Consume(
|
|||
const GAME_OBJECT_ID key_obj_id)
|
||||
{
|
||||
Inv_RemoveItem(key_obj_id);
|
||||
Item_AlignPosition(&m_KeyholePosition, keyhole_item, lara_item);
|
||||
Lara_AlignPosition(keyhole_item, &m_KeyholePosition);
|
||||
lara_item->goal_anim_state = LS_USE_KEY;
|
||||
do {
|
||||
Lara_Animate(lara_item);
|
||||
|
@ -71,6 +71,7 @@ static void M_Consume(
|
|||
static void M_Setup(OBJECT *const obj)
|
||||
{
|
||||
obj->collision_func = M_Collision;
|
||||
obj->bounds_func = M_Bounds;
|
||||
obj->save_flags = 1;
|
||||
}
|
||||
|
||||
|
@ -82,12 +83,13 @@ static void M_Collision(
|
|||
}
|
||||
|
||||
ITEM *const item = Item_Get(item_num);
|
||||
const OBJECT *const obj = Object_Get(item->object_id);
|
||||
if ((g_Inv_Chosen == NO_OBJECT && !g_Input.action)
|
||||
|| g_Lara.gun_status != LGS_ARMLESS || lara_item->gravity) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Item_TestPosition(m_KeyholeBounds, item, lara_item)) {
|
||||
if (!Lara_TestPosition(item, obj->bounds_func())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,21 +20,18 @@ typedef enum {
|
|||
MOVABLE_BLOCK_STATE_PULL = 3,
|
||||
} MOVABLE_BLOCK_STATE;
|
||||
|
||||
static int16_t m_MovableBlockBounds[12] = {
|
||||
-300,
|
||||
+300,
|
||||
+0,
|
||||
+0,
|
||||
-WALL_L / 2 - LARA_RADIUS - 80,
|
||||
-WALL_L / 2,
|
||||
-10 * DEG_1,
|
||||
+10 * DEG_1,
|
||||
-30 * DEG_1,
|
||||
+30 * DEG_1,
|
||||
-10 * DEG_1,
|
||||
+10 * DEG_1,
|
||||
static const OBJECT_BOUNDS m_MovableBlockBounds = {
|
||||
.shift = {
|
||||
.min = { .x = -300, .y = 0, .z = -WALL_L / 2 - LARA_RADIUS - 80, },
|
||||
.max = { .x = +300, .y = 0, .z = -WALL_L / 2, },
|
||||
},
|
||||
.rot = {
|
||||
.min = { .x = -10 * DEG_1, .y = -30 * DEG_1, .z = -10 * DEG_1, },
|
||||
.max = { .x = +10 * DEG_1, .y = +30 * DEG_1, .z = +10 * DEG_1, },
|
||||
},
|
||||
};
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void);
|
||||
static bool M_TestDestination(const ITEM *item, int32_t block_height);
|
||||
static bool M_TestPush(
|
||||
const ITEM *item, int32_t block_height, DIRECTION quadrant);
|
||||
|
@ -47,6 +44,11 @@ static void M_Draw(const ITEM *item);
|
|||
static void M_Control(int16_t item_num);
|
||||
static void M_Collision(int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void)
|
||||
{
|
||||
return &m_MovableBlockBounds;
|
||||
}
|
||||
|
||||
static bool M_TestDestination(
|
||||
const ITEM *const item, const int32_t block_height)
|
||||
{
|
||||
|
@ -199,6 +201,7 @@ static void M_Setup(OBJECT *const obj)
|
|||
obj->handle_save_func = M_HandleSave;
|
||||
obj->control_func = M_Control;
|
||||
obj->collision_func = M_Collision;
|
||||
obj->bounds_func = M_Bounds;
|
||||
obj->draw_func = M_Draw;
|
||||
obj->save_position = 1;
|
||||
obj->save_flags = 1;
|
||||
|
@ -303,7 +306,7 @@ static void M_Collision(
|
|||
break;
|
||||
}
|
||||
|
||||
if (!Item_TestPosition(m_MovableBlockBounds, item, lara_item)) {
|
||||
if (!Lara_TestPosition(item, obj->bounds_func())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -346,7 +349,7 @@ static void M_Collision(
|
|||
} else if (
|
||||
Item_TestAnimEqual(lara_item, LA_PUSHABLE_GRAB)
|
||||
&& Item_TestFrameEqual(lara_item, LF_PPREADY)) {
|
||||
if (!Item_TestPosition(m_MovableBlockBounds, item, lara_item)) {
|
||||
if (!Lara_TestPosition(item, obj->bounds_func())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,41 +26,29 @@
|
|||
#define LF_PICKUP_FLARE_UW 20
|
||||
#define LF_PICKUP_UW 18
|
||||
|
||||
int16_t g_PickupBounds[12] = {
|
||||
// clang-format off
|
||||
-WALL_L / 4,
|
||||
+WALL_L / 4,
|
||||
-100,
|
||||
+100,
|
||||
-WALL_L / 4,
|
||||
+WALL_L / 4,
|
||||
-10 * DEG_1,
|
||||
+10 * DEG_1,
|
||||
+0,
|
||||
+0,
|
||||
+0,
|
||||
+0,
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
static XYZ_32 m_PickupPosition = { .x = 0, .y = 0, .z = -100 };
|
||||
static XYZ_32 m_PickupPositionUW = { .x = 0, .y = -200, .z = -350 };
|
||||
|
||||
static int16_t m_PickupBoundsUW[12] = {
|
||||
// clang-format off
|
||||
-WALL_L / 2,
|
||||
+WALL_L / 2,
|
||||
-WALL_L / 2,
|
||||
+WALL_L / 2,
|
||||
-WALL_L / 2,
|
||||
+WALL_L / 2,
|
||||
-45 * DEG_1,
|
||||
+45 * DEG_1,
|
||||
-45 * DEG_1,
|
||||
+45 * DEG_1,
|
||||
-45 * DEG_1,
|
||||
+45 * DEG_1,
|
||||
// clang-format on
|
||||
static const OBJECT_BOUNDS m_PickUpBounds = {
|
||||
.shift = {
|
||||
.min = { .x = -WALL_L / 4, .y = -100, .z = -WALL_L / 4, },
|
||||
.max = { .x = +WALL_L / 4, .y = +100, .z = +WALL_L / 4, },
|
||||
},
|
||||
.rot = {
|
||||
.min = { .x = -10 * DEG_1, .y = 0, .z = 0, },
|
||||
.max = { .x = +10 * DEG_1, .y = 0, .z = 0, },
|
||||
},
|
||||
};
|
||||
|
||||
static const OBJECT_BOUNDS m_PickUpBoundsUW = {
|
||||
.shift = {
|
||||
.min = { .x = -WALL_L / 2, .y = -WALL_L / 2, .z = -WALL_L / 2, },
|
||||
.max = { .x = +WALL_L / 2, .y = +WALL_L / 2, .z = +WALL_L / 2, },
|
||||
},
|
||||
.rot = {
|
||||
.min = { .x = -45 * DEG_1, .y = -45 * DEG_1, .z = -45 * DEG_1, },
|
||||
.max = { .x = +45 * DEG_1, .y = +45 * DEG_1, .z = +45 * DEG_1, },
|
||||
},
|
||||
};
|
||||
|
||||
static void M_DoPickup(int16_t item_num);
|
||||
|
@ -107,13 +95,14 @@ static void M_DoFlarePickup(const int16_t item_num)
|
|||
static void M_DoAboveWater(const int16_t item_num, ITEM *const lara_item)
|
||||
{
|
||||
ITEM *const item = Item_Get(item_num);
|
||||
const OBJECT *const obj = Object_Get(item->object_id);
|
||||
const XYZ_16 old_rot = item->rot;
|
||||
|
||||
item->rot.x = 0;
|
||||
item->rot.y = lara_item->rot.y;
|
||||
item->rot.z = 0;
|
||||
|
||||
if (!Item_TestPosition(g_PickupBounds, item, lara_item)) {
|
||||
if (!Lara_TestPosition(item, obj->bounds_func())) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -145,7 +134,7 @@ static void M_DoAboveWater(const int16_t item_num, ITEM *const lara_item)
|
|||
lara_item->goal_anim_state = LS_STOP;
|
||||
g_Lara.gun_status = LGS_HANDS_BUSY;
|
||||
} else {
|
||||
Item_AlignPosition(&m_PickupPosition, item, lara_item);
|
||||
Lara_AlignPosition(item, &m_PickupPosition);
|
||||
lara_item->goal_anim_state = LS_PICKUP;
|
||||
do {
|
||||
Lara_Animate(lara_item);
|
||||
|
@ -163,13 +152,14 @@ cleanup:
|
|||
static void M_DoUnderwater(const int16_t item_num, ITEM *const lara_item)
|
||||
{
|
||||
ITEM *const item = Item_Get(item_num);
|
||||
const OBJECT *const obj = Object_Get(item->object_id);
|
||||
const XYZ_16 old_rot = item->rot;
|
||||
|
||||
item->rot.x = -25 * DEG_1;
|
||||
item->rot.y = lara_item->rot.y;
|
||||
item->rot.z = 0;
|
||||
|
||||
if (!Item_TestPosition(m_PickupBoundsUW, item, lara_item)) {
|
||||
if (!Lara_TestPosition(item, obj->bounds_func())) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -224,6 +214,7 @@ static void M_Setup(OBJECT *const obj)
|
|||
obj->handle_save_func = M_HandleSave;
|
||||
obj->activate_func = M_Activate;
|
||||
obj->collision_func = Pickup_Collision;
|
||||
obj->bounds_func = Pickup_Bounds;
|
||||
obj->draw_func = M_Draw;
|
||||
obj->save_position = 1;
|
||||
obj->save_flags = 1;
|
||||
|
@ -343,6 +334,15 @@ static void M_Draw(const ITEM *const item)
|
|||
Matrix_Pop();
|
||||
}
|
||||
|
||||
const OBJECT_BOUNDS *Pickup_Bounds(void)
|
||||
{
|
||||
if (g_Lara.water_status == LWS_UNDERWATER) {
|
||||
return &m_PickUpBoundsUW;
|
||||
} else {
|
||||
return &m_PickUpBounds;
|
||||
}
|
||||
}
|
||||
|
||||
void Pickup_Collision(
|
||||
const int16_t item_num, ITEM *const lara_item, COLL_INFO *const coll)
|
||||
{
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include "global/types.h"
|
||||
|
||||
extern int16_t g_PickupBounds[];
|
||||
|
||||
void Pickup_Collision(int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
|
||||
bool Pickup_Trigger(int16_t item_num);
|
||||
const OBJECT_BOUNDS *Pickup_Bounds(void);
|
||||
|
|
|
@ -17,23 +17,18 @@ static XYZ_32 m_PuzzleHolePosition = {
|
|||
.z = WALL_L / 2 - LARA_RADIUS - 85,
|
||||
};
|
||||
|
||||
static int16_t m_PuzzleHoleBounds[12] = {
|
||||
// clang-format off
|
||||
-200,
|
||||
+200,
|
||||
+0,
|
||||
+0,
|
||||
+WALL_L / 2 - 200,
|
||||
+WALL_L / 2,
|
||||
-10 * DEG_1,
|
||||
+10 * DEG_1,
|
||||
-30 * DEG_1,
|
||||
+30 * DEG_1,
|
||||
-10 * DEG_1,
|
||||
+10 * DEG_1,
|
||||
// clang-format on
|
||||
static const OBJECT_BOUNDS m_PuzzleHoleBounds = {
|
||||
.shift = {
|
||||
.min = { .x = -200, .y = 0, .z = WALL_L / 2 - 200, },
|
||||
.max = { .x = +200, .y = 0, .z = WALL_L / 2, },
|
||||
},
|
||||
.rot = {
|
||||
.min = { .x = -10 * DEG_1, .y = -30 * DEG_1, .z = -10 * DEG_1, },
|
||||
.max = { .x = +10 * DEG_1, .y = +30 * DEG_1, .z = +10 * DEG_1, },
|
||||
},
|
||||
};
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void);
|
||||
static void M_Refuse(const ITEM *lara_item);
|
||||
static void M_Consume(
|
||||
ITEM *lara_item, ITEM *puzzle_hole_item, GAME_OBJECT_ID puzzle_obj_id);
|
||||
|
@ -43,6 +38,11 @@ static void M_SetupDone(OBJECT *obj);
|
|||
static void M_HandleSave(ITEM *item, SAVEGAME_STAGE stage);
|
||||
static void M_Collision(int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void)
|
||||
{
|
||||
return &m_PuzzleHoleBounds;
|
||||
}
|
||||
|
||||
static void M_Refuse(const ITEM *const lara_item)
|
||||
{
|
||||
if (lara_item->pos.x != g_InteractPosition.x
|
||||
|
@ -58,7 +58,7 @@ static void M_Consume(
|
|||
const GAME_OBJECT_ID puzzle_obj_id)
|
||||
{
|
||||
Inv_RemoveItem(puzzle_obj_id);
|
||||
Item_AlignPosition(&m_PuzzleHolePosition, puzzle_hole_item, lara_item);
|
||||
Lara_AlignPosition(puzzle_hole_item, &m_PuzzleHolePosition);
|
||||
lara_item->goal_anim_state = LS_USE_PUZZLE;
|
||||
do {
|
||||
Lara_Animate(lara_item);
|
||||
|
@ -82,6 +82,7 @@ static void M_SetupEmpty(OBJECT *const obj)
|
|||
{
|
||||
obj->collision_func = M_Collision;
|
||||
obj->handle_save_func = M_HandleSave;
|
||||
obj->bounds_func = M_Bounds;
|
||||
obj->save_flags = 1;
|
||||
}
|
||||
|
||||
|
@ -103,10 +104,11 @@ static void M_Collision(
|
|||
const int16_t item_num, ITEM *const lara_item, COLL_INFO *const coll)
|
||||
{
|
||||
ITEM *const item = Item_Get(item_num);
|
||||
const OBJECT *const obj = Object_Get(item->object_id);
|
||||
|
||||
if (lara_item->current_anim_state != LS_STOP) {
|
||||
if (lara_item->current_anim_state != LS_USE_PUZZLE
|
||||
|| !Item_TestPosition(m_PuzzleHoleBounds, item, lara_item)
|
||||
|| !Lara_TestPosition(item, obj->bounds_func())
|
||||
|| !Item_TestFrameEqual(lara_item, LF_USE_PUZZLE)) {
|
||||
return;
|
||||
}
|
||||
|
@ -120,7 +122,7 @@ static void M_Collision(
|
|||
return;
|
||||
}
|
||||
|
||||
if (!Item_TestPosition(m_PuzzleHoleBounds, item, lara_item)) {
|
||||
if (!Lara_TestPosition(item, obj->bounds_func())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,40 +17,30 @@ static XYZ_32 g_PushSwitchPosition = { .x = 0, .y = 0, .z = 292 };
|
|||
static XYZ_32 m_AirlockPosition = { .x = 0, .y = 0, .z = 212 };
|
||||
static XYZ_32 m_SwitchUWPosition = { .x = 0, .y = 0, .z = 108 };
|
||||
|
||||
static int16_t m_SwitchBounds[12] = {
|
||||
// clang-format off
|
||||
-220,
|
||||
+220,
|
||||
+0,
|
||||
+0,
|
||||
+WALL_L / 2 - 220,
|
||||
+WALL_L / 2,
|
||||
-10 * DEG_1,
|
||||
+10 * DEG_1,
|
||||
-30 * DEG_1,
|
||||
+30 * DEG_1,
|
||||
-10 * DEG_1,
|
||||
+10 * DEG_1,
|
||||
// clang-format on
|
||||
static const OBJECT_BOUNDS m_SwitchBounds = {
|
||||
.shift = {
|
||||
.min = { .x = -220, .y = +0, .z = +WALL_L / 2 - 220, },
|
||||
.max = { .x = +220, .y = +0, .z = +WALL_L / 2, },
|
||||
},
|
||||
.rot = {
|
||||
.min = { .x = -10 * DEG_1, .y = -30 * DEG_1, .z = -10 * DEG_1, },
|
||||
.max = { .x = +10 * DEG_1, .y = +30 * DEG_1, .z = +10 * DEG_1, },
|
||||
},
|
||||
};
|
||||
|
||||
static int16_t m_SwitchBoundsUW[12] = {
|
||||
// clang-format off
|
||||
-WALL_L,
|
||||
+WALL_L,
|
||||
-WALL_L,
|
||||
+WALL_L,
|
||||
-WALL_L,
|
||||
+WALL_L / 2,
|
||||
-80 * DEG_1,
|
||||
+80 * DEG_1,
|
||||
-80 * DEG_1,
|
||||
+80 * DEG_1,
|
||||
-80 * DEG_1,
|
||||
+80 * DEG_1,
|
||||
// clang-format on
|
||||
static const OBJECT_BOUNDS m_SwitchBoundsUW = {
|
||||
.shift = {
|
||||
.min = { .x = -WALL_L, .y = -WALL_L, .z = -WALL_L, },
|
||||
.max = { .x = +WALL_L, .y = +WALL_L, .z = +WALL_L / 2, },
|
||||
},
|
||||
.rot = {
|
||||
.min = { .x = -80 * DEG_1, .y = -80 * DEG_1, .z = -80 * DEG_1, },
|
||||
.max = { .x = +80 * DEG_1, .y = +80 * DEG_1, .z = +80 * DEG_1, },
|
||||
},
|
||||
};
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void);
|
||||
static const OBJECT_BOUNDS *M_BoundsUW(void);
|
||||
static void M_AlignLara(ITEM *lara_item, ITEM *switch_item);
|
||||
static void M_SwitchOn(ITEM *switch_item, ITEM *lara_item);
|
||||
static void M_SwitchOff(ITEM *switch_item, ITEM *lara_item);
|
||||
|
@ -62,19 +52,29 @@ static void M_Collision(int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
|
|||
static void M_CollisionUW(int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
|
||||
static void M_Control(int16_t item_num);
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void)
|
||||
{
|
||||
return &m_SwitchBounds;
|
||||
}
|
||||
|
||||
static const OBJECT_BOUNDS *M_BoundsUW(void)
|
||||
{
|
||||
return &m_SwitchBoundsUW;
|
||||
}
|
||||
|
||||
static void M_AlignLara(ITEM *const lara_item, ITEM *const switch_item)
|
||||
{
|
||||
switch (switch_item->object_id) {
|
||||
case O_SWITCH_TYPE_AIRLOCK:
|
||||
Item_AlignPosition(&m_AirlockPosition, switch_item, lara_item);
|
||||
Lara_AlignPosition(switch_item, &m_AirlockPosition);
|
||||
break;
|
||||
|
||||
case O_SWITCH_TYPE_SMALL:
|
||||
Item_AlignPosition(&g_SmallSwitchPosition, switch_item, lara_item);
|
||||
Lara_AlignPosition(switch_item, &g_SmallSwitchPosition);
|
||||
break;
|
||||
|
||||
case O_SWITCH_TYPE_BUTTON:
|
||||
Item_AlignPosition(&g_PushSwitchPosition, switch_item, lara_item);
|
||||
Lara_AlignPosition(switch_item, &g_PushSwitchPosition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -139,28 +139,32 @@ static void M_Setup(OBJECT *const obj)
|
|||
{
|
||||
M_SetupBase(obj);
|
||||
obj->collision_func = M_Collision;
|
||||
obj->bounds_func = M_Bounds;
|
||||
}
|
||||
|
||||
static void M_SetupPushButton(OBJECT *const obj)
|
||||
{
|
||||
M_Setup(obj);
|
||||
obj->enable_interpolation = false;
|
||||
obj->bounds_func = M_Bounds;
|
||||
}
|
||||
|
||||
static void M_SetupUW(OBJECT *const obj)
|
||||
{
|
||||
M_SetupBase(obj);
|
||||
obj->collision_func = M_CollisionUW;
|
||||
obj->bounds_func = M_BoundsUW;
|
||||
}
|
||||
|
||||
static void M_Collision(
|
||||
const int16_t item_num, ITEM *const lara_item, COLL_INFO *const coll)
|
||||
{
|
||||
ITEM *const item = Item_Get(item_num);
|
||||
const OBJECT *const obj = Object_Get(item->object_id);
|
||||
if (!g_Input.action || item->status != IS_INACTIVE
|
||||
|| g_Lara.gun_status != LGS_ARMLESS || lara_item->gravity
|
||||
|| lara_item->current_anim_state != LS_STOP
|
||||
|| !Item_TestPosition(m_SwitchBounds, item, lara_item)) {
|
||||
|| !Lara_TestPosition(item, obj->bounds_func())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -193,6 +197,7 @@ static void M_CollisionUW(
|
|||
const int16_t item_num, ITEM *const lara_item, COLL_INFO *const coll)
|
||||
{
|
||||
ITEM *const item = Item_Get(item_num);
|
||||
const OBJECT *const obj = Object_Get(item->object_id);
|
||||
|
||||
if (!g_Input.action || item->status != IS_INACTIVE
|
||||
|| g_Lara.water_status != LWS_UNDERWATER
|
||||
|
@ -201,7 +206,7 @@ static void M_CollisionUW(
|
|||
return;
|
||||
}
|
||||
|
||||
if (!Item_TestPosition(m_SwitchBoundsUW, item, lara_item)) {
|
||||
if (!Lara_TestPosition(item, obj->bounds_func())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,33 +22,35 @@ static XYZ_32 m_ZiplineHandlePosition = {
|
|||
.y = 0,
|
||||
.z = WALL_L / 2 - 141,
|
||||
};
|
||||
static int16_t m_ZiplineHandleBounds[12] = {
|
||||
// clang-format off
|
||||
-WALL_L / 4,
|
||||
+WALL_L / 4,
|
||||
-100,
|
||||
+100,
|
||||
+WALL_L / 4,
|
||||
+WALL_L / 2,
|
||||
+0,
|
||||
+0,
|
||||
-25 * DEG_1,
|
||||
+25 * DEG_1,
|
||||
+0,
|
||||
+0,
|
||||
// clang-format on
|
||||
|
||||
static const OBJECT_BOUNDS m_ZiplineHandleBounds = {
|
||||
.shift = {
|
||||
.min = { .x = -WALL_L / 4, .y = -100, .z = +WALL_L / 4, },
|
||||
.max = { .x = +WALL_L / 4, .y = +100, .z = +WALL_L / 2, },
|
||||
},
|
||||
.rot = {
|
||||
.min = { .x = +0, .y = -25 * DEG_1, .z = +0, },
|
||||
.max = { .x = +0, .y = +25 * DEG_1, .z = +0, },
|
||||
},
|
||||
};
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void);
|
||||
static void M_Setup(OBJECT *obj);
|
||||
static void M_Initialise(int16_t item_num);
|
||||
static void M_Control(int16_t item_num);
|
||||
static void M_Collision(int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
|
||||
|
||||
static const OBJECT_BOUNDS *M_Bounds(void)
|
||||
{
|
||||
return &m_ZiplineHandleBounds;
|
||||
}
|
||||
|
||||
static void M_Setup(OBJECT *const obj)
|
||||
{
|
||||
obj->initialise_func = M_Initialise;
|
||||
obj->control_func = M_Control;
|
||||
obj->collision_func = M_Collision;
|
||||
obj->bounds_func = M_Bounds;
|
||||
obj->save_position = 1;
|
||||
obj->save_flags = 1;
|
||||
obj->save_anim = 1;
|
||||
|
@ -149,11 +151,12 @@ static void M_Collision(
|
|||
return;
|
||||
}
|
||||
|
||||
if (!Item_TestPosition(m_ZiplineHandleBounds, item, lara_item)) {
|
||||
const OBJECT *const obj = Object_Get(item->object_id);
|
||||
if (!Lara_TestPosition(item, obj->bounds_func())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Item_AlignPosition(&m_ZiplineHandlePosition, item, lara_item);
|
||||
Lara_AlignPosition(item, &m_ZiplineHandlePosition);
|
||||
g_Lara.gun_status = LGS_HANDS_BUSY;
|
||||
|
||||
lara_item->goal_anim_state = LS_ZIPLINE;
|
||||
|
|
|
@ -1,132 +1,48 @@
|
|||
#include "game/game_string.h"
|
||||
#include "game/input.h"
|
||||
#include "game/inventory_ring.h"
|
||||
#include "game/music.h"
|
||||
#include "game/option/option.h"
|
||||
#include "game/sound.h"
|
||||
#include "game/text.h"
|
||||
#include "global/vars.h"
|
||||
|
||||
#include <libtrx/config.h>
|
||||
#include <libtrx/utils.h>
|
||||
#include <libtrx/game/ui.h>
|
||||
|
||||
#include <stdio.h>
|
||||
typedef struct {
|
||||
UI_SOUND_SETTINGS_STATE *ui;
|
||||
} M_PRIV;
|
||||
|
||||
static TEXTSTRING *m_SoundText[4];
|
||||
static M_PRIV m_Priv = {};
|
||||
|
||||
static void M_InitText(void);
|
||||
static void M_ShutdownText(void);
|
||||
|
||||
static void M_InitText(void)
|
||||
static void M_Init(M_PRIV *const p)
|
||||
{
|
||||
CLAMPG(g_Config.audio.music_volume, 10);
|
||||
CLAMPG(g_Config.audio.sound_volume, 10);
|
||||
p->ui = UI_SoundSettings_Init();
|
||||
}
|
||||
|
||||
char text[32];
|
||||
sprintf(text, "\\{icon music} %2d", g_Config.audio.music_volume);
|
||||
m_SoundText[0] = Text_Create(0, 0, text);
|
||||
Text_AddBackground(m_SoundText[0], 128, 0, 0, 0, TS_REQUESTED);
|
||||
Text_AddOutline(m_SoundText[0], TS_REQUESTED);
|
||||
|
||||
sprintf(text, "\\{icon sound} %2d", g_Config.audio.sound_volume);
|
||||
m_SoundText[1] = Text_Create(0, 25, text);
|
||||
|
||||
m_SoundText[2] = Text_Create(0, -32, " ");
|
||||
Text_AddBackground(m_SoundText[2], 140, 85, 0, 0, TS_BACKGROUND);
|
||||
Text_AddOutline(m_SoundText[2], TS_BACKGROUND);
|
||||
|
||||
m_SoundText[3] = Text_Create(0, -30, GS(SOUND_SET_VOLUMES));
|
||||
Text_AddBackground(m_SoundText[3], 136, 0, 0, 0, TS_HEADING);
|
||||
Text_AddOutline(m_SoundText[3], TS_HEADING);
|
||||
|
||||
for (int32_t i = 0; i < 4; i++) {
|
||||
Text_CentreH(m_SoundText[i], true);
|
||||
Text_CentreV(m_SoundText[i], true);
|
||||
static void M_Shutdown(M_PRIV *const p)
|
||||
{
|
||||
if (p->ui != nullptr) {
|
||||
UI_SoundSettings_Free(p->ui);
|
||||
p->ui = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void M_ShutdownText(void)
|
||||
void Option_Sound_Control(INVENTORY_ITEM *const inv_item, const bool is_busy)
|
||||
{
|
||||
for (int32_t i = 0; i < 4; i++) {
|
||||
Text_Remove(m_SoundText[i]);
|
||||
m_SoundText[i] = nullptr;
|
||||
M_PRIV *const p = &m_Priv;
|
||||
if (is_busy) {
|
||||
return;
|
||||
}
|
||||
if (p->ui == nullptr) {
|
||||
M_Init(p);
|
||||
}
|
||||
UI_SoundSettings_Control(p->ui);
|
||||
}
|
||||
|
||||
void Option_Sound_Draw(INVENTORY_ITEM *const inv_item)
|
||||
{
|
||||
M_PRIV *const p = &m_Priv;
|
||||
if (p->ui != nullptr) {
|
||||
UI_SoundSettings(p->ui);
|
||||
}
|
||||
}
|
||||
|
||||
void Option_Sound_Shutdown(void)
|
||||
{
|
||||
M_ShutdownText();
|
||||
}
|
||||
|
||||
void Option_Sound_Control(INVENTORY_ITEM *const item, const bool is_busy)
|
||||
{
|
||||
if (is_busy) {
|
||||
return;
|
||||
}
|
||||
|
||||
char text[32];
|
||||
|
||||
if (m_SoundText[0] == nullptr) {
|
||||
M_InitText();
|
||||
}
|
||||
|
||||
if (g_InputDB.menu_up && g_SoundOptionLine > 0) {
|
||||
Text_RemoveOutline(m_SoundText[g_SoundOptionLine]);
|
||||
Text_RemoveBackground(m_SoundText[g_SoundOptionLine]);
|
||||
g_SoundOptionLine--;
|
||||
Text_AddBackground(
|
||||
m_SoundText[g_SoundOptionLine], 128, 0, 0, 0, TS_REQUESTED);
|
||||
Text_AddOutline(m_SoundText[g_SoundOptionLine], TS_REQUESTED);
|
||||
}
|
||||
|
||||
if (g_InputDB.menu_down && g_SoundOptionLine < 1) {
|
||||
Text_RemoveOutline(m_SoundText[g_SoundOptionLine]);
|
||||
Text_RemoveBackground(m_SoundText[g_SoundOptionLine]);
|
||||
g_SoundOptionLine++;
|
||||
Text_AddBackground(
|
||||
m_SoundText[g_SoundOptionLine], 128, 0, 0, 0, TS_REQUESTED);
|
||||
Text_AddOutline(m_SoundText[g_SoundOptionLine], TS_REQUESTED);
|
||||
}
|
||||
|
||||
if (g_SoundOptionLine) {
|
||||
bool changed = false;
|
||||
if (g_InputDB.menu_left && g_Config.audio.sound_volume > 0) {
|
||||
g_Config.audio.sound_volume--;
|
||||
changed = true;
|
||||
} else if (g_InputDB.menu_right && g_Config.audio.sound_volume < 10) {
|
||||
g_Config.audio.sound_volume++;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
sprintf(text, "\\{icon sound} %2d", g_Config.audio.sound_volume);
|
||||
Text_ChangeText(m_SoundText[1], text);
|
||||
Sound_SetMasterVolume(g_Config.audio.sound_volume);
|
||||
Sound_Effect(SFX_MENU_PASSPORT, nullptr, SPM_ALWAYS);
|
||||
}
|
||||
} else {
|
||||
bool changed = false;
|
||||
if (g_InputDB.menu_left && g_Config.audio.music_volume > 0) {
|
||||
g_Config.audio.music_volume--;
|
||||
changed = true;
|
||||
} else if (g_InputDB.menu_right && g_Config.audio.music_volume < 10) {
|
||||
g_Config.audio.music_volume++;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
sprintf(text, "\\{icon music} %2d", g_Config.audio.music_volume);
|
||||
Text_ChangeText(m_SoundText[0], text);
|
||||
Music_SetVolume(g_Config.audio.music_volume);
|
||||
Sound_Effect(SFX_MENU_PASSPORT, nullptr, SPM_ALWAYS);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_InputDB.menu_confirm || g_InputDB.menu_back) {
|
||||
Option_Sound_Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void Option_Sound_Draw(INVENTORY_ITEM *const item)
|
||||
{
|
||||
M_Shutdown(&m_Priv);
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ static RENDERER *M_GetRenderer(void)
|
|||
} else if (g_Config.rendering.render_mode == RM_HARDWARE) {
|
||||
r = &m_Renderer_HW;
|
||||
}
|
||||
ASSERT(r != nullptr);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -124,7 +123,6 @@ void Render_Init(void)
|
|||
|
||||
void Render_Shutdown(void)
|
||||
{
|
||||
LOG_DEBUG("");
|
||||
RENDERER *const r = M_GetRenderer();
|
||||
if (r != nullptr) {
|
||||
r->Close(r);
|
||||
|
|
|
@ -99,7 +99,7 @@ static void M_HandleQuit(void);
|
|||
static void M_ConfigureOpenGL(void);
|
||||
static bool M_CreateGameWindow(void);
|
||||
|
||||
static void M_ParseArgs(SHELL_ARGS *out_args);
|
||||
static void M_ShowHelp(void);
|
||||
static void M_LoadConfig(void);
|
||||
static void M_HandleConfigChange(const EVENT *event, void *data);
|
||||
|
||||
|
@ -342,30 +342,13 @@ static bool M_CreateGameWindow(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void M_ParseArgs(SHELL_ARGS *const out_args)
|
||||
static void M_ShowHelp(void)
|
||||
{
|
||||
const char **args = nullptr;
|
||||
int32_t arg_count = 0;
|
||||
Shell_GetCommandLine(&arg_count, &args);
|
||||
|
||||
out_args->mod = M_MOD_OG;
|
||||
|
||||
for (int32_t i = 0; i < arg_count; i++) {
|
||||
if (!strcmp(args[i], "-gold")) {
|
||||
out_args->mod = M_MOD_GM;
|
||||
}
|
||||
if ((!strcmp(args[i], "-l") || !strcmp(args[i], "--level"))
|
||||
&& i + 1 < arg_count) {
|
||||
out_args->level_to_play = args[i + 1];
|
||||
out_args->mod = M_MOD_CUSTOM_LEVEL;
|
||||
}
|
||||
if ((!strcmp(args[i], "-s") || !strcmp(args[i], "--save"))
|
||||
&& i + 1 < arg_count) {
|
||||
if (String_ParseInteger(args[i + 1], &out_args->save_to_load)) {
|
||||
out_args->save_to_load--;
|
||||
}
|
||||
}
|
||||
}
|
||||
puts("Currently available options:");
|
||||
puts("");
|
||||
puts("-g/--gold: launch The Golden Mask expansion pack.");
|
||||
puts("-l/--level <PATH>: launch a specific level file.");
|
||||
puts("-s/--save <NUM>: launch from a specific save slot (starts at 1).");
|
||||
}
|
||||
|
||||
static void M_LoadConfig(void)
|
||||
|
@ -433,10 +416,39 @@ static void M_HandleConfigChange(const EVENT *const event, void *const data)
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: refactor the hell out of me
|
||||
void Shell_Main(void)
|
||||
bool Shell_ParseArgs(const int32_t arg_count, const char **args)
|
||||
{
|
||||
M_ParseArgs(&m_Args);
|
||||
SHELL_ARGS *const out_args = &m_Args;
|
||||
out_args->mod = M_MOD_OG;
|
||||
|
||||
for (int32_t i = 0; i < arg_count; i++) {
|
||||
if (!strcmp(args[i], "-h") || !strcmp(args[i], "--help")) {
|
||||
M_ShowHelp();
|
||||
return false;
|
||||
}
|
||||
if (!strcmp(args[i], "-g") || !strcmp(args[i], "--gold")
|
||||
|| !strcmp(args[i], "-gold")) {
|
||||
out_args->mod = M_MOD_GM;
|
||||
}
|
||||
if ((!strcmp(args[i], "-l") || !strcmp(args[i], "--level"))
|
||||
&& i + 1 < arg_count) {
|
||||
out_args->level_to_play = args[i + 1];
|
||||
out_args->mod = M_MOD_CUSTOM_LEVEL;
|
||||
}
|
||||
if ((!strcmp(args[i], "-s") || !strcmp(args[i], "--save"))
|
||||
&& i + 1 < arg_count) {
|
||||
if (String_ParseInteger(args[i + 1], &out_args->save_to_load)) {
|
||||
out_args->save_to_load--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: refactor the hell out of me
|
||||
int32_t Shell_Main(void)
|
||||
{
|
||||
LOG_INFO("Game directory: %s", File_GetGameDirectory());
|
||||
|
||||
if (m_Args.mod == M_MOD_GM) {
|
||||
Object_Get(O_MONK_3)->setup_func = Monk3_Setup;
|
||||
|
@ -465,7 +477,7 @@ void Shell_Main(void)
|
|||
|
||||
if (!M_CreateGameWindow()) {
|
||||
Shell_ExitSystem("Failed to create game window");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Random_Seed();
|
||||
|
@ -561,7 +573,7 @@ void Shell_Main(void)
|
|||
if (gf_cmd.action == GF_NOOP
|
||||
|| gf_cmd.action == GF_EXIT_TO_TITLE) {
|
||||
Shell_ExitSystem("Title disabled & no replacement");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
gf_cmd = GF_RunTitle();
|
||||
|
@ -583,6 +595,7 @@ void Shell_Main(void)
|
|||
if (m_Args.level_to_play != nullptr) {
|
||||
Memory_FreePointer(&g_GameFlow.level_tables[GFLT_MAIN].levels[0].path);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Shell_Shutdown(void)
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
void Sound_Init(void);
|
||||
void Sound_Shutdown(void);
|
||||
|
||||
void Sound_SetMasterVolume(int32_t volume);
|
||||
void Sound_UpdateEffects(void);
|
||||
void Sound_StopEffect(SOUND_EFFECT_ID sample_id);
|
||||
void Sound_EndScene(void);
|
||||
int32_t Sound_GetMinVolume(void);
|
||||
int32_t Sound_GetMaxVolume(void);
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
#include "global/vars.h"
|
||||
|
||||
#include <libtrx/config.h>
|
||||
#include <libtrx/game/scaler.h>
|
||||
#include <libtrx/game/ui/common.h>
|
||||
|
||||
int32_t UI_GetCanvasWidth(void)
|
||||
{
|
||||
return Scaler_CalcInverse(g_PhdWinWidth, SCALER_TARGET_GENERIC);
|
||||
}
|
||||
|
||||
int32_t UI_GetCanvasHeight(void)
|
||||
{
|
||||
return Scaler_CalcInverse(g_PhdWinHeight, SCALER_TARGET_GENERIC);
|
||||
}
|
||||
|
||||
float UI_ScaleX(const float x)
|
||||
{
|
||||
return Scaler_Calc(x, SCALER_TARGET_GENERIC);
|
||||
}
|
||||
|
||||
float UI_ScaleY(const float y)
|
||||
{
|
||||
return Scaler_Calc(y, SCALER_TARGET_GENERIC);
|
||||
}
|
|
@ -151,13 +151,6 @@ typedef struct {
|
|||
int32_t pitch;
|
||||
} SKIDOO_INFO;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
XYZ_16 min;
|
||||
XYZ_16 max;
|
||||
} shift, rot;
|
||||
} OBJECT_BOUNDS;
|
||||
|
||||
typedef struct {
|
||||
int32_t xv;
|
||||
int32_t yv;
|
||||
|
|
|
@ -266,7 +266,6 @@ sources = [
|
|||
'game/spawn.c',
|
||||
'game/stats.c',
|
||||
'game/text.c',
|
||||
'game/ui/common.c',
|
||||
'game/ui/dialogs/graphic_settings.c',
|
||||
'game/ui/dialogs/stats.c',
|
||||
'game/viewport.c',
|
||||
|
|
|
@ -42,41 +42,33 @@ def extract_zip(zip_path: Path, dest_dir: Path) -> None:
|
|||
z.extractall(dest_dir)
|
||||
|
||||
|
||||
def download_assets(assets: list[tuple[str, Path]]) -> None:
|
||||
def download_assets(asset_urls: list[str], target_dir: Path) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmpdir_str:
|
||||
tmpdir = Path(tmpdir_str)
|
||||
for url, dest in assets:
|
||||
for url in asset_urls:
|
||||
filename = Path(url).name
|
||||
local_zip = tmpdir / filename
|
||||
download_to_file(url, local_zip)
|
||||
extract_zip(local_zip, dest)
|
||||
extract_zip(local_zip, target_dir)
|
||||
print("Asset download and extraction complete.")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
assets: dict[int, list[tuple[str, Path]]] = {
|
||||
1: [
|
||||
(
|
||||
"https://lostartefacts.dev/aux/tr1x/main.zip",
|
||||
Path("data/tr1/ship"),
|
||||
)
|
||||
],
|
||||
asset_urls_map: dict[int, list[str]] = {
|
||||
1: ["https://lostartefacts.dev/aux/tr1x/main.zip"],
|
||||
2: [
|
||||
(
|
||||
"https://lostartefacts.dev/aux/tr2x/main.zip",
|
||||
Path("data/tr2/ship"),
|
||||
)
|
||||
"https://lostartefacts.dev/aux/tr2x/main.zip",
|
||||
"https://lostartefacts.dev/aux/tr2x/trgm.zip",
|
||||
],
|
||||
}
|
||||
match str(args.game_version):
|
||||
case "1":
|
||||
download_assets(assets[1])
|
||||
case "2":
|
||||
download_assets(assets[2])
|
||||
case "all":
|
||||
download_assets(assets[1])
|
||||
download_assets(assets[2])
|
||||
|
||||
versions = {"1": [1], "2": [2], "all": [1, 2]}[args.game_version]
|
||||
for version in versions:
|
||||
download_assets(
|
||||
asset_urls_map[version],
|
||||
target_dir=PROJECT_PATHS[version].shipped_data_dir,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue