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

extern TYPE_InitialiseCreature InitialiseCreature;
extern TYPE_CreatureActive CreatureActive;
extern TYPE_CreatureAIInfo CreatureAIInfo;
extern TYPE_GetCreatureMood GetCreatureMood;
extern TYPE_CreatureMood CreatureMood;
extern TYPE_CreatureTurn CreatureTurn;
extern TYPE_CreatureTilt CreatureTilt;
extern TYPE_CreatureJoint CreatureJoint;
extern TYPE_CreatureAnimation CreatureAnimation;
extern TYPE_GetRandomControl GetRandomControl;
extern TYPE_CreatureEffect CreatureEffect;
extern TYPE2_DoBloodSplat DoBloodSplat_2;
extern TYPE_CreatureCollision CreatureCollision;
extern TYPE_DrawAnimatingItem DrawAnimatingItem;
extern TYPE_CreatureVault CreatureVault;
extern TYPE_CreatureKill CreatureKill;

static BITE_INFO yeti_biteL = { 12, 101, 19, 13 };
static BITE_INFO yeti_biteR = { 12, 101, 19, 10 };

#define HP_YETI (30)
#define YETI_PUNCH_DAMAGE  (100)
#define YETI_THUMP_DAMAGE  (150)
#define YETI_CHARGE_DAMAGE (200)
#define YETI_WAIT 19
#define YETI_KILL 14
#define YETI_DIE_ANIM 31
#define YETI_CLIMB1_ANIM 34
#define YETI_CLIMB2_ANIM 33
#define YETI_CLIMB3_ANIM 32
#define YETI_FALL3_ANIM 35
#define YETI_KILL_ANIM 36
#define YETI_WALK_TURN (ONE_DEGREE*4)
#define YETI_RUN_TURN  (ONE_DEGREE*6)
#define YETI_WAIT1_CHANCE 0x100
#define YETI_WAIT2_CHANCE (YETI_WAIT1_CHANCE + 0x100)
#define YETI_WALK_CHANCE  (YETI_WAIT2_CHANCE + 0x100)
#define YETI_STOP_ROAR_CHANCE 0x200
#define YETI_ATTACK1_RANGE SQUARE(WALL_L/2)       // stand: left or right
#define YETI_ATTACK1_ANGLE (ONE_DEGREE*60)
#define YETI_ATTACK2_RANGE SQUARE(STEP_L)         // stand: dual hand
#define YETI_ATTACK3_RANGE SQUARE(WALL_L*2)       // run: left or right
#define YETI_CLOSE_RANGE SQUARE(WALL_L*5/4)
#define YETI_STOP_ANGLE (ONE_DEGREE*45)
#define YETI_RUN_RANGE SQUARE(WALL_L*2)
#define YETI_TOUCHR 0x0700
#define YETI_TOUCHL 0x3800
#define YETI_TOUCH_DOUBLE (YETI_TOUCHR | YETI_TOUCHL)
#define YETI_VAULT_SHIFT 300

