#include <StdAfx.h>
#include "utility.h"
#include "Class/TRLog.h"
#include "Class/TRLara.h"
#include "phd_math.h"

#ifdef _WIN32
#include <direct.h>
#endif

extern TYPE_phd_PushMatrix phd_PushMatrix;
extern TYPE_phd_TranslateRel phd_TranslateRel;
extern TYPE_phd_PutPolygons phd_PutPolygons;
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 TYPE2_S_GetObjectBounds S_GetObjectBounds_2;
extern TYPE_CalculateObjectLighting CalculateObjectLighting;
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_phd_PopMatrix_I phd_PopMatrix_I;
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_phd_RotYXZ_I phd_RotYXZ_I;
extern TYPE_gar_RotYXZsuperpack gar_RotYXZsuperpack;
extern TYPE_InitInterpolate InitInterpolate;
extern TYPE_GetFrames GetFrames;
extern TYPE_S_PrintShadow S_PrintShadow;
extern TYPE_phd_TranslateAbs phd_TranslateAbs;
extern TYPE2_GetBoundsAccurate GetBoundsAccurate_2;
extern TYPE_GetRandomControl GetRandomControl;
extern TYPE2_GetJointAbsPosition GetJointAbsPosition_2;
extern TYPE_TriggerDynamic TriggerDynamic;
extern TYPE_TriggerGunSmoke TriggerGunSmoke;
extern TYPE2_GetBoundsAccurate GetBoundsAccurate_2;
extern TYPE_phd_sqrt phd_sqrt;
extern TYPE_phd_atan phd_atan;
extern TYPE_GetAITarget GetAITarget;
extern TYPE_CreatureAIInfo CreatureAIInfo;
extern TYPE_AlertAllGuards AlertAllGuards;
extern TYPE_ShotLara ShotLara;
extern TYPE_GetFloor GetFloor;
extern TYPE_Richochet Richochet;
extern TYPE_DoBloodSplat DoBloodSplat;
extern TYPE_GetWaterDepth GetWaterDepth;
extern TYPE_GetWaterHeight GetWaterHeight;
extern TYPE_CreateFlare CreateFlare;
extern TYPE_DoFlareInHand DoFlareInHand;
extern TYPE_set_flare_arm set_flare_arm;
extern TYPE_draw_flare_meshes draw_flare_meshes;
extern TYPE_undraw_flare_meshes undraw_flare_meshes;
extern TYPE_SoundEffect SoundEffect;
extern TYPE_ready_flare ready_flare;
extern TYPE_InitialiseNewWeapons InitialiseNewWeapons;
extern TYPE_DrawAnimatingItem DrawAnimatingItem;
extern TYPE_CreatureActive CreatureActive;
extern TYPE_TriggerActive TriggerActive;
extern TYPE_phd_GetVectorAngles phd_GetVectorAngles;
extern TYPE_CreatureCollision CreatureCollision;

Utility Utils;
WeaponParser WeapParser;

#define WADE_DEPTH (STEP_L)
#define SWIM_DEPTH 730

void Utility::EnableZone(short object, CREATURE_INFO* creature)
{
	if (object >= 0 && object < TR_OBJECTS_NUMBER)
	{
		switch (MapToFirst(object, SLOTS_NUMBER))
		{
		case TR2_SPIDER1:
			creature->LOT.step = 512;
			creature->LOT.drop = -512;
			creature->LOT.fly = 0;
			creature->LOT.zone = ZONE_HUMAN;
			break;
		case TR1_BAT1:
		case TR2_CROW1:
		case TR2_EAGLE1:
			creature->LOT.step = 20480;
			creature->LOT.drop = -20480;
			creature->LOT.fly = 16;
			creature->LOT.zone = ZONE_FLYER;
			break;
		case TR2_BARRACUDA1:
			creature->LOT.step = 20480;
			creature->LOT.drop = -20480;
			creature->LOT.fly = 16;
			creature->LOT.zone = ZONE_CROC;
			break;
		case TR2_STICK_GOON1:
		case TR2_YETI1:
		case TR3_LIZARD1:
			creature->LOT.step = 1024;
			creature->LOT.drop = -1024;
			creature->LOT.fly = 0;
			creature->LOT.zone = ZONE_HUMAN;
			break;
		case TR1_GIANT_MUTANT1:
		case TR1_TYRANNOSAUR1:
		case TR2_TYRANNOSAUR1:
		case TR2_BIRD_MONSTER1:
			creature->LOT.step = 256;
			creature->LOT.drop = -256;
			creature->LOT.block_mask = BLOCKABLE;
			creature->LOT.fly = 0;
			creature->LOT.zone = ZONE_BASIC;
			break;
		case TR1_WOLF1:
		case TR1_LION_MALE1:
		case TR1_LION_FEMALE1:
		case TR1_PANTHER1:
			creature->LOT.step = 256;
			creature->LOT.drop = -1024;
			creature->LOT.fly = 0;
			creature->LOT.zone = ZONE_BASIC;
			break;
		case TR1_GORILLA1:
			creature->LOT.step = 512;
			creature->LOT.drop = -1024;
			creature->LOT.fly = 0;
			creature->LOT.zone = ZONE_HUMAN;
			break;
		case TR5_GUARD_FOUR1:
		case TR5_ARMED_BADDY_TWO1:
			creature->LOT.step = 1024;
			creature->LOT.drop = -1024;
			creature->LOT.fly = 0;
			creature->LOT.can_jump = 1;
			creature->LOT.zone = ZONE_HUMAN;
			break;
		}
	}
}

