#include <StdAfx.h>
#include "monk.h"
#include <trng_core.h>
#include "utility.h"
#include "Class/TRLara.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_CreatureTilt CreatureTilt;
extern TYPE_CreatureJoint CreatureJoint;
extern TYPE2_DoBloodSplat DoBloodSplat_2;
extern TYPE_DrawAnimatingItem DrawAnimatingItem;
extern TYPE_GetRandomControl GetRandomControl;
extern TYPE_GetAITarget GetAITarget;
extern TYPE_phd_atan phd_atan;
extern TYPE2_GetBoundsAccurate GetBoundsAccurate_2;
extern TYPE_SoundEffect SoundEffect;

#define HP_MONK (30)
#define MONK_WALK_TURN (ONE_DEGREE*3)
#define MONK_RUN_TURN (ONE_DEGREE*4)
#define MONK_CLOSE_RANGE SQUARE(WALL_L/2)
#define MONK_LONG_RANGE SQUARE(WALL_L)
#define MONK_ATTACK5_RANGE SQUARE(WALL_L*3)
#define MONK_WALK_RANGE SQUARE(WALL_L*2)
#define MONK_HIT_RANGE (STEP_L*2)
#define MONK_TOUCH (0x4000)
#define MONK_DIE_ANIM (20)
#define OCB_MONK_NORMAL (0x1)
#define OCB_MONK_AGRESSIVE (0x2)
#define MONK_BIFF_DAMAGE (150)
#define MONK_BIFF_ENEMY_DAMAGE (5)

static BITE_INFO monk_hit = { -23, 16, 265, 14 };

