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

extern TYPE_CreatureActive CreatureActive;
extern TYPE_CreatureCollision CreatureCollision;
extern TYPE_InitialiseCreature InitialiseCreature;
extern TYPE_CreatureAnimation CreatureAnimation;
extern TYPE_CreatureJoint CreatureJoint;
extern TYPE_CreatureTilt CreatureTilt;
extern TYPE_CreatureAIInfo CreatureAIInfo;
extern TYPE_CreatureTurn CreatureTurn;
extern TYPE_CreatureMood CreatureMood;
extern TYPE_GetCreatureMood GetCreatureMood;
extern TYPE_SoundEffect SoundEffect;
extern TYPE_GetRandomControl GetRandomControl;
extern TYPE_Targetable Targetable;
extern TYPE_ShotLara ShotLara;

#define HP_CULT1 (25)
#define CULT1_WALK_TURN (910)
#define CULT1_RUN_TURN (910)
#define CULT1_RUN_RANGE (0x400000)
#define CULT1_DAMAGE 50
#define CULT1_DEATH_BY_SHOTGUN 20
#define CULT1_DEATH_BY_PISTOL 21
#define CULT1_MOVE_CHANCE (0x100)
#define CULT1_ANIM_CHANCE (0x4000)
#define CULT1_STOP_CHANCE (0x300)

static BITE_INFO cult1_bite = EnemyBite[TROFF_SILENCER];

enum CULT1_STATE {
    ST_CULT1_EMPTY1,
    ST_CULT1_WALK,    // -> 2 / 3
    ST_CULT1_RUN,     // -> 3 / (stateid: 9, frame 11) or (stateid: 9, frame: 26)
    ST_CULT1_STOP,    // -> 1 / 2 / 5 / 6 / 10
    ST_CULT1_WAIT,    // -> 3
    ST_CULT1_GUARD,   // -> 3
    ST_CULT1_AIM1,    // -> 3 / 7   
    ST_CULT1_SHOT1,
    ST_CULT1_EMPTY2,
    ST_CULT1_SHOT2,   // -> 2
    ST_CULT1_AIM2,    // -> 3 / 11
    ST_CULT1_SHOT3,   // -> 3
    ST_CULT1_DEATH1,
    ST_CULT1_DEATH2
};

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

    ITEM_INFO* item;
    CREATURE_INFO* silencer;
    AI_INFO info;
    short angle, torso_y, tilt;
    int random;
    short dmg1, dmg2, dmg3;

    item = &Ptr_VetItems[item_number];
    silencer = (CREATURE_INFO*)item->data;
    angle = torso_y = 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);

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

        switch (item->current_anim_state)
        {
            case ST_CULT1_STOP:
                silencer->maximum_turn = 0;
                if (item->required_anim_state)
                    item->goal_anim_state = item->required_anim_state;
                break;

            case ST_CULT1_WAIT:
                if (silencer->mood == MOOD_ESCAPE)
                {
                    item->required_anim_state = ST_CULT1_RUN;
                    item->goal_anim_state = ST_CULT1_STOP;
                }
                else
                {
                    if (Targetable(item, &info))
                    {
                        item->required_anim_state = (GetRandomControl() >= CULT1_ANIM_CHANCE ? ST_CULT1_AIM2 : ST_CULT1_AIM1);
                        item->goal_anim_state = ST_CULT1_STOP;
                    }
                    else if (silencer->mood != MOOD_BORED || !info.ahead)
                    {
                        if (info.distance >= CULT1_RUN_RANGE && silencer->mood != MOOD_BORED)
                        {
                            item->required_anim_state = ST_CULT1_RUN;
                            item->goal_anim_state = ST_CULT1_STOP;
                        }
                        else
                        {
                            item->required_anim_state = ST_CULT1_WALK;
                            item->goal_anim_state = ST_CULT1_STOP;
                        }
                    }
                    else
                    {
                        random = GetRandomControl();
                        if (random >= 1280)
                        {
                            if (random < 2560)
                            {
                                item->required_anim_state = ST_CULT1_WALK;
                                item->goal_anim_state = ST_CULT1_STOP;
                            }
                        }
                        else
                        {
                            item->required_anim_state = ST_CULT1_GUARD;
                            item->goal_anim_state = ST_CULT1_STOP;
                        }
                    }
                }
                break;
            case ST_CULT1_WALK:
                silencer->maximum_turn = CULT1_WALK_TURN;

                if (silencer->mood == MOOD_ESCAPE)
                {
                    item->goal_anim_state = ST_CULT1_RUN;
                }
                else if(Targetable(item, &info))
                {
                    item->required_anim_state = (GetRandomControl() >= CULT1_ANIM_CHANCE ? ST_CULT1_AIM2 : ST_CULT1_AIM1);
                    item->goal_anim_state = ST_CULT1_STOP;
                }
                else
                {
                    
                    if (info.distance > CULT1_RUN_RANGE || !info.ahead)
                        item->goal_anim_state = ST_CULT1_RUN;
                    else if (silencer->mood == MOOD_BORED && GetRandomControl() < CULT1_STOP_CHANCE)
                        item->goal_anim_state = ST_CULT1_STOP;
                }
                break;
            case ST_CULT1_RUN:
                silencer->maximum_turn = CULT1_RUN_TURN;
                silencer->flags = 0;
                tilt = (angle / 4);

                if (silencer->mood == MOOD_ESCAPE)
                {
                    if (Targetable(item, &info))
                        item->goal_anim_state = ST_CULT1_SHOT2;
                    break;
                }

                if (Targetable(item, &info))
                {
                    if (info.distance >= CULT1_RUN_RANGE && info.src_zone == info.target_zone)
                        item->goal_anim_state = ST_CULT1_SHOT2;
                    else
                        item->goal_anim_state = ST_CULT1_STOP;
                }
                else if (silencer->mood == MOOD_BORED)
                    item->goal_anim_state = ST_CULT1_STOP;
                break;

            case ST_CULT1_GUARD:
                if (Targetable(item, &info))
                {
                    item->required_anim_state = ST_CULT1_AIM1;
                    item->goal_anim_state = ST_CULT1_STOP;
                }
                else
                {
                    if (silencer->mood != MOOD_BORED || GetRandomControl() < CULT1_MOVE_CHANCE)
                        item->goal_anim_state = ST_CULT1_STOP;
                    else if (!info.ahead)
                        item->goal_anim_state = ST_CULT1_STOP;
                }
                break;

            case ST_CULT1_AIM1:
            case ST_CULT1_AIM2:
                silencer->flags = 0;

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

                if (silencer->mood == MOOD_ESCAPE)
                    item->goal_anim_state = ST_CULT1_STOP;
                else if (Targetable(item, &info))
                    item->goal_anim_state = (item->current_anim_state != ST_CULT1_AIM1 ? ST_CULT1_SHOT3 : ST_CULT1_SHOT1);
                else
                    item->goal_anim_state = ST_CULT1_STOP;
                break;
            case ST_CULT1_SHOT1:
            case ST_CULT1_SHOT3:
                if (info.ahead)
                {
                    torso_y = info.angle;
                }

                if (!silencer->flags)
                {
                    Utils.EnemyShot(item, &info, &cult1_bite, torso_y, DOUBLE_VALUE_ANIM(item->current_anim_state, ST_CULT1_SHOT1, DOUBLE_VALUE_ITEM(dmg1, CULT1_DAMAGE), DOUBLE_VALUE_ITEM(dmg3, CULT1_DAMAGE)));
                    item->fired_weapon = 2;
                    silencer->flags = 1;
                }
                break;
            case ST_CULT1_SHOT2:
                if (info.ahead)
                {
                    torso_y = info.angle;
                }

                if (!item->required_anim_state)
                {
                    if (!Utils.EnemyShot(item, &info, &cult1_bite, torso_y, DOUBLE_VALUE_ITEM(dmg2, CULT1_DAMAGE)))
                        item->goal_anim_state = ST_CULT1_RUN;
                    
                    item->fired_weapon = 2;
                }
                item->required_anim_state = ST_CULT1_SHOT2;
                break;
        }
    }

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