enum YETI_STATE {
    ST_YETI_EMPTY,
    ST_YETI_RUN,
    ST_YETI_STOP,
    ST_YETI_WALK,
    ST_YETI_ATTACK1,
    ST_YETI_ATTACK2,
    ST_YETI_ATTACK3,
    ST_YETI_WAIT1,
    ST_YETI_DEATH,
    ST_YETI_WAIT2,
    ST_YETI_CLIMB1,
    ST_YETI_CLIMB2,
    ST_YETI_CLIMB3,
    ST_YETI_FALL3,
    ST_YETI_KILL
};

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

    ITEM_INFO* item;
    CREATURE_INFO* yeti;
    AI_INFO info;
    short angle, torso, head;
    int random;
    int lara_alive;
    short dmg1, dmg2, dmg3, anim;

    item = &Ptr_VetItems[item_number];
    yeti = (CREATURE_INFO*)item->data;
    angle = torso = head = 0;
    lara_alive = (LaraItem->hit_points > 0);
    dmg1 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG1);
    dmg2 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG2);
    dmg3 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG3);
    anim = Utils.getObjectProperty(tsu_slots[item->object_number], PTY_ANIM);

    if (item->hit_points <= 0)
    {
        if (item->current_anim_state != ST_YETI_DEATH)
        {
            item->anim_number = Ptr_VetObjects[item->object_number].anim_index + YETI_DIE_ANIM;
            item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
            item->current_anim_state = ST_YETI_DEATH;
        }
    }
    else
    {
        CreatureAIInfo(item, &info);
        GetCreatureMood(item, &info, VIOLENT);
        CreatureMood(item, &info, VIOLENT);
        angle = CreatureTurn(item, yeti->maximum_turn);

        switch (item->current_anim_state)
        {
            case ST_YETI_STOP:
                if (info.ahead)
                    head = info.angle;

                yeti->flags = 0;
                yeti->maximum_turn = 0;

                if (yeti->mood == MOOD_ESCAPE)
                {
                    item->goal_anim_state = ST_YETI_RUN;
                }
                else if (item->required_anim_state)
                {
                    item->goal_anim_state = item->required_anim_state;
                }
                else if (yeti->mood == MOOD_BORED)
                {
                    random = GetRandomControl();
                    if (random < YETI_WAIT1_CHANCE || !lara_alive)
                        item->goal_anim_state = ST_YETI_WAIT1;
                    else if (random < YETI_WAIT2_CHANCE)
                        item->goal_anim_state = ST_YETI_WAIT2;
                    else if (random < YETI_WALK_CHANCE)
                        item->goal_anim_state = ST_YETI_WALK;
                }
                else if (info.ahead && info.distance < YETI_ATTACK2_RANGE)
                {
                    item->goal_anim_state = ST_YETI_ATTACK2;
                }
                else if (info.ahead && info.distance < YETI_ATTACK1_RANGE && ABS(info.angle) < YETI_ATTACK1_ANGLE)
                {
                    item->goal_anim_state = ST_YETI_ATTACK1;
                }
                else if (yeti->mood == MOOD_STALK)
                {
                    item->goal_anim_state = ST_YETI_WALK;
                }
                else
                {
                    item->goal_anim_state = ST_YETI_RUN;
                }
                break;
            case ST_YETI_WAIT1:
                if (info.ahead)
                    head = info.angle;

                if (yeti->mood == MOOD_ESCAPE || item->hit_status)
                {
                    item->goal_anim_state = ST_YETI_STOP;
                }
                else if (yeti->mood == MOOD_BORED)
                {
                    if (lara_alive)
                    {
                        random = GetRandomControl();
                        if (random < YETI_WAIT1_CHANCE)
                        {
                            item->goal_anim_state = ST_YETI_STOP;
                        }
                        else if (random < YETI_WAIT2_CHANCE)
                        {
                            item->goal_anim_state = ST_YETI_WAIT2;
                        }
                        else if (random < YETI_WALK_CHANCE)
                        {
                            item->goal_anim_state = ST_YETI_STOP;
                            item->required_anim_state = ST_YETI_WALK;
                        }
                    }
                }
                else if (GetRandomControl() < YETI_STOP_ROAR_CHANCE)
                {
                    item->goal_anim_state = ST_YETI_STOP;
                }
                break;
            case ST_YETI_WAIT2:
                if (info.ahead)
                    head = info.angle;

                if (yeti->mood == MOOD_ESCAPE || item->hit_status)
                {
                    item->goal_anim_state = ST_YETI_STOP;
                }
                else if (yeti->mood == MOOD_BORED)
                {
                    random = GetRandomControl();
                    if (random < YETI_WAIT1_CHANCE || !lara_alive)
                    {
                        item->goal_anim_state = ST_YETI_WAIT1;
                    }
                    else if (random < YETI_WAIT2_CHANCE)
                    {
                        item->goal_anim_state = ST_YETI_STOP;
                    }
                    else if (random < YETI_WALK_CHANCE)
                    {
                        item->goal_anim_state = ST_YETI_STOP;
                        item->required_anim_state = ST_YETI_WALK;
                    }
                }
                else if (GetRandomControl() < YETI_STOP_ROAR_CHANCE)
                {
                    item->goal_anim_state = ST_YETI_STOP;
                }
                break;
            case ST_YETI_WALK:
                if (info.ahead)
                    head = info.angle;

                yeti->maximum_turn = YETI_WALK_TURN;

                if (yeti->mood == MOOD_ESCAPE)
                {
                    item->goal_anim_state = ST_YETI_RUN;
                }
                else if (yeti->mood == MOOD_BORED)
                {
                    random = GetRandomControl();
                    if (random < YETI_WAIT1_CHANCE || !lara_alive)
                    {
                        item->goal_anim_state = ST_YETI_STOP;
                        item->required_anim_state = ST_YETI_WAIT1;
                    }
                    else if (random < YETI_WAIT2_CHANCE)
                    {
                        item->goal_anim_state = ST_YETI_STOP;
                        item->required_anim_state = ST_YETI_WAIT2;
                    }
                    else if (random < YETI_WALK_CHANCE)
                    {
                        item->goal_anim_state = ST_YETI_STOP;
                    }
                }
                else if (yeti->mood == MOOD_ATTACK)
                {
                    if (info.ahead && info.distance < YETI_CLOSE_RANGE)
                        item->goal_anim_state = ST_YETI_STOP;
                    else if (info.distance > YETI_RUN_RANGE)
                        item->goal_anim_state = ST_YETI_RUN;
                }
                break;
            case ST_YETI_RUN:
                if (info.ahead)
                    head = info.angle;

                yeti->flags = 0;
                yeti->maximum_turn = YETI_RUN_TURN;

                if (yeti->mood == MOOD_ESCAPE)
                {
                    break;
                }
                else if (yeti->mood == MOOD_BORED)
                {
                    item->goal_anim_state = ST_YETI_WALK;
                }
                else if (info.ahead && info.distance < YETI_CLOSE_RANGE && ABS(info.angle) < YETI_STOP_ANGLE)
                {
                    item->goal_anim_state = ST_YETI_STOP;
                }
                else if (info.ahead && info.distance < YETI_ATTACK3_RANGE)
                {
                    item->goal_anim_state = ST_YETI_ATTACK3;
                }
                else if (yeti->mood == MOOD_STALK)
                {
                    item->goal_anim_state = ST_YETI_WALK;
                }
                break;
            case ST_YETI_ATTACK1:
                if (info.ahead)
                    torso = info.angle;

                if (!yeti->flags && (item->touch_bits & YETI_TOUCHR))
                {
                    CreatureEffect(item, &yeti_biteR, DoBloodSplat_2);
                    LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg1, YETI_PUNCH_DAMAGE);
                    LaraItem->hit_status = 1;

                    yeti->flags = 1;
                }
                break;
            case ST_YETI_ATTACK2:
                if (info.ahead)
                    torso = info.angle;
                yeti->maximum_turn = YETI_WALK_TURN;

                if (!yeti->flags && (item->touch_bits & YETI_TOUCH_DOUBLE))
                {
                    if (item->touch_bits & YETI_TOUCHL)
                        CreatureEffect(item, &yeti_biteL, DoBloodSplat_2);
                    if (item->touch_bits & YETI_TOUCHR)
                        CreatureEffect(item, &yeti_biteR, DoBloodSplat_2);

                    LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg2, YETI_THUMP_DAMAGE);
                    LaraItem->hit_status = 1;

                    yeti->flags = 1;
                }
                break;
            case ST_YETI_ATTACK3:
                if (info.ahead)
                    torso = info.angle;

                if (!yeti->flags && (item->touch_bits & YETI_TOUCH_DOUBLE))
                {
                    if (item->touch_bits & YETI_TOUCHL)
                        CreatureEffect(item, &yeti_biteL, DoBloodSplat_2);
                    if (item->touch_bits & YETI_TOUCHR)
                        CreatureEffect(item, &yeti_biteR, DoBloodSplat_2);

                    LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg3, YETI_CHARGE_DAMAGE);
                    LaraItem->hit_status = 1;

                    yeti->flags = 1;
                }
                break;
        }
    }

    // if lara dead, play special kill anim:
    if (lara_alive && LaraItem->hit_points <= 0 && anim != NO_ITEM)
    {
        yeti->maximum_turn = 0;
        CreatureKill(item, YETI_KILL_ANIM, YETI_KILL, anim);
		tsu_killer = tsu_slots[item->object_number];
        return;
    }

    CreatureJoint(item, 0, torso);
    CreatureJoint(item, 1, head);

    /* Yeti can climb over blocks; nothing can stop him! */
    if (item->current_anim_state < ST_YETI_CLIMB1)
    {
        switch (CreatureVault(item_number, angle, 0, YETI_VAULT_SHIFT))
        {
            case 2:
                /* Half block jump */
                item->anim_number = Ptr_VetObjects[item->object_number].anim_index + YETI_CLIMB1_ANIM;
                item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
                item->current_anim_state = ST_YETI_CLIMB1;
                yeti->maximum_turn = 0;
                break;
            case 3:
                /* 3/4 block jump */
                item->anim_number = Ptr_VetObjects[item->object_number].anim_index + YETI_CLIMB2_ANIM;
                item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
                item->current_anim_state = ST_YETI_CLIMB2;
                yeti->maximum_turn = 0;
                break;
            case 4:
                /* Full block jump */
                item->anim_number = Ptr_VetObjects[item->object_number].anim_index + YETI_CLIMB3_ANIM;
                item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
                item->current_anim_state = ST_YETI_CLIMB3;
                yeti->maximum_turn = 0;
                break;
            case -4:
                /* Full block fall */
                item->anim_number = Ptr_VetObjects[item->object_number].anim_index + YETI_FALL3_ANIM;
                item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
                item->current_anim_state = ST_YETI_FALL3;
                yeti->maximum_turn = 0;
                break;
        }
    }
    else
    {
        CreatureAnimation(item_number, angle, 0);
    }
}

