objects/movable_block: fix angle resetting and snapping

This restores pushblock angles after performing collision tests, and
also snaps them to the grid on initialisation if a builder places them
at non 90 degree angles to avoid instead snapping during collision.

Resolves #2776.
This commit is contained in:
lahm86 2025-04-18 08:54:15 +01:00
parent dd2af3377a
commit 3e959a34db
10 changed files with 68 additions and 8 deletions

View file

@ -17,6 +17,7 @@
- fixed enemies in one-click high water appearing with a water tint, and not making any animation sounds (#2753)
- 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 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)

View file

@ -475,6 +475,7 @@ Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for det
- fixed a potential softlock when killing the Torso boss in Great Pyramid
- 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
#### Cheats
- added a fly cheat

View file

@ -37,6 +37,7 @@
- fixed a potential softlock in Floating Islands if returning towards the level start from the gold secret (#2590)
- fixed a potential softlock in Nightmare in Vegas where the bird monster could remain inactive, or the flip map not set (#1851)
- fixed invalid portals in The Deck between rooms 17 and 104, which could result in Lara seeing enemies in disconnected rooms (#2393)
- fixed pushblocks being rotated when Lara grabs them, most noticeable if asymmetric textures have been used (#2776)
- fixed the camera going out of bounds in 60fps near specific invalid floor data (known as no-space) (#2764, regression from 0.10)
- fixed sprites rendering black if no shade value is assigned in the level (#2701, regression from 0.8)
- fixed a crash if an image was missing

View file

@ -243,6 +243,7 @@ as Notepad.
- increased Barkhang Monastery rooftops key size
- increased Temple of Xian dragon seal size, and fixed inventory rotation
- fixed Floating Islands mystic plaque inventory rotation
- fixed pushblocks being rotated when Lara grabs them, most noticeable if asymmetric textures have been used
- improved the animation of Lara's braid
#### Cheats

View file

@ -185,6 +185,17 @@ void Object_DrawInterpolatedObject(
Matrix_TranslateRel16_ID(frame1->offset, frame2->offset);
Matrix_Rot16_ID(
frame1->mesh_rots[mesh_idx], frame2->mesh_rots[mesh_idx]);
if (extra_rotation != nullptr) {
if (obj->base_rot.y) {
Matrix_RotY_I(*extra_rotation++);
}
if (obj->base_rot.x) {
Matrix_RotX_I(*extra_rotation++);
}
if (obj->base_rot.z) {
Matrix_RotZ_I(*extra_rotation++);
}
}
} else {
const ANIM_BONE *const bone = Object_GetBone(obj, mesh_idx - 1);
if (bone->matrix_pop) {
@ -219,6 +230,17 @@ void Object_DrawInterpolatedObject(
if (mesh_idx == 0) {
Matrix_TranslateRel16(frame1->offset);
Matrix_Rot16(frame1->mesh_rots[mesh_idx]);
if (extra_rotation != nullptr) {
if (obj->base_rot.y) {
Matrix_RotY(*extra_rotation++);
}
if (obj->base_rot.x) {
Matrix_RotX(*extra_rotation++);
}
if (obj->base_rot.z) {
Matrix_RotZ(*extra_rotation++);
}
}
} else {
const ANIM_BONE *const bone = Object_GetBone(obj, mesh_idx - 1);
if (bone->matrix_pop) {

View file

@ -7,6 +7,11 @@
#include <stdlib.h>
typedef struct {
int16_t counter_rot[3];
int16_t original_rot;
} M_PRIV;
static int32_t m_BlockCount = 0;
static VECTOR *m_UnsortedBlocks = nullptr;
static int16_t *m_SortedBlocks = nullptr;
@ -54,6 +59,24 @@ void MovableBlock_Initialise(const int16_t item_num)
m_UnsortedBlocks = Vector_Create(sizeof(int16_t));
}
Vector_Add(m_UnsortedBlocks, (void *)&item_num);
// Ensure the block is snapped to the grid, otherwise the snapping occurs
// during collision tests and can appear jarring. Additional angles are
// stored to preserve item appearance in spite of control angle changes.
ITEM *const item = Item_Get(item_num);
M_PRIV *const data = GameBuf_Alloc(sizeof(M_PRIV), GBUF_ITEM_DATA);
item->data = data;
data->original_rot =
(((item->rot.y + DEG_180) / DEG_90) * DEG_90) - DEG_180;
MovableBlock_UpdateRotation(item, data->original_rot);
}
// TODO: make private
void MovableBlock_UpdateRotation(ITEM *const item, const int16_t rot_y)
{
item->rot.y = rot_y;
M_PRIV *const data = (M_PRIV *)item->data;
data->counter_rot[0] = data->original_rot - rot_y;
}
void MovableBlock_SetupFloor(void)

View file

@ -3,5 +3,6 @@
#include "../../rooms.h"
void MovableBlock_Initialise(int16_t item_num);
void MovableBlock_UpdateRotation(ITEM *item, int16_t rot_y);
void MovableBlock_SetupFloor(void);
void MovableBlock_HandleFlipMap(ROOM_FLIP_STATUS flip_status);

View file

@ -79,6 +79,12 @@ typedef struct OBJECT {
int16_t smartness;
bool enable_interpolation;
struct {
bool x;
bool y;
bool z;
} base_rot;
union {
uint16_t flags;
// clang-format off

View file

@ -278,6 +278,7 @@ static void M_Setup(OBJECT *const obj)
obj->save_position = 1;
obj->save_anim = 1;
obj->save_flags = 1;
obj->base_rot.y = true;
obj->bounds_func = M_Bounds;
}
@ -290,6 +291,7 @@ static void M_HandleSave(ITEM *const item, const SAVEGAME_STAGE stage)
item->status = IS_INACTIVE;
}
item->priv = item->status == IS_ACTIVE ? (void *)true : (void *)false;
MovableBlock_UpdateRotation(item, item->rot.y);
}
}
@ -367,16 +369,16 @@ static void M_Collision(
switch (quadrant) {
case DIR_NORTH:
item->rot.y = 0;
MovableBlock_UpdateRotation(item, 0);
break;
case DIR_EAST:
item->rot.y = DEG_90;
MovableBlock_UpdateRotation(item, DEG_90);
break;
case DIR_SOUTH:
item->rot.y = -DEG_180;
MovableBlock_UpdateRotation(item, -DEG_180);
break;
case DIR_WEST:
item->rot.y = -DEG_90;
MovableBlock_UpdateRotation(item, -DEG_90);
break;
default:
break;

View file

@ -203,6 +203,7 @@ static void M_Setup(OBJECT *const obj)
obj->save_position = 1;
obj->save_flags = 1;
obj->save_anim = 1;
obj->base_rot.y = true;
}
static void M_HandleSave(ITEM *const item, const SAVEGAME_STAGE stage)
@ -214,6 +215,7 @@ static void M_HandleSave(ITEM *const item, const SAVEGAME_STAGE stage)
item->status = IS_INACTIVE;
}
item->priv = item->status == IS_ACTIVE ? (void *)true : (void *)false;
MovableBlock_UpdateRotation(item, item->rot.y);
}
}
@ -286,16 +288,16 @@ static void M_Collision(
switch (quadrant) {
case DIR_NORTH:
item->rot.y = 0;
MovableBlock_UpdateRotation(item, 0);
break;
case DIR_EAST:
item->rot.y = DEG_90;
MovableBlock_UpdateRotation(item, DEG_90);
break;
case DIR_SOUTH:
item->rot.y = -DEG_180;
MovableBlock_UpdateRotation(item, -DEG_180);
break;
case DIR_WEST:
item->rot.y = -DEG_90;
MovableBlock_UpdateRotation(item, -DEG_90);
break;
default:
break;