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

extern TYPE_InitialiseCreature InitialiseCreature;
extern TYPE_CreatureActive CreatureActive;
extern TYPE_CreatureAnimation CreatureAnimation;
extern TYPE_GetCreatureMood GetCreatureMood;
extern TYPE_CreatureMood CreatureMood;
extern TYPE_CreatureTurn CreatureTurn;
extern TYPE_CreatureAIInfo CreatureAIInfo;
extern TYPE_CreatureEffect CreatureEffect;
extern TYPE_CreatureCollision CreatureCollision;
extern TYPE2_DoBloodSplat DoBloodSplat_2;
extern TYPE_DrawAnimatingItem DrawAnimatingItem;
extern TYPE_GetFrames GetFrames;
extern TYPE_S_PrintShadow S_PrintShadow;
extern TYPE_phd_PushMatrix phd_PushMatrix;
extern TYPE_phd_TranslateAbs phd_TranslateAbs;
extern TYPE_phd_TranslateRel phd_TranslateRel;
extern TYPE_phd_RotYXZ phd_RotYXZ;
extern TYPE_phd_RotY phd_RotY;
extern TYPE_phd_RotX phd_RotX;
extern TYPE_phd_RotZ phd_RotZ;
extern TYPE_phd_RotY_I phd_RotY_I;
extern TYPE_phd_RotX_I phd_RotX_I;
extern TYPE_phd_RotZ_I phd_RotZ_I;
extern TYPE_CreatureTilt CreatureTilt;
extern TYPE_ExplodingDeath ExplodingDeath;
extern TYPE_gar_RotYXZsuperpack gar_RotYXZsuperpack;
extern TYPE2_S_GetObjectBounds S_GetObjectBounds_2;
extern TYPE_CalculateObjectLighting CalculateObjectLighting;
extern TYPE_phd_PutPolygons phd_PutPolygons;
extern TYPE_phd_TranslateRel_ID phd_TranslateRel_ID;
extern TYPE_gar_RotYXZsuperpack_I gar_RotYXZsuperpack_I;
extern TYPE_phd_PutPolygons_I phd_PutPolygons_I;
extern TYPE_phd_PushMatrix_I phd_PushMatrix_I;
extern TYPE_phd_TranslateRel_I phd_TranslateRel_I;
extern TYPE_CreatureJoint CreatureJoint;
extern TYPE_InitInterpolate InitInterpolate;
extern TYPE_KillItem KillItem;
extern TYPE2_TriggerActive TriggerActive_2;
extern TYPE_DisableBaddieAI DisableBaddieAI;
extern TYPE_CreatureKill CreatureKill;
extern TYPE_GetRandomControl GetRandomControl;
extern TYPE_GetRandomDraw GetRandomDraw;
extern TYPE_TriggerGunSmoke TriggerGunSmoke;
extern TYPE_phd_PopMatrix_I phd_PopMatrix_I;
extern TYPE_SoundEffect SoundEffect;
extern TYPE_CreateEffect CreateEffect;

#define HP_SWORD_GUARDIAN (80)
#define SWORD_DAMAGE 300
#define SWORD_TOUCH (0xC000)

#define SWORD_WALK_TURN (910)
#define SWORD_FLY_TURN (728)

#define SWORD_LOW_ATTACK_RANGE (0x100000)
#define SWORD_HIGH_ATTACK_RANGE (0x400000)

static BITE_INFO sword_bite = { 0, 37, 550, 15 };

enum SWORD_GUARD_STATE {
    ST_SWORD_EMPTY,
    ST_SWORD_STOP,
    ST_SWORD_WALK,
    ST_SWORD_AIM1,
    ST_SWORD_ATTACK1,
    ST_SWORD_AIM2,
    ST_SWORD_ATTACK2,
    ST_SWORD_WAIT,
    ST_SWORD_FLY,
    ST_SWORD_AWAKE,
    ST_SWORD_AIM3,
    ST_SWORD_ATTACK3,
    ST_SWORD_DEATH
};

// for flying effect...
void SwordGuardian_SubFunc(ITEM_INFO* item)
{
    short fx_number, snd1;
    FX_INFO* fx;

    snd1 = Utils.getObjectProperty(tsu_slots[item->object_number], PTY_SND1);
    fx_number = CreateEffect(item->room_number);
    if (fx_number != NO_ITEM)
    {
        fx = &Ptr_VetEffects[fx_number];
        fx->pos.x_pos = (GetRandomDraw() / 128) + item->pos.x_pos - 128;
        fx->pos.y_pos = (GetRandomDraw() / 128) + item->pos.y_pos - 256;
        fx->pos.z_pos = (GetRandomDraw() / 128) + item->pos.z_pos - 128;
        fx->room_number = item->room_number;
        fx->object_number = Utils.getObjects(Utils.getLinks(tsu_slots[item->object_number], LNK_OBJECT2));
        fx->fallspeed = 30;
        fx->frame_number = Ptr_VetObjects[fx->object_number].mesh_index;
        fx->counter = fx->object_number;
        RotateItem(&fx->flag1);
    }

    if (snd1 != NO_ITEM)
        SoundEffect(snd1, &item->pos, 0);
}

