{$CLEO .s}
{$USE CLEO+}

SCRIPT_NAME 'LMINE'

//=========================================================
// LMINE - Landmine System (Autor: AlvarynGTA)
//---------------------------------------------------------
// ARGUMENTS
// --------------------------------------------------------
INT charActor, weaponMineID, modelMineID, timeReady, timeLimit, hiddenFlag, debugFlag, countLimit, mineCounterPtr
// --------------------------------------------------------
// VARIABLES
FLOAT mineX, mineY, mineZ
INT mineCounter, closestVeh, objMine, flagVehAttach, objCol, objHealth, tempN, charVictim
//=========================================================
//NOTE - missing level wanted in plant mine, and peds fearing

IF debugFlag >= 1 //DEBUG
THEN PRINT_FORMATTED "[LMINE] Arguments: CHR:%i; WPN:%i MDL:%i ARM:%ims EXP:%ims LIM:%i HID:%i" 2000 charActor weaponMineID modelMineID timeReady timeLimit countLimit hiddenFlag
END

////////////////////////////////////////////////////////////////////////////
// =========================================================
:system_landmine
// =========================================================
////////////////////////////////////////////////////////////////////////////

// =========================================================
:verify_char
// =========================================================
IF AND
    charActor > -1
    NOT DOES_CHAR_EXIST charActor
THEN GOTO @end_script
END

IF OR
    IS_CHAR_PLAYING_ANIM charActor "BOM_Plant_2Idle"
    IS_CHAR_DEAD charActor
    IS_CHAR_IN_AIR charActor
THEN GOTO @end_script
END

// =========================================================
:start_anim
// =========================================================
TIMERA = 0

IF NOT HAS_ANIMATION_LOADED "BOMBER"
THEN
    REQUEST_ANIMATION "BOMBER"
    LOAD_ALL_MODELS_NOW
END

TASK_PLAY_ANIM_NON_INTERRUPTABLE charActor "BOM_Plant_2Idle" "BOMBER" 2.5 0 0 0 0 -1
WAIT 5

// Wait for end anim in frame
:wait_anim
WAIT 5
IF AND
    TIMERA <= 500 // just frame to plant a land mine
    IS_CHAR_PLAYING_ANIM charActor "BOM_Plant_2Idle"
THEN GOTO @wait_anim
END

IF NOT DOES_CHAR_EXIST charActor
THEN GOTO @end_script
END

IF OR
    NOT IS_CHAR_PLAYING_ANIM charActor "BOM_Plant_2Idle"
    NOT IS_CURRENT_CHAR_WEAPON charActor weaponMineID
    IS_CHAR_DEAD charActor
    IS_CHAR_IN_AIR charActor
THEN
    IF debugFlag >= 1 //DEBUG
    THEN PRINT_STRING "[LMINE] Plant animation interrupted! Releasing..." 2000
    END
    GOTO @end_script
END

IF mineCounterPtr <> 0
THEN
    mineCounter = READ_MEMORY mineCounterPtr 4 0
    IF mineCounter >= countLimit
    THEN
        IF debugFlag >= 1 //DEBUG
        THEN PRINT_FORMATTED "[LMINE] Count limit reached (%i/%i)! Releasing..." 2000 mineCounter countLimit
        END

        GOTO @end_script
    ELSE
        mineCounter += 1
        WRITE_MEMORY mineCounterPtr 4 mineCounter 0
    END
END

// =========================================================
:create_mine
// =========================================================
// Create Objects
IF OR
    NOT IS_MODEL_IN_CDIMAGE modelMineID
    NOT IS_MODEL_IN_CDIMAGE #BARREL4
THEN
    PRINT_FORMATTED_NOW "[LMINE] Invalid model ID! [Landmine:%i; Barrel:%i]" 3000 modelMineID #BARREL4
    GOTO @end_script
END

// Preliminary mine placement coordinates
mineX, mineY, mineZ = GET_OFFSET_FROM_CHAR_IN_WORLD_COORDS charActor 0.0 0.7 0.0
mineZ = GET_GROUND_Z_FOR_3D_COORD mineX mineY mineZ
mineZ -= 2.5

IF NOT HAS_MODEL_LOADED modelMineID
THEN REQUEST_MODEL modelMineID
END
WHILE NOT HAS_MODEL_LOADED modelMineID
    WAIT 0
END

objMine = CREATE_OBJECT_NO_SAVE modelMineID mineX mineY mineZ 0 0 //mine object
IF DOES_OBJECT_EXIST objMine
THEN
    SET_OBJECT_SCALE objMine 1.2
    SET_OBJECT_VISIBLE objMine 0
END
MARK_MODEL_AS_NO_LONGER_NEEDED modelMineID

IF NOT HAS_MODEL_LOADED #BARREL4
THEN REQUEST_MODEL #BARREL4
END
WHILE NOT HAS_MODEL_LOADED #BARREL4
    WAIT 0
END

