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

extern TYPE_InitialiseCreature InitialiseCreature;
extern TYPE_CreatureCollision CreatureCollision;
extern TYPE_CreateEffect CreateEffect;
extern TYPE_CreatureActive CreatureActive;
extern TYPE_SoundEffect SoundEffect;
extern TYPE_ExplodingDeath ExplodingDeath;
extern TYPE_DisableBaddieAI DisableBaddieAI;
extern TYPE_KillItem KillItem;
extern TYPE_CreatureAIInfo CreatureAIInfo;
extern TYPE_Targetable Targetable;
extern TYPE_GetCreatureMood GetCreatureMood;
extern TYPE_CreatureMood CreatureMood;
extern TYPE_CreatureTurn CreatureTurn;
extern TYPE_GetRandomControl GetRandomControl;
extern TYPE_CreatureEffect CreatureEffect;
extern TYPE2_DoBloodSplat DoBloodSplat_2;
extern TYPE_CreatureJoint CreatureJoint;
extern TYPE_CreatureAnimation CreatureAnimation;

#define FLYER_CHARGE_DAMAGE 100
#define FLYER_LUNGE_DAMAGE 150
#define FLYER_PUNCH_DAMAGE 200
#define FLYER_PART_DAMAGE 100
#define FLYER_WALK_TURN (ONE_DEGREE * 2) // = 364
#define FLYER_RUN_TURN (ONE_DEGREE * 6) // = 1092
#define FLYER_POSE_CHANCE 80
#define FLYER_UNPOSE_CHANCE 256
#define FLYER_WALK_RANGE SQUARE(WALL_L * 9 / 2) // = 21233664
#define FLYER_ATTACK1_RANGE SQUARE(600) // = 360000
#define FLYER_ATTACK2_RANGE SQUARE(WALL_L * 5 / 2) // = 6553600
#define FLYER_ATTACK3_RANGE SQUARE(300) // = 90000
#define FLYER_ATTACK_RANGE SQUARE(WALL_L * 15 / 4) // = 14745600
#define FLYER_TOUCH 0x678
#define FLYER_BULLET1 1
#define FLYER_BULLET2 2
#define FLYER_FLYMODE 4
#define FLYER_TWIST 8
#define FLYER_HITPOINTS 50
#define FLYER_RADIUS (WALL_L / 3) // = 341
#define FLYER_SMARTNESS 0x7FFF

#define WARRIOR2_SMARTNESS 0x2000

#define ROCKET_SPEED 220
#define SHARD_SPEED 250

static BITE_INFO WarriorBite = { -27, 98, 0, 10 };
static BITE_INFO WarriorRocket = { 51, 213, 0, 14 };
static BITE_INFO WarriorShard = { -35, 269, 0, 9 };
static short WingedMutantSlot;

enum FLYER_ANIM {
    FLYER_EMPTY = 0,
    FLYER_STOP = 1,
    FLYER_WALK = 2,
    FLYER_RUN = 3,
    FLYER_ATTACK1 = 4,
    FLYER_DEATH = 5,
    FLYER_POSE = 6,
    FLYER_ATTACK2 = 7,
    FLYER_ATTACK3 = 8,
    FLYER_AIM1 = 9,
    FLYER_AIM2 = 10,
    FLYER_SHOOT = 11,
    FLYER_MUMMY = 12,
    FLYER_FLY = 13,
};

static short RocketGun(int x, int y, int z, short speed, short y_rot, short room_num)
{
    short fx_num = CreateEffect(room_num);
    if (fx_num != NO_ITEM) {
        FX_INFO* fx = &Ptr_VetEffects[fx_num];
        fx->room_number = room_num;
        fx->pos.x_pos = x;
        fx->pos.y_pos = y;
        fx->pos.z_pos = z;
        fx->pos.x_rot = 0;
        fx->pos.y_rot = y_rot;
        fx->pos.z_rot = 0;
        fx->object_number = Utils.getObjects(Utils.getLinks(tsu_slots[WingedMutantSlot], LNK_OBJECT1));
        fx->frame_number = 0;
        fx->speed = ROCKET_SPEED;
        fx->shade = 4096;
        Utils.ShootAtLara(fx);
    }
	return fx_num;
}

