
#ifndef ENTITY_H
#define ENTITY_H

#include <stdint.h>
#include <stdlib.h>

#include "core/base_types.h"

struct room_sector_s;
struct obb_s;
struct character_s;
struct ss_animation_s;
struct ss_bone_frame_s;
struct physics_data_s;
struct inventory_node_s;

#define ENTITY_ID_NONE                              (0xFFFFFFFF)

#define ENTITY_STATE_ENABLED                        (0x0001)    // Entity is enabled.
#define ENTITY_STATE_ACTIVE                         (0x0002)    // Entity is animated.
#define ENTITY_STATE_VISIBLE                        (0x0004)    // Entity is visible.
#define ENTITY_STATE_COLLIDABLE                     (0x0008)    // Collisions enabled.
#define ENTITY_STATE_NO_CAM_TARGETABLE              (0x0010)    // Disallow targeting by the camera.
#define ENTITY_STATE_DELETED                        (0x1000)    // Will be deleted on update.

#define ENTITY_TYPE_GENERIC                         (0x0000)    // Just an animating.
#define ENTITY_TYPE_INTERACTIVE                     (0x0001)    // Can respond to other entity's commands.
#define ENTITY_TYPE_TRIGGER_ACTIVATOR               (0x0002)    // Can activate triggers.
#define ENTITY_TYPE_HEAVYTRIGGER_ACTIVATOR          (0x0004)    // Can activate heavy triggers.
#define ENTITY_TYPE_PICKABLE                        (0x0008)    // Can be picked up.
#define ENTITY_TYPE_TRAVERSE                        (0x0010)    // Can be pushed/pulled.
#define ENTITY_TYPE_TRAVERSE_FLOOR                  (0x0020)    // Can be walked upon.
#define ENTITY_TYPE_DYNAMIC                         (0x0040)    // Acts as a physical dynamic object.
#define ENTITY_TYPE_ACTOR                           (0x0080)    // Is actor.

#define ENTITY_TYPE_SPAWNED                         (0x8000)    // Was spawned.

/*
 * SURFACE MOVEMENT DIRECTIONS
 */
#define ENT_STAY 0x00000000
#define ENT_MOVE_FORWARD 0x00000001
#define ENT_MOVE_BACKWARD 0x00000002
#define ENT_MOVE_LEFT 0x00000004
#define ENT_MOVE_RIGHT 0x00000008
#define ENT_MOVE_JUMP 0x00000010
#define ENT_MOVE_CROUCH 0x00000020

//   ====== ANIMATION COMMANDS ======
#define TR_ANIMCOMMAND_SETPOSITION  1
#define TR_ANIMCOMMAND_JUMPDISTANCE 2
#define TR_ANIMCOMMAND_EMPTYHANDS   3
#define TR_ANIMCOMMAND_KILL         4
#define TR_ANIMCOMMAND_PLAYSOUND    5
#define TR_ANIMCOMMAND_PLAYEFFECT   6
#define TR_ANIMCOMMAND_INTERACT     7

//   ====== ANIMATION EFFECTS FLAGS ======
#define TR_ANIMCOMMAND_CONDITION_LAND  0x4000
#define TR_ANIMCOMMAND_CONDITION_WATER 0X8000

