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

extern TYPE_InitialiseCreature InitialiseCreature;
extern TYPE_CreatureCollision CreatureCollision;
extern TYPE_CreatureActive CreatureActive;
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_CreatureFloat CreatureFloat;
extern TYPE_GetWaterHeight GetWaterHeight;
extern TYPE_CreatureUnderwater CreatureUnderwater;

#define CROCODILE_BITE_DAMAGE 100
#define CROCODILE_BITE_RANGE SQUARE(435) // = 189225
#define CROCODILE_DIE_ANIM 11
#define CROCODILE_FASTTURN_ANGLE 0x4000
#define CROCODILE_FASTTURN_RANGE SQUARE(WALL_L * 3) // = 9437184
#define CROCODILE_FASTTURN_TURN (6 * ONE_DEGREE) // = 1092
#define CROCODILE_TOUCH 0x3FC
#define CROCODILE_TURN (3 * ONE_DEGREE) // = 546
#define CROCODILE_HITPOINTS 20
#define CROCODILE_RADIUS (WALL_L / 3) // = 341
#define CROCODILE_SMARTNESS 0x2000

#define ALLIGATOR_BITE_DAMAGE 100
#define ALLIGATOR_DIE_ANIM 4
#define ALLIGATOR_FLOAT_SPEED (WALL_L / 32) // = 32
#define ALLIGATOR_TURN (3 * ONE_DEGREE) // = 546
#define ALLIGATOR_HITPOINTS 20
#define ALLIGATOR_RADIUS (WALL_L / 3) // = 341
#define ALLIGATOR_SMARTNESS 0x400

static BITE_INFO CrocodileBite = { 5, -21, 467, 9 };

enum CROCODILE_ANIM {
    CROCODILE_EMPTY = 0,
    CROCODILE_STOP = 1,
    CROCODILE_RUN = 2,
    CROCODILE_WALK = 3,
    CROCODILE_FASTTURN = 4,
    CROCODILE_ATTACK1 = 5,
    CROCODILE_ATTACK2 = 6,
    CROCODILE_DEATH = 7,
};

