Skip to content

Commit

Permalink
tr2: port Dragon_Control
Browse files Browse the repository at this point in the history
  • Loading branch information
rr- committed Oct 9, 2024
1 parent 6684edd commit 3476c57
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 17 deletions.
16 changes: 8 additions & 8 deletions docs/tr2/progress.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions docs/tr2/progress.txt
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ typedef struct __unaligned { // decompiled
int16_t head_rotation;
int16_t neck_rotation;
int16_t maximum_turn;
uint16_t flags;
int16_t flags;
int16_t item_num;
MOOD_TYPE mood;
LOT_INFO lot;
Expand Down Expand Up @@ -3073,7 +3073,7 @@ typedef enum {
0x00417A10 0x00AB +R int16_t __cdecl Effect_MissileFlame(int32_t x, int32_t y, int32_t z, int16_t speed, PHD_ANGLE yrot, int16_t room_num);
0x00417AC0 0x02ED + void __cdecl Dragon_Collision(int16_t item_num, ITEM *lara_item, COLL_INFO *coll);
0x00417DB0 0x00D9 +R void __cdecl Dragon_Bones(int16_t item_num);
0x00417E90 0x0519 -R void __cdecl DragonControl(int16_t back_num);
0x00417E90 0x0519 + void __cdecl Dragon_Control(int16_t back_num);
0x004183E0 0x0114 -R void __cdecl InitialiseBartoli(int16_t item_num);
0x00418500 0x0193 -R void __cdecl BartoliControl(int16_t item_num);
0x004186A0 0x0287 -R void __cdecl DinoControl(int16_t item_num);
Expand Down Expand Up @@ -4693,3 +4693,4 @@ typedef enum {
0x00464590 - const uint16_t g_Requester_SelectionGour2[];
0x004645A8 - const uint16_t g_Requester_UnselectionGour1[];
0x005216E0 - uint16_t g_InvColors[17]; // INV_COLOR_NUMBER_OF
0x00464150 - BITE g_DragonMouth;
2 changes: 1 addition & 1 deletion src/libtrx/include/libtrx/game/creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ typedef struct __PACKING {
int16_t head_rotation;
int16_t neck_rotation;
int16_t maximum_turn;
uint16_t flags;
int16_t flags;
int16_t item_num;
MOOD_TYPE mood;
LOT_INFO lot;
Expand Down
249 changes: 244 additions & 5 deletions src/tr2/game/objects/creatures/dragon.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#include "game/objects/creatures/dragon.h"

#include "decomp/effects.h"
#include "game/creature.h"
#include "game/input.h"
#include "game/lara/control.h"
#include "game/lara/misc.h"
#include "game/lot.h"
#include "game/math.h"
#include "game/random.h"
#include "game/sound.h"
#include "global/funcs.h"
#include "global/vars.h"

Expand All @@ -14,6 +18,15 @@
#define DRAGON_L_COL -512
#define DRAGON_R_COL +512
#define DRAGON_ALMOST_LIVE 100
#define DRAGON_CLOSE_RANGE 9437184
#define DRAGON_STOP_RANGE 37748736
#define DRAGON_TOUCH_DAMAGE 10
#define DRAGON_SWIPE_DAMAGE 250
#define DRAGON_WALK_TURN (PHD_DEGREE * 2) // = 364
#define DRAGON_NEED_TURN (PHD_DEGREE) // = 182
#define DRAGON_TOUCH_L 0x7F000000
#define DRAGON_TOUCH_R 0x000000FE
#define DRAGON_LIVE_TIME 330

typedef enum {
// clang-format off
Expand All @@ -35,14 +48,19 @@ typedef enum {
// clang-format on
} DRAGON_ANIM;

static const BITE m_DragonMouth = {
.pos = { .x = 35, .y = 171, .z = 1168 },
.mesh_num = 12,
};

static void M_MarkDragonDead(const ITEM *dragon_back_item);
static void M_PullDagger(ITEM *lara_item, ITEM *dragon_back_item);
static void M_PushLaraAway(ITEM *lara_item, ITEM *dragon_item, int32_t shift);

static void M_MarkDragonDead(const ITEM *const dragon_back_item)
{
const ITEM *const dragon_front_item =
Item_Get((int16_t)(intptr_t)dragon_back_item->data);
const int16_t dragon_front_item_num = (intptr_t)dragon_back_item->data;
const ITEM *const dragon_front_item = Item_Get(dragon_front_item_num);
CREATURE *const creature = dragon_front_item->data;
creature->flags = -1;
}
Expand Down Expand Up @@ -149,9 +167,9 @@ void __cdecl Dragon_Bones(const int16_t item_num)
return;
}

const ITEM *const dragon_item = &g_Items[item_num];
const ITEM *const dragon_item = Item_Get(item_num);

ITEM *const bone_back = &g_Items[bone_back_item_num];
ITEM *const bone_back = Item_Get(bone_back_item_num);
bone_back->object_id = O_DRAGON_BONES_3;
bone_back->pos.x = dragon_item->pos.x;
bone_back->pos.y = dragon_item->pos.y;
Expand All @@ -163,7 +181,7 @@ void __cdecl Dragon_Bones(const int16_t item_num)
bone_back->shade_1 = -1;
Item_Initialise(bone_back_item_num);

ITEM *const bone_front = &g_Items[bone_front_item_num];
ITEM *const bone_front = Item_Get(bone_front_item_num);
bone_front->object_id = O_DRAGON_BONES_2;
bone_front->pos.x = dragon_item->pos.x;
bone_front->pos.y = dragon_item->pos.y;
Expand All @@ -176,3 +194,224 @@ void __cdecl Dragon_Bones(const int16_t item_num)
Item_Initialise(bone_front_item_num);
bone_front->mesh_bits = ~0xC00000u;
}

void __cdecl Dragon_Control(const int16_t item_num)
{
const int16_t dragon_back_item_num = item_num;
ITEM *const dragon_back_item = Item_Get(item_num);
if (dragon_back_item->object_id == O_DRAGON_FRONT) {
return;
}

const int16_t dragon_front_item_num = (intptr_t)dragon_back_item->data;
ITEM *const dragon_front_item = Item_Get(dragon_front_item_num);
if (!Creature_Activate(dragon_front_item_num)) {
return;
}

int16_t angle = 0;
int16_t head = 0;
CREATURE *const creature = dragon_front_item->data;

if (dragon_front_item->hit_points <= 0) {
if (dragon_front_item->current_anim_state != DRAGON_ANIM_DEATH) {
dragon_front_item->anim_num =
g_Objects[O_DRAGON_FRONT].anim_idx + 21;
dragon_front_item->frame_num =
g_Anims[dragon_front_item->anim_num].frame_base;
dragon_front_item->goal_anim_state = DRAGON_ANIM_DEATH;
dragon_front_item->current_anim_state = DRAGON_ANIM_DEATH;
creature->flags = 0;
} else if (creature->flags >= 0) {
CreateBartoliLight(dragon_front_item_num);
creature->flags++;
if (creature->flags == DRAGON_LIVE_TIME) {
dragon_front_item->goal_anim_state = DRAGON_ANIM_STOP;
}
if (creature->flags >= DRAGON_LIVE_TIME + DRAGON_ALMOST_LIVE) {
dragon_front_item->hit_points =
g_Objects[O_DRAGON_FRONT].hit_points / 2;
}
} else {
if (creature->flags > -20) {
// clang-format off
AddDynamicLight(
dragon_front_item->pos.x,
dragon_front_item->pos.y,
dragon_front_item->pos.z,
((4 * Random_GetDraw()) >> 15) + 12 + creature->flags / 2,
((4 * Random_GetDraw()) >> 15) + 10 + creature->flags / 2);
// clang-format on
}

if (creature->flags == -100) {
Dragon_Bones(dragon_front_item_num);
} else if (creature->flags == -200) {
LOT_DisableBaddieAI(dragon_front_item_num);
Item_Kill(dragon_front_item_num);
dragon_front_item->status = IS_DEACTIVATED;
Item_Kill(dragon_back_item_num);
dragon_back_item->status = IS_DEACTIVATED;
} else if (creature->flags < -100) {
dragon_front_item->pos.y += 10;
dragon_back_item->pos.y += 10;
}

creature->flags--;
return;
}
} else {
AI_INFO info;
Creature_AIInfo(dragon_front_item, &info);
Creature_Mood(dragon_front_item, &info, MOOD_ATTACK);

angle = Creature_Turn(dragon_front_item, DRAGON_WALK_TURN);
const bool is_ahead = info.ahead && info.distance > DRAGON_CLOSE_RANGE
&& info.distance < DRAGON_STOP_RANGE;
if (dragon_front_item->touch_bits) {
g_LaraItem->hit_status = 1;
g_LaraItem->hit_points -= DRAGON_TOUCH_DAMAGE;
}

switch (dragon_front_item->current_anim_state) {
case DRAGON_ANIM_WALK:
creature->flags = 0;
if (is_ahead) {
dragon_front_item->goal_anim_state = DRAGON_ANIM_STOP;
} else if (angle < -DRAGON_NEED_TURN) {
if (info.distance < DRAGON_STOP_RANGE && info.ahead) {
dragon_front_item->goal_anim_state = DRAGON_ANIM_STOP;
} else {
dragon_front_item->goal_anim_state = DRAGON_ANIM_LEFT;
}
} else if (angle > DRAGON_NEED_TURN) {
if (info.distance < DRAGON_STOP_RANGE && info.ahead) {
dragon_front_item->goal_anim_state = DRAGON_ANIM_STOP;
} else {
dragon_front_item->goal_anim_state = DRAGON_ANIM_RIGHT;
}
}
break;

case DRAGON_ANIM_LEFT:
if (angle > -DRAGON_NEED_TURN || is_ahead) {
dragon_front_item->goal_anim_state = DRAGON_ANIM_WALK;
}
break;

case DRAGON_ANIM_RIGHT:
if (angle < DRAGON_NEED_TURN || is_ahead) {
dragon_front_item->goal_anim_state = DRAGON_ANIM_WALK;
}
break;

case DRAGON_ANIM_AIM:
dragon_front_item->rot.y -= angle;
if (info.ahead) {
head = -info.angle;
}

if (is_ahead) {
creature->flags = 30;
dragon_front_item->goal_anim_state = DRAGON_ANIM_FIRE;
} else {
creature->flags = 0;
dragon_front_item->goal_anim_state = DRAGON_ANIM_AIM;
}
break;

case DRAGON_ANIM_FIRE:
dragon_front_item->rot.y -= angle;
if (info.ahead) {
head = -info.angle;
}

Sound_Effect(SFX_DRAGON_FIRE, &dragon_front_item->pos, SPM_NORMAL);

if (creature->flags != 0) {
if (info.ahead) {
Creature_Effect(
dragon_front_item, &m_DragonMouth, Effect_MissileFlame);
}
creature->flags--;
} else {
dragon_front_item->goal_anim_state = DRAGON_ANIM_STOP;
}
break;

case DRAGON_ANIM_STOP:
dragon_front_item->rot.y -= angle;
if (is_ahead) {
dragon_front_item->goal_anim_state = DRAGON_ANIM_AIM;
} else if (info.distance > DRAGON_STOP_RANGE || !info.ahead) {
dragon_front_item->goal_anim_state = DRAGON_ANIM_WALK;
} else if (
info.distance >= DRAGON_CLOSE_RANGE || creature->flags != 0) {
if (info.angle < 0) {
dragon_front_item->goal_anim_state = DRAGON_ANIM_TURN_LEFT;
} else {
dragon_front_item->goal_anim_state = DRAGON_ANIM_TURN_RIGHT;
}
} else {
creature->flags = 1;
if (info.angle < 0) {
dragon_front_item->goal_anim_state = DRAGON_ANIM_SWIPE_LEFT;
} else {
dragon_front_item->goal_anim_state =
DRAGON_ANIM_SWIPE_RIGHT;
}
}
break;

case DRAGON_ANIM_TURN_LEFT:
creature->flags = 0;
dragon_front_item->rot.y += -PHD_DEGREE - angle;
break;

case DRAGON_ANIM_TURN_RIGHT:
creature->flags = 0;
dragon_front_item->rot.y += PHD_DEGREE - angle;
break;

case DRAGON_ANIM_SWIPE_LEFT:
if ((dragon_front_item->touch_bits & DRAGON_TOUCH_L) != 0) {
g_LaraItem->hit_status = 1;
g_LaraItem->hit_points -= DRAGON_SWIPE_DAMAGE;
creature->flags = 0;
}
break;

case DRAGON_ANIM_SWIPE_RIGHT:
if ((dragon_front_item->touch_bits & DRAGON_TOUCH_R) != 0) {
g_LaraItem->hit_status = 1;
g_LaraItem->hit_points -= DRAGON_SWIPE_DAMAGE;
creature->flags = 0;
}
break;

default:
break;
}
}

Creature_Head(dragon_front_item, head);
Creature_Animate(dragon_front_item_num, angle, 0);
dragon_back_item->current_anim_state =
dragon_front_item->current_anim_state;
dragon_back_item->anim_num = dragon_front_item->anim_num
+ g_Objects[O_DRAGON_BACK].anim_idx
- g_Objects[O_DRAGON_FRONT].anim_idx;
dragon_back_item->frame_num = dragon_front_item->frame_num
+ g_Anims[dragon_back_item->anim_num].frame_base
- g_Anims[dragon_front_item->anim_num].frame_base;
dragon_back_item->pos.x = dragon_front_item->pos.x;
dragon_back_item->pos.y = dragon_front_item->pos.y;
dragon_back_item->pos.z = dragon_front_item->pos.z;
dragon_back_item->rot.x = dragon_front_item->rot.x;
dragon_back_item->rot.y = dragon_front_item->rot.y;
dragon_back_item->rot.z = dragon_front_item->rot.z;
if (dragon_back_item->room_num != dragon_front_item->room_num) {
Item_NewRoom(dragon_back_item_num, dragon_front_item->room_num);
}
return;
}
2 changes: 2 additions & 0 deletions src/tr2/game/objects/creatures/dragon.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ void __cdecl Dragon_Collision(
int16_t item_num, ITEM *lara_item, COLL_INFO *coll);

void __cdecl Dragon_Bones(int16_t item_num);

void __cdecl Dragon_Control(int16_t item_num);
1 change: 0 additions & 1 deletion src/tr2/global/funcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#define Tiger_Control ((void __cdecl (*)(int16_t item_num))0x00417510)
#define ControlTwinkle ((void __cdecl (*)(int16_t fx_num))0x004177B0)
#define CreateBartoliLight ((void __cdecl (*)(int16_t item_num))0x00417930)
#define DragonControl ((void __cdecl (*)(int16_t back_num))0x00417E90)
#define InitialiseBartoli ((void __cdecl (*)(int16_t item_num))0x004183E0)
#define BartoliControl ((void __cdecl (*)(int16_t item_num))0x00418500)
#define DinoControl ((void __cdecl (*)(int16_t item_num))0x004186A0)
Expand Down
1 change: 1 addition & 0 deletions src/tr2/global/vars_decomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define g_CineTickRate (*(int32_t*)0x004640B8) // = 0x8000
#define g_CD_TrackID (*(int16_t*)0x004640BC) // = -1
#define g_FlipEffect (*(int32_t*)0x004640C4) // = -1
#define g_DragonMouth (*(BITE*)0x00464150)
#define g_BoxLines (*(int32_t(*)[12][2])0x00464180)
#define g_AssaultBestTime (*(int32_t*)0x004641F0) // = -1
#define g_EffectRoutines (*((void(__cdecl *(*)[32])(ITEM *item))0x004641F8))
Expand Down
Loading

0 comments on commit 3476c57

Please sign in to comment.