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

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

#define APE_ATTACK_DAMAGE 200
#define APE_TOUCH 0xFF00
#define APE_DIE_ANIM 7
#define APE_RUN_TURN (ONE_DEGREE * 5) // = 910
#define APE_DISPLAY_ANGLE (ONE_DEGREE * 45) // = 8190
#define APE_ATTACK_RANGE SQUARE(430) // = 184900
#define APE_PANIC_RANGE SQUARE(WALL_L * 2) // = 4194304
#define APE_JUMP_CHANCE 160
#define APE_WARN1_CHANCE (APE_JUMP_CHANCE + 160) // = 320
#define APE_WARN2_CHANCE (APE_WARN1_CHANCE + 160) // = 480
#define APE_RUN_LEFT_CHANCE (APE_WARN2_CHANCE + 272) // = 752
#define APE_ATTACK_FLAG 1
#define APE_VAULT_ANIM 19
#define APE_TURN_L_FLAG 2
#define APE_TURN_R_FLAG 4
#define APE_SHIFT 75
#define APE_HITPOINTS 22
#define APE_RADIUS (WALL_L / 3) // = 341
#define APE_SMARTNESS 0x7FFF

static BITE_INFO ApeBite = { 0, -19, 75, 15 };

enum APE_ANIM {
    APE_EMPTY = 0,
    APE_STOP = 1,
    APE_WALK = 2,
    APE_RUN = 3,
    APE_ATTACK1 = 4,
    APE_DEATH = 5,
    APE_WARNING = 6,
    APE_WARNING2 = 7,
    APE_RUN_LEFT = 8,
    APE_RUN_RIGHT = 9,
    APE_JUMP = 10,
    APE_VAULT = 11,
};

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

    ITEM_INFO* item = &Ptr_VetItems[item_num];
    CREATURE_INFO* ape = (CREATURE_INFO*) item->data;
    short head = 0;
    short angle = 0;
    short dmg1 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG1);

    if (item->hit_points <= 0) {
        if (item->current_anim_state != APE_DEATH) {
            item->current_anim_state = APE_DEATH;
            item->anim_number = Ptr_VetObjects[item->object_number].anim_index + APE_DIE_ANIM
                + (short)(GetRandomControl() / 0x4000);
            item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
        }
    } else {
        AI_INFO info;
        CreatureAIInfo(item, &info);

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

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

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

        if (item->hit_status || info.distance < APE_PANIC_RANGE) {
            ape->flags |= APE_ATTACK_FLAG;
        }

        switch (item->current_anim_state) {
        case APE_STOP:
            ape->maximum_turn = 0;

            if (item->required_anim_state) {
                item->goal_anim_state = item->required_anim_state;
            } else if (info.bite && info.distance < APE_ATTACK_RANGE) {
                item->goal_anim_state = APE_ATTACK1;
            } else if (
                !(ape->flags & APE_ATTACK_FLAG)
                && info.src_zone == info.target_zone && info.ahead) {
                short random = GetRandomControl() >> 5;
                if (random < APE_JUMP_CHANCE) {
                    item->goal_anim_state = APE_JUMP;
                } else if (random < APE_WARN1_CHANCE) {
                    item->goal_anim_state = APE_WARNING;
                } else if (random < APE_WARN2_CHANCE) {
                    item->goal_anim_state = APE_WARNING2;
                } else if (random < APE_RUN_LEFT_CHANCE) {
                    item->goal_anim_state = APE_RUN_LEFT;
                    ape->maximum_turn = 0;
                } else {
                    item->goal_anim_state = APE_RUN_RIGHT;
                    ape->maximum_turn = 0;
                }
            } else {
                item->goal_anim_state = APE_RUN;
            }
            break;

        case APE_RUN:
            ape->maximum_turn = APE_RUN_TURN;
            if (!ape->flags && info.angle > -APE_DISPLAY_ANGLE
                && info.angle < APE_DISPLAY_ANGLE) {
                item->goal_anim_state = APE_STOP;
            } else if (info.ahead && (item->touch_bits & APE_TOUCH)) {
                item->required_anim_state = APE_ATTACK1;
                item->goal_anim_state = APE_STOP;
            } else if (ape->mood != MOOD_ESCAPE) {
                short random = GetRandomControl();
                if (random < APE_JUMP_CHANCE) {
                    item->required_anim_state = APE_JUMP;
                    item->goal_anim_state = APE_STOP;
                } else if (random < APE_WARN1_CHANCE) {
                    item->required_anim_state = APE_WARNING;
                    item->goal_anim_state = APE_STOP;
                } else if (random < APE_WARN2_CHANCE) {
                    item->required_anim_state = APE_WARNING2;
                    item->goal_anim_state = APE_STOP;
                }
            }
            break;

        case APE_RUN_LEFT:
            item->goal_anim_state = APE_STOP;
            break;

        case APE_RUN_RIGHT:
            item->goal_anim_state = APE_STOP;
            break;

        case APE_ATTACK1:
            ape->maximum_turn = APE_RUN_TURN;
            if (!item->required_anim_state && (item->touch_bits & APE_TOUCH)) {
                CreatureEffect(item, &ApeBite, DoBloodSplat_2);
                LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg1, APE_ATTACK_DAMAGE);
                LaraItem->hit_status = 1;
                item->required_anim_state = APE_STOP;
            }
            break;
        }
    }

    CreatureJoint(item, 0, head);

    if (item->current_anim_state == APE_VAULT) {
        CreatureAnimation(item_num, angle, 0);
    } else {
		if (CreatureVault(item_num, angle, 0, APE_SHIFT) == 2) {
            item->current_anim_state = APE_VAULT;
            item->anim_number = Ptr_VetObjects[item->object_number].anim_index + APE_VAULT_ANIM;
            item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
    		ape->maximum_turn = 0;
		}
    }
}

void InitialiseTR1_Ape()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        tomb[TR1_GORILLA1 + index].set_name("Ape");
        tomb[TR1_GORILLA1 + index].initialise(TR1_GORILLA1 + index, FUNCTION_ZONE_BEFORE | FUNCTION_SHADOW, QUERY_VAULT);
        tomb[TR1_GORILLA1 + index].set_shadow_size(128);
        tomb[TR1_GORILLA1 + index].set_func_initialise(InitialiseCreature);
        tomb[TR1_GORILLA1 + index].set_func_collide(CreatureCollision);
        tomb[TR1_GORILLA1 + index].set_func_control(CtrlTR1_Ape);
        tomb[TR1_GORILLA1 + index].set_func_draw(DrawAnimatingItemCustom, NULL);
        tomb[TR1_GORILLA1 + index].set_health(APE_HITPOINTS);
        tomb[TR1_GORILLA1 + index].set_radius_and_pivot(APE_RADIUS, 250);
        tomb[TR1_GORILLA1 + index].set_hit_effect(HIT_BLOOD);
        tomb[TR1_GORILLA1 + index].set_creature(TRUE);
        tomb[TR1_GORILLA1 + index].set_rotation_meshtree(13, ROT_Y);
        tomb[TR1_GORILLA1 + index].set_save(TRUE, TRUE, TRUE, FALSE, TRUE);
    }
}