//   ====== ANIMATION EFFECTS / FLIPEFFECTS ======
#define TR_EFFECT_CHANGEDIRECTION       0
#define TR_EFFECT_SHAKESCREEN           1
#define TR_EFFECT_PLAYFLOODSOUND        2
#define TR_EFFECT_BUBBLE                3
#define TR_EFFECT_ENDLEVEL              4
#define TR_EFFECT_ACTIVATECAMERA        5
#define TR_EFFECT_ACTIVATEKEY           6
#define TR_EFFECT_ENABLEEARTHQUAKES     7
#define TR_EFFECT_GETCROWBAR            8
#define TR_EFFECT_CURTAINFX             9  // Effect 9 is empty in TR4.
#define TR_EFFECT_PLAYSOUND_TIMERFIELD  10
#define TR_EFFECT_PLAYEXPLOSIONSOUND    11
#define TR_EFFECT_DISABLEGUNS           12
#define TR_EFFECT_ENABLEGUNS            13
#define TR_EFFECT_GETRIGHTGUN           14
#define TR_EFFECT_GETLEFTGUN            15
#define TR_EFFECT_FIRERIGHTGUN          16
#define TR_EFFECT_FIRELEFTGUN           17
#define TR_EFFECT_MESHSWAP1             18
#define TR_EFFECT_MESHSWAP2             19
#define TR_EFFECT_MESHSWAP3             20
#define TR_EFFECT_INV_ON                21 // Effect 21 is unknown at offset 4376F0.
#define TR_EFFECT_INV_OFF               22 // Effect 22 is unknown at offset 437700.
#define TR_EFFECT_HIDEOBJECT            23
#define TR_EFFECT_SHOWOBJECT            24
#define TR_EFFECT_STATUEFX              25 // Effect 25 is empty in TR4.
#define TR_EFFECT_RESETHAIR             26
#define TR_EFFECT_BOILERFX              27 // Effect 27 is empty in TR4.
#define TR_EFFECT_SETFOGCOLOUR          28
#define TR_EFFECT_GHOSTTRAP             29 // Effect 29 is unknown at offset 4372F0
#define TR_EFFECT_LARALOCATION          30
#define TR_EFFECT_CLEARSCARABS          31
#define TR_EFFECT_PLAYSTEPSOUND         32 // Also called FOOTPRINT_FX in TR4 source code.

// Effects 33 - 42 are assigned to FLIP_MAP0-FLIP_MAP9 in TR4 source code,
// but are empty in TR4 binaries.
#define TR_EFFECT_GETWATERSKIN          43
#define TR_EFFECT_REMOVEWATERSKIN       44
#define TR_EFFECT_LARALOCATIONPAD       45
#define TR_EFFECT_KILLALLENEMIES        46

#define ENTITY_CALLBACK_NONE                        (0x00000000)
#define ENTITY_CALLBACK_ACTIVATE                    (0x00000001)
#define ENTITY_CALLBACK_DEACTIVATE                  (0x00000002)
#define ENTITY_CALLBACK_COLLISION                   (0x00000004)
#define ENTITY_CALLBACK_STAND                       (0x00000008)
#define ENTITY_CALLBACK_HIT                         (0x00000010)
#define ENTITY_CALLBACK_ATTACK                      (0x00000020)
#define ENTITY_CALLBACK_SHOOT                       (0x00000040)

#define ENTITY_SUBSTANCE_NONE                     0
#define ENTITY_SUBSTANCE_WATER_SHALLOW            1
#define ENTITY_SUBSTANCE_WATER_WADE               2
#define ENTITY_SUBSTANCE_WATER_SWIM               3
#define ENTITY_SUBSTANCE_QUICKSAND_SHALLOW        4
#define ENTITY_SUBSTANCE_QUICKSAND_CONSUMED       5

#define ENTITY_TLAYOUT_MASK     0x1F    // Activation mask
#define ENTITY_TLAYOUT_EVENT    0x20    // Last trigger event
#define ENTITY_TLAYOUT_LOCK     0x40    // Activity lock
#define ENTITY_TLAYOUT_SSTATUS  0x80    // Sector status


typedef void (*collision_callback_t)(struct entity_s *ent, struct collision_node_s *cn);

// Specific in-game entity structure.

typedef struct activation_point_s
{
    float                               offset[4];       // where we can activate object (dx, dy, dz, r)
    float                               direction[4];    // direction_xyz, cos(lim)
}activation_point_t, *activation_point_p;