bool Utility::getPlugin(LPSTR name)
{
    int found;
    found = FindPluginID(name);
    if (found)
        return true;
    else
        return false;
}

short Utility::getLinks(int tsu_links_flags, int link_type)
{
    if (tsu_links_flags >= 0 && tsu_links_flags < TR_OBJECTS_NUMBER && link_type >= 0 && link_type < LNK_NUMBER)
        return tsu_links[tsu_links_flags][link_type];
    return NO_ITEM;
}

short Utility::getObjects(int tsu_objects_flags)
{
    if (tsu_objects_flags >= 0 && tsu_objects_flags < TR_OBJECTS_NUMBER)
        return tsu_objects[tsu_objects_flags];
    return NO_ITEM;
}

bool Utility::getSnowmobileControl(ControlVehicles control)
{
    SWITCH(control)
        CASE_R(IN_ACTION, PerformConditionTrigger(NULL, 13, 8, 1));
        CASE_R(IN_FORWARD, PerformConditionTrigger(NULL, 13, 0, 1));
        CASE_R(IN_BACKWARD, PerformConditionTrigger(NULL, 13, 1, 1));
        CASE_R(IN_LEFT, PerformConditionTrigger(NULL, 13, 2, 1));
        CASE_R(IN_RIGHT, PerformConditionTrigger(NULL, 13, 3, 1));
        CASE_R(IN_SLOW, PerformConditionTrigger(NULL, 13, 6, 1));
        CASE_R(IN_SPACE, PerformConditionTrigger(NULL, 12, 57, 1));
        CASE_R(IN_UP_DOWN, PerformConditionTrigger(NULL, 13, 0, 1)|PerformConditionTrigger(NULL, 13, 1, 1));
        CASE_R(IN_LEFT_RIGHT, PerformConditionTrigger(NULL, 13, 2, 1)|PerformConditionTrigger(NULL, 13, 3, 1));
        CASE_R(IN_JUMP, PerformConditionTrigger(NULL, 13, 7, 1));
        CASE_R(IN_ROLL, PerformConditionTrigger(NULL, 13, 12, 1));
        CASE_R(IN_LOOK, PerformConditionTrigger(NULL, 13, 11, 1));
    SWITCH_END;

    logger.for_value("This command is not registered !: ", control);
    return false;
}

void Utility::jmn_PopMatrix()
{
    *Trng.pGlobTomb4->pAdr->pZonaRecord30 -= 48;
}

int Utility::getRelativeAnimation(ITEM_INFO* item)
{
    return (Ptr_VetObjects[item->object_number].anim_index - item->anim_number);
}

int Utility::getRelativeFrame(ITEM_INFO* item)
{
    return (Ptr_VetAnimations[item->anim_number].frame_base - item->frame_number);
}

bool Utility::getPluginAimingStatus()
{
    return tsu_aiming_status;
}

bool Utility::getPluginAiming(int TSU_flags)
{
    if (TSU_flags >= 0 && TSU_flags < AIM_NUMBER && tsu_aiming_status)
        return tsu_aiming[TSU_flags];
    return false;
}

void draw_flare(void)
{

}

void undraw_flare(void)
{

}

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

void Utility::ShootAtLara(FX_INFO * fx)
{
    int x, y, z, distance;
    short* bounds;

    x = LaraItem->pos.x_pos - fx->pos.x_pos;
    y = LaraItem->pos.y_pos - fx->pos.y_pos;
    z = LaraItem->pos.z_pos - fx->pos.z_pos;

    bounds = (short*)GetBoundsAccurate_2(LaraItem);
    y += bounds[3] + (bounds[2] - bounds[3]) * 3 / 4;

    distance = phd_sqrt_tr2(SQUARE(x) + SQUARE(z));
    fx->pos.x_rot = -phd_atan_tr2(distance, y);
    fx->pos.y_rot = phd_atan_tr2(z, x);
    fx->pos.x_rot += (GetRandomControl() - 0x4000) / 0x40;
    fx->pos.y_rot += (GetRandomControl() - 0x4000) / 0x40;
}