enum MONK_STATE {
    ST_MONK_EMPTY,
    ST_MONK_WAIT1,
    ST_MONK_WALK,
    ST_MONK_RUN,
    ST_MONK_ATTACK1,
    ST_MONK_ATTACK2,
    ST_MONK_ATTACK3,
    ST_MONK_ATTACK4,
    ST_MONK_AIM3,
    ST_MONK_DEATH,
    ST_MONK_ATTACK5,
    ST_MONK_WAIT2
};

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

    ITEM_INFO* item, *enemy;
    CREATURE_INFO* monk;
    AI_INFO info;
    short angle, torso_y, torso_x, tilt;
    int random;
    short dmg1, dmg2, dmg3, dmg4, dmg5, dmg, snd1, snd2, snd3, snd4, snd5, snd;

    item = &Ptr_VetItems[item_number];
    monk = (CREATURE_INFO*)item->data;
    angle = torso_y = torso_x = tilt = 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);
    dmg4 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG4);
    dmg5 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG5);
    snd1 = Utils.getObjectProperty(tsu_slots[item->object_number], PTY_SND1);
    snd2 = Utils.getObjectProperty(tsu_slots[item->object_number], PTY_SND2);
    snd3 = Utils.getObjectProperty(tsu_slots[item->object_number], PTY_SND3);
    snd4 = Utils.getObjectProperty(tsu_slots[item->object_number], PTY_SND4);
    snd5 = Utils.getObjectProperty(tsu_slots[item->object_number], PTY_SND5);
    random = GetRandomControl();

    if (item->hit_points <= 0)
    {
        if (item->current_anim_state != ST_MONK_DEATH)
        {
            item->anim_number = Ptr_VetObjects[item->object_number].anim_index + MONK_DIE_ANIM + (GetRandomControl() / 0x4000);
            item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
            item->current_anim_state = ST_MONK_DEATH;
        }
    }
    else
    {
        if (monk->hurt_by_lara)
        {
            mydata.save.current.monks_attack_lara = 1;
        }
        GetBaddieTarget(item_number, true);

        CreatureAIInfo(item, &info);

        if (!mydata.save.current.monks_attack_lara && monk->enemy == LaraItem)
            monk->enemy = NULL;

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

        if (info.ahead)
            torso_y = info.angle;

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

        switch (item->current_anim_state)
        {
            case ST_MONK_WAIT1:
                monk->flags &= 0x0FFF;

                if (!mydata.save.current.monks_attack_lara && info.ahead && Lara.getTarget() == item)
                    break;

                if (monk->mood == MOOD_BORED)
                    item->goal_anim_state = ST_MONK_WALK;
                else if (monk->mood == MOOD_ESCAPE)
                    item->goal_anim_state = ST_MONK_RUN;
                else if (info.ahead && info.distance < MONK_CLOSE_RANGE)
                {
                    if (GetRandomControl() < 0x7000)
                        item->goal_anim_state = ST_MONK_ATTACK1;
                    else
                        item->goal_anim_state = ST_MONK_WAIT2;
                }
                else if (info.ahead && info.distance < MONK_LONG_RANGE)
                    item->goal_anim_state = ST_MONK_ATTACK4;
                else if (info.ahead && info.distance < MONK_WALK_RANGE)
                    item->goal_anim_state = ST_MONK_WALK;
                else
                    item->goal_anim_state = ST_MONK_RUN;

                break;
            case ST_MONK_WAIT2:
                monk->flags &= 0x0FFF;
                monk->maximum_turn = 0;

                if (!mydata.save.current.monks_attack_lara && info.ahead && Lara.getTarget() == item)
                    break;
                
                if (monk->mood == MOOD_BORED)
                    item->goal_anim_state = ST_MONK_WALK;
                else if (monk->mood == MOOD_ESCAPE)
                    item->goal_anim_state = ST_MONK_RUN;
                else if (info.ahead && info.distance < MONK_CLOSE_RANGE)
                {
                    if (random < 0x3000)
                        item->goal_anim_state = ST_MONK_ATTACK2;
                    else if (random < 0x6000)
                        item->goal_anim_state = ST_MONK_AIM3;
                    else
                        item->goal_anim_state = ST_MONK_WAIT1;
                }
                else if (info.ahead && info.distance < MONK_WALK_RANGE)
                    item->goal_anim_state = ST_MONK_WALK;
                else
                    item->goal_anim_state = ST_MONK_RUN;
                break;

            case ST_MONK_WALK:
                monk->maximum_turn = MONK_WALK_TURN;

                if (monk->mood == MOOD_BORED)
                {
                    if (!mydata.save.current.monks_attack_lara && info.ahead && Lara.getTarget() == item)
                    {
                        if (GetRandomControl() < 0x4000)
                            item->goal_anim_state = ST_MONK_WAIT1;
                        else
                            item->goal_anim_state = ST_MONK_WAIT2;
                    }
                }
                else if (monk->mood == MOOD_ESCAPE)
                    item->goal_anim_state = ST_MONK_RUN;
                else if (info.ahead && info.distance < MONK_CLOSE_RANGE)
                {
                    if (GetRandomControl() < 0x4000)
                        item->goal_anim_state = ST_MONK_WAIT1;
                    else
                        item->goal_anim_state = ST_MONK_WAIT2;
                }
                else if (!info.ahead || info.distance > MONK_WALK_RANGE)
                    item->goal_anim_state = ST_MONK_RUN;
                break;
            case ST_MONK_RUN:
                monk->flags &= 0x0FFF;
                monk->maximum_turn = MONK_RUN_TURN;
                if (mydata.save.current.monks_attack_lara)
                    monk->maximum_turn += ONE_DEGREE;
                tilt = (angle >> 2);

                if (monk->mood == MOOD_BORED)
                    item->goal_anim_state = ST_MONK_WAIT1;
                else if (monk->mood != MOOD_ESCAPE)
                {
                    if (info.ahead && info.distance < MONK_CLOSE_RANGE)
                    {
                        if (GetRandomControl() < 0x4000)
                            item->goal_anim_state = ST_MONK_WAIT1;
                        else
                            item->goal_anim_state = ST_MONK_WAIT2;
                    }
                    else if (info.ahead && info.distance < MONK_ATTACK5_RANGE)
                        item->goal_anim_state = ST_MONK_ATTACK5;
                    else if (info.ahead && info.distance < MONK_WALK_RANGE)
                    {
                        if (GetRandomControl() < 0x4000)
                            item->goal_anim_state = ST_MONK_WAIT1;
                        else
                            item->goal_anim_state = ST_MONK_WAIT2;
                    }
                }
                break;

            case ST_MONK_AIM3:
                if (!info.ahead || info.distance > MONK_CLOSE_RANGE)
                    item->goal_anim_state = ST_MONK_WAIT2;
                else
                    item->goal_anim_state = ST_MONK_ATTACK3;
                break;

            case ST_MONK_ATTACK1:
            case ST_MONK_ATTACK2:
            case ST_MONK_ATTACK3:
            case ST_MONK_ATTACK4:
            case ST_MONK_ATTACK5:
                enemy = monk->enemy;

				if (item->current_anim_state == ST_MONK_ATTACK1)
                {
					dmg = dmg1;
					snd = snd1;
                }
				else if (item->current_anim_state == ST_MONK_ATTACK2)
                {
					dmg = dmg2;
					snd = snd2;
                }
				else if (item->current_anim_state == ST_MONK_ATTACK3)
                {
					dmg = dmg3;
					snd = snd3;
                }
				else if (item->current_anim_state == ST_MONK_ATTACK4)
                {
					dmg = dmg4;
					snd = snd4;
                }
				else
                {
					dmg = dmg5;
					snd = snd5;
                }

				if (enemy == LaraItem)
                {
                    if (!(monk->flags & 0xF000) && (item->touch_bits & MONK_TOUCH))
                    {
                        LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg, MONK_BIFF_DAMAGE);
                        LaraItem->hit_status = 1;

                        monk->flags |= 0x1000;
                        if (snd != NO_ITEM)
                            SoundEffect(snd, &item->pos, 0);
                        CreatureEffect(item, &monk_hit, DoBloodSplat_2);
                    }
                }
                else
                {
                    if (!(monk->flags & 0xF000) && enemy)
                    {
                        if ((ABS(enemy->pos.x_pos - item->pos.x_pos) < MONK_HIT_RANGE) &&
                            (ABS(enemy->pos.y_pos - item->pos.y_pos) < MONK_HIT_RANGE) &&
                            (ABS(enemy->pos.z_pos - item->pos.z_pos) < MONK_HIT_RANGE))
                        {
							if (dmg != NO_ITEM)
								dmg /= 30;
                            enemy->hit_points -= DOUBLE_VALUE_ITEM(dmg, MONK_BIFF_ENEMY_DAMAGE);
                            enemy->hit_status = 1;

                            monk->flags |= 0x1000;
                            if (snd != NO_ITEM)
                                SoundEffect(snd, &item->pos, 0);
                        }
                    }
                }
                break;
        }
    }

    CreatureTilt(item, tilt);
    CreatureJoint(item, 0, torso_y);
    CreatureAnimation(item_number, angle, 0);
}