void InitTR2_Yeti(short ItemIndex)
{
    InitialiseCreature(ItemIndex);
}

void InitialiseTR2_Yeti()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        tomb[TR2_YETI1 + index].set_name("Yeti");
        tomb[TR2_YETI1 + index].initialise(TR2_YETI1 + index, FUNCTION_ZONE_BEFORE | FUNCTION_SHADOW, QUERY_KILLER | QUERY_VAULT);
        tomb[TR2_YETI1 + index].set_shadow_size(128);
        tomb[TR2_YETI1 + index].set_func_initialise(InitTR2_Yeti);
        tomb[TR2_YETI1 + index].set_func_collide(CreatureCollision);
        tomb[TR2_YETI1 + index].set_func_control(CtrlTR2_Yeti);
        tomb[TR2_YETI1 + index].set_func_draw(DrawAnimatingItemCustom, NULL);
        tomb[TR2_YETI1 + index].set_health(HP_YETI);
        tomb[TR2_YETI1 + index].set_radius_and_pivot(128, 100);
        tomb[TR2_YETI1 + index].set_hit_effect(HIT_BLOOD);
        tomb[TR2_YETI1 + index].set_creature(TRUE);
        tomb[TR2_YETI1 + index].set_rotation_meshtree(6, ROT_Y);
        tomb[TR2_YETI1 + index].set_rotation_meshtree(14, ROT_Y);
        tomb[TR2_YETI1 + index].set_save(TRUE, TRUE, TRUE, FALSE, TRUE);
    }
}