bool Utility::Footstep::isFootstepCustomizeExist()
{
    return false;
}

short Utility::Footstep::getCustomizeFootstep(FloorSoundID sound_id)
{
    Get(enumGET.MY_CUSTOMIZE_COMMAND, CUST_TSU_FOOTSTEP, NO_ITEM);

    SWITCH(sound_id)
        CASE_NOT_EMPTY(FS_MUD, this->footstep_default.mud);
        CASE_NOT_EMPTY(FS_SNOW, this->footstep_default.snow);
        CASE_NOT_EMPTY(FS_SAND, this->footstep_default.sand);
        CASE_NOT_EMPTY(FS_GRAVEL, this->footstep_default.gravel);
        CASE_NOT_EMPTY(FS_ICE, this->footstep_default.ice);
        CASE_NOT_EMPTY(FS_WATER, this->footstep_default.water);
        CASE_NOT_EMPTY(FS_STONE, this->footstep_default.stone);
        CASE_NOT_EMPTY(FS_WOOD, this->footstep_default.wood);
        CASE_NOT_EMPTY(FS_METAL, this->footstep_default.metal);
        CASE_NOT_EMPTY(FS_MARBLE, this->footstep_default.marble);
        CASE_NOT_EMPTY(FS_GRASS, this->footstep_default.mud);
        CASE_NOT_EMPTY(FS_CONCRETE, this->footstep_default.concrete);
        CASE_NOT_EMPTY(FS_OLD_WOOD, this->footstep_default.old_wood);
        CASE_NOT_EMPTY(FS_OLD_METAL, this->footstep_default.old_metal);
        CASE_D1(logger.for_value("[getCustomizeFootstep()] the sound id is not defined: ", sound_id));
    SWITCH_END;

    return NO_ITEM;
}

void Utility::Footstep::setCustomizeFootstep(FloorSoundID sound_id)
{
    SWITCH(sound_id)
        CASE_C(FS_MUD, this->footstep.mud);
        CASE_C(FS_SNOW, this->footstep.snow);
        CASE_C(FS_SAND, this->footstep.sand);
        CASE_C(FS_GRAVEL, this->footstep.gravel);
        CASE_C(FS_ICE, this->footstep.ice);
        CASE_C(FS_WATER, this->footstep.water);
        CASE_C(FS_STONE, this->footstep.stone);
        CASE_C(FS_WOOD, this->footstep.wood);
        CASE_C(FS_METAL, this->footstep.metal);
        CASE_C(FS_MARBLE, this->footstep.marble);
        CASE_C(FS_GRASS, this->footstep.grass);
        CASE_C(FS_CONCRETE, this->footstep.concrete);
        CASE_C(FS_OLD_WOOD, this->footstep.old_wood);
        CASE_C(FS_OLD_METAL, this->footstep.old_metal);
        CASE_D1(logger.for_value("[setFootstep()] customized footstep sound id is unknown: ", sound_id));
    SWITCH_END;
}

void Utility::Footstep::initialiseFootstep()
{
    this->setFootstep(FS_MUD, 289);
    this->setFootstep(FS_SNOW, 292);
    this->setFootstep(FS_SAND, 292);
    this->setFootstep(FS_GRAVEL, 291);
    this->setFootstep(FS_ICE, 291);
    this->setFootstep(FS_WATER, 18);
    this->setFootstep(FS_STONE, 0);
    this->setFootstep(FS_WOOD, 293);
    this->setFootstep(FS_METAL, 295);
    this->setFootstep(FS_MARBLE, 294);
    this->setFootstep(FS_GRASS, 292);
    this->setFootstep(FS_CONCRETE, 0);
    this->setFootstep(FS_OLD_WOOD, 293);
    this->setFootstep(FS_OLD_METAL, 295);

    // this customize is exist ?
    if (this->isFootstepCustomizeExist())
    {
        logger.basic("Customize SoundFX Choosed by default (only if customize is in script) !");
        this->setCustomizeFootstep(FS_MUD);
        this->setCustomizeFootstep(FS_SNOW);
        this->setCustomizeFootstep(FS_SAND);
        this->setCustomizeFootstep(FS_GRAVEL);
        this->setCustomizeFootstep(FS_ICE);
        this->setCustomizeFootstep(FS_WATER);
        this->setCustomizeFootstep(FS_STONE);
        this->setCustomizeFootstep(FS_WOOD);
        this->setCustomizeFootstep(FS_METAL);
        this->setCustomizeFootstep(FS_MARBLE);
        this->setCustomizeFootstep(FS_GRASS);
        this->setCustomizeFootstep(FS_CONCRETE);
        this->setCustomizeFootstep(FS_OLD_WOOD);
        this->setCustomizeFootstep(FS_OLD_METAL);
    }
}