objCol = CREATE_OBJECT_NO_SAVE #BARREL4 mineX mineY mineZ 0 0 //invisible object with collision
IF DOES_OBJECT_EXIST objCol
THEN
    SET_OBJECT_VISIBLE objCol 0

    SET_OBJECT_RECORDS_COLLISIONS objCol 1
    SET_OBJECT_COLLISION objCol 0
    SET_OBJECT_COLLISION objMine 0

    SET_OBJECT_MASS objCol 1000.0
    SET_OBJECT_TURN_MASS objCol 1000.0
END
MARK_MODEL_AS_NO_LONGER_NEEDED #BARREL4

IF AND
    charActor > -1
    DOES_CHAR_EXIST charActor
    DOES_OBJECT_EXIST objMine
    DOES_OBJECT_EXIST objCol
THEN
    // --- Reduce ammo if there is no active infinite ammo cheat or 100% game progress ---
    IF AND
        NOT IS_CHEAT_ACTIVE 72 // CLEO+
        $GAME_COMPLETE == 0
    THEN ADD_AMMO_TO_CHAR charActor weaponMineID -1
    END

    ATTACH_OBJECT_TO_OBJECT objCol objMine 0.0 0.0 -0.775 0.0 0.0 0.0

    GOSUB @check_vehicle_or_ground

    GOTO @mine_ready
ELSE GOTO @clean
END

// =========================================================
:check_vehicle_or_ground
// =========================================================
WAIT 10
closestVeh, tempN = STORE_CLOSEST_ENTITIES charActor
tempN = -1

flagVehAttach = 0
IF AND
    DOES_VEHICLE_EXIST closestVeh
    NOT IS_CAR_DEAD closestVeh
THEN
    IF IS_CHAR_TOUCHING_VEHICLE charActor closestVeh
    THEN
        IF debugFlag >= 1 //DEBUG
        THEN PRINT_FORMATTED_NOW "[LMINE] Landmine (%i/%i) attached to vehicle %i." 2000 mineCounter countLimit closestVeh
        END

        ATTACH_OBJECT_TO_CAR objMine closestVeh 0.0 0.0 0.0 0.0 0.0 0.0
        flagVehAttach = 1
        RETURN
    END
END

PLACE_GROUND(charActor, objMine, debugFlag, mineCounter, countLimit)
RETURN

// =========================================================
:mine_ready
// =========================================================
SET_OBJECT_VISIBLE objMine 1
REPORT_MISSION_AUDIO_EVENT_AT_OBJECT objMine 1002 // Planting sound

IF flagVehAttach == 0
THEN SET_OBJECT_COLLISION objCol 1
END

TIMERA = 0
WHILE timeReady >= TIMERA // Time delay (default: 2 seconds)
    WAIT 0
    IF NOT IS_PLAYER_CONTROL_ON 0
    THEN GOTO @clean
    END

    IF flagVehAttach == 0
    THEN
        objHealth = GET_OBJECT_HEALTH objCol
        IF objHealth <= 0
        THEN GOTO @check_loop
        END
    ELSE
        IF IS_CAR_DEAD closestVeh
        THEN BREAK
        END
    END
END

IF flagVehAttach == 0
THEN ATTACH_OBJECT_TO_OBJECT objCol objMine 0.0 0.0 -0.4 0.0 0.0 0.0
ELSE SET_OBJECT_COLLISION objCol 1
END
IF hiddenFlag == 1
THEN SET_OBJECT_VISIBLE objMine 0
END

TIMERA = 0 //Timer limit
GOTO @check_loop
// =========================================================
:check_loop
// =========================================================

IF OR
    NOT DOES_OBJECT_EXIST objCol
    NOT DOES_OBJECT_EXIST objMine
THEN
    IF debugFlag >= 1 //DEBUG
    THEN PRINT_STRING "[LMINE] Landmine object disappeared! Cleaning..." 2000
    END
    GOTO @clean
END

IF TIMERA >= timeLimit // Time limit (default: 10 minutes)
THEN
    IF debugFlag >= 1 //DEBUG
    THEN PRINT_STRING "[LMINE] Landmine expired! Cleaning..." 2000
    END
    GOTO @clean
END

IF flagVehAttach == 1
THEN
    IF NOT DOES_VEHICLE_EXIST closestVeh
    THEN
        IF debugFlag >= 1 //DEBUG
        THEN PRINT_STRING "[LMINE] Attached vehicle disappeared! Cleaning..." 2000
        END
        GOTO @clean
    END
END

IF NOT IS_PLAYER_CONTROL_ON 0
THEN
    IF debugFlag >= 1 //DEBUG
    THEN PRINT_STRING "[LMINE] Player not playing! Cleaning..." 2000
    END
    GOTO @clean
END

IF NOT IS_PLAYER_PLAYING 0
THEN
    IF DOES_OBJECT_EXIST objCol
    THEN MARK_OBJECT_AS_NO_LONGER_NEEDED objCol //The object will cease to exist when the game no longer needs it, or when it moves away from it or respawns due to being wasted/busted.
    END
    IF DOES_OBJECT_EXIST objMine
    THEN MARK_OBJECT_AS_NO_LONGER_NEEDED objMine
    END