static short ShardGun(int x, int y, int z, short speed, short y_rot, short room_num)
{
    short fx_num = CreateEffect(room_num);
    if (fx_num != NO_ITEM) {
        FX_INFO* fx = &Ptr_VetEffects[fx_num];
        fx->room_number = room_num;
        fx->pos.x_pos = x;
        fx->pos.y_pos = y;
        fx->pos.z_pos = z;
        fx->pos.x_rot = 0;
        fx->pos.y_rot = y_rot;
        fx->pos.z_rot = 0;
        fx->object_number = Utils.getObjects(Utils.getLinks(tsu_slots[WingedMutantSlot], LNK_OBJECT2));
        fx->frame_number = 0;
        fx->speed = SHARD_SPEED;
        fx->shade = 3584;
        Utils.ShootAtLara(fx);
    }
	return fx_num;
}

void CtrlTR1_Flyer(short item_num)
{
    if (!CreatureActive(item_num))
        return;

    ITEM_INFO* item = &Ptr_VetItems[item_num];
    CREATURE_INFO* flyer = (CREATURE_INFO*) item->data;
    short head = 0;
    short angle = 0;
    short dmg1 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG1);
    short dmg2 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG2);
    short dmg3 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG3);
    short snd1 = Utils.getObjectProperty(tsu_slots[item->object_number], PTY_SND1);

    if (item->hit_points <= 0) {
		if (snd1 != NO_ITEM)
            SoundEffect(snd1, &item->pos, 0);
        ExplodingDeath(item_num, -1, 769);
        DisableBaddieAI(item_num);
        KillItem(item_num);
        item->status = STS_DESACTIVATED;
    } else {
        flyer->LOT.step = STEP_L;
        flyer->LOT.drop = -2 * STEP_L;
        flyer->LOT.fly = 0;
        flyer->LOT.zone = ZONE_BASIC;

        AI_INFO info;
        CreatureAIInfo(item, &info);

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

        int shoot1 = 0;
        int shoot2 = 0;
        if ((item->ocb_bits & 3) != 2 && Targetable(item, &info)
            && (info.src_zone != info.target_zone
                || info.distance > FLYER_ATTACK_RANGE)) {
            if (info.angle > 0 && info.angle < PHD_45) {
                shoot1 = 1;
            } else if (info.angle < 0 && info.angle > -PHD_45) {
                shoot2 = 1;
            }
        }

        if (!(item->ocb_bits & 3)) {
            if (item->current_anim_state == FLYER_FLY) {
                if ((flyer->flags & FLYER_FLYMODE) && flyer->mood != MOOD_ESCAPE
                    && info.src_zone == info.target_zone) {
                    flyer->flags &= ~FLYER_FLYMODE;
                }

                flyer->LOT.step = WALL_L * 20;
                flyer->LOT.drop = -WALL_L * 20;
                flyer->LOT.fly = STEP_L / 8;
                flyer->LOT.zone = ZONE_FLYER;
                CreatureAIInfo(item, &info);

				if (Ptr_VetRoom[LaraItem->room_number].FlagsRoom & SUNDERWATER || Lara.getWaterSurfaceDist() < -STEP_L)
					info.target_zone |= BLOCKED;
            } else if (
                (info.src_zone != info.target_zone && !shoot1 && !shoot2
                 && (!info.ahead || flyer->mood == MOOD_BORED))
                || flyer->mood == MOOD_ESCAPE) {
                flyer->flags |= FLYER_FLYMODE;
            }
        }

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

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

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

        switch (item->current_anim_state) {
        case FLYER_MUMMY:
			flyer->maximum_turn = 0;
            item->goal_anim_state = FLYER_STOP;
            break;

        case FLYER_STOP:
			flyer->maximum_turn = 0;
            flyer->flags &= ~(FLYER_BULLET1 | FLYER_BULLET2 | FLYER_TWIST);
            if (flyer->flags & FLYER_FLYMODE) {
                item->goal_anim_state = FLYER_FLY;
            } else if (item->touch_bits & FLYER_TOUCH) {
                item->goal_anim_state = FLYER_ATTACK3;
            } else if (info.bite && info.distance < FLYER_ATTACK3_RANGE) {
                item->goal_anim_state = FLYER_ATTACK3;
            } else if (info.bite && info.distance < FLYER_ATTACK1_RANGE) {
                item->goal_anim_state = FLYER_ATTACK1;
            } else if (shoot1) {
                item->goal_anim_state = FLYER_AIM1;
            } else if (shoot2) {
                item->goal_anim_state = FLYER_AIM2;
            } else if (
                flyer->mood == MOOD_BORED
                || (flyer->mood == MOOD_STALK
                    && info.distance < FLYER_WALK_RANGE)) {
                item->goal_anim_state = FLYER_POSE;
            } else {
                item->goal_anim_state = FLYER_RUN;
            }
            break;

        case FLYER_POSE:
			flyer->maximum_turn = 0;
            head = 0;
            if (shoot1 || shoot2 || (flyer->flags & FLYER_FLYMODE)) {
                item->goal_anim_state = FLYER_STOP;
            } else if (flyer->mood == MOOD_STALK) {
                if (info.distance < FLYER_WALK_RANGE) {
                    if (info.src_zone == info.target_zone
                        || GetRandomControl() < FLYER_UNPOSE_CHANCE) {
                        item->goal_anim_state = FLYER_WALK;
                    }
                } else {
                    item->goal_anim_state = FLYER_STOP;
                }
            } else if (
                flyer->mood == MOOD_BORED
                && GetRandomControl() < FLYER_UNPOSE_CHANCE) {
                item->goal_anim_state = FLYER_WALK;
            } else if (
                flyer->mood == MOOD_ATTACK || flyer->mood == MOOD_ESCAPE) {
                item->goal_anim_state = FLYER_STOP;
            }
            break;

        case FLYER_WALK:
            flyer->maximum_turn = FLYER_WALK_TURN;
            if (shoot1 || shoot2 || (flyer->flags & FLYER_FLYMODE)) {
                item->goal_anim_state = FLYER_STOP;
            } else if (
                flyer->mood == MOOD_ATTACK || flyer->mood == MOOD_ESCAPE) {
                item->goal_anim_state = FLYER_STOP;
            } else if (
                flyer->mood == MOOD_BORED
                || (flyer->mood == MOOD_STALK
                    && info.src_zone != info.target_zone)) {
                if (GetRandomControl() < FLYER_POSE_CHANCE) {
                    item->goal_anim_state = FLYER_POSE;
                }
            } else if (
                flyer->mood == MOOD_STALK && info.distance > FLYER_WALK_RANGE) {
                item->goal_anim_state = FLYER_STOP;
            }
            break;

        case FLYER_RUN:
            flyer->maximum_turn = FLYER_RUN_TURN;
            if (flyer->flags & FLYER_FLYMODE) {
                item->goal_anim_state = FLYER_STOP;
            } else if (item->touch_bits & FLYER_TOUCH) {
                item->goal_anim_state = FLYER_STOP;
            } else if (info.bite && info.distance < FLYER_ATTACK1_RANGE) {
                item->goal_anim_state = FLYER_STOP;
            } else if (info.ahead && info.distance < FLYER_ATTACK2_RANGE) {
                item->goal_anim_state = FLYER_ATTACK2;
            } else if (shoot1 || shoot2) {
                item->goal_anim_state = FLYER_STOP;
            } else if (
                flyer->mood == MOOD_BORED
                || (flyer->mood == MOOD_STALK
                    && info.distance < FLYER_WALK_RANGE)) {
                item->goal_anim_state = FLYER_STOP;
            }
            break;

        case FLYER_ATTACK1:
            if (item->required_anim_state == FLYER_EMPTY
                && (item->touch_bits & FLYER_TOUCH)) {
                CreatureEffect(item, &WarriorBite, DoBloodSplat_2);
                LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg1, FLYER_LUNGE_DAMAGE);
                LaraItem->hit_status = 1;
                item->required_anim_state = FLYER_STOP;
            }
            break;

        case FLYER_ATTACK2:
            if (item->required_anim_state == FLYER_EMPTY
                && (item->touch_bits & FLYER_TOUCH)) {
                CreatureEffect(item, &WarriorBite, DoBloodSplat_2);
                LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg2, FLYER_CHARGE_DAMAGE);
                LaraItem->hit_status = 1;
                item->required_anim_state = FLYER_RUN;
            }
            break;

        case FLYER_ATTACK3:
            if (item->required_anim_state == FLYER_EMPTY
                && (item->touch_bits & FLYER_TOUCH)) {
                CreatureEffect(item, &WarriorBite, DoBloodSplat_2);
                LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg3, FLYER_PUNCH_DAMAGE);
                LaraItem->hit_status = 1;
                item->required_anim_state = FLYER_STOP;
            }
            break;

        case FLYER_AIM1:
            flyer->flags |= FLYER_TWIST;
            flyer->flags |= FLYER_BULLET1;
            if (shoot1) {
                item->goal_anim_state = FLYER_SHOOT;
            } else {
                item->goal_anim_state = FLYER_STOP;
            }
            break;

        case FLYER_AIM2:
            flyer->flags |= FLYER_BULLET2;
            if (shoot2) {
                item->goal_anim_state = FLYER_SHOOT;
            } else {
                item->goal_anim_state = FLYER_STOP;
            }
            break;

        case FLYER_SHOOT:
			WingedMutantSlot = item->object_number;
            if (flyer->flags & FLYER_BULLET1) {
                flyer->flags &= ~FLYER_BULLET1;
                CreatureEffect(item, &WarriorShard, ShardGun);
            } else if (flyer->flags & FLYER_BULLET2) {
                flyer->flags &= ~FLYER_BULLET2;
                CreatureEffect(item, &WarriorRocket, RocketGun);
            }
            break;

        case FLYER_FLY:
            flyer->maximum_turn = FLYER_RUN_TURN;
            if (!(flyer->flags & FLYER_FLYMODE) && item->pos.y_pos == item->floor) {
                item->goal_anim_state = FLYER_STOP;
            }
            break;
        }

        if (!(flyer->flags & FLYER_TWIST)) {
            CreatureJoint(item, 1, head);
            flyer->joint_rotation[0] = 0;
        } else {
            CreatureJoint(item, 0, head);
            flyer->joint_rotation[1] = 0;
        }

        CreatureAnimation(item_num, angle, 0);
    }
}