void Utility::Footstep::setFootstep(FloorSoundID sound_id, short customize_id)
{
    SWITCH(sound_id)
        CASE(FS_MUD, this->footstep_default.mud, customize_id);
        CASE(FS_SNOW, this->footstep_default.snow, customize_id);
        CASE(FS_SAND, this->footstep_default.sand, customize_id);
        CASE(FS_GRAVEL, this->footstep_default.gravel, customize_id);
        CASE(FS_ICE, this->footstep_default.ice, customize_id);
        CASE(FS_WATER, this->footstep_default.water, customize_id);
        CASE(FS_STONE, this->footstep_default.stone, customize_id);
        CASE(FS_WOOD, this->footstep_default.wood, customize_id);
        CASE(FS_METAL, this->footstep_default.metal, customize_id);
        CASE(FS_MARBLE, this->footstep_default.marble, customize_id);
        CASE(FS_GRASS, this->footstep_default.grass, customize_id);
        CASE(FS_CONCRETE, this->footstep_default.concrete, customize_id);
        CASE(FS_OLD_WOOD, this->footstep_default.old_wood, customize_id);
        CASE(FS_OLD_METAL, this->footstep_default.old_metal, customize_id);
        CASE_D1(logger.for_value("[setFootstep()] default footstep sound id is unknown: ", sound_id));
    SWITCH_END;
}

short Utility::Footstep::getFootstep(FloorSoundID sound_id)
{
    if (this->isFootstepCustomizeExist())
    {
        SWITCH(sound_id)
            CASE_RDC(FS_MUD, this->footstep.mud);
            CASE_RDC(FS_SNOW, this->footstep.snow);
            CASE_RDC(FS_SAND, this->footstep.sand);
            CASE_RDC(FS_GRAVEL, this->footstep.gravel);
            CASE_RDC(FS_ICE, this->footstep.ice);
            CASE_RDC(FS_WATER, this->footstep.water);
            CASE_RDC(FS_STONE, this->footstep.stone);
            CASE_RDC(FS_WOOD, this->footstep.wood);
            CASE_RDC(FS_METAL, this->footstep.metal);
            CASE_RDC(FS_MARBLE, this->footstep.marble);
            CASE_RDC(FS_GRASS, this->footstep.grass);
            CASE_RDC(FS_CONCRETE, this->footstep.concrete);
            CASE_RDC(FS_OLD_WOOD, this->footstep.old_wood);
            CASE_RDC(FS_OLD_METAL, this->footstep.old_metal);
            CASE_D2(logger.for_value("[getFootstep()]  getting the customize footstep sound id is unknown: ", sound_id), logger.basic("[getFootstep()] returning the customize footstep id: -1"));
        SWITCH_END;
    }
    else
    {
        SWITCH(sound_id)
            CASE_RDD(FS_MUD, this->footstep_default.mud);
            CASE_RDD(FS_SNOW, this->footstep_default.snow);
            CASE_RDD(FS_SAND, this->footstep_default.sand);
            CASE_RDD(FS_GRAVEL, this->footstep_default.gravel);
            CASE_RDD(FS_ICE, this->footstep_default.ice);
            CASE_RDD(FS_WATER, this->footstep_default.water);
            CASE_RDD(FS_STONE, this->footstep_default.stone);
            CASE_RDD(FS_WOOD, this->footstep_default.wood);
            CASE_RDD(FS_METAL, this->footstep_default.metal);
            CASE_RDD(FS_MARBLE, this->footstep_default.marble);
            CASE_RDD(FS_GRASS, this->footstep_default.grass);
            CASE_RDD(FS_CONCRETE, this->footstep_default.concrete);
            CASE_RDD(FS_OLD_WOOD, this->footstep_default.old_wood);
            CASE_RDD(FS_OLD_METAL, this->footstep_default.old_metal);
            CASE_D2(logger.for_value("[getFootstep()]  getting the default footstep sound id is unknown: ", sound_id), logger.basic("[getFootstep()] returning the default footstep id: -1"));
        SWITCH_END;
    }

    return NO_ITEM;
}

void Utility::DrawMuzzleFlash_LightAndSmoke(ITEM_INFO* item, BITE_INFO *bite)
{
    StrMovePosition pos;
    pos.RelX = bite->x;
    pos.RelY = bite->y;
    pos.RelZ = bite->z;
    GetJointAbsPosition_2(item, &pos, bite->mesh_num);
    TriggerDynamic(pos.RelX, pos.RelY, pos.RelZ, 13, 128, 128, 128);                      // light
}