void InitialiseTR2_GoonSilencer()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        tomb[TR2_MASKED_GOON1 + index].set_name("Goon Silencer");
        tomb[TR2_MASKED_GOON1 + index].initialise(TR2_MASKED_GOON1 + index, FUNCTION_SHADOW, QUERY_GUNFLASH);
        tomb[TR2_MASKED_GOON1 + index].set_shadow_size(128);
        tomb[TR2_MASKED_GOON1 + index].set_func_initialise(InitialiseCreature);
        tomb[TR2_MASKED_GOON1 + index].set_func_collide(CreatureCollision);
        tomb[TR2_MASKED_GOON1 + index].set_func_control(CtrlTR2_MGSilencer);
        tomb[TR2_MASKED_GOON1 + index].set_bitoffset(TROFF_SILENCER);
        tomb[TR2_MASKED_GOON1 + index].set_func_draw(DrawAnimatingItemCustom, NULL);
        tomb[TR2_MASKED_GOON1 + index].set_health(HP_CULT1);
        tomb[TR2_MASKED_GOON1 + index].set_radius_and_pivot(102, 50);
        tomb[TR2_MASKED_GOON1 + index].set_hit_effect(HIT_BLOOD);
        tomb[TR2_MASKED_GOON1 + index].set_creature(TRUE);
        tomb[TR2_MASKED_GOON1 + index].set_rotation_meshtree(0, ROT_Y);
        tomb[TR2_MASKED_GOON1 + index].set_save(TRUE, TRUE, TRUE, FALSE, TRUE);
    }
}