void CtrlTR2_SwordGuardian(short ItemIndex)
{
    if (!CreatureActive(ItemIndex))
        return;

    ITEM_INFO* item;
    OBJECT_INFO* slot;
    CREATURE_INFO* sword;
    AI_INFO info;
    short angle, head, torso, tilt;
    bool lara_alive;
    short dmg1, dmg2, dmg3, snd2;

    item = &Ptr_VetItems[ItemIndex];
    slot = &Ptr_VetObjects[item->object_number];
    sword = (CREATURE_INFO*)item->data;
    angle = head = torso = tilt = 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);
    snd2 = Utils.getObjectProperty(tsu_slots[item->object_number], PTY_SND2);

    if (item->hit_points <= 0)
    {
        item->meshswap_meshbits >>= 1;
        item->current_anim_state = ST_SWORD_DEATH;

        if (!item->meshswap_meshbits)
        {
            if (snd2 != NO_ITEM)
                SoundEffect(snd2, &item->pos, 0);
            ExplodingDeath(ItemIndex, -1, 256);
            DisableBaddieAI(ItemIndex);
            KillItem(ItemIndex);
            item->status = STS_DESACTIVATED;
        }
    }
    else
    {
        sword->LOT.step = 256;
        sword->LOT.drop = -512;
        sword->LOT.fly = 0;
        sword->LOT.zone = ZONE_BASIC;
        CreatureAIInfo(item, &info);

        if (Ptr_VetRoom[LaraItem->room_number].FlagsRoom & SUNDERWATER || Lara.getWaterSurfaceDist() < -STEP_L)
            info.target_zone |= BLOCKED;

        if (item->current_anim_state == ST_SWORD_FLY && info.src_zone != info.target_zone)
        {
            sword->LOT.step = 20480;
            sword->LOT.drop = -20480;
            sword->LOT.fly = 32;
            sword->LOT.zone = ZONE_FLYER;
            CreatureAIInfo(item, &info);

            if (Ptr_VetRoom[LaraItem->room_number].FlagsRoom & SUNDERWATER || Lara.getWaterSurfaceDist() < -STEP_L)
                info.target_zone |= BLOCKED;
        }

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

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

        switch (item->current_anim_state)
        {
            case ST_SWORD_STOP:
                sword->maximum_turn = 0;

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

                if (lara_alive)
                {
                    if (info.bite && info.distance < SWORD_LOW_ATTACK_RANGE)
                    {
                        if (GetRandomControl() >= 0x4000)
                            item->goal_anim_state = ST_SWORD_AIM2;
                        else
                            item->goal_anim_state = ST_SWORD_AIM1;
                    }
                    else
                    {
                        if (info.src_zone == info.target_zone)
                            item->goal_anim_state = ST_SWORD_WALK;
                        else
                            item->goal_anim_state = ST_SWORD_FLY;
                    }
                }
                else
                {
                    item->goal_anim_state = ST_SWORD_WAIT;
                }
                break;

            case ST_SWORD_WALK:
                sword->maximum_turn = SWORD_WALK_TURN;

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

                if (lara_alive)
                {
                    if (info.bite && info.distance < SWORD_HIGH_ATTACK_RANGE)
                        item->goal_anim_state = ST_SWORD_AIM3;
                    else if (info.src_zone != info.target_zone)
                        item->goal_anim_state = ST_SWORD_STOP;
                }
                else
                {
                    item->goal_anim_state = ST_SWORD_STOP;
                }
                break;

            case ST_SWORD_AIM1:
                sword->flags = 0;

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

                if (!info.bite || info.distance >= SWORD_LOW_ATTACK_RANGE)
                    item->goal_anim_state = ST_SWORD_STOP;
                else
                    item->goal_anim_state = ST_SWORD_ATTACK1;
                break;

            case ST_SWORD_AIM2:
                sword->flags = 0;

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

                if (!info.bite || info.distance >= SWORD_LOW_ATTACK_RANGE)
                    item->goal_anim_state = ST_SWORD_STOP;
                else
                    item->goal_anim_state = ST_SWORD_ATTACK2;
                break;

            case ST_SWORD_AIM3:
                sword->flags = 0;

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

                if (!info.bite || info.distance >= SWORD_HIGH_ATTACK_RANGE)
                    item->goal_anim_state = ST_SWORD_WALK;
                else
                    item->goal_anim_state = ST_SWORD_ATTACK3;
                break;

            case ST_SWORD_FLY:
                sword->maximum_turn = SWORD_FLY_TURN;

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

                SwordGuardian_SubFunc(item);

                if (!sword->LOT.fly)
                {
                    item->pos.x_rot = 0;
                    item->goal_anim_state = ST_SWORD_STOP;
                }
                break;

            case ST_SWORD_ATTACK1:
            case ST_SWORD_ATTACK2:
            case ST_SWORD_ATTACK3:
                if (info.ahead)
                    torso = info.angle;

                if (!sword->flags && (item->touch_bits & SWORD_TOUCH))
                {
					if (item->current_anim_state == ST_SWORD_ATTACK1)
						LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg1, SWORD_DAMAGE);
					else if (item->current_anim_state == ST_SWORD_ATTACK2)
						LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg2, SWORD_DAMAGE);
					else
						LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg3, SWORD_DAMAGE);
                    LaraItem->hit_status = 1;
                    CreatureEffect(item, &sword_bite, DoBloodSplat_2);
                    sword->flags = 1;
                }
                break;

            case ST_SWORD_AWAKE:
                sword->maximum_turn = 0;

                if (!sword->flags)
                {
                    if (!item->meshswap_meshbits)
                        item->poisoned = false;
                    item->meshswap_meshbits = (item->meshswap_meshbits << 1) + 1;
                    sword->flags = 3;
                }
                else
                {
                    sword->flags--;
                }
                break;
        }
    }

    if (item->hit_points > 0)
    {
        CreatureTilt(item, tilt);
        CreatureJoint(item, 0, torso);
        CreatureJoint(item, 1, head);
        CreatureAnimation(ItemIndex, angle, 0);
    }
}