int Utility::EnemyShot(ITEM_INFO *item, AI_INFO *info, BITE_INFO *bite, short torso_angle, int damage)
{
    DrawMuzzleFlash_LightAndSmoke(item, bite);
    return ShotLara(item, info, bite, torso_angle, damage);
}

short Utility::getObjectAttribute(int slot_id, int attribute_type)
{
    if (slot_id >= 0 && slot_id < TR_OBJECTS_NUMBER && attribute_type >= 0 && attribute_type < ATT_NUMBER && tsu_objects[slot_id] != NO_ITEM)
        return tsu_attributes[slot_id][attribute_type];
    return NO_ITEM;
}

short Utility::getObjectProperty(int slot_id, int property_type)
{
    if (slot_id >= 0 && slot_id < TR_OBJECTS_NUMBER && property_type >= 0 && property_type < PTY_NUMBER && tsu_objects[slot_id] != NO_ITEM)
        return tsu_properties[slot_id][property_type];
    return NO_ITEM;
}

short Utility::getObjectOption(int slot_id, int option_type)
{
    if (slot_id >= 0 && slot_id < TR_OBJECTS_NUMBER && option_type >= 0 && option_type < OPT_NUMBER && tsu_objects[slot_id] != NO_ITEM)
        return tsu_options[slot_id][option_type];
    return NO_ITEM;
}

short Utility::getObjectMeshswap(int slot_id, int mesh_id, int meshswap_type)
{
    if (slot_id >= 0 && slot_id < TR_OBJECTS_NUMBER && mesh_id >= 0 && mesh_id < 32 && meshswap_type >= 0 && meshswap_type < MSH_NUMBER && tsu_objects[slot_id] != NO_ITEM)
        return tsu_meshswaps[slot_id][mesh_id][meshswap_type];
    return NO_ITEM;
}

short Utility::getObjectSprite(int slot_id, int sprite_type)
{
    if (slot_id >= 0 && slot_id < TR_OBJECTS_NUMBER && sprite_type >= 0 && sprite_type < SPR_NUMBER && tsu_objects[slot_id] != NO_ITEM)
        return tsu_sprites[slot_id][sprite_type];
    return NO_ITEM;
}

bool Utility::getVehicleControl(VehicleID id, ControlVehicles control)
{
    SWITCH(id)
        CASE_R(VEH_SNOWMOBILE, this->getSnowmobileControl(control));
    SWITCH_END;

    logger.for_value("This command is not registered !: ", control);
    return false;
}

bool Utility::getFloorSound(ITEM_INFO* item, FloorSoundID sound_id_to_get)
{
    short sound, room_number;
    FLOOR_INFO* floor;

    floor = (FLOOR_INFO*)GetFloor(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, &room_number);
    sound = ConvertSFXTypeToTR4(floor->fx);

    SWITCH(sound_id_to_get)
        CASE_CR(FS_MUD, sound, sound_id_to_get, true);
        CASE_CR(FS_SNOW, sound, sound_id_to_get, true);
        CASE_CR(FS_SAND, sound, sound_id_to_get, true);
        CASE_CR(FS_GRAVEL, sound, sound_id_to_get, true);
        CASE_CR(FS_ICE, sound, sound_id_to_get, true);
        CASE_CR(FS_WATER, sound, sound_id_to_get, true);
        CASE_CR(FS_STONE, sound, sound_id_to_get, true);
        CASE_CR(FS_WOOD, sound, sound_id_to_get, true);
        CASE_CR(FS_METAL, sound, sound_id_to_get, true);
        CASE_CR(FS_MARBLE, sound, sound_id_to_get, true);
        CASE_CR(FS_GRASS, sound, sound_id_to_get, true);
        CASE_CR(FS_CONCRETE, sound, sound_id_to_get, true);
        CASE_CR(FS_OLD_WOOD, sound, sound_id_to_get, true);
        CASE_CR(FS_OLD_METAL, sound, sound_id_to_get, true);
    SWITCH_END;

    logger.for_value("Wrong or Unknown sound type detected !!: ", sound_id_to_get);
    return false;
}

int Utility::getSnowmobileSound(short SNOW_flags)
{
    if (Get(enumGET.MY_CUSTOMIZE_COMMAND, CUST_TSU_SNOWMOBILE_SFX, SNOW_flags))
    {
        return GET.pCust->pVetArg[SNOW_flags];
    }
    else
    {
        SWITCH(SNOW_flags)
            CASE_R(SNOW_START, 131);
            CASE_R(SNOW_STOP, 143);
            CASE_R(SNOW_HITF, 136);
            CASE_R(SNOW_HITB, 135);
            CASE_R(SNOW_IDLE, 132);
            CASE_R(SNOW_MOVING, 134);
            CASE_R(SNOW_MOVING_MAX, 133);
        SWITCH_END;
    }

    return NO_ITEM;
}