enum ALLIGATOR_ANIM {
    ALLIGATOR_EMPTY = 0,
    ALLIGATOR_SWIM = 1,
    ALLIGATOR_ATTACK = 2,
    ALLIGATOR_DEATH = 3,
};

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

    ITEM_INFO* item = &Ptr_VetItems[item_num];
    CREATURE_INFO* croc = (CREATURE_INFO*) item->data;
    short head = 0;
    short angle = 0;
    short object_number = item->object_number;

	if (!item->reserved_4) {
	    short dmg1 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG1);
		if (item->hit_points <= 0) {
			if (item->current_anim_state != CROCODILE_DEATH) {
				item->current_anim_state = CROCODILE_DEATH;
				item->anim_number =
					Ptr_VetObjects[item->object_number].anim_index + CROCODILE_DIE_ANIM;
				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);

			if (item->current_anim_state == CROCODILE_FASTTURN) {
				item->pos.y_rot += CROCODILE_FASTTURN_TURN;
			} else {
				angle = CreatureTurn(item, croc->maximum_turn);
			}

			switch (item->current_anim_state) {
			case CROCODILE_STOP:
				croc->maximum_turn = 0;
				if (info.bite && info.distance < CROCODILE_BITE_RANGE) {
					item->goal_anim_state = CROCODILE_ATTACK1;
				} else if (croc->mood == MOOD_ESCAPE) {
					item->goal_anim_state = CROCODILE_RUN;
				} else if (croc->mood == MOOD_ATTACK) {
					if ((info.angle < -CROCODILE_FASTTURN_ANGLE
						 || info.angle > CROCODILE_FASTTURN_ANGLE)
						&& info.distance > CROCODILE_FASTTURN_RANGE) {
						item->goal_anim_state = CROCODILE_FASTTURN;
					} else {
						item->goal_anim_state = CROCODILE_RUN;
					}
				} else if (croc->mood == MOOD_STALK) {
					item->goal_anim_state = CROCODILE_WALK;
				}
				break;

			case CROCODILE_WALK:
				croc->maximum_turn = CROCODILE_TURN;
				if (info.ahead && (item->touch_bits & CROCODILE_TOUCH)) {
					item->goal_anim_state = CROCODILE_STOP;
				} else if (croc->mood == MOOD_ATTACK || croc->mood == MOOD_ESCAPE) {
					item->goal_anim_state = CROCODILE_RUN;
				} else if (croc->mood == MOOD_BORED) {
					item->goal_anim_state = CROCODILE_STOP;
				}
				break;

			case CROCODILE_FASTTURN:
				if (info.angle > -CROCODILE_FASTTURN_ANGLE
					&& info.angle < CROCODILE_FASTTURN_ANGLE) {
					item->goal_anim_state = CROCODILE_WALK;
				}
				break;

			case CROCODILE_RUN:
				croc->maximum_turn = CROCODILE_TURN;
				if (info.ahead && (item->touch_bits & CROCODILE_TOUCH)) {
					item->goal_anim_state = CROCODILE_STOP;
				} else if (croc->mood == MOOD_STALK) {
					item->goal_anim_state = CROCODILE_WALK;
				} else if (croc->mood == MOOD_BORED) {
					item->goal_anim_state = CROCODILE_STOP;
				} else if (
					croc->mood == MOOD_ATTACK
					&& info.distance > CROCODILE_FASTTURN_RANGE
					&& (info.angle < -CROCODILE_FASTTURN_ANGLE
						|| info.angle > CROCODILE_FASTTURN_ANGLE)) {
					item->goal_anim_state = CROCODILE_STOP;
				}
				break;

			case CROCODILE_ATTACK1:
				if (item->required_anim_state == CROCODILE_EMPTY) {
					CreatureEffect(item, &CrocodileBite, DoBloodSplat_2);
					LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg1, CROCODILE_BITE_DAMAGE);
					LaraItem->hit_status = 1;
					item->required_anim_state = CROCODILE_STOP;
				}
				break;
			}

			if (Ptr_VetRoom[item->room_number].FlagsRoom & SUNDERWATER) {
				item->reserved_4 = 1;
				item->object_number = Utils.getObjects(Utils.getLinks(tsu_slots[object_number], LNK_OBJECT1));
				item->anim_number = Ptr_VetObjects[item->object_number].anim_index;
				item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
				item->current_anim_state = Ptr_VetAnimations[item->anim_number].current_anim_state;
				item->goal_anim_state = item->current_anim_state;
				croc->LOT.step = WALL_L * 20;
				croc->LOT.drop = -WALL_L * 20;
				croc->LOT.fly = STEP_L / 16;
				croc->LOT.zone = ZONE_CROC;
			}
		}

		CreatureJoint(item, 0, head);
		CreatureAnimation(item_num, angle, 0);
	} else {
        item->object_number = Utils.getObjects(Utils.getLinks(tsu_slots[object_number], LNK_OBJECT1));
	    short dmg1 = Utils.getObjectAttribute(tsu_slots[item->object_number], ATT_DMG1);
        int wh = GetWaterHeight(
            item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, item->room_number);

		if (item->hit_points <= 0) {
			if (item->current_anim_state != ALLIGATOR_DEATH) {
				item->current_anim_state = ALLIGATOR_DEATH;
				item->anim_number =
					Ptr_VetObjects[item->object_number].anim_index + ALLIGATOR_DIE_ANIM;
				item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
			}

            if (wh != NO_HEIGHT)
				CreatureFloat(item_num);
		} else {
			AI_INFO info;
			CreatureAIInfo(item, &info);

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

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

			GetCreatureMood(item, &info, VIOLENT);
			CreatureMood(item, &info, VIOLENT);
			angle = CreatureTurn(item, croc->maximum_turn);

			switch (item->current_anim_state) {
			case ALLIGATOR_SWIM:
				croc->maximum_turn = CROCODILE_TURN;
				if (info.bite && item->touch_bits) {
					item->goal_anim_state = ALLIGATOR_ATTACK;
				}
				break;

			case ALLIGATOR_ATTACK:
				croc->maximum_turn = 0;
				if (item->frame_number == Ptr_VetAnimations[item->anim_number].frame_base + 9) {
					item->required_anim_state = ALLIGATOR_EMPTY;
				}

				if (info.bite && item->touch_bits) {
					if (item->required_anim_state == ALLIGATOR_EMPTY) {
						CreatureEffect(item, &CrocodileBite, DoBloodSplat_2);
						LaraItem->hit_points -= DOUBLE_VALUE_ITEM(dmg1, ALLIGATOR_BITE_DAMAGE);
						LaraItem->hit_status = 1;
						item->required_anim_state = ALLIGATOR_SWIM;
					}
				} else {
					item->goal_anim_state = ALLIGATOR_SWIM;
				}
				break;
			}

            if (wh == NO_HEIGHT) {
                item->reserved_4 = 0;
                item->object_number = object_number;
                item->anim_number = Ptr_VetObjects[item->object_number].anim_index;
                item->frame_number = Ptr_VetAnimations[item->anim_number].frame_base;
                item->current_anim_state = Ptr_VetAnimations[item->anim_number].current_anim_state;
                item->goal_anim_state = item->current_anim_state;
                item->pos.y_pos = item->floor;
                item->pos.x_rot = 0;
                croc->LOT.step = STEP_L;
                croc->LOT.drop = -2 * STEP_L;
                croc->LOT.fly = 0;
                croc->LOT.zone = ZONE_BASIC;
            }

            CreatureJoint(item, 0, head);
            CreatureAnimation(item_num, angle, 0);
            CreatureUnderwater(item, STEP_L);
		}
	}

	item->object_number = object_number;
}