void InitTR1_Flyer(short item_num)
{
    InitialiseCreature(item_num);
}

void InitialiseTR1_Warrior()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        short dependency = Utils.getLinks(TR1_WINGED_MUTANT1 + index, LNK_OBJECT1);
        if (dependency >= 0 && dependency < TR_OBJECTS_NUMBER && MapToFirst(dependency, SLOTS_NUMBER) == TR1_MUTANT_GRENADE1 && tomb[dependency].get_object())
        {
            short dependency2 = Utils.getLinks(TR1_WINGED_MUTANT1 + index, LNK_OBJECT2);
            if (dependency2 >= 0 && dependency2 < TR_OBJECTS_NUMBER && MapToFirst(dependency2, SLOTS_NUMBER) == TR1_MUTANT_BULLET1 && tomb[dependency2].get_object())
            {
				tomb[TR1_WINGED_MUTANT1 + index].set_name("Warrior");
				tomb[TR1_WINGED_MUTANT1 + index].initialise(TR1_WINGED_MUTANT1 + index, FUNCTION_SHADOW, 0);
				tomb[TR1_WINGED_MUTANT1 + index].set_shadow_size(85);
				tomb[TR1_WINGED_MUTANT1 + index].set_func_initialise(InitTR1_Flyer);
				tomb[TR1_WINGED_MUTANT1 + index].set_func_collide(CreatureCollision);
				tomb[TR1_WINGED_MUTANT1 + index].set_func_control(CtrlTR1_Flyer);
				tomb[TR1_WINGED_MUTANT1 + index].set_func_draw(DrawAnimatingItemCustom, NULL);
				tomb[TR1_WINGED_MUTANT1 + index].set_health(FLYER_HITPOINTS);
				tomb[TR1_WINGED_MUTANT1 + index].set_radius_and_pivot(FLYER_RADIUS, 150);
				tomb[TR1_WINGED_MUTANT1 + index].set_hit_effect(HIT_BLOOD);
				tomb[TR1_WINGED_MUTANT1 + index].set_creature(TRUE);
				tomb[TR1_WINGED_MUTANT1 + index].set_rotation_meshtree(0, ROT_Y);
				tomb[TR1_WINGED_MUTANT1 + index].set_rotation_meshtree(2, ROT_Y);
				tomb[TR1_WINGED_MUTANT1 + index].set_save(TRUE, TRUE, TRUE, FALSE, TRUE);
			}
		}
    }
}
