#include <StdAfx.h>
#include "trex.h"
#include <trng_core.h>
#include "utility.h"
#include "Class/TRClass.h"

extern TYPE_CreatureCollision CreatureCollision;
extern TYPE_InitialiseCreature InitialiseCreature;
extern TYPE_CreatureActive CreatureActive;
extern TYPE_CreatureAnimation CreatureAnimation;
extern TYPE_CreatureAIInfo CreatureAIInfo;
extern TYPE_GetCreatureMood GetCreatureMood;
extern TYPE_CreatureMood CreatureMood;
extern TYPE_CreatureTurn CreatureTurn;
extern TYPE_CreatureEffect CreatureEffect;
extern TYPE_DoBloodSplat DoBloodSplat;
extern TYPE_DrawAnimatingItem DrawAnimatingItem;
extern TYPE_CreatureJoint CreatureJoint;
extern TYPE_DoBloodSplat DoBloodSplat;
extern TYPE_GetRandomControl GetRandomControl;
extern TYPE_CreatureKill CreatureKill;
extern TYPE_GetFloor GetFloor;

#define HP_TREX (100)
#define DINO_RUN_TURN  (ONE_DEGREE*4)
#define DINO_WALK_TURN (ONE_DEGREE*2)
#define DINO_TOUCH (0x3000)
#define DINO_TOUCH_DAMAGE 1
#define DINO_TRAMPLE_DAMAGE 10
#define DINO_BITE_DAMAGE 10000
#define DINO_ROAR_CHANCE 0x200
#define DINO_RUN_RANGE SQUARE(WALL_L*5)
#define DINO_ATTACK_RANGE SQUARE(WALL_L*4)
#define DINO_BITE_RANGE SQUARE(1500)
#define DINO_HIT_RADIUS SQUARE(WALL_L*2/3)

static BITE_INFO TrexBite = { 0, 32, 64, 13 };

enum DINO_STATE {
    ST_DINO_EMPTY1,
    ST_DINO_STOP,
    ST_DINO_WALK,
    ST_DINO_RUN,
    ST_DINO_EMPTY2,
    ST_DINO_DEATH,
    ST_DINO_ROAR,
    ST_DINO_ATTACK2,
    ST_DINO_KILL
};

void CtrlTR2_TRex(short item_number)
{
    if (!CreatureActive(item_number))
        return;

    ITEM_INFO* item;
    CREATURE_INFO* dino;
    AI_INFO info;
    short angle, head;
    short dmg1, dmg2, anim;

    item = &Ptr_VetItems[item_number];
    dino = (CREATURE_INFO*)item->data;
    angle = 0; head = 0;
    dmg1 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG1);
    dmg2 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG2);
    anim = Utils.getObjectProperty(tsu_slots[item->object_number], PTY_ANIM);

    if (item->hit_points <= 0)
    {
        if (item->current_anim_state == ST_DINO_STOP)
            item->goal_anim_state = ST_DINO_DEATH;
        else
            item->goal_anim_state = ST_DINO_STOP;
    }
    else
    {
        CreatureAIInfo(item, &info);

        // rotate the head to lara.
        if (info.ahead)
            head = info.angle;

        GetCreatureMood(item, &info, VIOLENT);
        CreatureMood(item, &info, VIOLENT);

        angle = CreatureTurn(item, dino->maximum_turn);

        /* An enemy touching the dino takes damage just from that */
        if (item->touch_bits)
            LaraItem->hit_points -= DOUBLE_VALUE_ANIM(item->current_anim_state, ST_DINO_RUN, DOUBLE_VALUE_ITEM(dmg2, DINO_TRAMPLE_DAMAGE), DOUBLE_VALUE_ITEM(dmg1, DINO_TOUCH_DAMAGE));

        /* Flag if enemy behind and facing us - stop and turn else they can chase in rings */
        dino->flags = (dino->mood != MOOD_ESCAPE && !info.ahead && info.enemy_facing > -FRONT_ARC && info.enemy_facing < FRONT_ARC);

        /* Flag if enemy is close ahead - walk to bite range */
        if (!dino->flags && info.distance > DINO_BITE_RANGE && info.distance < DINO_ATTACK_RANGE && info.bite)
            dino->flags = 1;

        switch (item->current_anim_state)
        {
            case ST_DINO_STOP:
                dino->maximum_turn = 0;

                if (item->required_anim_state)
                {
                    item->goal_anim_state = item->required_anim_state;
                }
                else if (info.distance < DINO_BITE_RANGE && info.bite)
                {
                    item->goal_anim_state = ST_DINO_ATTACK2;
                }
                else if (dino->mood == MOOD_BORED || dino->flags)
                {
                    item->goal_anim_state = ST_DINO_WALK;
                }
                else
                {
                    item->goal_anim_state = ST_DINO_RUN;
                }
                break;
            case ST_DINO_WALK:
                dino->maximum_turn = DINO_WALK_TURN;

                if (dino->mood == MOOD_BORED || dino->flags)
                {
                    if (info.ahead && GetRandomControl() < DINO_ROAR_CHANCE)
                    {
                        item->required_anim_state = ST_DINO_ROAR;
                        item->goal_anim_state = ST_DINO_STOP;
                    }
                }
                else
                {
                    item->goal_anim_state = ST_DINO_STOP;
                }
                break;
            case ST_DINO_RUN:
                dino->maximum_turn = DINO_RUN_TURN;

                if (info.distance < DINO_RUN_RANGE && info.bite)
                {
                    item->goal_anim_state = ST_DINO_STOP;
                }
                else if (dino->flags)
                {
                    item->goal_anim_state = ST_DINO_STOP;
                }
                else if (dino->mood != MOOD_ESCAPE && info.ahead && GetRandomControl() < DINO_ROAR_CHANCE)
                {
                    item->required_anim_state = ST_DINO_ROAR;
                    item->goal_anim_state = ST_DINO_STOP;
                }
                else if (dino->mood == MOOD_BORED)
                {
                    item->goal_anim_state = ST_DINO_STOP;
                }
                break;
            case ST_DINO_ATTACK2:
                if (item->touch_bits & DINO_TOUCH)
                {
                    LaraItem->hit_points -= DINO_BITE_DAMAGE;
                    LaraItem->hit_status = 1;
                    if (anim != NO_ITEM)
                    {
                        dino->maximum_turn = 0;
                        CreatureKill(item, 11, ST_DINO_KILL, anim);
						tsu_killer = tsu_slots[item->object_number];
                        return;
                    }
                }

                item->required_anim_state = ST_DINO_WALK;
                break;
        }
    }

    CreatureJoint(item, 0, head / 2);
	if (MapToFirst(tsu_slots[item->object_number], SLOTS_NUMBER) == TR1_TYRANNOSAUR1)
		CreatureJoint(item, 1, head / 2);
    CreatureAnimation(item_number, angle, 0);
}