void InitTR2_SwordGuardian(short ItemIndex)
{
    ITEM_INFO* item = &Ptr_VetItems[ItemIndex];
    InitialiseCreature(ItemIndex);

    item->status = STS_NOT_ACTIVE;
    item->really_active = FALSE; // cant be targeted unless is triggered.
}

void DrawTR2_XianSwordGuardian(ITEM_INFO* item)
{
    DrawAnimatingItem(item);
}

void InitialiseTR2_SwordGuardianStatue()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        tomb[TR2_SWORD_XIAN_GUARD_STATUE1 + index].set_name("Sword Guardian Statue");
        tomb[TR2_SWORD_XIAN_GUARD_STATUE1 + index].initialise(TR2_SWORD_XIAN_GUARD_STATUE1 + index, 0, 0);
    }
}

void InitialiseTR2_SwordGuardian()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        short dependency = Utils.getLinks(TR2_SWORD_XIAN_GUARD1 + index, LNK_OBJECT1);
        if (dependency >= 0 && dependency < TR_OBJECTS_NUMBER && MapToFirst(dependency, SLOTS_NUMBER) == TR2_SWORD_XIAN_GUARD_STATUE1)
        {
            OBJECT_INFO* object_statue = tomb[dependency].get_object();
            if (object_statue)
            {
                short dependency2 = Utils.getLinks(TR2_SWORD_XIAN_GUARD1 + index, LNK_OBJECT2);
                if (dependency2 >= 0 && dependency2 < TR_OBJECTS_NUMBER && MapToFirst(dependency2, SLOTS_NUMBER) == TR2_SPARKLE1 && tomb[dependency2].get_object())
                {
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_name("Sword Guardian");
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].initialise(TR2_SWORD_XIAN_GUARD1 + index, FUNCTION_SHADOW, QUERY_ZOMBIE);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_shadow_size(128);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_func_initialise(InitTR2_SwordGuardian);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_func_collide(CreatureCollision);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_func_control(CtrlTR2_SwordGuardian);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_func_draw(DrawTR2_XianSwordGuardian, NULL);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_health(HP_SWORD_GUARDIAN);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_radius_and_pivot(204, 0);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_hit_effect(HIT_BLOOD);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_creature(TRUE);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_rotation_meshtree(6, ROT_Y);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_rotation_meshtree(16, ROT_Y);
                    tomb[TR2_SWORD_XIAN_GUARD1 + index].set_save(TRUE, TRUE, TRUE, TRUE, TRUE);

                    OBJECT_INFO* object = tomb[TR2_SWORD_XIAN_GUARD1 + index].get_object();
                    if (object)
                    {
                        for (int mesh = 0; mesh < object->nmeshes; ++mesh)
                            Ptr_VetMeshes[object->mesh_index + mesh * 2] = Ptr_VetMeshes[object_statue->mesh_index + mesh * 2];
                    }
                }
            }
        }
    }
}