ifdef::env-github[]
:tip-caption: :bulb:
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
:caution-caption: :fire:
:warning-caption: :warning:
endif::[]
:toc: left
:toclevels: 5

= Garage

This module manages garages and character vehicles.

Each owned vehicle has a saved state which can be extended with new properties.

[NOTE]
====
.Vehicles in FiveM/GTA V are entities which can unload/load/despawn themselves on multiple clients, this module try to handle it this way.
* it tracks the owned vehicles with a decorator and will try to re-own the vehicles when near them
* if multiple versions of the same owned vehicle exist at the same place, it will try to delete the others
* vehicles states are saved and it will try to re-spawn the vehicles if near their last saved position
* if a vehicle is stuck or completely lost somewhere, players can force its re-spawn at the garage by paying a fee
====

== Extension

=== User

[source,lua]
----
self.cdata.vehicles
self.cdata.rent_vehicles
self.vehicle_states

-- get owned vehicles
-- return map of model
User:getVehicles()

-- get vehicle model state table (may be async)
User:getVehicleState(model)
----

=== Server

[source,lua]
----
self.cfg
self.models -- map of all garage defined models

-- get vehicle trunk chest id by character id and model
Garage.getVehicleChestId(cid, model)
----

=== Client

[source,lua]
----
self.vehicles -- map of vehicle model => veh id (owned vehicles)
self.hash_models -- map of hash => model

-- veh: vehicle game id
-- return owner character id and model or nil if not managed by vRP
Garage:getVehicleInfo(veh)

-- spawn vehicle (will despawn first)
-- will be placed on ground properly
-- one vehicle per model allowed at the same time
--
-- state: (optional) vehicle state (client)
-- position: (optional) {x,y,z}, if not passed the vehicle will be spawned on the player (and will be put inside the vehicle)
-- rotation: (optional) quaternion {x,y,z,w}, if passed with the position, will be applied to the vehicle entity
Garage:spawnVehicle(model, state, position, rotation) 

-- return true if despawned
Garage:despawnVehicle(model)

Garage:despawnVehicles()

-- get all game vehicles
-- return list of veh
Garage:getAllVehicles()

-- return map of veh => distance
Garage:getNearestVehicles(radius)

-- return veh
Garage:getNearestVehicle(radius)

Garage:trySpawnOutVehicles()

-- try re-own vehicles
Garage:tryOwnVehicles()

-- cleanup invalid owned vehicles
Garage:cleanupVehicles()

Garage:fixNearestVehicle(radius)

Garage:replaceNearestVehicle(radius)

-- return model or nil
Garage:getNearestOwnedVehicle(radius)

-- return ok,x,y,z
Garage:getAnyOwnedVehiclePosition()

-- return x,y,z or nil
Garage:getOwnedVehiclePosition(model)

Garage:putInOwnedVehicle(model)

-- eject the ped from the vehicle
Garage:ejectVehicle()

Garage:isInVehicle()

-- return model or nil if not in owned vehicle
Garage:getInOwnedVehicleModel()

-- VEHICLE STATE

Garage:getVehicleCustomization(veh)

-- partial update per property
Garage:setVehicleCustomization(veh, custom)

Garage:getVehicleState(veh)

-- partial update per property
Garage:setVehicleState(veh, state)

-- VEHICLE COMMANDS

Garage:vc_openDoor(model, door_index)

Garage:vc_closeDoor(model, door_index)

Garage:vc_detachTrailer(model)

Garage:vc_detachTowTruck(model)

Garage:vc_detachCargobob(model)

Garage:vc_toggleEngine(model)

-- return true if locked, false if unlocked
Garage:vc_toggleLock(model)

-- TUNNEL

Garage.tunnel.spawnVehicle = Garage.spawnVehicle
Garage.tunnel.despawnVehicle = Garage.despawnVehicle
Garage.tunnel.despawnVehicles = Garage.despawnVehicles
Garage.tunnel.fixNearestVehicle = Garage.fixNearestVehicle
Garage.tunnel.replaceNearestVehicle = Garage.replaceNearestVehicle
Garage.tunnel.getNearestOwnedVehicle = Garage.getNearestOwnedVehicle
Garage.tunnel.getAnyOwnedVehiclePosition = Garage.getAnyOwnedVehiclePosition
Garage.tunnel.getOwnedVehiclePosition = Garage.getOwnedVehiclePosition
Garage.tunnel.putInOwnedVehicle = Garage.putInOwnedVehicle
Garage.tunnel.getInOwnedVehicleModel = Garage.getInOwnedVehicleModel
Garage.tunnel.trySpawnOutVehicles = Garage.trySpawnOutVehicles
Garage.tunnel.cleanupVehicles = Garage.cleanupVehicles
Garage.tunnel.tryOwnVehicles = Garage.tryOwnVehicles
Garage.tunnel.ejectVehicle = Garage.ejectVehicle
Garage.tunnel.isInVehicle = Garage.isInVehicle
Garage.tunnel.vc_openDoor = Garage.vc_openDoor
Garage.tunnel.vc_closeDoor = Garage.vc_closeDoor
Garage.tunnel.vc_detachTrailer = Garage.vc_detachTrailer
Garage.tunnel.vc_detachTowTruck = Garage.vc_detachTowTruck
Garage.tunnel.vc_detachCargobob = Garage.vc_detachCargobob
Garage.tunnel.vc_toggleEngine = Garage.vc_toggleEngine
Garage.tunnel.vc_toggleLock = Garage.vc_toggleLock
----

.Events
[horizontal]
`garageVehicleSpawn(model)`:: called when a vehicle is spawned
`garageVehicleDespawn(model)`:: called when a vehicle is despawned

== Item

=== repairkit

Used to repair vehicles, but can be used for other stuff.

== Menu

=== vehicle

Owned vehicle menu.

.data
[horizontal]
model:: vehicle model

=== garage

Garage menu.

.data
[horizontal]
type:: garage type
vehicles:: garage type table

=== garage.owned

Garage sub-menu.
Same data as `garage`.

=== garage.buy

Garage sub-menu.
Same data as `garage`.

=== garage.sell

Garage sub-menu.
Same data as `garage`.

=== garage.rent

Garage sub-menu.
Same data as `garage`.

== Permission

=== in_vehicle

`!in_vehicle`

Will do a tunnel call.

=== in_owned_vehicle

`!in_owned_vehicle[.<model>]`

Will do a tunnel call.

[horizontal]
model:: (optional) vehicle model

.Examples
[horizontal]
`!in_owned_vehicle`:: check if inside an owned vehicle
`!in_owned_vehicle.taxi`:: check if inside owned taxi model

== Vehicle state

[horizontal]
customization:: customization properties
condition:: damages properties
position, rotation:: position/rotation for persistence
locked:: doors state