void InitialiseTR1_TRex()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        tomb[TR1_TYRANNOSAUR1 + index].set_name("TRex1");
        tomb[TR1_TYRANNOSAUR1 + index].initialise(TR1_TYRANNOSAUR1 + index, FUNCTION_ZONE_BEFORE | FUNCTION_SHADOW, QUERY_KILLER);
        tomb[TR1_TYRANNOSAUR1 + index].set_shadow_size(128);
        tomb[TR1_TYRANNOSAUR1 + index].set_func_initialise(InitialiseCreature);
        tomb[TR1_TYRANNOSAUR1 + index].set_func_collide(CreatureCollision);
        tomb[TR1_TYRANNOSAUR1 + index].set_func_control(CtrlTR2_TRex);
        tomb[TR1_TYRANNOSAUR1 + index].set_func_draw(DrawAnimatingItemCustom, NULL);
        tomb[TR1_TYRANNOSAUR1 + index].set_health(HP_TREX);
        tomb[TR1_TYRANNOSAUR1 + index].set_radius_and_pivot(341, 2000);
        tomb[TR1_TYRANNOSAUR1 + index].set_hit_effect(HIT_BLOOD);
        tomb[TR1_TYRANNOSAUR1 + index].set_creature(TRUE);
        tomb[TR1_TYRANNOSAUR1 + index].set_rotation_meshtree(10, ROT_Y);
        tomb[TR1_TYRANNOSAUR1 + index].set_rotation_meshtree(11, ROT_Y);
        tomb[TR1_TYRANNOSAUR1 + index].set_save(TRUE, TRUE, TRUE, FALSE, TRUE);
    }
}

void InitialiseTR2_TRex()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        tomb[TR2_TYRANNOSAUR1 + index].set_name("TRex");
        tomb[TR2_TYRANNOSAUR1 + index].initialise(TR2_TYRANNOSAUR1 + index, FUNCTION_ZONE_BEFORE | FUNCTION_SHADOW, QUERY_KILLER);
        tomb[TR2_TYRANNOSAUR1 + index].set_shadow_size(64);
        tomb[TR2_TYRANNOSAUR1 + index].set_func_initialise(InitialiseCreature);
        tomb[TR2_TYRANNOSAUR1 + index].set_func_collide(CreatureCollision);
        tomb[TR2_TYRANNOSAUR1 + index].set_func_control(CtrlTR2_TRex);
        tomb[TR2_TYRANNOSAUR1 + index].set_func_draw(DrawAnimatingItemCustom, NULL);
        tomb[TR2_TYRANNOSAUR1 + index].set_health(HP_TREX);
        tomb[TR2_TYRANNOSAUR1 + index].set_radius_and_pivot(341, 1800);
        tomb[TR2_TYRANNOSAUR1 + index].set_hit_effect(HIT_BLOOD);
        tomb[TR2_TYRANNOSAUR1 + index].set_creature(TRUE);
        tomb[TR2_TYRANNOSAUR1 + index].set_rotation_meshtree(10, ROT_Y);
        tomb[TR2_TYRANNOSAUR1 + index].set_save(TRUE, TRUE, TRUE, FALSE, TRUE);
    }
}