output: animate room sprites (#1282)

This allows room sprites that are part of a sequence with more than one
texture to be animated. This occurs at the same rate as regular
animated textures.

Resolves #449.
This commit is contained in:
lahm86 2024-04-08 15:21:42 +01:00 committed by GitHub
parent 32e61c581b
commit ca32163133
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 97 additions and 32 deletions

View file

@ -13,6 +13,7 @@
- added Italian localization to the config tool
- added the ability to move the look camera while targeting an enemy in combat (#1187)
- added the ability to skip fade-out in stats screens
- added support for animated room sprites in custom levels and an option to animate plant sprites in The Cistern and Tomb of Tihocan (#449)
- changed stats no longer disappear during fade-out (#1211)
- changed the way music timestamps are internally handled resets music position in existing saves
- changed vertex and fragment shaders into unified files that are runtime pre-processed for OpenGL versions 2.1 or 3.3

View file

@ -1371,6 +1371,15 @@ provided with the game achieves.
<code>braid_cut2_cut4.bin</code>
</td>
</tr>
<tr valign="top">
<td>
<code>cistern_plants.bin</code>
</td>
<td>
This disables the animation on sprite ID 193 in The Cistern and Tomb of
Tihocan.
</td>
</tr>
<tr valign="top">
<td>
<code>khamoon_mummy.bin</code>

View file

@ -369,6 +369,7 @@ Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for det
- added optional fade effects
- added a vsync option
- added contextual arrows to menu options
- added support for animated room sprites, which also restores intended behavior in, for example, The Cistern room 0
- changed the Scion in The Great Pyramid from spawning blood when hit to a richochet effect
- fixed thin black lines between polygons
- fixed black screen flashing when navigating the inventory

View file

@ -229,6 +229,7 @@
"injections": [
"data/cistern_fd.bin",
"data/cistern_itemrots.bin",
"data/cistern_plants.bin",
"data/cistern_textures.bin",
],
"sequence": [
@ -253,6 +254,7 @@
"type": "normal",
"music": 58,
"injections": [
"data/cistern_plants.bin",
"data/tihocan_fd.bin",
"data/tihocan_itemrots.bin",
"data/tihocan_textures.bin",

Binary file not shown.

View file

@ -136,6 +136,7 @@ typedef struct {
bool enable_target_change;
TARGET_LOCK_MODE target_mode;
bool enable_loading_screens;
bool fix_animated_sprites;
struct {
int32_t layout;

View file

@ -158,6 +158,7 @@ const CONFIG_OPTION g_ConfigOptionMap[] = {
{ .name = "text_scale", .type = COT_DOUBLE, .target = &g_Config.ui.text_scale, .default_value = &(double){DEFAULT_UI_SCALE}, 0},
{ .name = "bar_scale", .type = COT_DOUBLE, .target = &g_Config.ui.bar_scale, .default_value = &(double){DEFAULT_UI_SCALE}, 0},
{ .name = "new_game_plus_unlock", .type = COT_BOOL, .target = &g_Config.profile.new_game_plus_unlock, .default_value = &(bool){false}, 0},
{ .name = "fix_animated_sprites", .type = COT_BOOL, .target = &g_Config.fix_animated_sprites, .default_value = &(bool){true}, 0},
// clang-format on
// guard

View file

@ -37,6 +37,7 @@ typedef enum INJECTION_TYPE {
INJ_LARA_JUMPS = 6,
INJ_ITEM_POSITION = 7,
INJ_PS1_ENEMY = 8,
INJ_DISABLE_ANIM_SPRITE = 9,
} INJECTION_TYPE;
typedef struct INJECTION {
@ -223,6 +224,9 @@ static void Inject_LoadFromFile(INJECTION *injection, const char *filename)
case INJ_PS1_ENEMY:
injection->relevant = g_Config.restore_ps1_enemies;
break;
case INJ_DISABLE_ANIM_SPRITE:
injection->relevant = !g_Config.fix_animated_sprites;
break;
default:
LOG_WARNING("%s is of unknown type %d", filename, injection->type);
break;
@ -487,24 +491,24 @@ static void Inject_TextureData(
for (int i = 0; i < inj_info->sprite_count; i++) {
GAME_OBJECT_ID object_num;
int16_t num_meshes;
int16_t mesh_index;
File_Read(&object_num, sizeof(int32_t), 1, fp);
File_Read(&num_meshes, sizeof(int16_t), 1, fp);
File_Read(&mesh_index, sizeof(int16_t), 1, fp);
if (object_num < O_NUMBER_OF) {
File_Read(&g_Objects[object_num], sizeof(int16_t), 1, fp);
File_Read(
&g_Objects[object_num].mesh_index, sizeof(int16_t), 1, fp);
g_Objects[object_num].mesh_index += level_info->sprite_info_count;
level_info->sprite_info_count -= g_Objects[object_num].nmeshes;
g_Objects[object_num].loaded = 1;
} else {
int32_t static_num = object_num - O_NUMBER_OF;
File_Skip(fp, 2);
File_Read(
&g_StaticObjects[static_num].mesh_number, sizeof(int16_t), 1,
fp);
g_StaticObjects[static_num].mesh_number +=
level_info->sprite_info_count;
level_info->sprite_info_count++;
OBJECT_INFO *object = &g_Objects[object_num];
object->nmeshes = num_meshes;
object->mesh_index = mesh_index + level_info->sprite_info_count;
object->loaded = 1;
} else if (object_num - O_NUMBER_OF < STATIC_NUMBER_OF) {
STATIC_INFO *object = &g_StaticObjects[object_num - O_NUMBER_OF];
object->nmeshes = num_meshes;
object->mesh_number = mesh_index + level_info->sprite_info_count;
object->loaded = true;
}
level_info->sprite_info_count -= num_meshes;
level_info->sprite_count++;
}
}

View file

@ -484,6 +484,7 @@ static bool Level_LoadObjects(MYFILE *fp)
File_Read(&object->c.min.z, sizeof(int16_t), 1, fp);
File_Read(&object->c.max.z, sizeof(int16_t), 1, fp);
File_Read(&object->flags, sizeof(int16_t), 1, fp);
object->loaded = true;
}
File_Read(&m_LevelInfo.texture_count, sizeof(int32_t), 1, fp);
@ -528,18 +529,22 @@ static bool Level_LoadSprites(MYFILE *fp)
File_Read(&m_LevelInfo.sprite_count, sizeof(int32_t), 1, fp);
for (int i = 0; i < m_LevelInfo.sprite_count; i++) {
GAME_OBJECT_ID object_num;
int16_t num_meshes;
int16_t mesh_index;
File_Read(&object_num, sizeof(int32_t), 1, fp);
File_Read(&num_meshes, sizeof(int16_t), 1, fp);
File_Read(&mesh_index, sizeof(int16_t), 1, fp);
if (object_num < O_NUMBER_OF) {
File_Read(&g_Objects[object_num], sizeof(int16_t), 1, fp);
File_Read(
&g_Objects[object_num].mesh_index, sizeof(int16_t), 1, fp);
g_Objects[object_num].loaded = 1;
} else {
int32_t static_num = object_num - O_NUMBER_OF;
File_Skip(fp, 2);
File_Read(
&g_StaticObjects[static_num].mesh_number, sizeof(int16_t), 1,
fp);
OBJECT_INFO *object = &g_Objects[object_num];
object->nmeshes = num_meshes;
object->mesh_index = mesh_index;
object->loaded = 1;
} else if (object_num - O_NUMBER_OF < STATIC_NUMBER_OF) {
STATIC_INFO *object = &g_StaticObjects[object_num - O_NUMBER_OF];
object->nmeshes = num_meshes;
object->mesh_number = mesh_index;
object->loaded = true;
}
}
return true;
@ -947,18 +952,21 @@ bool Level_Initialise(int32_t level_num)
Overlay_HideGameInfo();
g_FlipStatus = 0;
for (int i = 0; i < MAX_FLIP_MAPS; i++) {
for (int32_t i = 0; i < MAX_FLIP_MAPS; i++) {
g_FlipMapTable[i] = 0;
}
for (int i = 0; i < MAX_CD_TRACKS; i++) {
for (int32_t i = 0; i < MAX_CD_TRACKS; i++) {
g_MusicTrackFlags[i] = 0;
}
/* Clear Object Loaded flags */
for (int i = 0; i < O_NUMBER_OF; i++) {
for (int32_t i = 0; i < O_NUMBER_OF; i++) {
g_Objects[i].loaded = 0;
}
for (int32_t i = 0; i < STATIC_NUMBER_OF; i++) {
g_StaticObjects[i].loaded = false;
}
Camera_Reset();
Pierre_Reset();

View file

@ -924,16 +924,16 @@ void Output_AnimateTextures(void)
{
m_WibbleOffset = Clock_GetLogicalFrame() % WIBBLE_SIZE;
if (!g_AnimTextureRanges) {
if (!Clock_IsAtLogicalFrame(5)) {
return;
}
if (Clock_IsAtLogicalFrame(5)) {
int16_t *ptr = g_AnimTextureRanges;
if (g_AnimTextureRanges) {
const int16_t *ptr = g_AnimTextureRanges;
int16_t i = *ptr++;
while (i > 0) {
int16_t j = *ptr++;
PHD_TEXTURE temp = g_PhdTextureInfo[*ptr];
const PHD_TEXTURE temp = g_PhdTextureInfo[*ptr];
while (j > 0) {
g_PhdTextureInfo[ptr[0]] = g_PhdTextureInfo[ptr[1]];
j--;
@ -944,6 +944,21 @@ void Output_AnimateTextures(void)
ptr++;
}
}
for (int32_t i = 0; i < STATIC_NUMBER_OF; i++) {
const STATIC_INFO *const static_info = &g_StaticObjects[i];
if (!static_info->loaded || static_info->nmeshes >= -1) {
continue;
}
const int32_t num_meshes = -static_info->nmeshes;
const PHD_SPRITE temp = g_PhdSpriteInfo[static_info->mesh_number];
for (int32_t j = 0; j < num_meshes - 1; j++) {
g_PhdSpriteInfo[static_info->mesh_number + j] =
g_PhdSpriteInfo[static_info->mesh_number + j + 1];
}
g_PhdSpriteInfo[static_info->mesh_number + num_meshes - 1] = temp;
}
}
void Output_RotateLight(int16_t pitch, int16_t yaw)

View file

@ -1804,6 +1804,8 @@ typedef struct SHADOW_INFO {
} SHADOW_INFO;
typedef struct STATIC_INFO {
bool loaded;
int16_t nmeshes;
int16_t mesh_number;
int16_t flags;
BOUNDS_16 p;

View file

@ -160,6 +160,10 @@
"Title": "Fix texture issues",
"Description": "Fixes original issues with missing or incorrect textures."
},
"fix_animated_sprites": {
"Title": "Fix sprite animations",
"Description": "Fixes original issues in The Cistern and Tomb of Tihocan where plant sprites in water areas do not animate."
},
"fix_item_rots": {
"Title": "Fix item rotation issues",
"Description": "Fixes original issues with some incorrectly rotated pickups when using the 3D pickups option."

View file

@ -328,6 +328,10 @@
"Title": "Arreglar problemas de textura",
"Description": "Corrige los problemas originales con texturas faltantes o incorrectas."
},
"fix_animated_sprites": {
"Title": "Arreglar animaciones de sprites",
"Description": "Corrige los problemas originales en La Cisterna y La Tumba de Tihocan donde los duendes de las plantas en las áreas de agua no se animan."
},
"fix_item_rots": {
"Title": "Arreglar problemas de rotación de objetos",
"Description": "Corrige problemas originales con algunas recogidas giradas incorrectamente al usar la opción de recogidas en 3D."

View file

@ -160,6 +160,10 @@
"Title": "Corrige les problèmes de texture",
"Description": "Corrige les bugs originaux connus de textures manquantes ou incorrectes."
},
"fix_animated_sprites": {
"Title": "Correction des animations des sprites",
"Description": "Corrige les problèmes originaux dans La Citerne et Le Tombe de Tihocan où les sprites végétaux dans les zones aquatiques ne s'animent pas."
},
"fix_item_rots": {
"Title": "Correction orientation des collectibles",
"Description": "Corrige des problèmes avec certains collectibles mal orientés, quand l'option des collectibles en 3D est utilisée."

View file

@ -160,6 +160,10 @@
"Title": "Correggi i problemi delle texture",
"Description": "Risolve i problemi riguardanti texture mancanti o errate."
},
"fix_animated_sprites": {
"Title": "Correggi le animazioni degli sprite",
"Description": "Risolve i problemi originali nella Cisterna e nella Tomba di Tihocan per cui gli sprite delle piante nelle aree acquatiche non si animavano."
},
"fix_item_rots": {
"Title": "Correggi l'orientamento degli oggetti",
"Description": "Risolve i problemi relativi all'orientamento errato di alcuni oggetti quando viene utilizzata l'opzione Oggetti 3D."

View file

@ -151,6 +151,11 @@
"DataType": "Bool",
"DefaultValue": true
},
{
"Field": "fix_animated_sprites",
"DataType": "Bool",
"DefaultValue": true
},
{
"Field": "fix_qwop_glitch",
"DataType": "Bool",