#include "..\script_component.hpp"
/*
 * Author: Dslyecxi, Jonpas, kymckay
 * Handles drawing the currently selected or cooked throwable.
 *
 * Arguments:
 * None
 *
 * Return Value:
 * None
 *
 * Example:
 * call ace_advanced_throwing_fnc_drawThrowable
 *
 * Public: No
 */

if (dialog || {!(ACE_player getVariable [QGVAR(inHand), false])} || {!([ACE_player, true] call FUNC(canPrepare))}) exitWith {
    [ACE_player, "In dialog or no throwable in hand or cannot prepare throwable"] call FUNC(exitThrowMode);
};

private _primed = ACE_player getVariable [QGVAR(primed), false];
private _activeThrowable = ACE_player getVariable [QGVAR(activeThrowable), objNull];

// Exit if throwable died primed in hand
if (isNull _activeThrowable && {_primed}) exitWith {
    [ACE_player, "Throwable died primed in hand"] call FUNC(exitThrowMode);
};

private _throwable = currentThrowable ACE_player;

// Inventory check
if (_throwable isEqualTo [] && {!_primed}) exitWith {
    [ACE_player, "No valid throwables"] call FUNC(exitThrowMode);
};

private _throwableMag = _throwable param [0, "#none"];

// If not primed, double check we actually have the magazine in inventory
if ((!_primed) && {!((_throwableMag in (uniformItems ACE_player)) || {_throwableMag in (vestItems ACE_player)} || {_throwableMag in (backpackItems ACE_player)})}) exitWith {
    [ACE_player, "No valid throwable (glitched currentThrowable)"] call FUNC(exitThrowMode);
};

// Get correct throw power for primed grenade
if (_primed) then {
    // If ammo type is not found:
    // What we're trying to throw must not be a normal throwable because it is not in our lookup hash (e.g. 40mm smoke)
    // Just use HandGrenade as it has an average initSpeed value
    _throwableMag = (uiNamespace getVariable QGVAR(ammoMagLookup)) getOrDefault [typeOf _activeThrowable, "HandGrenade"];
};

// Some throwables have different classname for magazine and ammo
// Primed magazine may be different, read speed before checking primed magazine!
private _throwSpeed = getNumber (configFile >> "CfgMagazines" >> _throwableMag >> "initSpeed");

// Reduce power of throw over shoulder and to sides
private _unitDirVisual = getDirVisual ACE_player;
private _cameraDir = getCameraViewDirection ACE_player;
_cameraDir = (_cameraDir select 0) atan2 (_cameraDir select 1);

private _phi = abs (_cameraDir - _unitDirVisual) % 360;
_phi = [_phi, 360 - _phi] select (_phi > 180);

private _power = linearConversion [0, 180, _phi - 30, 1, 0.3, true];
ACE_player setVariable [QGVAR(throwSpeed), _throwSpeed * _power];

#ifdef DEBUG_MODE_FULL
hintSilent format ["Heading: %1\nPower: %2\nSpeed: %3\nThrowMag: %4\nMuzzle: %5", _phi, _power, _throwSpeed * _power, _throwableMag, ACE_player getVariable [QGVAR(activeMuzzle), ""]];
#endif

private _throwableType = getText (configFile >> "CfgMagazines" >> _throwableMag >> "ammo");

if (!([ACE_player] call FUNC(canThrow)) && {!_primed}) exitWith {
    if (!isNull _activeThrowable) then {
        deleteVehicle _activeThrowable;
        // Restore muzzle ammo (setAmmo 1 has no impact if no appliccable throwable in inventory)
        ACE_player setAmmo [ACE_player getVariable [QGVAR(activeMuzzle), ""], 1];
    };
};

