Skip to content

Commit

Permalink
creature: perform safer conversion of hybrids (#1517)
Browse files Browse the repository at this point in the history
A check will be performed before switching rats and crocodiles to
ensure the target object is loaded. A similar check is done for
skate kid's skateboard before trying to draw it.

Resolves #1444.
  • Loading branch information
lahm86 authored Sep 14, 2024
1 parent e5d7036 commit 3304c98
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- fixed a potential softlock when killing the Torso boss in Great Pyramid (#1236)
- fixed Bacon Lara re-spawning after saving and loading (#1500, regression from 0.7)
- fixed config JSON not sanitizing some numeric values (#1515)
- fixed potential crashes in custom levels if hybrid creature objects are not present in the level (#1444)
- changed `/tp` console command to look for the closest place to teleport to when targeting items (#1484)
- changed the door cheat to also target drawbridges
- improved appearance of textures around edges when bilinear filter is off (#1483)
Expand Down
44 changes: 36 additions & 8 deletions src/game/creature.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@
#include "global/vars.h"
#include "math/math.h"

#include <libtrx/log.h>

#include <stddef.h>

#define MAX_CREATURE_DISTANCE (WALL_L * 30)

static bool Creature_SwitchToWater(
int16_t item_num, int32_t *wh, const HYBRID_INFO *info);
int16_t item_num, const int32_t *wh, const HYBRID_INFO *info);
static bool Creature_SwitchToLand(
int16_t item_num, int32_t *wh, const HYBRID_INFO *info);
int16_t item_num, const int32_t *wh, const HYBRID_INFO *info);
static bool Creature_TestSwitchOrKill(
int16_t item_num, GAME_OBJECT_ID target_id);

void Creature_Initialise(int16_t item_num)
{
Expand Down Expand Up @@ -709,11 +713,11 @@ bool Creature_ShootAtLara(
}

bool Creature_EnsureHabitat(
int16_t item_num, int32_t *wh, const HYBRID_INFO *info)
const int16_t item_num, int32_t *const wh, const HYBRID_INFO *const info)
{
// Test the environment for a hybrid creature. Record the water height and
// return whether or not a type conversion has taken place.
ITEM_INFO *item = &g_Items[item_num];
const ITEM_INFO *const item = &g_Items[item_num];
*wh = Room_GetWaterHeight(
item->pos.x, item->pos.y, item->pos.z, item->room_num);

Expand All @@ -729,13 +733,14 @@ bool Creature_IsBoss(const int16_t item_num)
}

static bool Creature_SwitchToWater(
int16_t item_num, int32_t *wh, const HYBRID_INFO *info)
const int16_t item_num, const int32_t *const wh,
const HYBRID_INFO *const info)
{
if (*wh == NO_HEIGHT) {
return false;
}

ITEM_INFO *item = &g_Items[item_num];
ITEM_INFO *const item = &g_Items[item_num];

if (item->hit_points <= 0) {
// Dead land creatures should remain in their pose permanently.
Expand All @@ -744,6 +749,10 @@ static bool Creature_SwitchToWater(

// The land creature is alive and the room has been flooded. Switch to the
// water creature.
if (!Creature_TestSwitchOrKill(item_num, info->water.id)) {
return false;
}

item->object_id = info->water.id;
Item_SwitchToAnim(item, info->water.active_anim, 0);
item->current_anim_state = g_Anims[item->anim_num].current_anim_state;
Expand All @@ -754,13 +763,18 @@ static bool Creature_SwitchToWater(
}

static bool Creature_SwitchToLand(
int16_t item_num, int32_t *wh, const HYBRID_INFO *info)
const int16_t item_num, const int32_t *const wh,
const HYBRID_INFO *const info)
{
if (*wh != NO_HEIGHT) {
return false;
}

ITEM_INFO *item = &g_Items[item_num];
if (!Creature_TestSwitchOrKill(item_num, info->land.id)) {
return false;
}

ITEM_INFO *const item = &g_Items[item_num];

// Switch to the land creature regardless of death state.
item->object_id = info->land.id;
Expand Down Expand Up @@ -790,3 +804,17 @@ static bool Creature_SwitchToLand(

return true;
}

static bool Creature_TestSwitchOrKill(
const int16_t item_num, const GAME_OBJECT_ID target_id)
{
if (g_Objects[target_id].loaded) {
return true;
}

LOG_WARNING(
"Object %d is not loaded; item %d cannot be converted.", target_id,
item_num);
Item_Kill(item_num);
return false;
}
10 changes: 10 additions & 0 deletions src/game/objects/creatures/skate_kid.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "global/const.h"
#include "global/vars.h"

#include <libtrx/log.h>
#include <libtrx/utils.h>

#define SKATE_KID_STOP_SHOT_DAMAGE 50
Expand Down Expand Up @@ -57,6 +58,12 @@ void SkateKid_Setup(OBJECT_INFO *obj)
obj->save_anim = 1;
obj->save_flags = 1;
g_AnimBones[obj->bone_index] |= BEB_ROT_Y;

if (!g_Objects[O_SKATEBOARD].loaded) {
LOG_WARNING(
"Skateboard object (%d) is not loaded and so will not be drawn.",
O_SKATEBOARD);
}
}

void SkateKid_Initialise(int16_t item_num)
Expand Down Expand Up @@ -168,6 +175,9 @@ void SkateKid_Control(int16_t item_num)
void SkateKid_Draw(ITEM_INFO *item)
{
Object_DrawAnimatingItem(item);
if (!g_Objects[O_SKATEBOARD].loaded) {
return;
}

int16_t relative_anim =
item->anim_num - g_Objects[item->object_id].anim_index;
Expand Down

0 comments on commit 3304c98

Please sign in to comment.