void Utility::checkWaterHeight_Vehicles(ITEM_INFO* v, void(*SkidooExplode)(ITEM_INFO *current_vehicle))
{
    int wh, wd, hfw;

    wd = GetWaterDepth(v->pos.x_pos, v->pos.y_pos, v->pos.z_pos, v->room_number);
    wh = GetWaterHeight(v->pos.x_pos, v->pos.y_pos, v->pos.z_pos, v->room_number);

    if (wh != NO_HEIGHT)
        hfw = v->pos.y_pos - wh;
    else
        hfw = NO_HEIGHT;

    if ((hfw != NO_HEIGHT) && (hfw > WADE_DEPTH) && (wd > (SWIM_DEPTH - STEP_L)))
        SkidooExplode(v);
}

#define CHECK_FLAREBOX PerformConditionTrigger("Plugin_ClassicInventory", 101, 23, 1)
#define DELETE_FLAREBOX PerformFlipeffect("Plugin_ClassicInventory", 701, 23, 1)

bool Utility::Inv_RequestItem(short slot)
{
    return false;
}

void Utility::Inv_RemoveItem(short slot)
{

}

bool Utility::IsVaultEnabled(short object, int vault)
{
	bool enabled;

	enabled = false;
	if (object >= 0 && object < TR_OBJECTS_NUMBER)
	{
		switch (MapToFirst(object, SLOTS_NUMBER))
		{
		case TR2_STICK_GOON1:
		case TR2_YETI1:
		case TR3_LIZARD1:
			if (vault == -4 || vault >= 2 && vault <= 4)
				enabled = true;
			break;
		case TR1_GORILLA1:
			if (vault == 2)
				enabled = true;
			break;
		case TR5_GUARD_FOUR1:
		case TR5_ARMED_BADDY_TWO1:
			if (vault >= -4 && vault <= -2 || vault >= 2 && vault <= 4)
				enabled = true;
			break;
		}
	}
	return enabled;
}

void Utility::AddPoison(short poison)
{
	int value;

	value = Lara.getPoison1() + (poison << 4);
	if (value < 0)
		value = 0;
	else if (value > 32767)
		value = 32767;
	Lara.setPoison1(value);
	Lara.setPoison2(Lara.getPoison1());
	mydata.save.current.poisoned = value;
	mydata.save.current.dpoisoned = mydata.save.current.poisoned;
}

short Utility::GetPoison()
{
	return Lara.getPoison1() >> 4;
}

bool Utility::isFolderExists(LPCSTR folder_name)
{
    return false;
}

bool Utility::isFileExists(LPCSTR file_name)
{
    return false;
}

void Utility::createFolders(LPCSTR folder_name)
{

}

LPSTR Utility::ConvertToCHAR::FootstepToCHAR(FloorSoundID sound_id)
{
    SWITCH(sound_id)
        CASE_R(FS_MUD, "FS_MUD");
        CASE_R(FS_SNOW, "FS_SNOW");
        CASE_R(FS_SAND, "FS_SAND");
        CASE_R(FS_GRAVEL, "FS_GRAVEL");
        CASE_R(FS_ICE, "FS_ICE");
        CASE_R(FS_WATER, "FS_WATER");
        CASE_R(FS_STONE, "FS_STONE");
        CASE_R(FS_WOOD, "FS_WOOD");
        CASE_R(FS_METAL, "FS_METAL");
        CASE_R(FS_MARBLE, "FS_MARBLE");
        CASE_R(FS_GRASS, "FS_GRASS");
        CASE_R(FS_CONCRETE, "FS_CONCRETE");
        CASE_R(FS_OLD_WOOD, "FS_OLD_WOOD");
        CASE_R(FS_OLD_METAL, "FS_OLD_METAL");
    SWITCH_END;

    logger.for_value("[FootstepToCHAR()] getting the footstep sound name is unknown: ", sound_id);
    logger.basic("[FootstepToCHAR()] returning the default name !");
    return "UNKNOWN";
}