END

//Check for explosion
objHealth = GET_OBJECT_HEALTH objCol
IF OR
    objHealth <= 0
    HAS_OBJECT_COLLIDED_WITH_ANYTHING objCol
THEN
    IF debugFlag >= 1 //DEBUG
    THEN PRINT_STRING "[LMINE] Landmine exploded! Cleaning..." 2000
    END

    DETACH_OBJECT objCol 0.0 0.0 0.0 0

    mineX, mineY, mineZ = GET_OFFSET_FROM_OBJECT_IN_WORLD_COORDS objMine 0.0 0.0 0.0
    ADD_EXPLOSION mineX mineY mineZ 5

    GOTO @clean
END

WAIT 25
GOTO @check_loop

// ==================================================
:clean
// ==================================================
IF mineCounterPtr <> 0
THEN
    mineCounter = READ_MEMORY mineCounterPtr 4 0
    IF mineCounter > 0
    THEN
        mineCounter -= 1
        WRITE_MEMORY mineCounterPtr 4 mineCounter 0
    END
END

IF DOES_OBJECT_EXIST objCol
THEN DELETE_OBJECT objCol
END
objCol = -1

IF DOES_OBJECT_EXIST objMine
THEN DELETE_OBJECT objMine
END
objMine = -1

// ==================================================
:end_script
// ==================================================
TERMINATE_THIS_CUSTOM_SCRIPT

// ===================================================================================================
FUNCTION PLACE_GROUND(charActor:INT, objMine:INT, debugFlag:INT, mineCounter:INT, countLimit:INT)
    FLOAT Nx, Ny, Nz, Nl, tempN
    FLOAT yaw, roll, pitch, cosYaw, sinYaw, Nxn, Nyn
    FLOAT mineX, mineY, mineZ
    IF AND
        DOES_OBJECT_EXIST objMine
        DOES_CHAR_EXIST charActor
    THEN
        mineX, mineY, mineZ = GET_OFFSET_FROM_CHAR_IN_WORLD_COORDS charActor 0.0 0.7 0.0
        //------------------------------------
        // Slopes (float)
        //------------------------------------
        // Point Z in X+ (float)
        tempN = mineX
        tempN += 0.1
        Nx = GET_GROUND_Z_FOR_3D_COORD tempN mineY mineZ
        // Point Z in Y+ (float)
        tempN = mineY
        tempN += 0.1
        Ny = GET_GROUND_Z_FOR_3D_COORD mineX tempN mineZ
        // Point Z in XY (float)
        tempN = GET_GROUND_Z_FOR_3D_COORD mineX mineY mineZ

        // deltaZx
        Nx -= tempN
        Nx /= 0.1
        // deltaZy
        Ny -= tempN
        Ny /= 0.1

        //------------------------------------
        // Plane Normal
        //------------------------------------
        Nx = Nx
        Nx *= -1.0
        Ny = Ny
        Ny *= -1.0
        Nz = 1.0

        // Normalize vector (float)
        Nl = Nx
        Nl *= Nx
        tempN = Ny
        tempN *= Ny
        Nl += tempN
        tempN = Nz
        tempN *= Nz
        Nl += tempN

        Nl = SQRT Nl
        IF Nl > 0.0
        THEN
            Nx /= Nl
            Ny /= Nl
            Nz /= Nl
        END
        //------------------------------------
        // Rotate the normal by yaw (float)
        //------------------------------------
        yaw = GET_CHAR_HEADING charActor
        cosYaw = COS yaw
        sinYaw = SIN yaw

        // Nx'
        Nxn = Nx
        Nxn *= cosYaw
        tempN = Ny
        tempN *= sinYaw
        Nxn += tempN
        Nxn *= -1.0
        // Ny'
        Nyn = Nx
        Nyn *= sinYaw
        tempN = Ny
        tempN *= cosYaw
        Nyn -= tempN
        Nyn *= -1.0
        // Nz not changes
        Nz = Nz

        //------------------------------------
        // Extract angles
        //------------------------------------
        // roll = atan2(Ny', Nz)
        roll = GET_ANGLE_FROM_TWO_COORDS 0.0 0.0 Nyn Nz    // CLEO+
        // pitch = atan2(Nx', Nz)
        pitch = GET_ANGLE_FROM_TWO_COORDS 0.0 0.0 Nxn Nz   // CLEO+

        mineZ = GET_GROUND_Z_FOR_3D_COORD mineX mineY mineZ
        SET_OBJECT_COORDINATES objMine mineX mineY mineZ
        SET_OBJECT_ROTATION objMine roll pitch yaw

        IF debugFlag >= 1 //DEBUG
        THEN PRINT_FORMATTED_NOW "[LMINE] Landmine (%i/%i) placed in ground. [Ang(%.2f; %.2f; %.2f); Nrm(%.2f; %.2f; %.2f)]" 2000 mineCounter countLimit roll pitch yaw Nxn Nyn Nz
        END
    END
END
// ===================================================================================================