void InitTR2_Monk(short item_number)
{
    InitialiseCreature(item_number);
}

void InitialiseTR2_Monk1()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        tomb[TR2_MONK1 + index].set_name("Monk 1");
        tomb[TR2_MONK1 + index].initialise(TR2_MONK1 + index, FUNCTION_SHADOW, 0);
        tomb[TR2_MONK1 + index].set_shadow_size(128);
        tomb[TR2_MONK1 + index].set_func_initialise(InitTR2_Monk);
        tomb[TR2_MONK1 + index].set_func_collide(CreatureCollision);
        tomb[TR2_MONK1 + index].set_func_control(CtrlTR2_Monk);
        tomb[TR2_MONK1 + index].set_func_draw(DrawAnimatingItemCustom, NULL);
        tomb[TR2_MONK1 + index].set_health(HP_MONK);
        tomb[TR2_MONK1 + index].set_radius_and_pivot(102, 0);
        tomb[TR2_MONK1 + index].set_hit_effect(HIT_BLOOD);
        tomb[TR2_MONK1 + index].set_creature(TRUE);
        tomb[TR2_MONK1 + index].set_rotation_meshtree(6, ROT_Y);
        tomb[TR2_MONK1 + index].set_save(TRUE, TRUE, TRUE, FALSE, TRUE);
    }
}