if (isNull _activeThrowable || {(_throwableType != typeOf _activeThrowable) && {!_primed}}) then {
    if (!isNull _activeThrowable) then {
        deleteVehicle _activeThrowable;
        // Restore muzzle ammo (setAmmo 1 has no impact if no appliccable throwable in inventory)
        ACE_player setAmmo [ACE_player getVariable [QGVAR(activeMuzzle), ""], 1];
    };
    _activeThrowable = _throwableType createVehicleLocal [0, 0, 0];
    _activeThrowable enableSimulation false;
    ACE_player setVariable [QGVAR(activeThrowable), _activeThrowable];

    // Set muzzle ammo to 0 to block vanilla throwing (can only be 0 or 1)
    private _muzzle = _throwableMag call FUNC(getMuzzle);
    ACE_player setAmmo [_muzzle, 0];
    ACE_player setVariable [QGVAR(activeMuzzle), _muzzle];
};

// Exit in case of explosion in hand
if (isNull _activeThrowable) exitWith {
    [ACE_player, "No active throwable (explosion in hand)"] call FUNC(exitThrowMode);
};

// Exit if locality changed (someone took the throwable from hand)
if (!local _activeThrowable && {ACE_player getVariable [QGVAR(localityChanged), true]}) exitWith {
    [ACE_player, "Throwable locality changed"] call FUNC(exitThrowMode);
};

// Set position
private _posHeadRel = ACE_player selectionPosition "head";

private _leanCoef = (_posHeadRel select 0) - 0.15; // 0.15 counters the base offset
// Don't take leaning into account when weapon is lowered due to jiggling when walking side-ways (bandaid)
if (abs _leanCoef < 0.15 || {vehicle ACE_player != ACE_player} || {weaponLowered ACE_player}) then {
    _leanCoef = 0;
};

private _posCameraWorld = AGLToASL (positionCameraToWorld [0, 0, 0]);
_posHeadRel = _posHeadRel vectorAdd [-0.03, 0.01, 0.15]; // Bring closer to eyePos value
private _posFin = ACE_player modelToWorldVisualWorld _posHeadRel;

private _throwType = ACE_player getVariable [QGVAR(throwType), THROW_TYPE_DEFAULT];

// Orient it nicely, point towards player
_activeThrowable setDir (_unitDirVisual + 90);

private _pitch = [-30, -90] select (_throwType == "high");
[_activeThrowable, _pitch, 0] call BIS_fnc_setPitchBank;

// Force drop mode if underwater
if (underwater player) then {
    ACE_player setVariable [QGVAR(dropMode), true];
};

if (ACE_player getVariable [QGVAR(dropMode), false]) then {
    _posFin = _posFin vectorAdd (AGLToASL (positionCameraToWorld [_leanCoef, 0, ACE_player getVariable [QGVAR(dropDistance), DROP_DISTANCE_DEFAULT]]));

    // Even vanilla throwables go through glass, only "GEOM" LOD will stop it but that will also stop it when there is no glass in a window
    if (lineIntersects [_posCameraWorld, _posFin vectorDiff _posCameraWorld]) then {
        ACE_player setVariable [QGVAR(dropDistance), ((ACE_player getVariable [QGVAR(dropDistance), DROP_DISTANCE_DEFAULT]) - 0.1) max DROP_DISTANCE_DEFAULT];
    };
} else {
    private _xAdjustBonus = [0, -0.075] select (_throwType == "high");
    private _yAdjustBonus = [0, 0.1] select (_throwType == "high");
    private _cameraOffset = [_leanCoef, 0, 0.3] vectorAdd [-0.1, -0.15, -0.03] vectorAdd [_xAdjustBonus, _yAdjustBonus, 0];

    _posFin = _posFin vectorAdd (AGLToASL (positionCameraToWorld _cameraOffset));

    if (vehicle ACE_player != ACE_player) then {
        // Counteract vehicle velocity including acceleration
        private _vectorDiff = (velocity (vehicle ACE_player)) vectorMultiply (time - (ACE_player getVariable [QGVAR(lastTick), time]) + 0.01);
        _posFin = _posFin vectorAdd _vectorDiff;
        ACE_player setVariable [QGVAR(lastTick), time];
    };
};

_activeThrowable setPosASL (_posFin vectorDiff _posCameraWorld);