void DrawTR1_Crocodile(ITEM_INFO* item)
{
	short object_number = item->object_number;
	if (item->reserved_4)
		item->object_number = Utils.getObjects(Utils.getLinks(tsu_slots[object_number], LNK_OBJECT1));
	DrawAnimatingItemCustom(item);
	if (item->reserved_4)
		item->object_number = object_number;
}

void InitialiseTR1_Alligator()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        tomb[TR1_CROCODILE_WATER1 + index].set_name("Alligator");
        tomb[TR1_CROCODILE_WATER1 + index].initialise(TR1_CROCODILE_WATER1 + index, FUNCTION_SHADOW, 0);
        tomb[TR1_CROCODILE_WATER1 + index].set_shadow_size(85);
        tomb[TR1_CROCODILE_WATER1 + index].set_health(CROCODILE_HITPOINTS);
        tomb[TR1_CROCODILE_WATER1 + index].set_radius_and_pivot(CROCODILE_RADIUS, 600);
        tomb[TR1_CROCODILE_WATER1 + index].set_hit_effect(HIT_BLOOD);
        tomb[TR1_CROCODILE_WATER1 + index].set_creature(TRUE);
        tomb[TR1_CROCODILE_WATER1 + index].set_water_creature(TRUE);
        tomb[TR1_CROCODILE_WATER1 + index].set_rotation_meshtree(7, ROT_Y);
        tomb[TR1_CROCODILE_WATER1 + index].set_save(TRUE, TRUE, TRUE, FALSE, TRUE);
    }
}

void InitialiseTR1_Crocodile()
{
    for (int index = 0; index < SLOTS_NUMBER; ++index)
    {
        short dependency = Utils.getLinks(TR1_CROCODILE_LAND1 + index, LNK_OBJECT1);
        if (dependency >= 0 && dependency < TR_OBJECTS_NUMBER && MapToFirst(dependency, SLOTS_NUMBER) == TR1_CROCODILE_WATER1 && tomb[dependency].get_object())
        {
            tomb[TR1_CROCODILE_LAND1 + index].set_name("Crocodile");
            tomb[TR1_CROCODILE_LAND1 + index].initialise(TR1_CROCODILE_LAND1 + index, FUNCTION_SHADOW, 0);
            tomb[TR1_CROCODILE_LAND1 + index].set_shadow_size(85);
            tomb[TR1_CROCODILE_LAND1 + index].set_func_initialise(InitialiseCreature);
            tomb[TR1_CROCODILE_LAND1 + index].set_func_collide(CreatureCollision);
            tomb[TR1_CROCODILE_LAND1 + index].set_func_control(CtrlTR1_Crocodile);
            tomb[TR1_CROCODILE_LAND1 + index].set_func_draw(DrawTR1_Crocodile, NULL);
            tomb[TR1_CROCODILE_LAND1 + index].set_health(CROCODILE_HITPOINTS);
            tomb[TR1_CROCODILE_LAND1 + index].set_radius_and_pivot(CROCODILE_RADIUS, 600);
            tomb[TR1_CROCODILE_LAND1 + index].set_hit_effect(HIT_BLOOD);
            tomb[TR1_CROCODILE_LAND1 + index].set_creature(TRUE);
            tomb[TR1_CROCODILE_LAND1 + index].set_rotation_meshtree(7, ROT_Y);
            tomb[TR1_CROCODILE_LAND1 + index].set_save(TRUE, TRUE, TRUE, FALSE, TRUE);
        }
    }
}