LPSTR Utility::ConvertToCHAR::GunTypeToCHAR(short value)
{
    switch (value)
    {
    case HOLD_PISTOLS:          return "HOLD_PISTOLS";
    case HOLD_UZI:              return "HOLD_UZI";
    case HOLD_SHOTGUN:          return "HOLD_SHOTGUN";
    case HOLD_CROSSBOW:         return "HOLD_CROSSBOW";
    case HOLD_GRENADEGUN:       return "HOLD_GRENADEGUN";
    case HOLD_REVOLVER:         return "HOLD_REVOLVER";
    case HOLD_FLARE:            return "HOLD_FLARE";
    case HOLD_ANY_TORCH:        return "HOLD_ANY_TORCH";
    case HOLD_FIRED_TORCH:      return "HOLD_FIRED_TORCH";
    case HOLD_JEEP:             return "HOLD_JEEP";
    case HOLD_KAYAK:            return "HOLD_KAYAK";
    case HOLD_MOTOR_BOAT:       return "HOLD_MOTOR_BOAT";
    case HOLD_OUT_TORCH:        return "HOLD_OUT_TORCH";
    case HOLD_POLE:             return "HOLD_POLE";
    case HOLD_ROPE:             return "HOLD_ROPE";
    case HOLD_SIDECAR:          return "HOLD_SIDECAR";
    case HOLD_SNOWMOBILE_GUNS:  return "HOLD_SNOWMOBILE";

    default:
        return "UNKNOWN GUN TYPE !!!";
    }
}

LPSTR Utility::ConvertToCHAR::WaterStatusToCHAR(short value)
{
    switch (value)
    {
    case LARA_ABOVEWATER:
        return "ABOVEWATER";
    case LARA_UNDERWATER:
        return "UNDERWATER";
    case LARA_SURFACE:
        return "SURFACE";
    case LARA_CHEAT:
        return "CHEAT";
    case LARA_WADE:
        return "WADE";
    default:
        return "UNKNOWN WATER STATUS !!!";
    }
}

LPSTR Utility::ConvertToCHAR::FlareAgeToCHAR(short value)
{
    if (Lara.getGunType() != HOLD_FLARE)
        return "FLARE_NOT_IN_HAND";
    else if (Lara.getGunType() == HOLD_FLARE)
        return "FLARE_USED_AFTER_ANIMATION";
    else
        return "UNKNOWN_STRING";
}

LPSTR Utility::ConvertToCHAR::WeaponBackItemToCHAR(short value)
{
    return "NO_ITEM";
}

void Utility::FindClass::Statics(ITEM_INFO* item, int *pStaticIndex, int *pStaticRoom)
{
    PHD_VECTOR pos;
    pos.x = item->pos.x_pos;
    pos.y = item->pos.y_pos;
    pos.z = item->pos.z_pos;

    Find(enumFIND.STATICS_NEARBY, -1, item->room_number, -1, 0, &pos);

    for (int i = 0; i < FIND.TotStatics; i++)
    {
        *pStaticIndex = FIND.VetStatics[i].ObjIndex;
        *pStaticRoom = FIND.VetStatics[i].RoomIndex;
    }
}

ITEM_INFO* Utility::FindClass::Moveables(ITEM_INFO* src, short slot_number, int distance)
{
    PHD_VECTOR pos;
    int i;
    WORD item_number;
    ITEM_INFO* item;
    OBJECT_INFO* obj;

    pos.x = src->pos.x_pos;
    pos.y = src->pos.y_pos;
    pos.z = src->pos.z_pos;

    if (slot_number != NULL)
        Find(enumFIND.ITEMS_NEARBY, slot_number, src->room_number, NO_ITEM, distance, &pos);
    else
        Find(enumFIND.ITEMS_NEARBY, NO_ITEM, src->room_number, NO_ITEM, distance, &pos);

    for (i = 0; i < FIND.TotItems; i++)
    {
        item_number = FIND.VetItems[i];
        if (item_number != NO_ITEM)
        {
            item = &Ptr_VetItems[item_number];
            if (item != nullptr)
            {
                obj = &Ptr_VetObjects[item->object_number];
                if (!obj->intelligent)
                    return item;
            }
        }
    }

    return nullptr;
}

ITEM_INFO* Utility::FindClass::Entity(ITEM_INFO* src, short slot_number, int distance)
{
    PHD_VECTOR pos;
    int i;
    WORD item_number;
    ITEM_INFO* item;
    OBJECT_INFO* obj;

    pos.x = src->pos.x_pos;
    pos.y = src->pos.y_pos;
    pos.z = src->pos.z_pos;

    if (slot_number != NULL)
        Find(enumFIND.ITEMS_NEARBY, slot_number, src->room_number, NO_ITEM, distance, &pos);
    else
        Find(enumFIND.ITEMS_NEARBY, NO_ITEM, src->room_number, NO_ITEM, distance, &pos);

    for (i = 0; i < FIND.TotItems; i++)
    {
        item_number = FIND.VetItems[i];
        if (item_number != NO_ITEM)
        {
            item = &Ptr_VetItems[item_number];
            if (item != nullptr)
            {
                obj = &Ptr_VetObjects[item->object_number];
                if (obj->intelligent)
                    return item;
            }
        }
    }

    return nullptr;
}

