diff --git a/docs/tr2/progress.svg b/docs/tr2/progress.svg index 0f32b5394..64195a182 100644 --- a/docs/tr2/progress.svg +++ b/docs/tr2/progress.svg @@ -69,10 +69,10 @@ Tomb2.exe progress according to the physical function order: -69.77% (868) · 27.81% (346) · 0% (0) · 2.41% (30) +69.86% (869) · 27.73% (345) · 0% (0) · 2.41% (30) - - + + @@ -584,7 +584,7 @@ void __cdecl Gun_Rifle_FireHarpoon(void); void __cdecl HarpoonBolt_Control(int16_t item_num); void __cdecl Gun_Rifle_FireGrenade(void); -void __cdecl Rocket_Control(int16_t item_num); +void __cdecl Grenade_Control(int16_t item_num); void __cdecl Gun_Rifle_Draw(LARA_GUN_TYPE weapon_type); void __cdecl Gun_Rifle_Undraw(LARA_GUN_TYPE weapon_type); void __cdecl Gun_Rifle_Animate(LARA_GUN_TYPE weapon_type); @@ -1324,10 +1324,10 @@ Tomb2.exe progress according to the function sizes: -73.92% · 25.75% · 0% · 0.33% +74.22% · 25.45% · 0% · 0.33% - - + + @@ -1392,7 +1392,7 @@ void __cdecl Cultist2_Control(int16_t item_num); void __cdecl Bandit2_Control(int16_t item_num); void __cdecl Cultist1_Control(int16_t item_num); -void __cdecl Rocket_Control(int16_t item_num); +void __cdecl Grenade_Control(int16_t item_num); void __cdecl XianKnight_Draw(const ITEM *item); void __cdecl SkidooDriver_Control(int16_t rider_num); void __cdecl Door_Initialise(int16_t item_num); diff --git a/docs/tr2/progress.txt b/docs/tr2/progress.txt index 350075dd2..1cdce0425 100644 --- a/docs/tr2/progress.txt +++ b/docs/tr2/progress.txt @@ -3439,7 +3439,7 @@ typedef enum { 0x0042BF60 0x0187 + void __cdecl Gun_Rifle_FireHarpoon(void); 0x0042C0F0 0x0344 + void __cdecl HarpoonBolt_Control(int16_t item_num); 0x0042C440 0x00F0 + void __cdecl Gun_Rifle_FireGrenade(void); -0x0042C530 0x03FD - void __cdecl Rocket_Control(int16_t item_num); +0x0042C530 0x03FD + void __cdecl Grenade_Control(int16_t item_num); 0x0042C930 0x0166 + void __cdecl Gun_Rifle_Draw(LARA_GUN_TYPE weapon_type); 0x0042CAA0 0x0104 + void __cdecl Gun_Rifle_Undraw(LARA_GUN_TYPE weapon_type); 0x0042CBB0 0x037E + void __cdecl Gun_Rifle_Animate(LARA_GUN_TYPE weapon_type); diff --git a/src/tr2/game/objects/general/grenade.c b/src/tr2/game/objects/general/grenade.c new file mode 100644 index 000000000..ef6a5916b --- /dev/null +++ b/src/tr2/game/objects/general/grenade.c @@ -0,0 +1,139 @@ +#include "game/objects/general/grenade.h" + +#include "game/creature.h" +#include "game/effects.h" +#include "game/gun/gun_misc.h" +#include "game/items.h" +#include "game/math.h" +#include "game/room.h" +#include "game/sound.h" +#include "global/funcs.h" +#include "global/vars.h" + +#define M_BLAST_RADIUS (WALL_L / 2) // = 512 +#define M_SPEED 200 +#define M_FALL_SPEED (M_SPEED - 10) // = 190 + +static void M_Explode(int16_t grenade_item_num, XYZ_32 pos); + +static void M_Explode(int16_t grenade_item_num, const XYZ_32 pos) +{ + const ITEM *const grenade_item = Item_Get(grenade_item_num); + const int16_t fx_num = Effect_Create(grenade_item->room_num); + if (fx_num != NO_ITEM) { + FX *const fx = &g_Effects[fx_num]; + fx->pos = pos; + fx->speed = 0; + fx->frame_num = 0; + fx->counter = 0; + fx->object_id = O_EXPLOSION; + } + Sound_Effect(SFX_EXPLOSION1, NULL, SPM_NORMAL); + Item_Kill(grenade_item_num); +} + +void __cdecl Grenade_Control(int16_t item_num) +{ + ITEM *const item = Item_Get(item_num); + + const XYZ_32 old_pos = item->pos; + + item->speed--; + if (item->speed < M_FALL_SPEED) { + item->fall_speed++; + } + item->pos.y += + item->fall_speed - ((item->speed * Math_Sin(item->rot.x)) >> W2V_SHIFT); + + const int16_t speed = (item->speed * Math_Cos(item->rot.x)) >> W2V_SHIFT; + item->pos.z += (speed * Math_Cos(item->rot.y)) >> W2V_SHIFT; + item->pos.x += (speed * Math_Sin(item->rot.y)) >> W2V_SHIFT; + + int16_t room_num = item->room_num; + const SECTOR *const sector = + Room_GetSector(item->pos.x, item->pos.y, item->pos.z, &room_num); + item->floor = Room_GetHeight(sector, item->pos.x, item->pos.y, item->pos.z); + if (item->room_num != room_num) { + Item_NewRoom(item_num, room_num); + } + + bool explode = false; + int32_t radius = 0; + if (item->pos.y >= item->floor + || item->pos.y + <= Room_GetCeiling(sector, item->pos.x, item->pos.y, item->pos.z)) { + radius = M_BLAST_RADIUS; + explode = true; + } + + for (int16_t target_item_num = Room_Get(item->room_num)->item_num; + target_item_num != NO_ITEM; + target_item_num = Item_Get(target_item_num)->next_item) { + ITEM *const target_item = Item_Get(target_item_num); + const OBJECT *const target_obj = + Object_GetObject(target_item->object_id); + if (target_item == g_LaraItem) { + continue; + } + if (!target_item->collidable) { + continue; + } + + if (target_item->object_id != O_WINDOW_1 + && (!target_obj->intelligent || target_item->status == IS_INVISIBLE + || target_obj->collision == NULL)) { + continue; + } + + const FRAME_INFO *const frame = Item_GetBestFrame(target_item); + const BOUNDS_16 *const bounds = &frame->bounds; + + const int32_t cdy = item->pos.y - target_item->pos.y; + if (cdy + radius < bounds->min_y || cdy - radius > bounds->max_y) { + continue; + } + + const int32_t cy = Math_Cos(target_item->rot.y); + const int32_t sy = Math_Sin(target_item->rot.y); + const int32_t cdx = item->pos.x - target_item->pos.x; + const int32_t cdz = item->pos.z - target_item->pos.z; + const int32_t odx = old_pos.x - target_item->pos.x; + const int32_t odz = old_pos.z - target_item->pos.z; + + const int32_t rx = (cy * cdx - sy * cdz) >> W2V_SHIFT; + const int32_t sx = (cy * odx - sy * odz) >> W2V_SHIFT; + if ((rx + radius < bounds->min_x && sx + radius < bounds->min_x) + || (rx - radius > bounds->max_x && sx - radius > bounds->max_x)) { + continue; + } + + const int32_t rz = (sy * cdx + cy * cdz) >> W2V_SHIFT; + const int32_t sz = (sy * odx + cy * odz) >> W2V_SHIFT; + if ((rz + radius < bounds->min_z && sz + radius < bounds->min_z) + || (rz - radius > bounds->max_z && sz - radius > bounds->max_z)) { + continue; + } + + if (target_item->object_id == O_WINDOW_1) { + SmashWindow(target_item_num); + } else { + // XXX: missing check if obj is intelligent? + Gun_HitTarget(target_item, NULL, 30); + + explode = true; + g_SaveGame.statistics.hits++; + + if (target_item->hit_points <= 0) { + g_SaveGame.statistics.kills++; + if (target_item->object_id != O_DRAGON_FRONT + && target_item->object_id != O_GIANT_YETI) { + Creature_Die(target_item_num, true); + } + } + } + } + + if (explode) { + M_Explode(item_num, old_pos); + } +} diff --git a/src/tr2/game/objects/general/grenade.h b/src/tr2/game/objects/general/grenade.h new file mode 100644 index 000000000..f3e85950d --- /dev/null +++ b/src/tr2/game/objects/general/grenade.h @@ -0,0 +1,5 @@ +#pragma once + +#include "global/types.h" + +void __cdecl Grenade_Control(const int16_t item_num); diff --git a/src/tr2/global/funcs.h b/src/tr2/global/funcs.h index 62afb9ac1..a663a9f2e 100644 --- a/src/tr2/global/funcs.h +++ b/src/tr2/global/funcs.h @@ -84,7 +84,6 @@ #define InitialiseHair ((void __cdecl (*)(void))0x00420EA0) #define HairControl ((void __cdecl (*)(int32_t in_cutscene))0x00420F20) #define DrawHair ((void __cdecl (*)(void))0x00421920) -#define Rocket_Control ((void __cdecl (*)(int16_t item_num))0x0042C530) #define Flare_DoLight ((int32_t __cdecl (*)(XYZ_32 *pos, int32_t flare_age))0x0042F7A0) #define Flare_DoInHand ((void __cdecl (*)(int32_t flare_age))0x0042F840) #define Flare_DrawInAir ((void __cdecl (*)(ITEM *item))0x0042F920) diff --git a/src/tr2/inject_exec.c b/src/tr2/inject_exec.c index aecc1c257..6e94b3b85 100644 --- a/src/tr2/inject_exec.c +++ b/src/tr2/inject_exec.c @@ -58,6 +58,7 @@ #include "game/objects/general/drawbridge.h" #include "game/objects/general/final_level_counter.h" #include "game/objects/general/gong_bonger.h" +#include "game/objects/general/grenade.h" #include "game/objects/general/harpoon_bolt.h" #include "game/objects/general/keyhole.h" #include "game/objects/general/lift.h" @@ -1024,6 +1025,7 @@ static void M_Objects(const bool enable) INJECT(enable, 0x004183E0, Bartoli_Initialise); INJECT(enable, 0x00418500, Bartoli_Control); INJECT(enable, 0x0042C0F0, HarpoonBolt_Control); + INJECT(enable, 0x0042C530, Grenade_Control); INJECT(enable, 0x004336F0, BodyPart_Control); INJECT(enable, 0x004338F0, MovableBlock_Initialise); INJECT(enable, 0x00433920, MovableBlock_Control); diff --git a/src/tr2/meson.build b/src/tr2/meson.build index 45b3e23ec..a952a7b81 100644 --- a/src/tr2/meson.build +++ b/src/tr2/meson.build @@ -166,6 +166,7 @@ dll_sources = [ 'game/objects/general/drawbridge.c', 'game/objects/general/final_level_counter.c', 'game/objects/general/gong_bonger.c', + 'game/objects/general/grenade.c', 'game/objects/general/harpoon_bolt.c', 'game/objects/general/keyhole.c', 'game/objects/general/lift.c',