typedef struct entity_s
{
    uint32_t                            id;                     // Unique entity ID
    int32_t                             OCB;                    // Object code bit (since TR4)
    
    uint32_t                            trigger_layout : 8;     // Mask + once + event + sector status flags
    uint32_t                            dir_flag : 8;           // (move direction)
    uint32_t                            move_type : 4;          // on floor / free fall / swim ....
    uint32_t                            no_fix_all : 1;         // only setPos and anim command can ignore that
    uint32_t                            no_move : 1;
    uint32_t                            no_anim_pos_autocorrection : 1;
    
    float                               timer;              // Set by "timer" trigger field
    uint32_t                            callback_flags;     // information about scripts callbacks
    uint16_t                            type_flags;
    uint16_t                            state_flags;
    
    float                               linear_speed;
    float                               anim_linear_speed;  // current linear speed from animation info
    float                               speed[3];           // speed of the entity XYZ
    
    uint32_t                            no_fix_skeletal_parts;
    struct ss_bone_frame_s             *bf;                 // current boneframe with full frame information
    struct physics_data_s              *physics;
    struct engine_transform_s           transform;
    
    struct obb_s                       *obb;                // oriented bounding box
    struct engine_container_s          *self;

    struct activation_point_s          *activation_point;
    struct inventory_node_s            *inventory;
    struct character_s                 *character;
}entity_t, *entity_p;


entity_p Entity_Create();
void Entity_InitActivationPoint(entity_p entity);
void Entity_Delete(entity_p entity);
void Entity_Enable(entity_p ent);
void Entity_Disable(entity_p ent);
void Entity_EnableCollision(entity_p ent);
void Entity_DisableCollision(entity_p ent);
void Entity_UpdateRoomPos(entity_p ent);
void Entity_MoveToRoom(entity_p entity, struct room_s *new_room);

void Entity_Frame(entity_p entity, float time);  // process frame + trying to change state

void Entity_RebuildBV(entity_p ent);
void Entity_UpdateTransform(entity_p entity);
int  Entity_CanTrigger(entity_p activator, entity_p trigger);
void Entity_RotateToTriggerZ(entity_p activator, entity_p trigger);
void Entity_RotateToTrigger(entity_p activator, entity_p trigger, int bone_to);
void Entity_CheckActivators(struct entity_s *ent);
int  Entity_Activate(struct entity_s *entity_object, struct entity_s *entity_activator, uint16_t trigger_mask, uint16_t trigger_op, uint16_t trigger_lock, uint16_t trigger_timer);
int  Entity_Deactivate(struct entity_s *entity_object, struct entity_s *entity_activator);

int  Entity_GetSubstanceState(entity_p entity);

void Entity_UpdateRigidBody(struct entity_s *ent, int force);
void Entity_GhostUpdate(struct entity_s *ent);

int  Entity_GetPenetrationFixVector(struct entity_s *ent, collision_callback_t callback, float reaction[3], float ent_move[3], int16_t filter);
int  Entity_CheckNextPenetration(struct entity_s *ent, collision_callback_t callback, float move[3], float reaction[3], int16_t filter);
void Entity_FixPenetrations(struct entity_s *ent, collision_callback_t callback, float move[3], int16_t filter);

void Entity_CheckCollisionCallbacks(entity_p ent);
void Entity_DoAnimCommands(entity_p entity, struct ss_animation_s *ss_anim);
void Entity_DoFlipEffect(entity_p entity, uint16_t effect_id, int16_t param);
void Entity_ProcessSector(entity_p ent);
void Entity_SetAnimation(entity_p entity, int anim_type, int animation, int frame, float new_transform[16] = NULL);
void Entity_MoveToSink(entity_p entity, struct static_camera_sink_s *sink);
void Entity_MoveForward(entity_p ent, float dist);
void Entity_MoveStrafe(entity_p ent, float dist);
void Entity_MoveVertical(entity_p ent, float dist);

#endif