ITEM_INFO* Utility::FindClass::PushBlock(ITEM_INFO* src)
{
    return nullptr;
}

void WeaponParser::Initialize()
{

}

void WeaponParser::setName(LPCSTR name)
{

}

void WeaponParser::setLock(short ymin, short ymax, short xmin, short xmax)
{

}

void WeaponParser::setLeft(short ymin, short ymax, short xmin, short xmax)
{

}

void WeaponParser::setRight(short ymin, short ymax, short xmin, short xmax)
{

}

void WeaponParser::setAimSpeed(short value)
{

}

void WeaponParser::setShotAccuracy(short value)
{

}

void WeaponParser::setGunHeight(short value)
{

}

void WeaponParser::setTargetDistance(short value)
{

}

void WeaponParser::setDamage(char value)
{

}

void WeaponParser::setRecoilFrame(char value)
{

}

void WeaponParser::setFlashTime(char value)
{

}

void WeaponParser::setDrawFrame(char value)
{

}

void WeaponParser::setSampleNumber(short value)
{

}

void WeaponParser::Save(LPCSTR file_name)
{

}

void WeaponParser::setComment(LPCSTR contents)
{

}

int MapToFirst(int value, int size)
{
    return value - value % size;
}

void RotateItem(short* orientation)
{
    short angle[2];

    phd_GetVectorAngles(Camera_Pos.x - Camera_Target.x, Camera_Pos.y - Camera_Target.y, Camera_Pos.z - Camera_Target.z, angle);
    orientation[1] = angle[0];
    orientation[0] = angle[1];
}

void GetBaddieTarget(short item_number, bool is_monk)
{
    ITEM_INFO* item, *enemy, *target;
    int slot, best_distance, distance, x, y, z;
    CREATURE_INFO* creature;
    short object, first;

    item = &Ptr_VetItems[item_number];
    best_distance = 0x7FFFFFFF;
    target = NULL;
    for (slot = 0; slot < 32; ++slot)
    {
        creature = &baddie_slots[slot];
        if (creature->item_num != -1 && creature->item_num != item_number)
        {
            enemy = &Ptr_VetItems[creature->item_num];
            object = tsu_slots[enemy->object_number];
            if (object >= 0 && object < TR_OBJECTS_NUMBER)
            {
                first = MapToFirst(object, SLOTS_NUMBER);
                if (is_monk ? first == TR2_MERCENARY1 || first == TR2_MERCENARY_BLACK_MASK1 : first == TR2_MONK1)
                {
                    x = (enemy->pos.x_pos - item->pos.x_pos) >> 6;
                    y = (enemy->pos.y_pos - item->pos.y_pos) >> 6;
                    z = (enemy->pos.z_pos - item->pos.z_pos) >> 6;
                    distance = SQUARE(x) + SQUARE(y) + SQUARE(z);
                    if (distance < best_distance)
                    {
                        target = enemy;
                        best_distance = distance;
                    }
                }
            }
        }
    }
    creature = (CREATURE_INFO*) item->data;
    if (!target)
    {
        creature->enemy = is_monk && !mydata.save.current.monks_attack_lara ? NULL : LaraItem;
    }
    else
    {
        if (!is_monk || mydata.save.current.monks_attack_lara)
        {
            x = (LaraItem->pos.x_pos - item->pos.x_pos) >> 6;
            y = (LaraItem->pos.y_pos - item->pos.y_pos) >> 6;
            z = (LaraItem->pos.z_pos - item->pos.z_pos) >> 6;
            distance = SQUARE(x) + SQUARE(y) + SQUARE(z);
            if (distance < best_distance)
            {
                target = LaraItem;
                best_distance = distance;
            }
        }
        enemy = creature->enemy;
        if (enemy && enemy->status == STS_ACTIVE)
        {
            x = (enemy->pos.x_pos - item->pos.x_pos) >> 6;
            y = (enemy->pos.y_pos - item->pos.y_pos) >> 6;
            z = (enemy->pos.z_pos - item->pos.z_pos) >> 6;
            distance = SQUARE(x) + SQUARE(y) + SQUARE(z);
            if (distance < best_distance + 4194304)
                creature->enemy = target;
        }
        else
        {
            creature->enemy = target;
        }
    }
}

DWORD DecodeTimer(WORD Timer, WORD Extra)
{
	if (Timer != TIMER_EXTENDED)
		return Timer;
	return 1 << (Extra - 1);
}